fix normals

This commit is contained in:
numzero 2026-10-18 00:44:42 +03:00
parent 49cfc215a4
commit 5c6ef7c758
2 changed files with 71 additions and 62 deletions

View File

@ -7,73 +7,77 @@ use crate::{
render::mesh::{CpuMeshIndexed, Vertex},
};
pub struct CrownGear {
#[derive(Debug, Clone, Copy)]
pub struct CrownGearDesc {
pub profile: Profile,
pub pitch_radius: f32,
}
#[derive(Debug, Clone, Copy)]
pub struct CrownGearVisual {
pub inner_radius: f32,
pub outer_radius: f32,
pub base_thickness: f32,
}
impl CrownGear {
pub fn make_mesh(&self, sides: usize, color: Vec3) -> CpuMeshIndexed {
let teeth = 2.0 * self.pitch_radius;
let inner_scale = self.inner_radius / self.pitch_radius;
let outer_scale = self.outer_radius / self.pitch_radius;
pub fn make_mesh(
desc: &CrownGearDesc,
visual: &CrownGearVisual,
sides: usize,
color: Vec3,
) -> CpuMeshIndexed {
let teeth = 2.0 * desc.pitch_radius;
let inner_scale = visual.inner_radius / desc.pitch_radius;
let outer_scale = visual.outer_radius / desc.pitch_radius;
let mut mesh = CpuMeshIndexed::new();
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;
let rot = Mat3A::from_rotation_z(2.0 * PI * t);
let mut mesh = CpuMeshIndexed::new();
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;
let rot = Mat3A::from_rotation_z(2.0 * PI * t);
let tooth = t * teeth;
let y = self.profile.y_from_tooth(tooth);
let tooth = t * teeth;
let y = desc.profile.y_from_tooth(tooth);
let n_top = {
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);
vec3(-2.0 * PI * y, -dy_dt, 2.0 * PI * self.pitch_radius)
};
let n_top = {
let eps = 1e-3;
let dy_dt = teeth
* (desc.profile.y_from_tooth(tooth + eps) - desc.profile.y_from_tooth(tooth - eps))
/ (2.0 * eps);
vec3(-2.0 * PI * y, -dy_dt, 2.0 * PI * desc.pitch_radius)
};
let vertex = |x, z, n| Vertex {
position: rot * vec3(x, 0.0, z),
color,
normal: n,
};
mesh.vertices.extend([
// top
vertex(self.outer_radius, outer_scale * y, n_top),
vertex(self.inner_radius, inner_scale * y, n_top),
// bottom
vertex(self.inner_radius, -self.base_thickness, -Vec3::Z),
vertex(self.outer_radius, -self.base_thickness, -Vec3::Z),
// inner
vertex(self.inner_radius, inner_scale * y, -Vec3::X),
vertex(self.inner_radius, -self.base_thickness, -Vec3::X),
// outer
vertex(self.outer_radius, -self.base_thickness, Vec3::X),
vertex(self.outer_radius, outer_scale * y, Vec3::X),
]);
let vertex = |x, z, n| Vertex {
position: rot * vec3(x, 0.0, z),
color,
normal: n,
};
mesh.vertices.extend([
// top
vertex(visual.outer_radius, outer_scale * y, n_top),
vertex(visual.inner_radius, inner_scale * y, n_top),
// bottom
vertex(visual.inner_radius, -visual.base_thickness, -Vec3::Z),
vertex(visual.outer_radius, -visual.base_thickness, -Vec3::Z),
// inner
vertex(visual.inner_radius, inner_scale * y, -Vec3::X),
vertex(visual.inner_radius, -visual.base_thickness, -Vec3::X),
// outer
vertex(visual.outer_radius, -visual.base_thickness, Vec3::X),
vertex(visual.outer_radius, outer_scale * y, Vec3::X),
]);
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()),
);
mesh.faces.push(
[base2 + j2, base1 + j2, base2 + j1].map(|index| index.try_into().unwrap()),
);
}
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()));
mesh.faces
.push([base2 + j2, base1 + j2, base2 + j1].map(|index| index.try_into().unwrap()));
}
mesh
}
mesh
}

View File

@ -80,14 +80,19 @@ impl Core {
let depth = Self::create_depth_buffer(&device, pixel_size);
let mesh_pipeline = render::mesh::Pipeline::new(&device);
let crown_gear_mesh = crown_gear::CrownGear {
profile: Default::default(),
pitch_radius: 24.0,
inner_radius: 16.0,
outer_radius: 30.0,
base_thickness: 2.0,
}
.make_mesh(600, vec3(0.5, 0.5, 0.5));
let crown_gear_mesh = crown_gear::make_mesh(
&crown_gear::CrownGearDesc {
profile: Default::default(),
pitch_radius: 24.0,
},
&crown_gear::CrownGearVisual {
inner_radius: 16.0,
outer_radius: 30.0,
base_thickness: 2.0,
},
600,
vec3(0.5, 0.5, 0.5),
);
let mesh_gray = render::mesh::GpuMeshIndexed::new(&device, &crown_gear_mesh);
Self::configure_surface(&surface, &device, pixel_size);