diff --git a/src/main.rs b/src/main.rs index 18c3665..ef0c8f6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,5 @@ -use eruption::init; +mod vulkan; fn main() { - init(); - - + vulkan::init(); } \ No newline at end of file diff --git a/src/shader/composit.rs b/src/shader/composit.rs deleted file mode 100644 index 6b34326..0000000 --- a/src/shader/composit.rs +++ /dev/null @@ -1,25 +0,0 @@ -pub(crate) mod vs { - vulkano_shaders::shader! { - ty: "vertex", - src: r" - #version 450 - layout(location = 0) in vec2 position; - void main() { - gl_Position = vec4(position, 0.0, 1.0); - } - ", - } -} - -pub(crate) mod fs { - vulkano_shaders::shader! { - ty: "fragment", - src: r" - #version 450 - layout(location = 0) out vec4 f_color; - void main() { - f_color = vec4(1.0, 0.0, 0.0, 1.0); - } - ", - } -} \ No newline at end of file diff --git a/src/shader/mod.rs b/src/shader/mod.rs index b6c03fc..2aede5f 100644 --- a/src/shader/mod.rs +++ b/src/shader/mod.rs @@ -1,4 +1,4 @@ -mod composit; +mod composite; use std::sync::Arc; use vulkano::device::Device; @@ -11,8 +11,8 @@ use crate::Vertex2d; pub fn create_program(render_pass: &Arc, device: &Arc) -> Arc { - let vs = composit::vs::load(device.clone()).unwrap(); - let fs = composit::fs::load(device.clone()).unwrap(); + let vs = composite::vs::load(device.clone()).unwrap(); + let fs = composite::fs::load(device.clone()).unwrap(); // Before we draw we have to create what is called a pipeline. This is similar to an OpenGL // program, but much more specific. diff --git a/src/shader/src/composite.frag b/src/shader/src/composite.frag new file mode 100644 index 0000000..826a409 --- /dev/null +++ b/src/shader/src/composite.frag @@ -0,0 +1,16 @@ +#version 450 + +#include + +layout(location = 0) in vec2 texture_coordinate; + +layout(location = 0) out vec4 frag_color; + +void main() { + + vec2 uv = texture_coordinate; + + vec3 color = trace_path(uv); + + frag_color = vec4(color, 1.0); +} \ No newline at end of file diff --git a/src/shader/src/composite.vert b/src/shader/src/composite.vert new file mode 100644 index 0000000..2325a61 --- /dev/null +++ b/src/shader/src/composite.vert @@ -0,0 +1,11 @@ +#version 450 + +layout(location = 0) in vec2 position; +layout(location = 1) in vec2 texture; + +layout(location = 0) out vec2 texture_coordinate; + +void main() { + texture_coordinate = texture; + gl_Position = vec4(position, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/shader/src/pathtracing/camera.glsl b/src/shader/src/pathtracing/camera.glsl new file mode 100644 index 0000000..e8586e4 --- /dev/null +++ b/src/shader/src/pathtracing/camera.glsl @@ -0,0 +1,22 @@ + +layout(push_constant) uniform Camera { + vec3 position; + vec3 front; + vec3 up; + vec3 left; + float fov; +} camera; + +vec3 generate_view_ray_direction(in vec2 uv) { + // convert camera fov from degrees to relative factor for scaling normalized front vector + float fov = 1.0 / tan(DegreeToRadians(camera.fov) * 0.5); + + return normalize(camera.front * fov + camera.up * uv.x + camera.left * uv.y); +} + +Ray generate_view_ray(in vec2 uv) { + Ray view_ray; + view_ray.origin = camera.position; + view_ray.direction = generate_view_ray_direction(uv); + return view_ray; +} \ No newline at end of file diff --git a/src/shader/src/pathtracing/common.glsl b/src/shader/src/pathtracing/common.glsl new file mode 100644 index 0000000..c43bd32 --- /dev/null +++ b/src/shader/src/pathtracing/common.glsl @@ -0,0 +1,7 @@ + +#define DegreeToRadians(x) (x * 0.01745329251994330) + +struct Ray { + vec3 origin; + vec3 direction; +}; \ No newline at end of file diff --git a/src/shader/src/pathtracing/pathtracer.glsl b/src/shader/src/pathtracing/pathtracer.glsl new file mode 100644 index 0000000..4233c82 --- /dev/null +++ b/src/shader/src/pathtracing/pathtracer.glsl @@ -0,0 +1,9 @@ + +#include +#include + +vec3 trace_path(in vec2 uv) { + Ray view_ray = generate_view_ray(uv); + + return view_ray.direction; +} \ No newline at end of file diff --git a/src/vulkan/composite.rs b/src/vulkan/composite.rs new file mode 100644 index 0000000..46469d0 --- /dev/null +++ b/src/vulkan/composite.rs @@ -0,0 +1,14 @@ +pub(crate) mod vs { + vulkano_shaders::shader! { + ty: "vertex", + path: "src/shader/src/composite.vert" + } +} + +pub(crate) mod fs { + vulkano_shaders::shader! { + ty: "fragment", + include: ["src/shader/src"], + path: "src/shader/src/composite.frag" + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/vulkan/mod.rs similarity index 94% rename from src/lib.rs rename to src/vulkan/mod.rs index 470cff1..b64d66e 100644 --- a/src/lib.rs +++ b/src/vulkan/mod.rs @@ -1,4 +1,4 @@ -mod shader; +mod composite; use std::sync::Arc; use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, Properties, Queue, QueueCreateInfo, QueueFlags}; @@ -11,7 +11,7 @@ use vulkano::{sync, VulkanLibrary}; use vulkano_win::VkSurfaceBuild; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::{Window, WindowBuilder}; -use vulkano::buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage}; +use vulkano::buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer}; use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents}; use vulkano::image::view::ImageView; @@ -29,29 +29,36 @@ use winit::event::{Event, WindowEvent}; struct Vertex2d { #[format(R32G32_SFLOAT)] position: [f32; 2], + #[format(R32G32_SFLOAT)] + texture: [f32; 2] } -const QUAD_VERTICES: [Vertex2d; 6] = [ - Vertex2d { - position: [-1.0, -1.0] - }, - Vertex2d { - position: [1.0, -1.0] - }, - Vertex2d { - position: [1.0, 1.0] - }, - - Vertex2d { - position: [-1.0, -1.0] - }, - Vertex2d { - position: [1.0, 1.0] - }, - Vertex2d { - position: [-1.0, 1.0] - } -]; +fn textured_quad() -> (Vec, Vec) { + ( + vec![ + Vertex2d { + position: [-1.0, -1.0], + texture: [0.0, 0.0] + }, + Vertex2d { + position: [1.0, -1.0], + texture: [1.0, 0.0] + }, + Vertex2d { + position: [1.0, 1.0], + texture: [1.0, 1.0] + }, + Vertex2d { + position: [-1.0, 1.0], + texture: [0.0, 1.0] + } + ], + vec![ + 0, 1, 2, + 0, 2, 3 + ] + ) +} pub fn init() { let lib = VulkanLibrary::new().unwrap(); @@ -96,18 +103,7 @@ pub fn init() { let memory_allocator = StandardMemoryAllocator::new_default(device.clone()); - let vertex_buffer = Buffer::from_iter( - &memory_allocator, - BufferCreateInfo { - usage: BufferUsage::VERTEX_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - usage: MemoryUsage::Upload, - ..Default::default() - }, - QUAD_VERTICES, - ).unwrap(); + let (vertex_buffer, index_buffer) = create_quad_buffer(&memory_allocator); // At this point, OpenGL initialization would be finished. However in Vulkan it is not. OpenGL // implicitly does a lot of computation whenever you draw. In Vulkan, you have to do all this @@ -157,7 +153,7 @@ pub fn init() { // that, we store the submission of the previous frame here. let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); - let pipeline = shader::create_program(&render_pass, &device); + let pipeline = composite::create_program(&render_pass, &device); event_loop.run(move |event, _, control_flow| { match event { @@ -204,7 +200,7 @@ pub fn init() { // window. Simply restarting the loop is the easiest way to fix this // issue. Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return, - Err(e) => panic!("failed to recreate swapchain: {e}"), + Err(e) => panic!("failed to recreate swapchain: {}", e), }; swapchain = new_swapchain; @@ -234,7 +230,7 @@ pub fn init() { recreate_swapchain = true; return; } - Err(e) => panic!("failed to acquire next image: {e}"), + Err(e) => panic!("failed to acquire next image: {}", e), }; // `acquire_next_image` can be successful, but suboptimal. This means that the @@ -287,8 +283,9 @@ pub fn init() { .set_viewport(0, [viewport.clone()]) .bind_pipeline_graphics(pipeline.clone()) .bind_vertex_buffers(0, vertex_buffer.clone()) + .bind_index_buffer(index_buffer.clone()) // We add a draw command. - .draw(vertex_buffer.len() as u32, 1, 0, 0) + .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0) .unwrap() // We leave the render pass. Note that if we had multiple subpasses we could // have called `next_subpass` to jump to the next subpass. @@ -327,7 +324,7 @@ pub fn init() { previous_frame_end = Some(sync::now(device.clone()).boxed()); } Err(e) => { - panic!("failed to flush future: {e}"); + panic!("failed to flush future: {}", e); // previous_frame_end = Some(sync::now(device.clone()).boxed()); } } @@ -337,6 +334,38 @@ pub fn init() { }); } +fn create_quad_buffer(memory_allocator: &StandardMemoryAllocator) -> (Subbuffer<[Vertex2d]>, Subbuffer<[u32]>) { + let (vertices, indices) = textured_quad(); + + let vertex_buffer = Buffer::from_iter( + memory_allocator, + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + usage: MemoryUsage::Upload, + ..Default::default() + }, + vertices, + ).unwrap(); + + let index_buffer = Buffer::from_iter( + memory_allocator, + BufferCreateInfo { + usage: BufferUsage::INDEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + usage: MemoryUsage::Upload, + ..Default::default() + }, + indices, + ).unwrap(); + + (vertex_buffer, index_buffer) +} + /// This function is called once during initialization, then again whenever the window is resized. fn window_size_dependent_setup( images: &[Arc],