From e3a59f3f26cd12a8e5dab71f8593c40fc08d09e9 Mon Sep 17 00:00:00 2001 From: DotWith Date: Tue, 2 Apr 2024 21:36:44 -0400 Subject: [PATCH] Normals fixed --- bevy_rmesh/Cargo.toml | 2 +- bevy_rmesh/src/loader.rs | 28 ++++++----- rmesh/Cargo.toml | 2 +- rmesh/src/lib.rs | 106 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 121 insertions(+), 17 deletions(-) diff --git a/bevy_rmesh/Cargo.toml b/bevy_rmesh/Cargo.toml index a3b1f34..3f358fe 100755 --- a/bevy_rmesh/Cargo.toml +++ b/bevy_rmesh/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_rmesh" -version = "0.3.1" +version = "0.3.2" edition = "2021" license = "MIT OR Apache-2.0" description = "A Bevy extension for RMesh loading" diff --git a/bevy_rmesh/src/loader.rs b/bevy_rmesh/src/loader.rs index ac1ed80..8bbacae 100755 --- a/bevy_rmesh/src/loader.rs +++ b/bevy_rmesh/src/loader.rs @@ -13,7 +13,7 @@ use bevy::render::{ mesh::{Indices, Mesh}, render_resource::PrimitiveTopology, }; -use rmesh::{read_rmesh, CalcBoundBox, ROOM_SCALE}; +use rmesh::{read_rmesh, ExtMesh, ROOM_SCALE}; pub struct RMeshLoader { pub(crate) supported_compressed_formats: CompressedImageFormats, @@ -53,7 +53,10 @@ async fn load_rmesh<'a, 'b>( // let mut entity_meshes = vec![]; for (i, complex_mesh) in header.meshes.iter().enumerate() { - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default()); + let mut mesh = Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetUsages::default(), + ); let positions: Vec<_> = complex_mesh .vertices @@ -69,24 +72,25 @@ async fn load_rmesh<'a, 'b>( let tex_coords: Vec<_> = complex_mesh .vertices .iter() - .flat_map(|v| { - [ - [v.tex_coords[0][0], 1.0 - v.tex_coords[0][1]], // First UV channel - [v.tex_coords[1][0], 1.0 - v.tex_coords[1][1]], // Second UV channel - ] - }) + // .flat_map(|v| { + // [ + // [v.tex_coords[0][0], 1.0 - v.tex_coords[0][1]], // First UV channel + // [v.tex_coords[1][0], 1.0 - v.tex_coords[1][1]], // Second UV channel + // ] + // }) + .map(|v| v.tex_coords[0]) .collect(); - let indices = complex_mesh + let indices: Vec = complex_mesh .triangles .iter() .flat_map(|strip| strip.iter().rev().copied()) .collect(); + let normals = complex_mesh.calculate_normals(); mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, tex_coords); - mesh.insert_indices(Indices::U32(indices)); - mesh.duplicate_vertices(); - mesh.compute_flat_normals(); + mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); + mesh.insert_indices(Indices::U32(indices)); // TODO: Colliders need this second call for indices let mesh = load_context.add_labeled_asset(format!("Mesh{0}", i), mesh); diff --git a/rmesh/Cargo.toml b/rmesh/Cargo.toml index 15d4672..7e06a8f 100644 --- a/rmesh/Cargo.toml +++ b/rmesh/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rmesh" -version = "0.3.4" +version = "0.3.5" edition = "2021" license = "MIT OR Apache-2.0" description = "A parser for the rmesh extension" diff --git a/rmesh/src/lib.rs b/rmesh/src/lib.rs index dfc59c6..9e4b68f 100644 --- a/rmesh/src/lib.rs +++ b/rmesh/src/lib.rs @@ -131,7 +131,7 @@ pub struct TriggerBox { pub name: FixedLengthString, } -impl CalcBoundBox for SimpleMesh { +impl ExtMesh for SimpleMesh { fn bounding_box(&self) -> Bounds { let mut min_x = f32::INFINITY; let mut min_y = f32::INFINITY; @@ -158,9 +158,58 @@ impl CalcBoundBox for SimpleMesh { let max_point = [max_x, max_y, max_z]; Bounds::new(min_point, max_point) } + + fn calculate_normals(&self) -> Vec<[f32; 3]> { + // Initialize vertex normals with zero vectors + let mut vertex_normals = vec![[0.0, 0.0, 0.0]; self.vertices.len()]; + + // Calculate face normals and accumulate them to vertex normals + for triangle in &self.triangles { + let vertex0 = self.vertices[triangle[0] as usize]; + let vertex1 = self.vertices[triangle[1] as usize]; + let vertex2 = self.vertices[triangle[2] as usize]; + + let edge1 = [ + vertex1[0] - vertex0[0], + vertex1[1] - vertex0[1], + vertex1[2] - vertex0[2], + ]; + let edge2 = [ + vertex2[0] - vertex0[0], + vertex2[1] - vertex0[1], + vertex2[2] - vertex0[2], + ]; + + let normal = [ + edge1[1] * edge2[2] - edge1[2] * edge2[1], + edge1[2] * edge2[0] - edge1[0] * edge2[2], + edge1[0] * edge2[1] - edge1[1] * edge2[0], + ]; + + // Accumulate face normal to the vertices of the triangle + for i in 0..3 { + let vertex_index = triangle[i] as usize; + vertex_normals[vertex_index][0] += normal[0]; + vertex_normals[vertex_index][1] += normal[1]; + vertex_normals[vertex_index][2] += normal[2]; + } + } + + // Normalize vertex normals + for normal in &mut vertex_normals { + let length = (normal[0].powi(2) + normal[1].powi(2) + normal[2].powi(2)).sqrt(); + if length != 0.0 { + normal[0] /= length; + normal[1] /= length; + normal[2] /= length; + } + } + + vertex_normals + } } -impl CalcBoundBox for ComplexMesh { +impl ExtMesh for ComplexMesh { fn bounding_box(&self) -> Bounds { let mut min_x = f32::INFINITY; let mut min_y = f32::INFINITY; @@ -187,11 +236,62 @@ impl CalcBoundBox for ComplexMesh { let max_point = [max_x, max_y, max_z]; Bounds::new(min_point, max_point) } + + fn calculate_normals(&self) -> Vec<[f32; 3]> { + // Initialize vertex normals with zero vectors + let mut vertex_normals = vec![[0.0, 0.0, 0.0]; self.vertices.len()]; + + // Calculate face normals and accumulate them to vertex normals + for triangle in &self.triangles { + let vertex0 = self.vertices[triangle[0] as usize].position; + let vertex1 = self.vertices[triangle[1] as usize].position; + let vertex2 = self.vertices[triangle[2] as usize].position; + + let edge1 = [ + vertex1[0] - vertex0[0], + vertex1[1] - vertex0[1], + vertex1[2] - vertex0[2], + ]; + let edge2 = [ + vertex2[0] - vertex0[0], + vertex2[1] - vertex0[1], + vertex2[2] - vertex0[2], + ]; + + let normal = [ + edge1[1] * edge2[2] - edge1[2] * edge2[1], + edge1[2] * edge2[0] - edge1[0] * edge2[2], + edge1[0] * edge2[1] - edge1[1] * edge2[0], + ]; + + // Accumulate face normal to the vertices of the triangle + for i in 0..3 { + let vertex_index = triangle[i] as usize; + vertex_normals[vertex_index][0] += normal[0]; + vertex_normals[vertex_index][1] += normal[1]; + vertex_normals[vertex_index][2] += normal[2]; + } + } + + // Normalize vertex normals + for normal in &mut vertex_normals { + let length = (normal[0].powi(2) + normal[1].powi(2) + normal[2].powi(2)).sqrt(); + if length != 0.0 { + normal[0] /= length; + normal[1] /= length; + normal[2] /= length; + } + } + + vertex_normals + } } -pub trait CalcBoundBox { +pub trait ExtMesh { /// Used for aabb calc fn bounding_box(&self) -> Bounds; + /// Calculate normals for the vertices based on the triangle faces. + fn calculate_normals(&self) -> Vec<[f32; 3]>; } pub struct Bounds {