From 48418b88cb12f6baea3766dea0ebc1e6dc06c2b7 Mon Sep 17 00:00:00 2001 From: Till Date: Sat, 27 Jul 2019 00:13:20 +0200 Subject: [PATCH] depth buffer --- .idea/inspectionProfiles/Project_Default.xml | 6 ++ shaders/line.vert | 8 +- src/main.rs | 19 +++-- src/vulkan.rs | 83 ++++++++++++-------- 4 files changed, 73 insertions(+), 43 deletions(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..98c34ff --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/shaders/line.vert b/shaders/line.vert index 0d82f83..d0d7709 100644 --- a/shaders/line.vert +++ b/shaders/line.vert @@ -2,6 +2,12 @@ layout(location = 0) in vec3 position; +layout(push_constant) uniform LinePushConstants { + mat4 model; + mat4 view; + mat4 projection; +} push; + void main() { - gl_Position = vec4(position, 1.0); + gl_Position = push.projection * push.view * push.model * vec4(position, 1.0); } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 4fbe008..05890ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ use std::iter::FromIterator; use cgmath::{Matrix4, Rad, Point3, Vector3, Deg}; mod vulkan; -use vulkan::vs::ty::PushConstants; const PRINT_KEYBOARD_INPUT: bool = false; @@ -24,7 +23,7 @@ impl Game for TestGame { let mut proj = cgmath::perspective( Rad::from(Deg(45.0)), - game_data.aspect_ratio, + game_data.dimensions[0] as f32 / game_data.dimensions[1] as f32, 0.1, 10.0 ); @@ -34,9 +33,11 @@ impl Game for TestGame { game_data.push_constants.model = model.into(); game_data.push_constants.view = view.into(); game_data.push_constants.projection = proj.into(); + game_data.line_push_constants.view = view.into(); + game_data.line_push_constants.projection = proj.into(); } - fn on_window_event(self: &mut Self, game_data: &mut GameData, event: &Event) -> bool { + fn on_window_event(self: &mut Self, game_data: &mut GameData, event: &Event) { match event { Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input }, .. } => { if PRINT_KEYBOARD_INPUT { @@ -61,7 +62,6 @@ impl Game for TestGame { } _ => {} } - return false; } } @@ -69,10 +69,13 @@ fn main() { let mut game = TestGame {}; vulkan::init( "models/box.obj", - vec![ - LinePoint { position: [-0.9, 1., 0.] }, - LinePoint { position: [0.9, 0., 0.] }, - ], + (-10..10) + .flat_map(|it| vec![ + LinePoint { position: [it as f32, -10., 0.] }, + LinePoint { position: [it as f32, 10., 0.] }, + LinePoint { position: [-10., it as f32, 0.] }, + LinePoint { position: [10., it as f32, 0.] }, + ]).collect(), &mut game ); } \ No newline at end of file diff --git a/src/vulkan.rs b/src/vulkan.rs index d833820..4adf066 100644 --- a/src/vulkan.rs +++ b/src/vulkan.rs @@ -2,7 +2,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer}; use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; use vulkano::device::{Device, DeviceExtensions}; use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract}; -use vulkano::image::{SwapchainImage, AttachmentImage}; +use vulkano::image::{SwapchainImage, AttachmentImage, ImageUsage}; use vulkano::instance::{Instance, PhysicalDevice, ApplicationInfo, Version, InstanceExtensions}; use vulkano::pipeline::{GraphicsPipeline}; use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule}; @@ -13,7 +13,8 @@ use vulkano::sync::{GpuFuture, FlushError}; use vulkano::sync; use vulkano::pipeline::vertex::{SingleBufferDefinition}; use vulkano::descriptor::PipelineLayoutAbstract; -use vulkano::format::Format; +use vulkano::format::{Format, ClearValue}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; use vulkano_win::VkSurfaceBuild; @@ -30,10 +31,11 @@ use shade_runner; use shade_runner::{CompiledShaders, Entry}; use shaderc; -use crate::PushConstants; -use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vs::ty::PushConstants; +use line_vs::ty::LinePushConstants; use tobj::{load_obj}; +use vulkano::pipeline::depth_stencil::DepthStencil; const VALIDATION_LAYERS: &[&str] = &[ "VK_LAYER_LUNARG_standard_validation" @@ -62,20 +64,19 @@ pub trait Game { fn update(self: &mut Self, game_data: &mut GameData); /// Returns true if event should be ignored by the vulkan handler - fn on_window_event(self: &mut Self, game_data: &mut GameData, event: &Event) -> bool; + fn on_window_event(self: &mut Self, game_data: &mut GameData, event: &Event); } pub struct GameData { pub start_time: SystemTime, pub line_vertices: Vec, pub push_constants: PushConstants, + pub line_push_constants: LinePushConstants, pub recreate_pipeline: bool, - pub aspect_ratio: f32, + pub dimensions: [u32; 2], pub shutdown: bool, } - - pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) { let mut data = GameData { push_constants: PushConstants { @@ -85,11 +86,16 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) view: Matrix4::identity().into(), projection: Matrix4::identity().into(), }, + line_push_constants: LinePushConstants { + model: Matrix4::identity().into(), + view: Matrix4::identity().into(), + projection: Matrix4::identity().into(), + }, start_time: SystemTime::now(), recreate_pipeline: false, - aspect_ratio: 1.0, shutdown: false, line_vertices, + dimensions: [0, 0] }; if ENABLE_VALIDATION_LAYERS { @@ -190,7 +196,7 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) // These drivers will allow anything but the only sensible value is the window dimensions. // // Because for both of these cases, the swapchain needs to be the window dimensions, we just use that. - let initial_dimensions = if let Some(dimensions) = window.get_inner_size() { + data.dimensions = if let Some(dimensions) = window.get_inner_size() { let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); [dimensions.0, dimensions.1] } else { @@ -198,7 +204,7 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) }; Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, - initial_dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha, + data.dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha, PresentMode::Fifo, true, None).unwrap() }; @@ -221,6 +227,8 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) store: DontCare, format: Format::D16Unorm, samples: 1, + initial_layout: ImageLayout::Undefined, + final_layout: ImageLayout::DepthStencilAttachmentOptimal, } }, pass: { @@ -231,8 +239,8 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap(); - let mut pipeline = create_pipeline(device.clone(), sub_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false).unwrap(); - let line_pipeline = create_pipeline(device.clone(), sub_pass.clone(), "shaders/line.vert", "shaders/line.frag", true).unwrap(); + let mut pipeline = create_pipeline(device.clone(), sub_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false).unwrap(); + let line_pipeline = create_pipeline(device.clone(), sub_pass.clone(), "shaders/line.vert", "shaders/line.frag", true ).unwrap(); // Dynamic viewports allow us to recreate just the viewport when the window is resized // Otherwise we would have to recreate the whole pipeline. @@ -240,7 +248,7 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) // The render pass we created above only describes the layout of our framebuffers. Before we // can draw we also need to create the actual framebuffers. - let mut framebuffers = window_size_dependent_setup(device.clone(), &images, render_pass.clone(), &mut dynamic_state, &mut data.aspect_ratio); + let mut framebuffers = window_size_dependent_setup(device.clone(), &images, render_pass.clone(), &mut dynamic_state); let mut recreate_swapchain = false; @@ -278,7 +286,8 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) swapchain = new_swapchain; // Because framebuffers contains an Arc on the old swapchain, we need to // recreate framebuffers as well. - framebuffers = window_size_dependent_setup(device.clone(), &new_images, render_pass.clone(), &mut dynamic_state, &mut data.aspect_ratio); + framebuffers = window_size_dependent_setup(device.clone(), &new_images, render_pass.clone(), &mut dynamic_state); + data.dimensions = images[0].dimensions(); recreate_swapchain = false; } @@ -311,22 +320,15 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) game.update(&mut data); - // Specify the color to clear the framebuffer with i.e. blue - let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into(), 1f32.into()); - let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap() // Before we can draw, we have to *enter a render pass*. There are two methods to do // this: `draw_inline` and `draw_secondary`. The latter is a bit more advanced and is // not covered here. - // - // The third parameter builds the list of values to clear the attachments with. The API - // is similar to the list of attachments when building the framebuffers, except that - // only the attachments that use `load: Clear` appear in the list. - .begin_render_pass(framebuffers[image_num].clone(), false, clear_values).unwrap() + .begin_render_pass(framebuffers[image_num].clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into(), ClearValue::Depth(1.0)]).unwrap() // We are now inside the first subpass of the render pass. We add a draw command. .draw_indexed(pipeline.clone(), &dynamic_state, mesh_vertex_buffer.clone(), mesh_index_buffer.clone(), (), data.push_constants.clone()).unwrap() - .draw(line_pipeline.clone(), &dynamic_state, line_vertex_buffer.clone(), (), ()).unwrap() + .draw(line_pipeline.clone(), &dynamic_state, line_vertex_buffer.clone(), (), data.line_push_constants.clone()).unwrap() // We leave the render pass by calling `draw_end`. Note that if we had multiple // subpasses we could have called `next_inline` (or `next_secondary`) to jump to the @@ -363,12 +365,11 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) // wait would happen. Blocking may be the desired behavior, but if you don't want to // block you should spawn a separate thread dedicated to submissions. events_loop.poll_events(|ev| { - if !game.on_window_event(&mut data, &ev) { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => data.shutdown = true, - Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true, - _ => {} - } + game.on_window_event(&mut data, &ev); + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => data.shutdown = true, + Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true, + _ => {} } }); if data.shutdown { return; } @@ -376,9 +377,8 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) } /// This method is called once during initialization, then again whenever the window is resized -fn window_size_dependent_setup(device: Arc, images: &[Arc>], render_pass: Arc, dynamic_state: &mut DynamicState, aspect_ratio: &mut f32) -> Vec> { +fn window_size_dependent_setup(device: Arc, images: &[Arc>], render_pass: Arc, dynamic_state: &mut DynamicState) -> Vec> { let dimensions = images[0].dimensions(); - *aspect_ratio = dimensions[0] as f32 / dimensions[1] as f32; let viewport = Viewport { origin: [0.0, 0.0], @@ -387,12 +387,12 @@ fn window_size_dependent_setup(device: Arc, images: &[Arc }).collect::>() @@ -405,6 +405,13 @@ pub mod vs { } } +pub mod line_vs { + vulkano_shaders::shader!{ + ty: "vertex", + path: "shaders/line.vert" + } +} + pub mod fs { vulkano_shaders::shader! { ty: "fragment", @@ -412,6 +419,13 @@ pub mod fs { } } +pub mod line_fs { + vulkano_shaders::shader! { + ty: "fragment", + path: "shaders/line.frag" + } +} + fn create_pipeline(device: Arc, sub_pass: Subpass>, vertex_shader_path: &str, fragment_shader_path: &str, is_line: bool) -> Option, Box, Arc>>> { if let Some((shader, shader_data)) = read_shader(vertex_shader_path, fragment_shader_path) { let vertex_shader_entry; @@ -443,6 +457,7 @@ fn create_pipeline( .vertex_shader(vertex_shader_entry.clone(), ()) .line_list() .viewports_dynamic_scissors_irrelevant(1) + .depth_stencil(DepthStencil::simple_depth_test()) .fragment_shader(fragment_shader_entry.clone(), ()) .render_pass(sub_pass.clone()) .build(device.clone())