# How the Smooth Normal Degrees Parameter Affects Feature Detection in AutoRemesher

> Discover how AutoRemesher's smooth normal degrees parameter impacts feature detection. Understand its role in PN-Triangle subdivision and exclusive reliance on sharp-edge angle thresholds for accurate results.

- Repository: [Jeremy HU/autoremesher](https://github.com/huxingyi/autoremesher)
- Tags: deep-dive
- Published: 2026-07-11

---

**TLDR:** In huxingyi/autoremesher, the smooth normal degrees parameter controls PN-Triangle subdivision to create smoother projection surfaces, but it does not directly influence which edges are classified as features—feature detection remains exclusively governed by the sharp-edge angle threshold.

The smooth normal degrees parameter in AutoRemesher configures an optional preprocessing stage that smooths the input mesh before remeshing iterations begin. While this setting affects the geometric surface used for vertex projection in [`isotropicremesher.cpp`](https://github.com/huxingyi/autoremesher/blob/main/isotropicremesher.cpp), it operates independently of the feature detection logic that identifies sharp creases and boundaries. Understanding this distinction is crucial for achieving predictable results when remeshing CAD or scanned models with hard edges.

## What the Smooth Normal Degrees Parameter Controls

When you invoke `setSmoothNormalDegrees()` with a positive value (declared in [`thirdparty/isotropicremesher/isotropicremesher.h`](https://github.com/huxingyi/autoremesher/blob/main/thirdparty/isotropicremesher/isotropicremesher.h)), the remesher executes a three-stage smoothing pipeline inside `IsotropicRemesher::remesh()` before the main remeshing iterations commence.

### Computing Per-Vertex Smooth Normals

The method `computeSmoothVertexNormals()` calculates an angle-area weighted average of adjoining face normals for each vertex. It filters these contributions using an angular threshold converted from degrees to radians (`thresholdRadians = degrees·π/180`), storing the results in the member variable `m_smoothVertexNormals`. These values are subsequently copied to the half-edge mesh vertices via `vertex->_smoothNormal` for use during subdivision.

### PN-Triangle Subdivision and AABB Tree Construction

Next, `subdivideMeshWithPNTriangles()` generates refined geometry by computing edge mid-points using the smooth normals (`pnTriangleEdgeMidpoint`). This process creates `m_smoothVertices` and `m_smoothTriangles` representing a higher-resolution curved surface. The system then builds a new AABB tree from this subdivided mesh, which the projection step uses instead of the original piecewise-linear geometry to guide vertex placement.

## How Feature Detection Actually Works

Feature detection occurs independently in `IsotropicHalfedgeMesh::featureEdges()`, defined in [`thirdparty/isotropicremesher/isotropichalfedgemesh.cpp`](https://github.com/huxingyi/autoremesher/blob/main/thirdparty/isotropicremesher/isotropichalfedgemesh.cpp). This routine marks an edge as "featured" when the dihedral angle between two incident faces exceeds the sharp-edge threshold set via `setSharpEdgeIncludedAngle()`.

Crucially, the algorithm examines raw **face normals** (`leftFace->_normal`) and completely ignores the smooth normals computed earlier. The detection logic checks `m_sharpEdgeThresholdRadians` and operates on the original mesh topology, not the PN-Triangle subdivided version. Consequently, adjusting the smooth normal degrees does not alter the set of edges identified as sharp features.

## The Indirect Relationship Between Smooth Normals and Features

Although the smooth normal degrees parameter does not directly affect feature classification, it indirectly influences final mesh quality. By projecting vertices onto the smoother PN-Triangle surface rather than the original faceted geometry, the remesher can reduce the appearance of spurious artifacts in regions where the input mesh was noisy or poorly tessellated. However, genuine hard edges exceeding the sharp-edge angle threshold will remain preserved regardless of the smoothing setting, because feature detection relies solely on the angle between raw face normals.

## Practical Configuration Example

To enable normal smoothing while maintaining explicit control over feature detection, configure both parameters as shown in this implementation pattern:

```cpp
#include "isotropicremesher.h"

// Initialize remesher with your mesh data
IsotropicRemesher remesher(vertices, triangles);

// Enable 30-degree normal smoothing for PN-Triangle subdivision
remesher.setSmoothNormalDegrees(30.0);

// Preserve edges where face normals differ by more than 30 degrees
remesher.setSharpEdgeIncludedAngle(30.0);

// Execute 5 remeshing iterations
remesher.remesh(5);

```

Inside `IsotropicRemesher::remesh()` (located in [`thirdparty/isotropicremesher/isotropicremesher.cpp`](https://github.com/huxingyi/autoremesher/blob/main/thirdparty/isotropicremesher/isotropicremesher.cpp)), the implementation conditionalizes the smoothing pipeline separately from feature detection:

```cpp
if (m_smoothNormalDegrees > 0.0) {
    computeSmoothVertexNormals();       // Step 1: Normal smoothing
    subdivideMeshWithPNTriangles();     // Step 2: PN-Triangle subdivision
    // Build AABB tree from the smooth (subdivided) mesh
    // Projection later uses this smoother representation
}
...
// Feature detection (independent of smooth normals)
if (m_sharpEdgeThresholdRadians > 0) {
    splitLongEdges(maxTargetLengthSquared);
    m_halfedgeMesh->updateTriangleNormals();
    m_halfedgeMesh->featureEdges(m_sharpEdgeThresholdRadians);
}

```

## Summary

- The **smooth normal degrees** parameter activates PN-Triangle subdivision by triggering `computeSmoothVertexNormals()` and `subdivideMeshWithPNTriangles()` in [`isotropicremesher.cpp`](https://github.com/huxingyi/autoremesher/blob/main/isotropicremesher.cpp).
- **Feature detection** relies solely on the sharp-edge angle threshold in `IsotropicHalfedgeMesh::featureEdges()`, examining raw face normals (`leftFace->_normal`) without considering smooth normals.
- Smooth normals create a curved projection surface that improves vertex placement quality, but they do not alter which edges the algorithm classifies as sharp features.
- Configure both `setSmoothNormalDegrees()` and `setSharpEdgeIncludedAngle()` independently to control surface smoothness versus feature preservation.

## Frequently Asked Questions

### Does increasing smooth normal degrees reduce sharp features in the output?

No. The smooth normal degrees parameter only affects the projection surface used during vertex placement via PN-Triangle subdivision. It does not modify the feature detection logic that relies on the sharp-edge angle threshold in `featureEdges()`. To reduce the number of preserved sharp features, you must increase the angle threshold passed to `setSharpEdgeIncludedAngle()`, not the smooth normal degrees.

### What value should I set for smooth normal degrees?

A typical value ranges between **15 and 45 degrees**, depending on how much smoothing your input mesh requires. This value defines the angular threshold in `computeSmoothVertexNormals()` for including adjacent face normals in the weighted average. Set it to `0.0` to disable PN-Triangle subdivision entirely, causing vertices to project directly onto the original piecewise-linear geometry.

### Why does feature detection use face normals instead of smooth normals?

The `featureEdges()` method in [`isotropichalfedgemesh.cpp`](https://github.com/huxingyi/autoremesher/blob/main/isotropichalfedgemesh.cpp) uses raw face normals (`leftFace->_normal`) because it must detect geometric creases based on the actual dihedral angles between adjacent faces. Smooth normals represent averaged, artificial directions used for interpolating subdivision surfaces, not the true geometric discontinuities that define sharp edges in the original model.

### Where is the smooth normal logic implemented in the source code?

The smooth normal logic resides in [`thirdparty/isotropicremesher/isotropicremesher.cpp`](https://github.com/huxingyi/autoremesher/blob/main/thirdparty/isotropicremesher/isotropicremesher.cpp), specifically within `computeSmoothVertexNormals()`, `subdivideMeshWithPNTriangles()`, and the conditional block inside `remesh()`. The public API declarations are located in [`thirdparty/isotropicremesher/isotropicremesher.h`](https://github.com/huxingyi/autoremesher/blob/main/thirdparty/isotropicremesher/isotropicremesher.h), while the isolated feature detection routine remains in [`thirdparty/isotropicremesher/isotropichalfedgemesh.cpp`](https://github.com/huxingyi/autoremesher/blob/main/thirdparty/isotropicremesher/isotropichalfedgemesh.cpp).