-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Meshing for Triangle3d
primitive
#12686
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
49a941d
39ac125
830b526
72c95aa
20eeb80
a999453
f5d247f
54d9264
b66bf03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ mod cylinder; | |
mod plane; | ||
mod sphere; | ||
mod torus; | ||
pub(crate) mod triangle3d; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is this in a different format to the other module declarations? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's pub(crate) so that the |
||
|
||
pub use capsule::*; | ||
pub use cylinder::*; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
use bevy_math::{primitives::Triangle3d, Vec3}; | ||
use wgpu::PrimitiveTopology; | ||
|
||
use crate::{ | ||
mesh::{Indices, Mesh, Meshable}, | ||
render_asset::RenderAssetUsages, | ||
}; | ||
|
||
impl Meshable for Triangle3d { | ||
type Output = Mesh; | ||
|
||
fn mesh(&self) -> Self::Output { | ||
let positions: Vec<_> = self.vertices.into(); | ||
let uvs: Vec<_> = uv_coords(self).into(); | ||
|
||
// Every vertex has the normal of the face of the triangle (or zero if the triangle is degenerate). | ||
let normal: Vec3 = self.normal().map_or(Vec3::ZERO, |n| n.into()); | ||
let normals = vec![normal; 3]; | ||
|
||
let indices = Indices::U32(vec![0, 1, 2]); | ||
|
||
Mesh::new( | ||
PrimitiveTopology::TriangleList, | ||
RenderAssetUsages::default(), | ||
) | ||
.with_inserted_indices(indices) | ||
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) | ||
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) | ||
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) | ||
} | ||
} | ||
|
||
/// Unskewed uv-coordinates for a [`Triangle3d`]. | ||
#[inline] | ||
pub(crate) fn uv_coords(triangle: &Triangle3d) -> [[f32; 2]; 3] { | ||
let [a, b, c] = triangle.vertices; | ||
|
||
let main_length = a.distance(b); | ||
let Some(x) = (b - a).try_normalize() else { | ||
return [[0., 0.], [1., 0.], [0., 1.]]; | ||
}; | ||
let y = c - a; | ||
|
||
// `x` corresponds to one of the axes in uv-coordinates; | ||
// to uv-map the triangle without skewing, we use the orthogonalization | ||
// of `y` with respect to `x` as the second direction and construct a rectangle that | ||
// contains `triangle`. | ||
let y_proj = y.project_onto_normalized(x); | ||
|
||
// `offset` represents the x-coordinate of the point `c`; note that x has been shrunk by a | ||
// factor of `main_length`, so `offset` follows it. | ||
let offset = y_proj.dot(x) / main_length; | ||
|
||
// Obtuse triangle leaning to the left => x direction extends to the left, shifting a from 0. | ||
if offset < 0. { | ||
let total_length = 1. - offset; | ||
let a_uv = [offset.abs() / total_length, 0.]; | ||
let b_uv = [1., 0.]; | ||
let c_uv = [0., 1.]; | ||
|
||
[a_uv, b_uv, c_uv] | ||
} | ||
// Obtuse triangle leaning to the right => x direction extends to the right, shifting b from 1. | ||
else if offset > 1. { | ||
let a_uv = [0., 0.]; | ||
let b_uv = [1. / offset, 0.]; | ||
let c_uv = [1., 1.]; | ||
|
||
[a_uv, b_uv, c_uv] | ||
} | ||
// Acute triangle => no extending necessary; a remains at 0 and b remains at 1. | ||
else { | ||
let a_uv = [0., 0.]; | ||
let b_uv = [1., 0.]; | ||
let c_uv = [offset, 1.]; | ||
|
||
[a_uv, b_uv, c_uv] | ||
} | ||
} | ||
|
||
impl From<Triangle3d> for Mesh { | ||
fn from(triangle: Triangle3d) -> Self { | ||
triangle.mesh() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::uv_coords; | ||
use bevy_math::primitives::Triangle3d; | ||
|
||
#[test] | ||
fn uv_test() { | ||
use bevy_math::vec3; | ||
let mut triangle = Triangle3d::new(vec3(0., 0., 0.), vec3(2., 0., 0.), vec3(-1., 1., 0.)); | ||
|
||
let [a_uv, b_uv, c_uv] = uv_coords(&triangle); | ||
assert_eq!(a_uv, [1. / 3., 0.]); | ||
assert_eq!(b_uv, [1., 0.]); | ||
assert_eq!(c_uv, [0., 1.]); | ||
|
||
triangle.vertices[2] = vec3(3., 1., 0.); | ||
let [a_uv, b_uv, c_uv] = uv_coords(&triangle); | ||
assert_eq!(a_uv, [0., 0.]); | ||
assert_eq!(b_uv, [2. / 3., 0.]); | ||
assert_eq!(c_uv, [1., 1.]); | ||
|
||
triangle.vertices[2] = vec3(2., 1., 0.); | ||
let [a_uv, b_uv, c_uv] = uv_coords(&triangle); | ||
assert_eq!(a_uv, [0., 0.]); | ||
assert_eq!(b_uv, [1., 0.]); | ||
assert_eq!(c_uv, [1., 1.]); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✨fancy✨