Skip to content

Commit 70a56dd

Browse files
committed
Improve outline normal generation for flat meshes.
1 parent c8492ed commit 70a56dd

2 files changed

Lines changed: 39 additions & 25 deletions

File tree

examples/ui_mode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ impl Shapes {
9393
impl FromWorld for Shapes {
9494
fn from_world(world: &mut World) -> Self {
9595
let mut meshes = world.get_resource_mut::<Assets<Mesh>>().unwrap();
96-
let settings = GenerateOutlineNormalsSettings::default().with_stretch_edges(true);
96+
let settings = GenerateOutlineNormalsFrom::ExternalBisector.into();
9797
Self {
9898
cone: meshes.add(
9999
Cone::new(1.0, 1.0)

src/generate.rs

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,27 +47,38 @@ impl Iterator for IndexIterator<'_> {
4747

4848
impl ExactSizeIterator for IndexIterator<'_> {}
4949

50+
/// Source from which outline normals are derived.
51+
#[derive(Copy, Clone, Default, PartialEq, Eq)]
52+
#[non_exhaustive]
53+
pub enum GenerateOutlineNormalsFrom {
54+
/// Use vertex normals provided by the mesh. This falls back to
55+
/// `FaceNormal` if no vertex normals are available.
56+
#[default]
57+
VertexNormal,
58+
/// Use normals computed from face geometry.
59+
FaceNormal,
60+
/// Use the external bisector at each vertex. This is suitable for
61+
/// non-manifold meshes.
62+
ExternalBisector,
63+
}
64+
5065
/// Settings for generating mesh outline normals.
5166
#[derive(Clone, Default)]
5267
pub struct GenerateOutlineNormalsSettings {
53-
ignore_vertex_normals: bool,
54-
stretch_edges: bool,
68+
from: GenerateOutlineNormalsFrom,
5569
}
5670

5771
/// Settings for generating mesh outline normals.
5872
impl GenerateOutlineNormalsSettings {
59-
/// If true, any pre-existing vertex normals are ignored and freshly
60-
/// calculated face normals are used when generating outline normals.
61-
pub fn with_ignore_vertex_normals(mut self, value: bool) -> Self {
62-
self.ignore_vertex_normals = value;
73+
pub fn with_from(mut self, value: GenerateOutlineNormalsFrom) -> Self {
74+
self.from = value;
6375
self
6476
}
77+
}
6578

66-
/// If true, an extra component is added to the generated outline normals
67-
/// to angle them outwards at edges of non-manifold meshes.
68-
pub fn with_stretch_edges(mut self, value: bool) -> Self {
69-
self.stretch_edges = value;
70-
self
79+
impl From<GenerateOutlineNormalsFrom> for GenerateOutlineNormalsSettings {
80+
fn from(value: GenerateOutlineNormalsFrom) -> Self {
81+
Self::default().with_from(value)
7182
}
7283
}
7384

@@ -128,7 +139,11 @@ impl OutlineMeshExt for Mesh {
128139
)),
129140
}?;
130141
let normals = match self.attribute(Mesh::ATTRIBUTE_NORMAL) {
131-
Some(VertexAttributeValues::Float32x3(p)) if !settings.ignore_vertex_normals => Some(p),
142+
Some(VertexAttributeValues::Float32x3(p))
143+
if settings.from == GenerateOutlineNormalsFrom::VertexNormal =>
144+
{
145+
Some(p)
146+
}
132147
_ => None,
133148
};
134149
let mut map = HashMap::<[FloatOrd; 3], Vec3>::with_capacity(positions.len());
@@ -142,21 +157,20 @@ impl OutlineMeshExt for Mesh {
142157
let n = map
143158
.entry([FloatOrd(p0.x), FloatOrd(p0.y), FloatOrd(p0.z)])
144159
.or_default();
145-
*n += angle
146-
* if let Some(ns) = normals {
147-
// Use vertex normal
148-
Vec3::from(ns[j0])
149-
} else {
150-
// Calculate face normal
151-
(p1 - p0).cross(p2 - p0).normalize_or_zero()
152-
};
153-
if settings.stretch_edges {
160+
let vector = if settings.from == GenerateOutlineNormalsFrom::ExternalBisector {
161+
// External bisector
154162
let face_normal = (p1 - p0).cross(p2 - p0);
155163
let perp1 = Dir3::new(face_normal.cross(p0 - p1)).unwrap();
156164
let perp2 = Dir3::new(face_normal.cross(p2 - p0)).unwrap();
157-
let stretch = perp1.slerp(perp2, 0.5).as_vec3();
158-
*n += angle * stretch;
159-
}
165+
perp1.slerp(perp2, 0.5).as_vec3()
166+
} else if let Some(ns) = normals {
167+
// Use vertex normal
168+
Vec3::from(ns[j0])
169+
} else {
170+
// Calculate face normal
171+
(p1 - p0).cross(p2 - p0).normalize_or_zero()
172+
};
173+
*n += angle * vector;
160174
}
161175
}
162176
let mut outlines = Vec::with_capacity(positions.len());

0 commit comments

Comments
 (0)