primitive meshes
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
//! Plane primitive — horizontal plane in XZ with subdivisions.
|
||||
|
||||
use crate::core::geometry::Geometry;
|
||||
|
||||
/// Generates a horizontal plane in the XZ plane (normal +Y), centered at (0, 0, 0), with
|
||||
/// `width` × `depth` dimensions, subdivided into `seg_x` × `seg_z` cells.
|
||||
pub fn plane(width: f32, depth: f32, seg_x: u32, seg_z: u32) -> Geometry {
|
||||
let sx = seg_x.max(1);
|
||||
let sz = seg_z.max(1);
|
||||
let (mut positions, mut normals, mut uvs, mut indices) = (
|
||||
Vec::<[f32; 3]>::new(),
|
||||
Vec::<[f32; 3]>::new(),
|
||||
Vec::<[f32; 2]>::new(),
|
||||
Vec::<u16>::new(),
|
||||
);
|
||||
for z in 0..=sz {
|
||||
let vz = z as f32 / sz as f32;
|
||||
for x in 0..=sx {
|
||||
let vx = x as f32 / sx as f32;
|
||||
positions.push([(vx - 0.5) * width, 0.0, (vz - 0.5) * depth]);
|
||||
normals.push([0.0, 1.0, 0.0]);
|
||||
uvs.push([vx, vz]);
|
||||
}
|
||||
}
|
||||
for z in 0..sz {
|
||||
for x in 0..sx {
|
||||
let a = z * (sx + 1) + x;
|
||||
let b = a + 1;
|
||||
let c = (z + 1) * (sx + 1) + x;
|
||||
let d = c + 1;
|
||||
indices
|
||||
.extend_from_slice(&[a as u16, c as u16, b as u16, b as u16, c as u16, d as u16]);
|
||||
}
|
||||
}
|
||||
Geometry::new(positions)
|
||||
.with_normals(normals)
|
||||
.with_uvs(uvs)
|
||||
.with_indices(indices)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use glam::Vec3;
|
||||
|
||||
fn assert_valid(geo: &Geometry) {
|
||||
geo.validate().expect("generated geometry must validate");
|
||||
let positions = &geo.positions;
|
||||
let normals = geo.normals.as_ref().expect("normals present");
|
||||
let uvs = geo.uvs.as_ref().expect("uvs present");
|
||||
let indices = geo.indices.as_ref().expect("indices present");
|
||||
assert_eq!(normals.len(), positions.len());
|
||||
assert_eq!(uvs.len(), positions.len());
|
||||
for n in normals {
|
||||
let len = Vec3::from_array(*n).length();
|
||||
assert!((len - 1.0).abs() < 1e-3);
|
||||
}
|
||||
for &i in indices {
|
||||
assert!((i as usize) < positions.len());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plane_counts() {
|
||||
let g = plane(2.0, 3.0, 1, 1);
|
||||
assert_eq!(g.positions.len(), 4);
|
||||
assert_eq!(g.indices.as_ref().unwrap().len(), 6);
|
||||
assert_valid(&g);
|
||||
assert!(g.positions.iter().all(|p| p[1] == 0.0));
|
||||
let g2 = plane(2.0, 3.0, 4, 5);
|
||||
assert_eq!(g2.positions.len(), (4 + 1) * (5 + 1));
|
||||
assert_valid(&g2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user