Fix issues with the normal matrix

This commit is contained in:
SeanOMik 2023-11-17 14:52:38 -05:00
parent 6826d43c8b
commit 039e99281a
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
7 changed files with 84 additions and 39 deletions

View File

@ -27,7 +27,7 @@ tobj = { version = "3.2.1", features = [
]} ]}
instant = "0.1" instant = "0.1"
async-trait = "0.1.65" async-trait = "0.1.65"
glam = { version = "0.24.0", features = ["bytemuck"] } glam = { version = "0.24.0", features = ["bytemuck", "debug-glam-assert"] }
gilrs-core = "0.5.6" gilrs-core = "0.5.6"
syn = "2.0.26" syn = "2.0.26"
quote = "1.0.29" quote = "1.0.29"

View File

@ -57,6 +57,9 @@ impl Criteria for FixedTimestep {
#[derive(Clone)] #[derive(Clone)]
struct TpsAccumulator(f32); struct TpsAccumulator(f32);
#[derive(Component)]
struct CubeFlag;
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let setup_sys = |world: &mut World| -> anyhow::Result<()> { let setup_sys = |world: &mut World| -> anyhow::Result<()> {
@ -68,7 +71,7 @@ async fn main() {
let mut resman = world.get_resource_mut::<ResourceManager>().unwrap(); let mut resman = world.get_resource_mut::<ResourceManager>().unwrap();
//let diffuse_texture = resman.request::<Texture>("assets/happy-tree.png").unwrap(); //let diffuse_texture = resman.request::<Texture>("assets/happy-tree.png").unwrap();
let antique_camera_model = resman.request::<Model>("assets/AntiqueCamera.glb").unwrap(); //let antique_camera_model = resman.request::<Model>("assets/AntiqueCamera.glb").unwrap();
//let cube_model = resman.request::<Model>("assets/cube-texture-bin.glb").unwrap(); //let cube_model = resman.request::<Model>("assets/cube-texture-bin.glb").unwrap();
let cube_model = resman.request::<Model>("assets/texture-sep/texture-sep.gltf").unwrap(); let cube_model = resman.request::<Model>("assets/texture-sep/texture-sep.gltf").unwrap();
drop(resman); drop(resman);
@ -103,17 +106,22 @@ async fn main() {
}, */ }, */
TransformComponent::from(cube_tran), TransformComponent::from(cube_tran),
ModelComponent(cube_model.clone()), ModelComponent(cube_model.clone()),
CubeFlag,
)); ));
let mut light_tran = Transform::from_xyz(3.5, 0.0, -7.0); let mut light_tran = Transform::from_xyz(1.5, 2.5, -8.5);
light_tran.scale = Vec3::new(0.5, 0.5, 0.5); light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
world.spawn(( world.spawn((
PointLight { PointLight {
color: Vec3::new(0.361, 0.984, 0.0), color: Vec3::new(1.0, 1.0, 1.0), //Vec3::new(0.361, 0.984, 0.0),
intensity: 1.0, intensity: 1.0,
constant: 1.0, /* constant: 1.0,
linear: 0.045, linear: 0.045,
quadratic: 0.0075, quadratic: 0.0075, */
constant: 1.0,
linear: 0.09,
quadratic: 0.032,
ambient: 0.2, ambient: 0.2,
diffuse: 0.5, diffuse: 0.5,
@ -147,10 +155,10 @@ async fn main() {
}; };
let spin_system = |world: &mut World| -> anyhow::Result<()> { let spin_system = |world: &mut World| -> anyhow::Result<()> {
const SPEED: f32 = 5.0; const SPEED: f32 = 7.0;
let delta_time = **world.get_resource::<DeltaTime>().unwrap(); let delta_time = **world.get_resource::<DeltaTime>().unwrap();
for transform in world.query_mut::<(&mut TransformComponent,)>().iter_mut() { for (transform, _) in world.query_mut::<(&mut TransformComponent, &CubeFlag)>().iter_mut() {
let t = &mut transform.transform; let t = &mut transform.transform;
t.rotate_y(math::Angle::Degrees(SPEED * delta_time)); t.rotate_y(math::Angle::Degrees(SPEED * delta_time));
} }
@ -164,7 +172,7 @@ async fn main() {
let mut sys = BatchedSystem::new(); let mut sys = BatchedSystem::new();
sys.with_criteria(FixedTimestep::new(45)); sys.with_criteria(FixedTimestep::new(45));
//sys.with_system(spin_system); //sys.with_system(spin_system);
sys.with_system(fps_system); //sys.with_system(fps_system);
game.with_system("fixed", sys, &[]); game.with_system("fixed", sys, &[]);
fps_plugin(game); fps_plugin(game);
@ -203,7 +211,7 @@ async fn main() {
game.world().insert_resource(action_handler); game.world().insert_resource(action_handler);
game.with_plugin(InputActionPlugin); game.with_plugin(InputActionPlugin);
game.with_system("test_actions", test_system, &[]); //game.with_system("test_actions", test_system, &[]);
}; };
Game::initialize().await Game::initialize().await

View File

@ -92,11 +92,17 @@ impl Transform {
/// will be equal to `rhs`. When `alpha` is outside of range `[0, 1]`, the result is linearly /// will be equal to `rhs`. When `alpha` is outside of range `[0, 1]`, the result is linearly
/// extrapolated. /// extrapolated.
pub fn lerp(&self, rhs: Transform, alpha: f32) -> Self { pub fn lerp(&self, rhs: Transform, alpha: f32) -> Self {
let mut res = self.clone();
res.translation = self.translation.lerp(rhs.translation, alpha); if alpha.is_finite() {
res.rotation = self.rotation.lerp(rhs.rotation, alpha); let mut res = self.clone();
res.scale = self.scale.lerp(rhs.scale, alpha); res.translation = self.translation.lerp(rhs.translation, alpha);
res.rotation = self.rotation.lerp(rhs.rotation, alpha);
res.scale = self.scale.lerp(rhs.scale, alpha);
res
} else {
self.clone()
}
res
} }
} }

View File

@ -1,4 +1,5 @@
use super::texture::RenderTexture; use super::texture::RenderTexture;
use super::texture::RenderTexture;
#[derive(Clone)] #[derive(Clone)]
pub struct Material { pub struct Material {
@ -19,7 +20,8 @@ impl Material {
shader_id: value.shader_uuid.unwrap_or(0), shader_id: value.shader_uuid.unwrap_or(0),
diffuse_texture, diffuse_texture,
ambient: glam::Vec3::new(1.0, 0.5, 0.31), ambient: glam::Vec3::new(1.0, 0.5, 0.31),
diffuse: glam::Vec3::new(value.base_color.x, value.base_color.y, value.base_color.z), //diffuse: glam::Vec3::new(value.base_color.x, value.base_color.y, value.base_color.z),
diffuse: glam::Vec3::new(1.0, 0.5, 0.31),
specular: glam::Vec3::new(0.5, 0.5, 0.5), specular: glam::Vec3::new(0.5, 0.5, 0.5),
shininess: 32.0, shininess: 32.0,
} }

View File

@ -1,5 +1,6 @@
// Vertex shader // Vertex shader
const max_light_count: u32 = 16u;
const max_light_count: u32 = 16u; const max_light_count: u32 = 16u;
struct VertexInput { struct VertexInput {
@ -24,6 +25,7 @@ struct PointLight {
position: vec4<f32>, position: vec4<f32>,
color: vec4<f32>, color: vec4<f32>,
intensity: f32, intensity: f32,
constant: f32, constant: f32,
linear: f32, linear: f32,
@ -32,6 +34,10 @@ struct PointLight {
ambient: f32, ambient: f32,
diffuse: f32, diffuse: f32,
specular: f32, specular: f32,
ambient: f32,
diffuse: f32,
specular: f32,
}; };
struct Lights { struct Lights {
@ -42,7 +48,7 @@ struct Lights {
@group(1) @binding(0) @group(1) @binding(0)
var<uniform> u_model_transform: mat4x4<f32>; var<uniform> u_model_transform: mat4x4<f32>;
@group(1) @binding(1) @group(1) @binding(1)
var<uniform> u_model_normal_matrix: mat3x3<f32>; var<uniform> u_model_normal_matrix: mat4x4<f32>;
@group(2) @binding(0) @group(2) @binding(0)
var<uniform> u_camera: CameraUniform; var<uniform> u_camera: CameraUniform;
@ -59,8 +65,10 @@ fn vs_main(
out.tex_coords = model.tex_coords; out.tex_coords = model.tex_coords;
out.clip_position = u_camera.view_proj * u_model_transform * vec4<f32>(model.position, 1.0); out.clip_position = u_camera.view_proj * u_model_transform * vec4<f32>(model.position, 1.0);
out.world_normal = u_model_normal_matrix * model.normal; // the normal mat is actually only a mat3x3, but there's a bug in wgpu: https://github.com/gfx-rs/wgpu-rs/issues/36
let normal_mat = mat3x3(u_model_normal_matrix[0].xyz, u_model_normal_matrix[1].xyz, u_model_normal_matrix[2].xyz);
out.world_normal = normalize(normal_mat * model.normal, );
var world_position: vec4<f32> = u_model_transform * vec4<f32>(model.position, 1.0); var world_position: vec4<f32> = u_model_transform * vec4<f32>(model.position, 1.0);
out.world_position = world_position.xyz; out.world_position = world_position.xyz;
@ -76,9 +84,17 @@ struct Material {
shininess: f32, shininess: f32,
} }
struct Material {
ambient: vec4<f32>,
diffuse: vec4<f32>,
specular: vec4<f32>,
shininess: f32,
}
@group(0) @binding(0) @group(0) @binding(0)
var t_diffuse: texture_2d<f32>; var t_diffuse: texture_2d<f32>;
@group(0) @binding(1) @group(0) @binding(1)
@group(0) @binding(1)
var s_diffuse: sampler; var s_diffuse: sampler;
@group(4) @binding(0) @group(4) @binding(0)
@ -91,8 +107,9 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
var light_res = vec3<f32>(0.0); var light_res = vec3<f32>(0.0);
for (var i = 0u; i < u_lights.point_light_count; i++) { for (var i = 0u; i < u_lights.point_light_count; i++) {
light_res += blinn_phong_point_light(in.world_position, in.world_normal, u_lights.point_lights[i], u_material); light_res += blinn_phong_point_light(in.world_position, in.world_normal, u_lights.point_lights[i], u_material);
light_res += blinn_phong_point_light(in.world_position, in.world_normal, u_lights.point_lights[i], u_material);
} }
let light_object_res = light_res * object_color.xyz; let light_object_res = light_res * (object_color.xyz/* * u_material.diffuse.xyz*/);
return vec4<f32>(light_object_res, object_color.a); return vec4<f32>(light_object_res, object_color.a);
} }
@ -105,31 +122,40 @@ fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_li
// We don't need (or want) much ambient light, so 0.1 is fine // We don't need (or want) much ambient light, so 0.1 is fine
//let ambient_strength = 0.1; //let ambient_strength = 0.1;
var ambient_color = light_color * material.ambient.xyz; var ambient_color = light_color * material.ambient.xyz;
//let ambient_strength = 0.1;
var ambient_color = light_color * material.ambient.xyz;
//// diffuse //// //// diffuse ////
let light_dir = normalize(light_pos - world_pos); let light_dir = normalize(light_pos - world_pos);
let diffuse_strength = max(dot(world_norm, light_dir), 0.0); let diffuse_strength = max(dot(world_norm, light_dir), 0.0);
var diffuse_color = light_color * (diffuse_strength * material.diffuse.xyz); var diffuse_color = light_color * (diffuse_strength * material.diffuse.xyz);
var diffuse_color = light_color * (diffuse_strength * material.diffuse.xyz);
//// end of diffuse //// //// end of diffuse ////
//// specular //// //// specular ////
let view_dir = normalize(camera_view_pos - world_pos); let view_dir = normalize(camera_view_pos - world_pos);
let half_dir = normalize(view_dir + light_dir); let half_dir = normalize(view_dir + light_dir);
let specular_strength = pow(max(dot(world_norm, half_dir), 0.0), material.shininess);
var specular_color = specular_strength * (light_color * material.specular.xyz);
let specular_strength = pow(max(dot(world_norm, half_dir), 0.0), material.shininess); let specular_strength = pow(max(dot(world_norm, half_dir), 0.0), material.shininess);
var specular_color = specular_strength * (light_color * material.specular.xyz); var specular_color = specular_strength * (light_color * material.specular.xyz);
//// end of specular //// //// end of specular ////
//// point light attenuation //// //// point light attenuation ////
let distance = length(light_pos - world_pos); /*let distance = length(light_pos - world_pos);
let attenuation = 1.0 / (point_light.constant + point_light.linear * distance + let attenuation = 1.0 / (point_light.constant + point_light.linear * distance +
point_light.quadratic * (distance * distance)); point_light.quadratic * (distance * distance));*/
ambient_color *= attenuation * point_light.intensity * point_light.ambient; //ambient_color *= attenuation * point_light.intensity * point_light.ambient;
diffuse_color *= attenuation * point_light.intensity * point_light.diffuse; //diffuse_color *= attenuation * point_light.intensity * point_light.diffuse;
specular_color *= attenuation * point_light.intensity * point_light.specular; //specular_color *= attenuation * point_light.intensity * point_light.specular;
//// end of point light attenuation //// //// end of point light attenuation ////
ambient_color *= point_light.ambient;
diffuse_color *= point_light.diffuse;
specular_color *= point_light.specular;
return (ambient_color + diffuse_color + specular_color); return (ambient_color + diffuse_color + specular_color) * /*attenuation * */ point_light.intensity;
} }

View File

@ -1,6 +1,7 @@
use std::{collections::{VecDeque, HashMap}, num::NonZeroU64}; use std::{collections::{VecDeque, HashMap}, num::NonZeroU64};
use edict::EntityId; use edict::EntityId;
use tracing::debug;
use wgpu::Limits; use wgpu::Limits;
use std::mem; use std::mem;
@ -63,7 +64,7 @@ impl TransformBuffers {
}); });
let mut s = Self { let mut s = Self {
max_transform_count: limits.max_uniform_buffer_binding_size as usize / (mem::size_of::<glam::Mat4>() + mem::size_of::<glam::Mat3>()), max_transform_count: limits.max_uniform_buffer_binding_size as usize / (mem::size_of::<glam::Mat4>() * 2),
buffer_bindgroups: Vec::new(), buffer_bindgroups: Vec::new(),
bindgroup_layout, bindgroup_layout,
just_updated: HashMap::new(), just_updated: HashMap::new(),
@ -85,6 +86,10 @@ impl TransformBuffers {
.expect("Use 'insert_entity' for new entities"); .expect("Use 'insert_entity' for new entities");
self.just_updated.insert(entity, indices); self.just_updated.insert(entity, indices);
debug!("Normal: {normal_matrix:?}");
let normal_matrix = glam::Mat4::from_mat3(normal_matrix);
let buffer = self.buffer_bindgroups.get(indices.buffer_index).unwrap(); let buffer = self.buffer_bindgroups.get(indices.buffer_index).unwrap();
let offset = Self::index_offset(limits, indices); let offset = Self::index_offset(limits, indices);
queue.write_buffer(&buffer.transform_buf, offset, bytemuck::bytes_of(&transform)); queue.write_buffer(&buffer.transform_buf, offset, bytemuck::bytes_of(&transform));
@ -173,7 +178,7 @@ impl TransformBuffers {
let transform_buffer = device.create_buffer( let transform_buffer = device.create_buffer(
&wgpu::BufferDescriptor { &wgpu::BufferDescriptor {
label: Some(&format!("Transform Buffer {}", self.buffer_bindgroups.len())), label: Some(&format!("B_Transform_{}", self.buffer_bindgroups.len())),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
size: max_buffer_sizes, size: max_buffer_sizes,
mapped_at_creation: false, mapped_at_creation: false,
@ -182,19 +187,17 @@ impl TransformBuffers {
let normal_mat_buffer = device.create_buffer( let normal_mat_buffer = device.create_buffer(
&wgpu::BufferDescriptor { &wgpu::BufferDescriptor {
label: Some(&format!("Normal Matrix Buffer {}", self.buffer_bindgroups.len())), label: Some(&format!("B_NormalMatrix_{}", self.buffer_bindgroups.len())),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
size: max_buffer_sizes, size: max_buffer_sizes,
mapped_at_creation: false, mapped_at_creation: false,
} }
); );
/* let stride = limits.min_uniform_buffer_offset_alignment as u64 let tran_stride = mem::size_of::<glam::Mat4>();
+ mem::size_of::<glam::Mat4>() as u64 + mem::size_of::<glam::Mat3>() as u64; */ // although a normal matrix only needs to be a mat3, there's a weird issue with
let tran_stride = limits.min_uniform_buffer_offset_alignment as u64 // misalignment from wgpu or spirv-cross: https://github.com/gfx-rs/wgpu-rs/issues/36
+ mem::size_of::<glam::Mat4>() as u64; let norm_stride = mem::size_of::<glam::Mat4>();
let norm_stride = limits.min_uniform_buffer_offset_alignment as u64
+ mem::size_of::<glam::Mat3>() as u64;
let transform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { let transform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &self.bindgroup_layout, layout: &self.bindgroup_layout,
@ -205,7 +208,7 @@ impl TransformBuffers {
wgpu::BufferBinding { wgpu::BufferBinding {
buffer: &transform_buffer, buffer: &transform_buffer,
offset: 0, offset: 0,
size: Some(NonZeroU64::new(tran_stride).unwrap()) size: Some(NonZeroU64::new(tran_stride as u64).unwrap())
} }
) )
}, },
@ -215,12 +218,12 @@ impl TransformBuffers {
wgpu::BufferBinding { wgpu::BufferBinding {
buffer: &normal_mat_buffer, buffer: &normal_mat_buffer,
offset: 0, offset: 0,
size: Some(NonZeroU64::new(norm_stride).unwrap()) size: Some(NonZeroU64::new(norm_stride as u64).unwrap())
} }
) )
} }
], ],
label: Some("transform_bind_group"), label: Some("BG_Transforms"),
}); });
let entry = TransformBufferEntry { let entry = TransformBufferEntry {

View File

@ -34,7 +34,7 @@ impl DescVertexBufferLayout for Vertex {
format: wgpu::VertexFormat::Float32x2, // Vec2 format: wgpu::VertexFormat::Float32x2, // Vec2
}, },
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, offset: std::mem::size_of::<[f32; 5]>() as wgpu::BufferAddress,
shader_location: 2, shader_location: 2,
format: wgpu::VertexFormat::Float32x3, // Vec3 format: wgpu::VertexFormat::Float32x3, // Vec3
} }