From 8735f2d409cd094b5169bacdfe9c6d10fa94380e Mon Sep 17 00:00:00 2001 From: Asuro Date: Thu, 25 Feb 2021 21:36:29 +0100 Subject: [PATCH] hotload shader + directional light --- config/input.toml | 6 ++++-- shaders/triangle.frag | 5 ++++- shaders/triangle.frag.spv | Bin 3472 -> 3608 bytes shaders/triangle.vert | 1 + shaders/triangle.vert.spv | Bin 4372 -> 4436 bytes src/game/mod.rs | 21 ++++++++++++--------- src/vulkan/mod.rs | 11 +++++++++-- src/vulkan/pipelines.rs | 36 +++++++++++++++++++++++++----------- 8 files changed, 55 insertions(+), 25 deletions(-) diff --git a/config/input.toml b/config/input.toml index c2867d4..1b60ca1 100644 --- a/config/input.toml +++ b/config/input.toml @@ -1,3 +1,6 @@ +# Scan codes are in decimal +# See here: https://www.millisecond.com/support/docs/v6/html/language/scancodes.htm + [[button]] name = "quit" scan_code = 1 @@ -8,8 +11,7 @@ scan_code = 59 [[button]] name = "reload_shaders" -scan_code = 19 -ctrl = true +scan_code = 63 [[button]] name = "print_framerate" diff --git a/shaders/triangle.frag b/shaders/triangle.frag index 19b75d0..2290422 100644 --- a/shaders/triangle.frag +++ b/shaders/triangle.frag @@ -6,6 +6,7 @@ layout(binding = 0) uniform ObjectUniformData { mat4 projection; float time; vec3 light_position; + vec3 light_directional_rotation; vec3 camera_position; } ubo; @@ -23,7 +24,9 @@ void main() { vec3 normal_cam_u = texture(normal_tex, tex_coords).rgb; normal_cam_u = normal_cam_u * 2.0 - 1.0; normal_cam_u = normalize(tbn * normal_cam_u); - vec3 light_direction_cam_u = normalize(ubo.light_position - position_wld); + + // vec3 light_direction_cam_u = normalize(ubo.light_position - position_wld); + vec3 light_direction_cam_u = normalize(vec3(sin(ubo.time), 1.0, cos(ubo.time))); float ambient_strength = 0.1; vec3 light_color = vec3(1.0, 1.0, 1.0); diff --git a/shaders/triangle.frag.spv b/shaders/triangle.frag.spv index 9b5530c112a5fa41d24d7ea91ed49e739e388f1c..8b419f3f469b208c5cd7b64957072ae740c2fcbe 100644 GIT binary patch literal 3608 zcmZQ(Qf6mhU}WH8;9#g`fB-=TCI&_Z1_o{hHZbk(6YQf`T#}+^Vrl?V!N3=CkLo0ypgk`QEIV31>AUpOlrFTvE)yz{(q?eTehWIaed7uXz7 z*h1vsZcEIGFUl`TgsFp=!OFnEkeryCT9gXT70nzr z1}7vrgdR2qHwFfV;)2xV(wxMi__D;D(o~RHYz*!U3=E*KLj*lU9F%ro9*Hl{NrAYN zogspOfuSfhEhjY@DYh6ude|9ak?lb8AjmHu1K{>U9R~6@D1GLamc&Da7(im6#02vn zC=r3gKxr77-oUPLXJ7%RH6@V47#J8}d_@KZaM}j(LFo>Z4?s#ld=MLiLGkUuzygk6 zkQ^xPJdn~7C_RG2k;OpyMu35V0j3X>zL52S_#k}_U^S3*2@*r-gNT9BA4pvTk~)xk zKw=Y+#6al|B(?xa3}hcjYy;T8%wYF}%meuil+KXD0>lS}1;`&Dc~E?U{0>tO3U?46 zCJzd8Wc?sMNI%FAApM~52dM|~g&CN@VXO!)Ng&}Z#=y+L#=yX!z`(#D&cMO|@;8VN z@|yw!3j+rO16T|sF3G^jzy;2~ppp;d0t5z`58_EPFf(v7Fo4y8^z(oO!DS)?gEa#S z1BeeQYe2#v`}m>ef&2$j4~i?0Ss-zcdJrF!9zbFs^}b9Ap>+g9D5& z3FbH0OE9o7$Uxl>^N%b8#O)w)koh1!EPO!fRTvl;Kz4x4mt)`n#}!BnghAl~3I`Yl zxmOLEZb4-o$UG1q6o(-Hh%&G+Xh6djvxph;IyaFNhCP528&O z7#Pl;Ib*BCzy^*Ba|Q+mkRM?frp^}ZZw3YsA7qaQln*l36KW60A36-|U_bgYFff4h zz%a->klJ8q7=io=@)L*;N{28%fZUV>HoL(Iq&^E=H$lP;q#ncvrBhItgZQ902c=7p z77!m~9w=Rc%rj$P1*b_+c!T6YdVVl4F@W+6NG&M+f$A)nTR?nJUV`yK;RPz6VSJE0 zs7yxYgUVwVAEX{s4#W5$^`NpB#s|rR%3K&9Bo8WUk@=vq6vhXs2bG^NK1e;N%mndm z8Cbx1fscU!T;_rJpmZ(7zyPjW!x>n?@gTy$zyMMM68C4|0LQT?0|Ns{9E3sP0tzco znzCbH2G`*rd60P^d&C$Rz+!#i+KPcef`NenBnHYC0njufg_dTTp=zZWAnHN#Ftb5o zAhSVvL>}5E0r5e0fyxO`d`yJu2bDD-H6U>ws9m7)2;^Q@1_lO@Jj`5>xFZ8A11QaF zGcbVbSWsR7nGH%)It-w+%fJ9K2gKKfrbAG90g{91)x)A!pMik^Bo5OHYH)$v018)- z94s6R85kHq=7Q2XNDW9m$X`ZKyFhLRsR6kel+HlnAT}tCf$|}U4N702JP32QB?AKk zNFKxonPtVmzyMMMiw|oC1_qEANF7K&C_RG2VCwCl@dxAEGcbVLR#U*O2?hpG-2_qt z66axH2bXz{Q1^oJIVk@^)G&kF7$7;2S)edU;xR1 z%A7!`zx){(7(n8n^bHdWfQo_Q4ki`|6$7PzSUd)S+LjCq3?TI&d60WR{tIP*w4Y(= zJB)#W0i+fr4ss(%O*qtzAb*17L4F10agaF7oJeRK)I;mUCjVY{29O$%ILK^J9D>@+pzr|2 zHAo&5-!QpksJ)>43sMIvmqGS|$|R5+$R3axpoTLjK4JVc1_p4uuN4{>=?n}EAT=Oy zkQ$JmK#g4Fbeze+zyJ~hsRh{qD(66AF!ebM3=E*O4ddrBFo4^&jnJ|J)X4#<0g1!Z z9~@CfdOPDNDdSR Rpn47@_LqT?!GeL20RZW0D_;Nr delta 1867 zcmbOsGeMe{nMs+Qfq{{Mi-CioVj{0Uryc_XLk0r_L;1#3Q$}`n22}2M?mEn{ccT0|Ns{6%0!v znHdjO+~5RKozB3(0CKM|0|NudO&~rfMnGa9J`V!}1IX(jEg(L~&E=CF+1=|wt~G|b z7$n2Nz`y{Cc#scZd~+muka|$`Bg;FY$%7&vS>6pv9%Ozff-lAZGB64uzyMN^xLKCN zn6VyYh7Q=r3=FmmEZ~sSXJ7y)+h%Y=WneI1U|;~L0g3ZKL)Q=*Lm+p6>fq?;}AEX{64{{JV{)5osJD7oi0i+lt4ss zlRt6`*MpKUOlu4S0|Ur9SPaK9Ffc?jFff3`LB@e1E)MEMPz;0QL9q;zOMuErF)%QI z)PXWK$R<#(0Lg*u0hy7+z`y|VA~IQ#NoIatVorQfen}#T$-uzIzz$Z& xy1AB7ok`Gxffd4KU|>*YU|`s=c_H&gMqv)HATI+00|>J*Ffj0KPGsH84FFOA6zl*1 delta 36 scmcbjG(~Ac86!J813v=;1Iy;6jOt9AA26?DWMrS*&nmfj4eJVS0JNbB8vp>, + pub paused: bool, } impl Game for TestGame { @@ -48,7 +50,7 @@ impl Game for TestGame { } if self.input.button_just_pressed("reload_shaders") { - renderer.game_data.recreate_pipeline = true; + renderer.recreate_swapchain = true; } if self.input.button_just_pressed("quicksave") { @@ -65,17 +67,15 @@ impl Game for TestGame { } if self.input.button_just_pressed("test") { - if renderer.render_config.msaa_samples > 0 { - renderer.render_config.msaa_samples = 0; - } else { - renderer.render_config.msaa_samples = 8; - } - renderer.recreate_swapchain = true; + self.paused = !self.paused; } // Custom game object stuff let light_pos = self.player.camera.position * -1.0; - self.player.update(frame_time, &self.input, renderer); + if !self.paused { + self.player.update(frame_time, &self.input, renderer); + } + self.game_objects[1].get_game_object_mut(renderer).unwrap().rotation = Quaternion::from_angle_y(Deg(time * -20.)).normalize(); // End frame self.last_time = time; @@ -86,9 +86,11 @@ impl Game for TestGame { projection: self.player.camera.proj.into(), time, light_position: light_pos.into(), + light_directional_rotation: [45.0, 45.0, 0.0], camera_position: self.player.camera.position.into(), _dummy0: [0; 12], _dummy1: [0; 4], + _dummy2: [0; 4], } } } @@ -103,6 +105,7 @@ impl TestGame { texture_index_counter: 0, last_time: 0.0, components: vec![], + paused: false, } } diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 38933ff..095a060 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -250,7 +250,7 @@ impl VulkanRenderer { let pipelines: Vec> = vec![ Box::new(DefaultShader::new(device.clone(), render_pass.clone())), - // Box::new(LineShader::new(device.clone(), render_pass.clone(), line_vertex_buffer.clone())), + Box::new(LineShader::new(device.clone(), render_pass.clone(), line_vertex_buffer.clone())), ]; // Dynamic viewports allow us to recreate just the viewport when the window is resized @@ -269,9 +269,11 @@ impl VulkanRenderer { projection: Matrix4::identity().into(), time: 0.0, light_position: [0.0, 0.0, 0.0], + light_directional_rotation: [0.0, 0.0, 0.0], camera_position: [0.0, 0.0, 0.0], _dummy0: [0; 12], _dummy1: [0; 4], + _dummy2: [0; 4], }; for _ in 0..swapchain.num_images() { @@ -347,7 +349,7 @@ impl VulkanRenderer { self.pipelines = vec![ Box::new(DefaultShader::new(self.device.clone(), self.render_pass.clone())), - // Box::new(LineShader::new(self.device.clone(), self.render_pass.clone(), self.line_vertex_buffer.clone())), + Box::new(LineShader::new(self.device.clone(), self.render_pass.clone(), self.line_vertex_buffer.clone())), ]; self.swapchain = new_swapchain; @@ -473,6 +475,11 @@ impl VulkanRenderer { pub fn start_event_loop(mut renderer: VulkanRenderer, mut game: Box, event_loop: EventLoop<()>) { event_loop.run(move |event, _, control_flow| { game.on_window_event(&event); + + if renderer.game_data.shutdown { + *control_flow = ControlFlow::Exit; + } + match event { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { *control_flow = ControlFlow::Exit; diff --git a/src/vulkan/pipelines.rs b/src/vulkan/pipelines.rs index 361bb8d..2fd00c1 100644 --- a/src/vulkan/pipelines.rs +++ b/src/vulkan/pipelines.rs @@ -1,12 +1,13 @@ use std::{convert::TryInto, io::{Read, Write}, sync::Arc}; -use vulkano::{command_buffer::AutoCommandBufferBuilder, descriptor::{descriptor::ShaderStages, descriptor_set::PersistentDescriptorSet}}; +use vulkano::{command_buffer::AutoCommandBufferBuilder, descriptor::{descriptor::ShaderStages, descriptor_set::PersistentDescriptorSet}, pipeline::shader::ShaderModule}; use vulkano::command_buffer::DynamicState; use vulkano::device::Device; use vulkano::framebuffer::RenderPassAbstract; use vulkano::framebuffer::Subpass; use vulkano::pipeline::GraphicsPipeline; use vulkano::pipeline::GraphicsPipelineAbstract; +use vulkano::pipeline::shader::GraphicsShaderType; use crate::GameObject; use crate::vulkan::{LinePoint, Vertex}; @@ -42,6 +43,16 @@ pub struct DefaultShader { pipeline: GP, } +fn shader_module_from_file(device: Arc, path: &str) -> Arc { + let mut file = std::fs::File::open(path).unwrap(); + let mut buffer = vec![]; + file.read_to_end(&mut buffer).unwrap(); + let words: Vec = buffer.chunks_exact(4).map(|c| u32::from_ne_bytes(c.try_into().unwrap())).collect(); + unsafe { + ShaderModule::from_words(device.clone(), &words).unwrap() + } +} + impl DefaultShader { pub fn new(device: Arc, render_pass: RP) -> Self { DefaultShader { @@ -51,7 +62,6 @@ impl DefaultShader { fn create_pipeline(device: Arc, render_pass: RP) -> GP { let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap(); - let vertex_shader = vs::Shader::load(device.clone()).unwrap(); #[cfg(debug_assertions)] { @@ -65,22 +75,26 @@ impl DefaultShader { } unsafe { - let mut fs_file = std::fs::File::open("shaders/triangle.frag.spv").unwrap(); - let mut fs_buf = vec![]; - fs_file.read_to_end(&mut fs_buf).unwrap(); - let fs_words: Vec = fs_buf.chunks_exact(4).map(|c| u32::from_ne_bytes(c.try_into().unwrap())).collect(); - let fs_module = vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &fs_words).unwrap(); + static ENTRY_NAME: [u8; 5usize] = [109u8, 97u8, 105u8, 110u8, 0]; + let entry_name_c = std::ffi::CStr::from_ptr(ENTRY_NAME.as_ptr() as *const _); + + let fs_module = shader_module_from_file(device.clone(), "shaders/triangle.frag.spv"); let fs_layout = fs::Layout(ShaderStages { fragment: true, ..ShaderStages::none() }); - static FS_NAME: [u8; 5usize] = [109u8, 97u8, 105u8, 110u8, 0]; - let fs_name_c = std::ffi::CStr::from_ptr(FS_NAME.as_ptr() as *const _); - let fs_entry = fs_module.graphics_entry_point(fs_name_c, fs::MainInput, fs::MainOutput, fs_layout, vulkano::pipeline::shader::GraphicsShaderType::Fragment); + let fs_entry = fs_module.graphics_entry_point(entry_name_c, fs::MainInput, fs::MainOutput, fs_layout, GraphicsShaderType::Fragment); + + let vs_module = shader_module_from_file(device.clone(), "shaders/triangle.vert.spv"); + let vs_layout = vs::Layout(ShaderStages { + vertex: true, + ..ShaderStages::none() + }); + let vs_entry = vs_module.graphics_entry_point(entry_name_c, vs::MainInput, vs::MainOutput, vs_layout, GraphicsShaderType::Vertex); Arc::new(GraphicsPipeline::start() .vertex_input_single_buffer::() - .vertex_shader(vertex_shader.main_entry_point(), ()) + .vertex_shader(vs_entry, ()) .triangle_list() .viewports_dynamic_scissors_irrelevant(1) .depth_stencil_simple_depth()