From d7378ab5cabc40be419d7bed5882178bf5e06758 Mon Sep 17 00:00:00 2001 From: Verox001 Date: Thu, 16 Jan 2025 13:05:57 +0100 Subject: [PATCH] Finished light diffusion --- src/lib.rs | 40 ++++++++++++++++++++++++++-------------- src/shader.wgsl | 43 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 18 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 129f9fe..d39814b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -179,22 +179,24 @@ struct Instance { impl Instance { fn to_raw(&self) -> InstanceRaw { + let model = + cgmath::Matrix4::from_translation(self.position) * cgmath::Matrix4::from(self.rotation); InstanceRaw { - model: (cgmath::Matrix4::from_translation(self.position) - * cgmath::Matrix4::from(self.rotation)) - .into(), + model: model.into(), + normal: cgmath::Matrix3::from(self.rotation).into(), } } } #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +#[allow(dead_code)] struct InstanceRaw { - #[allow(dead_code)] model: [[f32; 4]; 4], + normal: [[f32; 3]; 3], } -impl InstanceRaw { +impl model::Vertex for InstanceRaw { fn desc() -> wgpu::VertexBufferLayout<'static> { use std::mem; wgpu::VertexBufferLayout { @@ -206,11 +208,13 @@ impl InstanceRaw { attributes: &[ wgpu::VertexAttribute { offset: 0, + // While our vertex shader only uses locations 0, and 1 now, in later tutorials, we'll + // be using 2, 3, and 4 for Vertex. We'll start at slot 5 to not conflict with them later shader_location: 5, format: wgpu::VertexFormat::Float32x4, }, // A mat4 takes up 4 vertex slots as it is technically 4 vec4s. We need to define a slot - // for each vec4. We don't have to do this in code though. + // for each vec4. We don't have to do this in code, though. wgpu::VertexAttribute { offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress, shader_location: 6, @@ -226,6 +230,21 @@ impl InstanceRaw { shader_location: 8, format: wgpu::VertexFormat::Float32x4, }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 16]>() as wgpu::BufferAddress, + shader_location: 9, + format: wgpu::VertexFormat::Float32x3, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 19]>() as wgpu::BufferAddress, + shader_location: 10, + format: wgpu::VertexFormat::Float32x3, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 22]>() as wgpu::BufferAddress, + shader_location: 11, + format: wgpu::VertexFormat::Float32x3, + }, ], } } @@ -430,14 +449,7 @@ impl<'a> State<'a> { let position = cgmath::Vector3 { x, y: 0.0, z }; - let rotation = if position.is_zero() { - cgmath::Quaternion::from_axis_angle( - cgmath::Vector3::unit_z(), - cgmath::Deg(0.0), - ) - } else { - cgmath::Quaternion::from_axis_angle(position.normalize(), cgmath::Deg(45.0)) - }; + let rotation = cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(180.0)); Instance { position, rotation } }) diff --git a/src/shader.wgsl b/src/shader.wgsl index c182e66..5c33ddb 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -1,5 +1,12 @@ // Vertex shader +struct Light { + position: vec3, + color: vec3, +} +@group(2) @binding(0) +var light: Light; + struct Camera { view_proj: mat4x4, } @@ -9,18 +16,24 @@ var camera: Camera; struct VertexInput { @location(0) position: vec3, @location(1) tex_coords: vec2, -} + @location(2) normal: vec3, +}; struct InstanceInput { @location(5) model_matrix_0: vec4, @location(6) model_matrix_1: vec4, @location(7) model_matrix_2: vec4, @location(8) model_matrix_3: vec4, + @location(9) normal_matrix_0: vec3, + @location(10) normal_matrix_1: vec3, + @location(11) normal_matrix_2: vec3, } struct VertexOutput { @builtin(position) clip_position: vec4, @location(0) tex_coords: vec2, -} + @location(1) world_normal: vec3, + @location(2) world_position: vec3, +}; @vertex fn vs_main( @@ -33,9 +46,18 @@ fn vs_main( instance.model_matrix_2, instance.model_matrix_3, ); + + let normal_matrix = mat3x3( + instance.normal_matrix_0, + instance.normal_matrix_1, + instance.normal_matrix_2, + ); var out: VertexOutput; out.tex_coords = model.tex_coords; - out.clip_position = camera.view_proj * model_matrix * vec4(model.position, 1.0); + out.world_normal = normal_matrix * model.normal; + var world_position: vec4 = model_matrix * vec4(model.position, 1.0); + out.world_position = world_position.xyz; + out.clip_position = camera.view_proj * world_position; return out; } @@ -48,5 +70,18 @@ var s_diffuse: sampler; @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4 { - return textureSample(t_diffuse, s_diffuse, in.tex_coords); + let object_color: vec4 = textureSample(t_diffuse, s_diffuse, in.tex_coords); + + let light_dir = normalize(light.position - in.world_position); + + let diffuse_strength = max(dot(in.world_normal, light_dir), 0.0); + let diffuse_color = light.color * diffuse_strength; + + // We don't need (or want) much ambient light, so 0.1 is fine + let ambient_strength = 0.1; + let ambient_color = light.color * ambient_strength; + + let result = (ambient_color + diffuse_color) * object_color.xyz; + + return vec4(result, object_color.a); } \ No newline at end of file