Skip to content

Numerically stable normal computation #1352

Open

Description

@elalish

Is there a canonical way to compute the limit surface normal using your API? I've seen in one of your examples N = normalize( cross( dPu, dPv) );, but this is numerically unstable at rounded corners, since dPu and dPv become parallel. I would imagine there are other places it struggles as well, e.g. examples from #947. I was a little surprised your evaluate API doesn't return a surface normal, so I'm hoping you have some guidance for a reliable solution?

Activity

  1. davidgyu commented on Jun 26, 2025

    @davidgyu
    Member

    Filed as internal issue #OSD-460

  2. rgirish28 commented on Oct 9, 2026

    @rgirish28

    We’ve run into similar instability when computing surface normals from dPdu and dPdv. Since our subdivision system uses the Bfr API, could we port the approach used to handle degenerate cases in the GLSL shaders? If not, what reliable alternative would you recommend for computing normals using BFR? We currently compute vertex normals in post-subdivision by averaging the contribution from adjacent faces.

  3. barfowl commented on Oct 11, 2026

    @barfowl
    Collaborator

    Sorry for the delay dealing with this. There has been some discussion and development internally on extending the API to provide surface normals, but it has stalled given other Pixar priorities (an update here was warranted long ago).

    In the meantime, I have some code I can share that can be used externally to resolve common degenerate cases. It does not port the shader implementations (more on that later) but has a sound mathematical basis and is similarly effective. It makes use of second derivatives in cases where the first derivatives are zero or parallel and the simple cross product fails.

    I'll package that up as an extension to one of the Bfr tutorials and try to post a branch soon.

  4. barfowl commented on Oct 19, 2026

    @barfowl
    Collaborator

    I've prepared a branch on my fork (tutorial_normal_eval) with some code to deal with this issue until OpenSubdiv provides its own solution:

    • I've modified ./tutorials/bfr/tutorial_1_2 (a simple tessellation example that generates points and normals in Obj format) with additional external code to make use of second derivatives when the simple cross product of first derivatives fails.
    • Some of the new external code is written to be completely independent of OpenSubdiv while some is written to work with it, i.e. making use of the independent solution with Bfr::Surface (see patchNormal.cpp for the former and extendedSurface.cpp for the latter).
    • A directory of example shapes was also created to verify the improvement. This includes most cases noted in the old issue #947 cited above along with a few others.

    See the README file added to the tutorial directory first for an overview and more information.

  5. rgirish28 commented on Oct 27, 2026

    @rgirish28

    Thanks @barfowl for this! We have a few assets that cause some issues with the original normal computation, I'll test it with them and see if your new method resolves it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions