Mesh Auto Smooth and Normals Design Changes #93551

Open
opened 2021-12-01 19:29:14 +01:00 by Hans Goudey · 14 comments

Background

Recently we have been discussing the best way to expose auto smoothing meshes in geometry nodes.
One of the goals of geometry nodes is to allow more flexibility over geometry data, but also to be easily accessible.
However, currently corner normals on meshes are overly complex and not flexible for a few reasons:

  • Auto Smooth is an action applied to meshes, but it in the interface it looks like a property.
    • This removes flexibility and makes the way it works less obvious.
  • Smoothing is controlled by two redundant flags, on faces (ME_SMOOTH) and edges (ME_SHARP).
    • Face "shade smooth" flags are redundant because it just means that all the face's edges should be sharp.
  • Auto smooth 0 and 180 degree angles are hidden non-intuitive special cases.
  • Derived data (face corner "split" normals) are not properly separated from user-defined data (custom normals).

#68893 is also related.

Changes

  1. Remove the Auto Smooth option, replacing it with a geometry node group that sets the mesh sharp_edge attribute procedurally based on an angle.
    • The node group can also be applied, to keep the same sharp edges while the mesh deforms.
  2. For display, only calculate the required normals.
    • If all edges/faces are sharp, only use face normals (true normals).
    • If all edges/faces are smooth, only use smoothed vertex normals.
    • With a combination of sharp and smooth elements, automatically use face corner normals (split normals).
  3. Make derived face corner normals accessible separately from custom normals, with the existing Normal input geometry node.
  4. Make custom normals a separate optional built-in attribute that overrides derived normals for rendering.
    • Custom normals can be stored in the existing face-corner space (as short2), or in a regular 3D float vector attribute.
  5. To keep performance the same, extend automatic evaluated mesh sharing ("instancing") between evaluate objects to support the case where the modifiers are the same.

Existing files would not change, and we can still have the simple "Shade Smooth/Flat/Auto" operators.

Implementation

  • Versioning to remove the Auto Smooth option and angle on mesh data blocks:
    • Expose the sharp edge flag as a builtin attribute.
    • Add a geometry nodes modifier that sets the sharp_edge attribute on edges according to the auto-smooth angle.
  • Add an API function to give the required normals domain based on edge and face sharp tags.
    • Use the function in many places to retrieve the correct normals.
  • Expose custom normals as a builtin attribute
    • Somehow expose or abstract the face-corner space storage
    • Allow storing custom normals as simple 3D vectors.
  • Extend automatic instancing to handle cases where the modifiers are the same.
### Background Recently we have been discussing the best way to expose auto smoothing meshes in geometry nodes. One of the goals of geometry nodes is to allow more flexibility over geometry data, but also to be easily accessible. However, currently corner normals on meshes are overly complex and not flexible for a few reasons: * `Auto Smooth` is an **action** applied to meshes, but it in the interface it looks like a property. * This removes flexibility and makes the way it works less obvious. * Smoothing is controlled by two redundant flags, on faces (`ME_SMOOTH`) and edges (`ME_SHARP`). * Face "shade smooth" flags are redundant because it just means that all the face's edges should be sharp. * Auto smooth 0 and 180 degree angles are hidden non-intuitive special cases. * **Derived data** (face corner "split" normals) are not properly separated from **user-defined** data (custom normals). #68893 is also related. ### Changes 1. Remove the `Auto Smooth` option, replacing it with a geometry node group that sets the mesh `sharp_edge` attribute procedurally based on an angle. - The node group can also be applied, to keep the same sharp edges while the mesh deforms. 2. For display, only calculate the required normals. - If all edges/faces are sharp, only use face normals (true normals). - If all edges/faces are smooth, only use smoothed vertex normals. - With a combination of sharp and smooth elements, automatically use face corner normals (split normals). 3. Make derived face corner normals accessible separately from custom normals, with the existing `Normal` input geometry node. 4. Make custom normals a separate optional built-in attribute that overrides derived normals for rendering. - Custom normals can be stored in the existing face-corner space (as `short2`), or in a regular 3D float vector attribute. 4. To keep performance the same, extend automatic evaluated mesh sharing ("instancing") between evaluate objects to support the case where the modifiers are the same. Existing files would not change, and we can still have the simple "Shade Smooth/Flat/Auto" operators. ### Implementation - [x] Versioning to remove the `Auto Smooth` option and angle on mesh data blocks: - [x] Expose the sharp edge flag as a builtin attribute. - [x] Add a geometry nodes modifier that sets the `sharp_edge` attribute on edges according to the auto-smooth angle. - [x] Add an API function to give the required normals domain based on edge and face sharp tags. - [ ] Use the function in many places to retrieve the correct normals. - [ ] Expose custom normals as a builtin attribute - [ ] Somehow expose or abstract the face-corner space storage - [ ] Allow storing custom normals as simple 3D vectors. - [ ] Extend automatic instancing to handle cases where the modifiers are the same.
Hans Goudey changed title from Mesh Smoothing and Normals Design Changes to Mesh Auto Smooth and Normals Design Changes 2021-12-01 20:27:24 +01:00

Remove shade_smooth and replace it with edge_sharp ? Does it mean all meshes will be smoothed by default and only be unsmoothed by assigning sharps?

Remove `shade_smooth` and replace it with `edge_sharp` ? Does it mean all meshes will be smoothed by default and only be unsmoothed by assigning sharps?

Having a geometry node for setting sharps is great, but please retain a simple checkbox and angle slider for this somewhere. Adding modifiers, changing views and editing node trees would make this previously simple task slow, cumbersome, unintuitive and non-discoverable.

Alternatively, make this into a standalone modifier that shares the geometry nodes code.

Edit: Ah. Missed the bit about the modifier in the versioning section. No objections then :)

Having a geometry node for setting sharps is great, but please retain a simple checkbox and angle slider for this somewhere. Adding modifiers, changing views and editing node trees would make this previously simple task slow, cumbersome, unintuitive and non-discoverable. Alternatively, make this into a standalone modifier that shares the geometry nodes code. Edit: Ah. Missed the bit about the modifier in the versioning section. No objections then :)

Remove shade_smooth and replace it with edge_sharp ? Does it mean all meshes will be smoothed by default and only be unsmoothed by assigning sharps?

On the user level, no.

> Remove `shade_smooth` and replace it with `edge_sharp` ? Does it mean all meshes will be smoothed by default and only be unsmoothed by assigning sharps? On the user level, no.

Hmm how does it work then? You said from the user level, does it mean that the user would still think of it as shade smooth, but under the hood it is actually backwards, it is assigning sharp edges rather than assigning smooth flags? I still don't think I get it

Hmm how does it work then? You said from the user level, does it mean that the user would still think of it as shade smooth, but under the hood it is actually backwards, it is assigning sharp edges rather than assigning smooth flags? I still don't think I get it

Yes, something like that. We could also invert the edge_sharp flag and store it as edge_smooth internally, that doesn't affect the user though. The main point is to get rid of the smooth/sharp option on faces because it's redundant with the smooth/sharp flag on edges.

Yes, something like that. We could also invert the `edge_sharp` flag and store it as `edge_smooth` internally, that doesn't affect the user though. The main point is to get rid of the smooth/sharp option on faces because it's redundant with the smooth/sharp flag on edges.

I have a few questions or problems with this proposal.

1 - Removing 'smooth face' flag

This will make some behaviors from user perspective not possible anymore. For example, how do you handle 'set face smooth' operation on a flat face sharing an edge with another flat face?

  • Currently, setting the face smooth will keep the shared edge sharp, as the other face remains flat.
  • If face flag is removed, the shared edge will be marked as smooth? Or something else?

Point being, you cannot say that edge and face flags are fully redundant, they are both combined to define the final sharp vs. smooth state of edges.

2 - Removing autosmooth from mesh and make it a geometry node

While I agree in general with the idea, imho the fact that it enforces generating a separate evaluated mesh for each object is an issue. And I definitely do not see the proposed 'work around' of using object instancing as an acceptable solution here.

Was wondering if having some obdata-level nodetree was ever considered? That would enable some different level of procedural processing of geometry, with some limitation regarding available 'context' info obviously (no object info...).

3 - Split evaluated normals vs. custom normals

I do not really understand what is the issue that is being addressed here, nor what is the proposed solution. Those two data are already very well separated?

  • Evaluated split normals are actual 3D vectors, just like 'regular' vertex normals.
  • Custom normals are stored as differential values from evaluated normals, applied on top of these when needed. 'When needed' is not only for rendering, they are also required for many geometry processing...
I have a few questions or problems with this proposal. 1 - Removing 'smooth face' flag ------------------------------------ This will make some behaviors from user perspective not possible anymore. For example, how do you handle 'set face smooth' operation on a flat face sharing an edge with another flat face? * Currently, setting the face smooth will keep the shared edge sharp, as the other face remains flat. * If face flag is removed, the shared edge will be marked as smooth? Or something else? Point being, you cannot say that edge and face flags are fully redundant, they are both combined to define the final sharp vs. smooth state of edges. 2 - Removing autosmooth from mesh and make it a geometry node ------------------------------------------------------------------------------- While I agree in general with the idea, imho the fact that it enforces generating a separate evaluated mesh for each object is an issue. And I definitely do not see the proposed 'work around' of using object instancing as an acceptable solution here. Was wondering if having some obdata-level nodetree was ever considered? That would enable some different level of procedural processing of geometry, with some limitation regarding available 'context' info obviously (no object info...). 3 - Split evaluated normals vs. custom normals ------------------------------------------------------- I do not really understand what is the issue that is being addressed here, nor what is the proposed solution. Those two data are already very well separated? * Evaluated split normals are actual 3D vectors, just like 'regular' vertex normals. * Custom normals are stored as differential values from evaluated normals, applied on top of these when needed. 'When needed' is not only for rendering, they are also required for many geometry processing...
Poster
Collaborator

Thanks for the feedback!

Point being, you cannot say that edge and face flags are fully redundant, they are both combined to define the final sharp vs. smooth state of edges.

Good point. I think it's fair to say they are redundant from the perspective of normal calculation, but from the editing perspective the task isn't quite right.
I think this is okay though, we can offset with better tools for creating edge selections if necessary. That specific change might be for the better.
If users just control the data that's used by normal calculation directly, things might be more intuitive.

And I definitely do not see the proposed 'work around' of using object instancing as an acceptable solution here.

That's fair. I guess it would nullify the object-data-sharing design we have now. Though I do think it shows that the design as a whole isn't very scalable.
Object-data level node trees is an interesting idea, but I sort of doubt it would be high enough on the priority list now, so I hope we could find a design that wouldn't depend on that.
I wonder if automatically de-duplicating object evaluation when meshes are shared and modifiers are the same would work.

3 - Split evaluated normals vs. custom normals

I think they are better separated than I thought when I wrote this task, at least internally. So the point is a bit unclear I guess. Here are some more specific suggestions:

  • Use the terms "Face corner normals" and "custom normals" in the UI to separate the two concepts and allow for custom normals on other domains.
  • Face corner normals should always be used if there are sharp edges.

Also, separate point-- I think it makes sense to allow setting custom normals directly as 3D vectors from a performance perspective, which would make more sense in a procedural context.

Thanks for the feedback! >Point being, you cannot say that edge and face flags are fully redundant, they are both combined to define the final sharp vs. smooth state of edges. Good point. I think it's fair to say they are redundant from the perspective of normal calculation, but from the editing perspective the task isn't quite right. I think this is okay though, we can offset with better tools for creating edge selections if necessary. That specific change might be for the better. If users just control the data that's used by normal calculation directly, things might be more intuitive. >And I definitely do not see the proposed 'work around' of using object instancing as an acceptable solution here. That's fair. I guess it would nullify the object-data-sharing design we have now. Though I do think it shows that the design as a whole isn't very scalable. Object-data level node trees is an interesting idea, but I sort of doubt it would be high enough on the priority list now, so I hope we could find a design that wouldn't depend on that. I wonder if automatically de-duplicating object evaluation when meshes are shared and modifiers are the same would work. >3 - Split evaluated normals vs. custom normals I think they are better separated than I thought when I wrote this task, at least internally. So the point is a bit unclear I guess. Here are some more specific suggestions: - Use the terms "Face corner normals" and "custom normals" in the UI to separate the two concepts and allow for custom normals on other domains. - Face corner normals should _always_ be used if there are sharp edges. Also, separate point-- I think it makes sense to allow setting custom normals directly as 3D vectors from a performance perspective, which would make more sense in a procedural context.

I do not understand all the details of the discussion, but as someone who is already working a lot with Normals in Geometry Nodes, I can attest that it would be very convenient if we had full access to Normals of each Domain, and Custom Normals, and the ability to properly set them from within GeoNodes.

I am giving this feedback to show that there is interest in these features among some users (Stylized/Toon/NPR artists). I know that these sorts of features would not be used in many workflows, but I hope we'll still get these options.

Currently, I am doing all sorts of extra/redundant edge splitting and interpolation to achieve within GeoNodes things that are standard outside of it. The lack of access to Custom Normals has also been a major blockage. If we also had UV Tangents available in GeoNodes for Normal Mapping, we would have full flexibility.

I do not understand all the details of the discussion, but as someone who is [already working a lot with Normals ](http://www.aversionofreality.com/blog/2022/4/21/custom-normals-workflow) in Geometry Nodes, I can attest that it would be very convenient if we had full access to Normals of each Domain, and Custom Normals, and the ability to properly set them from within GeoNodes. I am giving this feedback to show that there is interest in these features among some users (Stylized/Toon/NPR artists). I know that these sorts of features would not be used in many workflows, but I hope we'll still get these options. Currently, I am doing all sorts of extra/redundant edge splitting and interpolation to achieve within GeoNodes things that are standard outside of it. The lack of access to Custom Normals has also been a major blockage. If we also had UV Tangents available in GeoNodes for Normal Mapping, we would have full flexibility.

In #93551#1416105, @ColinBarton wrote:
access to Normals of each Domain

I'm not sure how to understand normals for all types of domains.
Since the render object is a polygon, it is logical that it is the only one that has a normal.
But since we won't have enough vertices for complex normals for several polygons, it is logical that we are talking about a face corner.
I'm not sure how edge normals should blend correctly for face corners as they do for vertices.

> In #93551#1416105, @ColinBarton wrote: > access to Normals of each Domain I'm not sure how to understand normals for all types of domains. Since the render object is a polygon, it is logical that it is the only one that has a normal. But since we won't have enough vertices for complex normals for several polygons, it is logical that we are talking about a face corner. I'm not sure how edge normals should blend correctly for face corners as they do for vertices.

In #93551#1416229, @mod_moder wrote:

In #93551#1416105, @ColinBarton wrote:
access to Normals of each Domain

I'm not sure how to understand normals for all types of domains.
Since the render object is a polygon, it is logical that it is the only one that has a normal.
But since we won't have enough vertices for complex normals for several polygons, it is logical that we are talking about a face corner.
I'm not sure how edge normals should blend correctly for face corners as they do for vertices.

Ah yes, I mean Face, Vertex, and Face Corner (which all end up as Face Corner). I don't think much can be done with Edges Normals except perhaps some curvature stuff.

> In #93551#1416229, @mod_moder wrote: >> In #93551#1416105, @ColinBarton wrote: >> access to Normals of each Domain > I'm not sure how to understand normals for all types of domains. > Since the render object is a polygon, it is logical that it is the only one that has a normal. > But since we won't have enough vertices for complex normals for several polygons, it is logical that we are talking about a face corner. > I'm not sure how edge normals should blend correctly for face corners as they do for vertices. Ah yes, I mean Face, Vertex, and Face Corner (which all end up as Face Corner). I don't think much can be done with Edges Normals except perhaps some curvature stuff.

Been trying to make game art tree meshes with a GeoNodes network. Surprisingly, it's been very simple, up until the point at which I actually need to transfer the normal information to the final mesh. Being able to set & bake down custom normals per Face Corner / Vertex would be excellent. I've been able to view exactly the normals I want to achieve with the viewer node in the 3.4 beta, but I have no way to actually bake these down to face corner data.

From the dummy artists to the folks who implement this on the code side, ty for working on this. GeoNodes are immensely cool and starting to finally come into their own with regards to generating game ready assets.

image.png image.png

Been trying to make game art tree meshes with a GeoNodes network. Surprisingly, it's been very simple, up until the point at which I actually need to transfer the normal information to the final mesh. Being able to set & bake down custom normals per Face Corner / Vertex would be excellent. I've been able to view exactly the normals I want to achieve with the viewer node in the 3.4 beta, but I have no way to actually bake these down to face corner data. From the dummy artists to the folks who implement this on the code side, ty for working on this. GeoNodes are immensely cool and starting to finally come into their own with regards to generating game ready assets. ![image.png](https://archive.blender.org/developer/F13943589/image.png) ![image.png](https://archive.blender.org/developer/F13943591/image.png)
Hans Goudey added this to the 4.0 milestone 2023-03-04 19:03:59 +01:00
Hans Goudey added this to the Nodes & Physics project 2023-03-04 19:04:23 +01:00
Hans Goudey added
Type
To Do
and removed
Type
Design
labels 2023-03-04 19:06:42 +01:00

The most important part I can control if the edge to be "Hard" or "Soft".
this will make life easier.
adding sharp edge and soft edge will be great step.

The most important part I can control if the edge to be "Hard" or "Soft". this will make life easier. adding sharp edge and soft edge will be great step.

This solution may solve this task: #107376

This solution may solve this task: https://projects.blender.org/blender/blender/issues/107376
Poster
Collaborator

I started to work on this here: https://projects.blender.org/HooglyBoogly/blender/src/branch/refactor-mesh-corner-normals-lazy

That branch contains most of the changes except for the ability to set custom normals in geometry nodes.

I started to work on this here: https://projects.blender.org/HooglyBoogly/blender/src/branch/refactor-mesh-corner-normals-lazy That branch contains most of the changes except for the ability to set custom normals in geometry nodes.
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
Eevee & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest/Import
Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest: Wayland
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
Eevee & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No Assignees
10 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#93551
There is no content yet.