From 4fad56a7d1f36e1227bda7589502790c9a29a33f Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 17 Oct 2026 22:55:45 +0300 Subject: [PATCH] fix normals for the gear teeth --- src/crown_gear.rs | 110 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 25 deletions(-) diff --git a/src/crown_gear.rs b/src/crown_gear.rs index 0ee3be1..d3e1b6b 100644 --- a/src/crown_gear.rs +++ b/src/crown_gear.rs @@ -23,7 +23,7 @@ impl CrownGear { let outer_scale = self.outer_radius / self.pitch_radius; let mut mesh = CpuMeshIndexed::new(); - mesh.vertices.reserve_exact(4 * sides); + mesh.vertices.reserve_exact(8 * sides); mesh.faces.reserve_exact(8 * sides); for k in 0..sides { let t = k as f32 / sides as f32; @@ -31,24 +31,22 @@ impl CrownGear { let (s, c) = phi.sin_cos(); let tooth = t * teeth; let y = self.profile.y_from_tooth(tooth); - mesh.vertices.push(Vertex { - position: vec3( - c * self.inner_radius, - s * self.inner_radius, - -self.base_thickness, - ), - color, - normal: Vec3::ZERO, // FIXME calculate the normal - }); - mesh.vertices.push(Vertex { - position: vec3( - c * self.outer_radius, - s * self.outer_radius, - -self.base_thickness, - ), - color, - normal: Vec3::ZERO, // FIXME calculate the normal - }); + let eps = 1e-3; + let dy_dt = teeth + * (self.profile.y_from_tooth(tooth + eps) - self.profile.y_from_tooth(tooth - eps)) + / (2.0 * eps); + + let v_radial = vec3(c * self.pitch_radius, s * self.pitch_radius, y); + let v_tan = vec3(-2.0 * PI * s, 2.0 * PI * c, dy_dt / self.pitch_radius); + let n_top = v_radial.cross(v_tan).normalize(); + + let n_top = vec3( + s * dy_dt - 2.0 * PI * c * y, + -c * dy_dt - 2.0 * PI * s * y, + 2.0 * PI * self.pitch_radius, + ); + + // top mesh.vertices.push(Vertex { position: vec3( c * self.outer_radius, @@ -56,7 +54,7 @@ impl CrownGear { outer_scale * y, ), color, - normal: Vec3::ZERO, // FIXME calculate the normal + normal: n_top, }); mesh.vertices.push(Vertex { position: vec3( @@ -65,12 +63,74 @@ impl CrownGear { inner_scale * y, ), color, - normal: Vec3::ZERO, // FIXME calculate the normal + normal: n_top, }); - let base1 = 4 * k; - let base2 = 4 * ((k + 1) % sides); - for j1 in 0..4 { - let j2 = (j1 + 1) % 4; + + // bottom + mesh.vertices.push(Vertex { + position: vec3( + c * self.inner_radius, + s * self.inner_radius, + -self.base_thickness, + ), + color, + normal: vec3(0.0, 0.0, -1.0), + }); + mesh.vertices.push(Vertex { + position: vec3( + c * self.outer_radius, + s * self.outer_radius, + -self.base_thickness, + ), + color, + normal: vec3(0.0, 0.0, -1.0), + }); + + // inner + mesh.vertices.push(Vertex { + position: vec3( + c * self.inner_radius, + s * self.inner_radius, + inner_scale * y, + ), + color, + normal: vec3(-c, -s, 0.0), + }); + mesh.vertices.push(Vertex { + position: vec3( + c * self.inner_radius, + s * self.inner_radius, + -self.base_thickness, + ), + color, + normal: vec3(-c, -s, 0.0), + }); + + // outer + mesh.vertices.push(Vertex { + position: vec3( + c * self.outer_radius, + s * self.outer_radius, + -self.base_thickness, + ), + color, + normal: vec3(c, s, 0.0), + }); + mesh.vertices.push(Vertex { + position: vec3( + c * self.outer_radius, + s * self.outer_radius, + outer_scale * y, + ), + color, + normal: vec3(c, s, 0.0), + }); + + let base1 = 8 * k; + let base2 = 8 * ((k + 1) % sides); + for j in 0..4 { + let j1 = 2 * j; + let j2 = 2 * j + 1; mesh.faces.push( [base1 + j1, base2 + j1, base1 + j2].map(|index| index.try_into().unwrap()), );