Normals of Low Polygon Mesh with hard/soft edge

Hello,

We are looking at producing assets without subdivisions (subdivisionScheme = “none”).
The assets are produced in Maya using a low polygon approach where the modeler choose the edge “hardness” manually.

In maya, the notion of “smooth” or “hard” edge controls the normals of the vertices of that edge.
If the edge is “hard” the normals are split per face, so the vertex has as many normals as adjacent faces.
If the edge is “smooth” the vertex has a single normal, being the mean of the normal of adjacent faces.
The look of the mesh is generated from this information.

From my investigation, it seems that USD cannot store this king of data.
Normals are either implicite (when using a subdivisionScheme which “define their own normals”) or explicit per vertex per face.

I know from experience that Alembic stores normals like USD, per vertex per face or nothing.

From my understanding, it looks like both Alembic and USD have been created to handle subdivision mesh and thus per edge normal has not been implemented.

Do you know the reason for this implementation ?
Would it make sens to allow the declaration of edge hardness ? (since a crease value per edge already exists).
Or maybe using the crease value to compute the normal even without subdivisionScheme.

Having the edge hardness stored rather than the vertex normal would reduce a lot the data size since normals would not be written to disk.

1 Like

UsdGeomMesh can absolutely accommodate this. There may be limitations or work to be done on the Maya Mesh exporter, but you can use SetNormalsInterpolation() on a Mesh object to set the normals’ interpolation to faceVarying (follow the link on the page I referenced above), which allows specification of a normal per face-vertex. Or you can not author the builtin normals property and instead create a UsdGeomPrimvar called normals and use all the primvar API to set interpolation to faceVarying and author the normals themselves.

Sorry, I realize you are asking for per-edge normals… but shouldn’t per-face-vertex normals give you strictly more expressibility? Though I realize it is not as good an encoding for interchange of “edge hardness”, but edge hardness as a concept is, as you say, something we only define for subdivision surfaces, since without a well-defined algorithm for specifying what hardness means, it becomes tricky.

Per-face-vertex normals miss the core need for parametric normal computation in polygonal workflows.

Hard/soft edges aren’t just encoding preferences - they’re procedural rules that define how normals compute dynamically. This is essential for:

  • Deforming meshes: Animation/rigging needs normals that update when the mesh deforms, without baking per-frame normals that lose the original smoothing intent.
  • Pipeline efficiency: One hard edge flag vs. gigabytes of per-frame/per-face-vertex normal data

The algorithms are well-defined and industry standard, and have been for decades:

  • Smoothing angle: Split normals where face angle > threshold
  • Smoothing groups: Average within polygon groups, split between groups
  • Edge flags: Per-edge hard/soft marking

If USD aims to be universal interchange, ignoring the polygonal paradigm seems counterproductive.

Current USD exports “flatten” procedural smoothing into explicit data, breaking editability and exploding file sizes.

It seems to me that it would make sense to at least have the “hard/smooth edge” approach implemented, like we already have creased edges for subdivision surfaces, as Hans said

Some notes:

  • Smoothing groups have certainly existed since at least 3ds max if not before, however implementation varies with different groups having preferred “golden” or “correct” implementations. I have personally implemented three different schemes trying to match the currently fashionable version that most looks like 3dsmax or Maya in any given year.

  • Per face normals do solve the problem, although they lose the original “smoothing group” intent.

    • zipping such data does compress dramatically, especially for planar surfaces that share a lot of normals

It could be possible to invent something like

``
uniform token normalStyle = “procedural”
float smoothingAngle = 30
int[] hardEdgeIndices = […]
``

but the more I think about it the more starts to look the existing subdivision tech:

  • Storing a mesh in USD using Subdivision CC or Loop and setting the level of subdivision to zero gives you a polygonal mesh whose normals, if evaluated, are the limit normals, respecting “sharpness” which is very much like “hardness”. USD does have creaseIndices, creaseSharpnesses, cornerSharpnesses that cover that idea.

I’m not arguing one way or another, just observing that maybe the existing functionality does work for the problem if you think of a polygon mesh as an unsubdivided subdivision surface with authored “hardness” data.

>zipping such data does compress dramatically, especially for planar surfaces that share a lot of normals

For this reason, we always store the normals as an indexed primvar. Most applications have caught up with this ( supporting primvars::normals in addition to just normals ). I had some issues in unreal with skinned models recently, but most other tools seem to be ok. This helps tremendously with the file size.

In my experience, smoothing groups are not as well defined between applications as is suggested here, but I will admit I have not relied on them much since moving away from 3ds max.