generate a faceted mesh
This commit is contained in:
parent
8c0ae03add
commit
cfbd5a41c3
|
|
@ -4,7 +4,7 @@ use glam::{Mat3A, Vec3, vec3};
|
|||
|
||||
use crate::{
|
||||
profile::Profile,
|
||||
render::mesh::{CpuMeshIndexed, Vertex},
|
||||
render::mesh::{MeshIndexed, Vertex},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
@ -20,17 +20,17 @@ pub struct CrownGearVisual {
|
|||
pub base_thickness: f32,
|
||||
}
|
||||
|
||||
pub fn make_mesh(
|
||||
pub fn make_mesh_smooth(
|
||||
desc: &CrownGearDesc,
|
||||
visual: &CrownGearVisual,
|
||||
sides: usize,
|
||||
color: Vec3,
|
||||
) -> CpuMeshIndexed {
|
||||
) -> MeshIndexed {
|
||||
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();
|
||||
let mut mesh = MeshIndexed::new();
|
||||
mesh.vertices.reserve_exact(8 * sides);
|
||||
mesh.faces.reserve_exact(8 * sides);
|
||||
for k in 0..sides {
|
||||
|
|
@ -81,3 +81,43 @@ pub fn make_mesh(
|
|||
}
|
||||
mesh
|
||||
}
|
||||
|
||||
pub fn make_mesh_simple(
|
||||
desc: &CrownGearDesc,
|
||||
visual: &CrownGearVisual,
|
||||
sides: usize,
|
||||
) -> MeshIndexed<Vec3> {
|
||||
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 = MeshIndexed::new();
|
||||
mesh.vertices.reserve_exact(4 * 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 = desc.profile.y_from_tooth(tooth);
|
||||
|
||||
let vertex = |x, z| rot * vec3(x, 0.0, z);
|
||||
mesh.vertices.extend([
|
||||
vertex(visual.inner_radius, -visual.base_thickness),
|
||||
vertex(visual.outer_radius, -visual.base_thickness),
|
||||
vertex(visual.outer_radius, outer_scale * y),
|
||||
vertex(visual.inner_radius, inner_scale * y),
|
||||
]);
|
||||
|
||||
let base1 = 4 * k;
|
||||
let base2 = 4 * ((k + 1) % sides);
|
||||
for j1 in 0..4 {
|
||||
let j2 = (j1 + 1) % 4;
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ 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::make_mesh(
|
||||
let crown_gear_mesh = crown_gear::make_mesh_simple(
|
||||
&crown_gear::CrownGearDesc {
|
||||
profile: Default::default(),
|
||||
pitch_radius: 24.0,
|
||||
|
|
@ -91,8 +91,10 @@ impl Core {
|
|||
base_thickness: 2.0,
|
||||
},
|
||||
600,
|
||||
vec3(0.5, 0.5, 0.5),
|
||||
);
|
||||
)
|
||||
.to_mesh()
|
||||
.to_standard_mesh(vec3(0.5, 0.5, 0.5))
|
||||
.into_indexed();
|
||||
let mesh_gray = render::mesh::GpuMeshIndexed::new(&device, &crown_gear_mesh);
|
||||
|
||||
Self::configure_surface(&surface, &device, pixel_size);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@ use bytemuck::{Pod, Zeroable, bytes_of, cast_slice};
|
|||
use glam::{Mat4, Vec3};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
pub use cpu::*;
|
||||
|
||||
mod cpu;
|
||||
|
||||
static SHADER: &str = include_str!("mesh.wgsl");
|
||||
|
||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||
|
|
@ -22,23 +26,6 @@ pub struct Params {
|
|||
pub _zero: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct CpuMesh {
|
||||
pub faces: Vec<[Vertex; 3]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct CpuMeshIndexed {
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub faces: Vec<[u16; 3]>,
|
||||
}
|
||||
|
||||
impl CpuMeshIndexed {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GpuMesh {
|
||||
vertices: wgpu::Buffer,
|
||||
vertex_count: u32,
|
||||
|
|
|
|||
102
src/render/mesh/cpu.rs
Normal file
102
src/render/mesh/cpu.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
use glam::Vec3;
|
||||
|
||||
use super::Vertex;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Mesh<T: Copy = Vertex> {
|
||||
pub faces: Vec<[T; 3]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MeshIndexed<T: Copy = Vertex> {
|
||||
pub vertices: Vec<T>,
|
||||
pub faces: Vec<[u16; 3]>,
|
||||
}
|
||||
|
||||
pub type CpuMesh = Mesh<Vertex>;
|
||||
pub type CpuMeshIndexed = MeshIndexed<Vertex>;
|
||||
|
||||
impl<T: Copy> Mesh<T> {
|
||||
pub fn new() -> Self {
|
||||
Self { faces: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn concat(meshes: impl IntoIterator<Item = Self>) -> Self {
|
||||
Self {
|
||||
faces: meshes
|
||||
.into_iter()
|
||||
.map(|mesh| mesh.faces)
|
||||
.flatten()
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_indexed(self) -> MeshIndexed<T> {
|
||||
if self.faces.len() >= (1 << 16) / 3 {
|
||||
panic!("too many faces");
|
||||
}
|
||||
let n_faces = self.faces.len() as u16;
|
||||
MeshIndexed {
|
||||
vertices: self.faces.into_iter().flatten().collect(),
|
||||
faces: (0..n_faces)
|
||||
.map(|face| [3 * face, 3 * face + 1, 3 * face + 2])
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mesh<Vec3> {
|
||||
pub fn to_standard_mesh(&self, color: Vec3) -> CpuMesh {
|
||||
CpuMesh {
|
||||
faces: self
|
||||
.faces
|
||||
.iter()
|
||||
.map(|face| {
|
||||
let [a, b, c] = face;
|
||||
let normal = (b - a).cross(c - a).normalize();
|
||||
face.map(|position| Vertex {
|
||||
position,
|
||||
color,
|
||||
normal,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> MeshIndexed<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
vertices: Vec::new(),
|
||||
faces: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn concat(meshes: impl IntoIterator<Item = Self>) -> Self {
|
||||
let mut ret = Self::new();
|
||||
for mesh in meshes {
|
||||
let base = ret.vertices.len() as u16;
|
||||
ret.vertices.extend(mesh.vertices);
|
||||
if ret.vertices.len() > 1 << 16 {
|
||||
panic!("too many vertices");
|
||||
}
|
||||
ret.faces.extend(
|
||||
mesh.faces
|
||||
.into_iter()
|
||||
.map(|face| face.map(|index| base + index)),
|
||||
);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn to_mesh(&self) -> Mesh<T> {
|
||||
Mesh {
|
||||
faces: self
|
||||
.faces
|
||||
.iter()
|
||||
.map(|face| face.map(|index| self.vertices[index as usize]))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user