diff --git a/build.rs b/build.rs index 16c85c0..a1c065d 100644 --- a/build.rs +++ b/build.rs @@ -58,9 +58,16 @@ fn main() { let mut compiler = shaderc::Compiler::new().expect("Unable to create shader compiler"); for shader in shaders { println!("cargo:rerun-if-changed={}", shader.src_path.as_os_str().to_str().unwrap()); - let compiled = compiler.compile_into_spirv(&shader.source, shader.kind, &shader.src_path.to_str().unwrap(), "main", Some(&options)).unwrap(); + let compiled = compiler.compile_into_spirv(&shader.source, shader.kind, &shader.src_path.to_str().unwrap(), "main", Some(&options)) + .expect("Shader error:"); write(shader.spv_path, compiled.as_binary_u8()).unwrap(); } + + // Rebuild if any of the cginc change + for path_str in glob("./src/shaders/**/*.cginc").unwrap() { + let path = path_str.unwrap(); + println!("cargo:rerun-if-changed={}", path.as_os_str().to_str().unwrap()); + } } diff --git a/src/app.rs b/src/app.rs index 823e310..56914a4 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,6 @@ use std::sync::Arc; use winit::event::Event; -use winit::{window::Window, dpi::PhysicalSize, event::WindowEvent}; +use winit::{window::Window, dpi::PhysicalSize}; use wgpu::util::DeviceExt; use crate::vertex::Vertex; @@ -9,11 +9,14 @@ use crate::camera::Camera; use crate::uniforms::Uniforms; use crate::camera_controller::CameraController; + +// A B +// C D const VERTICES: &[Vertex] = &[ - Vertex { position: [-1.0, 1.0, 0.0], uv: [0.0, 0.0] }, - Vertex { position: [ 1.0, 1.0, 0.0], uv: [1.0, 0.0] }, - Vertex { position: [ 1.0,-1.0, 0.0], uv: [1.0, 1.0] }, - Vertex { position: [-1.0,-1.0, 0.0], uv: [0.0, 1.0] }, + Vertex { position: [-1.0, 1.0, 0.0], uv: [0.0, 0.0] }, // A + Vertex { position: [ 1.0, 1.0, 0.0], uv: [1.0, 0.0] }, // B + Vertex { position: [ 1.0,-1.0, 0.0], uv: [1.0, 1.0] }, // C + Vertex { position: [-1.0,-1.0, 0.0], uv: [0.0, 1.0] }, // D ]; const INDICES: &[u16] = &[ @@ -156,7 +159,7 @@ impl App { entries: &[ wgpu::BindGroupLayoutEntry { binding: 0, - visibility: wgpu::ShaderStage::VERTEX, + visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, @@ -213,9 +216,9 @@ impl App { // Cam let aspect = swapchain_desc.width as f32 / swapchain_desc.height as f32; - let camera = Camera::new((0.0, 0.0, 2.0).into(), (0.0, 0.0, -1.0).into(), aspect); + let camera = Camera::new(aspect, 45.0); let mut uniforms = Uniforms::new(); - uniforms.update_projection_matrix(&camera); + uniforms.update(&camera); let camera_controller = CameraController::new(); // Buffers @@ -260,7 +263,7 @@ impl App { self.camera_controller.update_camera(&mut self.camera, delta_time); // Update projection matrix buffer - self.uniforms.update_projection_matrix(&self.camera); + self.uniforms.update(&self.camera); self.queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[self.uniforms])); } diff --git a/src/camera.rs b/src/camera.rs index 2017855..61b855f 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -20,13 +20,13 @@ pub struct Camera { impl Camera { - pub fn new(position: Point3, forward: Vector3, aspect: f32) -> Self { + pub fn new(aspect: f32, fov: f32) -> Self { Self { - position, - forward, + position: (0.0, 0.0, 0.0).into(), + forward: (0.0, 0.0, 1.0).into(), up: Vector3::unit_y(), aspect, - fovy: 45.0, + fovy: fov, znear: 0.1, zfar: 100.0 } @@ -36,9 +36,11 @@ impl Camera { self.aspect = aspect; } - pub fn projection_matrix(&self) -> Matrix4 { - let view = Matrix4::look_to_rh(self.position, self.forward, self.up); - let proj = cgmath::perspective(Deg(self.fovy), self.aspect, self.znear, self.zfar); - return OPENGL_TO_WGPU_MATRIX * proj * view; + pub fn proj_matrix(&self) -> Matrix4 { + return OPENGL_TO_WGPU_MATRIX * cgmath::perspective(Deg(self.fovy), self.aspect, self.znear, self.zfar); + } + + pub fn view_matrix(&self) -> Matrix4 { + return OPENGL_TO_WGPU_MATRIX * Matrix4::look_to_rh(self.position, self.forward, self.up); } } diff --git a/src/shaders/bin/shader.frag.spv b/src/shaders/bin/shader.frag.spv index bc8ab0f..97ef2c5 100644 Binary files a/src/shaders/bin/shader.frag.spv and b/src/shaders/bin/shader.frag.spv differ diff --git a/src/shaders/bin/shader.vert.spv b/src/shaders/bin/shader.vert.spv index 8179875..ffe964f 100644 Binary files a/src/shaders/bin/shader.vert.spv and b/src/shaders/bin/shader.vert.spv differ diff --git a/src/shaders/raymarching.cginc b/src/shaders/raymarching.cginc new file mode 100644 index 0000000..ec311d8 --- /dev/null +++ b/src/shaders/raymarching.cginc @@ -0,0 +1,91 @@ + +// Returns nearest distance to and object id from given point +vec2 map(in vec3 pos) +{ + vec2 d1 = vec2(sdPlane(pos), 1); + vec2 d2 = vec2(sdSphere(pos - vec3(0.0, 2.0, 0.0)), 2); + vec2 d3 = vec2(sdSphere(pos - vec3(2.0, 1.2, 2.0)), 3); + return sdUnion(sdUnion(d1, d2), d3); +} + +// Returns distance to and object id that has been intersected by ray +vec2 intersect(in vec3 ro, in vec3 rd) +{ + float depth = NEAR; + for(int i=0;i 0.0) + { + // Calculate intersection point, normal vector and reflection vector + vec3 pos = ro + rd * result.x; + vec3 nor = estimateNormal(pos); + vec3 ref = reflect(rd, nor); + + // Light + vec3 light = vec3(1); + + float dif = clamp( dot( nor, ld ), 0.0, 1.0 ); + light += 2.20*dif*vec3(1.30,1.00,0.70); + + vec3 hal = normalize( ld-rd ); + float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0); + spe *= dif; + spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,ld),0.0,1.0),5.0); + light += 5.00*spe*vec3(1.30,1.00,0.70); + + //float diffuse = max(dot(norm, -ld), 0); + //color *= diffuse; + + //vec3 ldr = normalize(reflect(-ld, norm)); + //float specular = max(dot(ldr, rd), 0.0); + //specular = pow(specular, 3); + //color += vec3(0.2) * specular; + + //float scatter = pow(1.0-dot(rd, -norm), 2); + + // Calculate color + vec3 color = vec3(0); + if(result.y == 1) color = vec3(0.0, 0.1, 0.01); + else if(result.y == 2) color = vec3(0.5, 0.7, 0.05); + else if(result.y == 3) color = vec3(0.0, 0.2, 0.7); + + // Return + color *= light; + return color; + } + else + { + return vec3(0); + } +} \ No newline at end of file diff --git a/src/shaders/shader.frag b/src/shaders/shader.frag index d971b97..7dc1d5d 100644 --- a/src/shaders/shader.frag +++ b/src/shaders/shader.frag @@ -1,13 +1,28 @@ // shader.frag #version 450 +// Variables layout(location=0) in vec2 vert_uv; -layout(location=0) out vec4 frag_color; - +layout(location=0) out vec4 out_color; layout(set=0, binding=0) uniform texture2D tex; layout(set=0, binding=1) uniform sampler tex_smp; +// Defines +#define PI 3.141592 +#define EPSILON 0.01 +#define NEAR 0.01 +#define MAX_STEPS 200 + +// Include +#include "shapes.cginc" +#include "raymarching.cginc" + void main() { - frag_color = texture(sampler2D(tex, tex_smp), vert_uv); + // Calculate ray + vec3 ro = vec3(0.0, 2, -6.0); // Ray origin + vec3 rd = normalize(vec3(vert_uv - vec2(0.5, 0.5), 1.001)); // Ray direction + + // Render + out_color = vec4(raymarch(ro, rd), 1); } \ No newline at end of file diff --git a/src/shaders/shader.vert b/src/shaders/shader.vert index 9e6efef..d4459e9 100644 --- a/src/shaders/shader.vert +++ b/src/shaders/shader.vert @@ -6,11 +6,14 @@ layout(location=0) out vec2 vert_uv; layout(set=1, binding=0) uniform Uniforms { - mat4 view_projection; + mat4 view; // world to camera + mat4 proj; // camera to screen + mat4 proj_inv; // screen to camera + vec3 cam_pos; // camera position }; void main() { vert_uv = in_uv; - gl_Position = view_projection * vec4(in_position, 1.0); + gl_Position = vec4(in_position, 1.0); } \ No newline at end of file diff --git a/src/shaders/shapes.cginc b/src/shaders/shapes.cginc new file mode 100644 index 0000000..88d60be --- /dev/null +++ b/src/shaders/shapes.cginc @@ -0,0 +1,14 @@ +float sdSphere(in vec3 pos) +{ + return length(pos) - 1.0; +} + +float sdPlane(in vec3 pos) +{ + return pos.y; +} + +vec2 sdUnion(vec2 a, vec2 b) +{ + return (a.x < b.x) ? a : b; +} \ No newline at end of file diff --git a/src/uniforms.rs b/src/uniforms.rs index 6dbd372..c1ffb4e 100644 --- a/src/uniforms.rs +++ b/src/uniforms.rs @@ -4,20 +4,29 @@ use crate::camera::Camera; #[repr(C)] -#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +#[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct Uniforms { - view_proj: [[f32; 4]; 4], + view: [[f32; 4]; 4], + proj: [[f32; 4]; 4], + proj_inv: [[f32; 4]; 4], + cam_pos: [f32; 3] } impl Uniforms { pub fn new() -> Self { - Self { - view_proj: cgmath::Matrix4::identity().into(), - } + Self::default() } - pub fn update_projection_matrix(&mut self, camera: &Camera) { - self.view_proj = camera.projection_matrix().into(); + pub fn update(&mut self, camera: &Camera) { + let view = camera.view_matrix(); + let proj = camera.proj_matrix(); + let proj_inv = proj.invert().unwrap(); + let cam_pos = camera.position; + + self.view = view.into(); + self.proj = proj.into(); + self.proj_inv = proj_inv.into(); + self.cam_pos = cam_pos.into(); } }