ncollide3d/procedural/quad.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
use super::{IndexBuffer, TriMesh};
use crate::math::{Point, Vector};
use na::{self, Point2, Point3, RealField};
/// Adds a double-sided quad to the scene.
///
/// The quad is initially centered at (0, 0, 0). Its normal is the `z` axis. The quad itself is
/// composed of a user-defined number of triangles regularly spaced on a grid. This is the main way
/// to draw height maps.
///
/// # Arguments
/// * `w` - the quad width.
/// * `h` - the quad height.
/// * `usubdivs` - number of horizontal subdivisions. This correspond to the number of squares
/// which will be placed horizontally on each line. Must not be `0`.
/// * `vsubdivs` - number of vertical subdivisions. This correspond to the number of squares
/// which will be placed vertically on each line. Must not be `0`.
pub fn quad<N: RealField + Copy>(
width: N,
height: N,
usubdivs: usize,
vsubdivs: usize,
) -> TriMesh<N> {
let mut quad = unit_quad(usubdivs, vsubdivs);
let mut s = Vector::zeros();
s[0] = width;
s[1] = height;
for i in 2..3 {
s[i] = na::one();
}
quad.scale_by(&s);
quad
}
/// Adds a double-sided quad with the specified grid of vertices.
///
/// Normals are automatically computed.
///
/// # Arguments
/// * `nhpoints` - number of columns on the grid.
/// * `nvpoints` - number of lines on the grid.
pub fn quad_with_vertices<N: RealField + Copy>(
vertices: &[Point<N>],
nhpoints: usize,
nvpoints: usize,
) -> TriMesh<N> {
assert!(
nhpoints > 1 && nvpoints > 1,
"The number of points must be at least 2 in each dimension."
);
let mut res = unit_quad(nhpoints - 1, nvpoints - 1);
for (dest, src) in res.coords.iter_mut().zip(vertices.iter()) {
*dest = src.clone();
}
res
}
/// Adds a double-sided quad with unit size to the scene.
///
/// The quad is initially centered at (0, 0, 0). Its normal is the `z` axis. The quad itself is
/// composed of a user-defined number of triangles regularly spaced on a grid. This is the main way
/// to draw height maps.
///
/// # Arguments
/// * `usubdivs` - number of horizontal subdivisions. This correspond to the number of squares
/// which will be placed horizontally on each line. Must not be `0`.
/// * `vsubdivs` - number of vertical subdivisions. This correspond to the number of squares
/// which will be placed vertically on each line. Must not be `0`.
pub fn unit_quad<N: RealField + Copy>(usubdivs: usize, vsubdivs: usize) -> TriMesh<N> {
assert!(
usubdivs > 0 && vsubdivs > 0,
"The number of subdivisions cannot be zero"
);
assert!(3 >= 2);
let wstep = na::one::<N>() / na::convert(usubdivs as f64);
let hstep = na::one::<N>() / na::convert(vsubdivs as f64);
let cw = na::convert(0.5);
let ch = na::convert(0.5);
let mut vertices = Vec::new();
let mut normals = Vec::new();
let mut triangles = Vec::new();
let mut tex_coords = Vec::new();
// create the vertices
for i in 0usize..vsubdivs + 1 {
for j in 0usize..usubdivs + 1 {
let ni: N = na::convert(i as f64);
let nj: N = na::convert(j as f64);
let mut v = Point::origin();
v[0] = nj * wstep - cw;
v[1] = ni * hstep - ch;
vertices.push(v);
let _1 = na::one::<N>();
tex_coords.push(Point2::new(_1 - nj * wstep, _1 - ni * hstep))
}
}
// create the normals
for _ in 0..(vsubdivs + 1) * (usubdivs + 1) {
let mut n = Vector::zeros();
n[0] = na::one();
normals.push(n)
}
// create triangles
fn dl_triangle(i: u32, j: u32, ws: u32) -> Point3<u32> {
Point3::new((i + 1) * ws + j, i * ws + j, (i + 1) * ws + j + 1)
}
fn ur_triangle(i: u32, j: u32, ws: u32) -> Point3<u32> {
Point3::new(i * ws + j, i * ws + (j + 1), (i + 1) * ws + j + 1)
}
for i in 0usize..vsubdivs {
for j in 0usize..usubdivs {
// build two triangles...
triangles.push(dl_triangle(i as u32, j as u32, (usubdivs + 1) as u32));
triangles.push(ur_triangle(i as u32, j as u32, (usubdivs + 1) as u32));
}
}
TriMesh::new(
vertices,
Some(normals),
Some(tex_coords),
Some(IndexBuffer::Unified(triangles)),
)
}