Ridges and valleys describe curvature-driven features on smooth surfaces. Many meshes, however, also contain
piecewise-smooth geometry: hard edges, chamfers, CAD-style corners, and manually sculpted creases. These features
are not curvature extrema; they are discontinuities in the surface normal field.
To detect these discontinuities, crease extraction uses the dihedral angle between adjacent faces. Unlike ridge and
valley tracing, it does not need curvature fields or principal directions. It works directly from mesh adjacency
and face normals, making it fast, robust, and applicable to any triangle mesh.
6.1 Computing the Dihedral Angle
For an edge shared by two faces, the dihedral angle measures how sharply those faces meet along the edge. The
calculation starts from the two adjacent face normals and produces an angle θ that describes crease sharpness.
A simple normal-to-normal comparison would compute:
\[\theta =\arccos\left(\left\langle n_{0},\; n_{1}\right\rangle \right)\]
That direct comparison can be unstable because it does not isolate rotation around the shared edge. To measure crease
sharpness more consistently, we first project both normals onto the plane orthogonal to the edge direction.
Let the edge be defined by its two endpoint vertices:
\[e=p_{1}-p_{0},\ \widehat{e}=\frac{e}{\parallel e\parallel }\]
Next, remove from each normal the component parallel to the edge direction:
\[n_{0}^{\prime }=n_{0}-\widehat{e}\text{\,}\left\langle n_{0},\; \widehat{e}\right\rangle\]
\[n_{1}^{\prime }=n_{1}-\widehat{e}\text{\,}\left\langle n_{1},\; \widehat{e}\right\rangle\]
Normalize the projected normals:
\[{\widehat{n}}_{0}^{\prime }=\frac{n_{0}^{\prime }}{\parallel n_{0}^{\prime }\parallel },\ {\widehat{n}}_{1}^{\prime }=\frac{n_{1}^{\prime }}{\parallel n_{1}^{\prime }\parallel }\]
Finally, compute the projected angle:
\[\theta =\arccos\left(\left\langle {\widehat{n}}_{0}^{\prime },\; {\widehat{n}}_{1}^{\prime }\right\rangle \right)\]
The resulting angle is expressed in degrees and remains stable even on irregular meshes.
6.1.1 Boundary Edges
If an edge has only one adjacent face, it lies on the mesh boundary. In this implementation, boundary edges are
assigned a dihedral angle of zero and are not classified as creases.
6.1.2 Thresholding Crease Angles
A user-defined threshold determines whether an edge is sharp enough to count as a crease:
\[\theta \geq {\tau }_{\theta }\ \Rightarrow \ {crease\ edge}\]
Typical threshold ranges are:
-
30°–45° for CAD models
-
50°–70° for scanned meshes
-
20°–30° for stylized assets with subtle creases
The extractor computes these angles using the adjacency structure built earlier, so no additional topology pass
is required.
6.2 Marking Crease Edges
Once each dihedral angle is available, crease detection becomes a simple filtering pass over the edge list:
- iterate over every mesh edge
- compute its dihedral angle
- mark the edge as a crease when the angle exceeds the threshold
The marked edges form a graph on the mesh. The next step is to convert that graph into ordered polylines.
6.3 Building Crease Polylines
Crease edges usually form connected chains. To make them useful for rendering and downstream processing, the
extractor assembles them into maximal polylines: the longest connected crease paths that can be traced without
reusing an edge.
6.3.1 Mapping Vertices to Crease Edges
First, the extractor builds a map from each vertex to the crease edges incident on it. This local lookup
makes it efficient to continue a polyline from one edge to the next.
6.3.2 Growing a Polyline
Starting from an unused crease edge, the extractor grows a line in both directions:
- Identify the edge’s two endpoint vertices.
- Grow one side of the polyline from each endpoint.
- At each step, choose an unused crease edge incident to the current vertex.
- move to the opposite endpoint of that edge
- mark the traversed edge as used
- continue until no unused crease edge remains
- Stop when both sides can no longer be extended.
This process produces two partial vertex sequences:
-
left side — the path grown from one endpoint
-
right side — the path grown from the other endpoint
The extractor reverses the left side and appends the right side, producing one ordered crease polyline.
6.3.3 Handling T-Junctions
Some meshes contain T-junctions, where more than two crease edges meet at the same vertex. The algorithm handles
these cases conservatively:
- follow one unused edge at a time
- never revisit an edge once it has been used
- split branching structures into separate polylines
This behavior is desirable because T-junctions usually represent multiple distinct crease paths rather than a
single continuous feature.
6.3.4 Minimum-Length Filtering
Very short crease polylines, such as one- or two-edge fragments, are often noise or insignificant detail. The extractor
discards any polyline shorter than minLineSize.
6.3.5 Final Assembly
Each accepted polyline is converted into a FeatureLine object containing:
- vertex indices
- 3D points for rendering
- optional smoothing, if enabled
The result is a clean set of crease lines ready for visualization or further processing.
6.4 Summary
Crease extraction is a direct and robust process:
- Compute dihedral angles for all mesh edges.
- Mark edges whose angle exceeds the crease threshold.
- Assemble connected crease edges into ordered polylines.
- Filter out short or insignificant line fragments.
- Convert accepted polylines into FeatureLine objects.
Unlike ridge and valley extraction, crease detection does not depend on curvature fields. It works directly from
connectivity and face normals, making it broadly applicable and especially effective for CAD models, mechanical
parts, and stylized assets.