Mesh: Make vertex normal calculation deterministic #111718

Merged
Hans Goudey merged 9 commits from HooglyBoogly/blender:mesh-normals-deterministic into main 2023-11-10 15:19:13 +01:00
Member

Currently, atomic additions in vertex normal calculation introduce
non-determinism that can influence the result of other operations,
sometimes causing non-reproduceable renders (in cases like #100250
and #101726). This is because the order used during threading when
accumulating face normals changes.

This commit fixes that non-determinism, using a vertex to face topology
map to calculate vertex normals without atomics. When the map is already
available, this can be faster too.

In the longer term future, this method of vertex normal calculation
means it will be easier to do partial recalculations when only part
of a mesh changes. That might be essential for cases like transforming
small selections in a non-BMesh edit mode.

As an experiment I tried a "fast" code path that avoids weighting face
normals by the corresponding corner angle when averaging them to
create vertex normals. This significantly reduces the necessary
computation and memory bandwidth for vertex normal calculation.
The results are shown below too, but it's not part of this PR.

I measured the FPS with two smooth shaded 16 million face grids:

Before After After (fast)
Created from scratch every frame 0.96 0.91 0.92
Deformed by geometry nodes 0.99 1.32 1.40

Though many other things besides normals are being tested here,
it's clear that the performance difference isn't that large either way,
though there is an observable regression with meshes created from
scratch, and there is a noticeable improvement when the topology
stays the same and is persistent.

Currently, atomic additions in vertex normal calculation introduce non-determinism that can influence the result of other operations, sometimes causing non-reproduceable renders (in cases like #100250 and #101726). This is because the order used during threading when accumulating face normals changes. This commit fixes that non-determinism, using a vertex to face topology map to calculate vertex normals without atomics. When the map is already available, this can be faster too. In the longer term future, this method of vertex normal calculation means it will be easier to do partial recalculations when only part of a mesh changes. That might be essential for cases like transforming small selections in a non-BMesh edit mode. As an experiment I tried a "fast" code path that avoids weighting face normals by the corresponding corner angle when averaging them to create vertex normals. This significantly reduces the necessary computation and memory bandwidth for vertex normal calculation. The results are shown below too, but it's not part of this PR. I measured the FPS with two smooth shaded 16 million face grids: | | Before | After | After (fast) | | -------------------------------- | ------ | ----- | ------------ | | Created from scratch every frame | 0.96 | 0.91 | 0.92 | | Deformed by geometry nodes | 0.99 | 1.32 | 1.40 | Though many other things besides normals are being tested here, it's clear that the performance difference isn't that large either way, though there is an observable regression with meshes created from scratch, and there is a noticeable improvement when the topology stays the same and is persistent.
Hans Goudey added 1 commit 2023-08-31 00:55:30 +02:00
05fedab237 Mesh: Refactor vertex normals for determinism
Currently, atomic additions in vertex normal calculation introduce
non-determinism that can influence the result of other operations,
sometimes causing non-reproduceable renders (in cases like #100250).
This is because the order used during threading when accumulating face
normals changes.

This commit fixes that non-determinism, using a vertex to face topology
map to calculate vertex normals normals without atomics. When the map is
already available, this can be faster too.

Internally, a new "fast" code path is available too. This avoids
weighting face normals by the corresponding corner angle when averaging
them to create face normals. This significantly reduces the necessary
computation and memory bandwidth for vertex normal calculation.

The "fast" option is included in this PR as a way to potentially reduce
the peformance impact of requiring the topology map.

TODO:
- [ ] Run performance tests in differenct smooth shading use cases
  - [ ] Large mesh build from scratch every frame
  - [ ] Armature deformation of large mesh without subdivision
- [ ] Test "fast" option and expose toggle in UI if it's worth it

In the longer term future, this method of vertex normal calculation
means it will be easier to do partial recalculations when only part
of a mesh changes. That might be essential for cases like transforming
small selections in a non-BMesh edit mode.
Hans Goudey changed title from Mesh: Refactor vertex normals for determinism to Mesh: Make vertex normal calculation deterministic 2023-08-31 00:56:30 +02:00
Hans Goudey requested review from Brecht Van Lommel 2023-08-31 04:12:15 +02:00
Hans Goudey requested review from Campbell Barton 2023-08-31 04:12:15 +02:00
Hans Goudey requested review from Jacques Lucke 2023-08-31 04:12:16 +02:00
Author
Member

To reviewers, I'm very curious about your opinions here! It is it worth a slight performance regression for non-persistent mesh topology to have deterministic normals? Or should we focus more on the deformation use case where this is actually an improvement? Is it worth keeping the old atomic code around if we go with this? Is "requiring" the memory for the vertex to face topology map okay? How can we factor in code simplicity and consistency between CPU and GPU implementations or other longer term benefits? This PR is helpful to those long term goals IMO.

Also, I'd like to keep in mind that we shouldn't need to calculate vertex normals at all when the mesh is shaded flat. I'll be able to address that after #108014 lands.

To reviewers, I'm very curious about your opinions here! It is it worth a slight performance regression for non-persistent mesh topology to have deterministic normals? Or should we focus more on the deformation use case where this is actually an improvement? Is it worth keeping the old atomic code around if we go with this? Is "requiring" the memory for the vertex to face topology map okay? How can we factor in code simplicity and consistency between CPU and GPU implementations or other longer term benefits? This PR is helpful to those long term goals IMO. Also, I'd like to keep in mind that we shouldn't need to calculate vertex normals at all when the mesh is shaded flat. I'll be able to address that after #108014 lands.
Hans Goudey added 1 commit 2023-08-31 04:23:36 +02:00
Contributor

There is other issue I reported #110430 and i found that is caused by the normal calculation, this changes add some new issues to text objects solidify modifier

4.0 hash: 411cd827b736 pr fast
image image image
There is other issue I reported https://projects.blender.org/blender/blender/issues/110430 and i found that is caused by the normal calculation, this changes add some new issues to text objects solidify modifier |4.0 hash: `411cd827b736`| pr |fast| |----|----|----| |![image](/attachments/b97b20fc-af60-4864-92d3-2c1b66311509)|![image](/attachments/6a742c6a-48f8-46e6-a7c1-64aa2f383808)|![image](/attachments/e329bfa4-5cfc-4c08-8541-a54aa82fbf94)|
174 KiB
310 KiB
442 KiB
Author
Member

#112065 optimizes the topology map creation a bit more. I hope that can help lessen the performance regression in the "Created from scratch every frame" case.

#112065 optimizes the topology map creation a bit more. I hope that can help lessen the performance regression in the "Created from scratch every frame" case.
Author
Member

I'll probably remove the "fast" option from this commit and consider that separately, but I'll wait for some response in this PR first, just so people can see it.

I'll probably remove the "fast" option from this commit and consider that separately, but I'll wait for some response in this PR first, just so people can see it.
Hans Goudey added 1 commit 2023-09-08 17:10:53 +02:00
buildbot/vexp-code-patch-coordinator Build done. Details
5f796cf33c
Merge branch 'main' into mesh-normals-deterministic
Author
Member

@blender-bot build

@blender-bot build

The performance seems acceptable if it's slower in some cases and faster in others. The memory usage seems like the main downside to me.

I wanted to try integer quantization as described in #101726, but also don't have a lot of time for this now. So maybe this solution is ok.

The performance seems acceptable if it's slower in some cases and faster in others. The memory usage seems like the main downside to me. I wanted to try integer quantization as described in #101726, but also don't have a lot of time for this now. So maybe this solution is ok.
Author
Member

The memory usage seems like the main downside to me.

Right. This method does require the topology map for cases where it probably wouldn't be required otherwise. However, the topology map is already used for other things (everywhere vert_to_corner_map is used currently) and I hope to use it more in the future for things like attribute interpolation. So I'd consider the cost amortized over more features. And overall it's less than the memory required for a UV map, for example.

I wanted to try integer quantization

Sounds interesting! Though one thing I like about this solution is that it makes the normal calculation simpler, with no need for atomics or temporary arrays of intermediate values. It also works equally for any mesh topology. Obviously can't rule out integer quantization without trying it though! That could still be investigated as a second option in the future.

>The memory usage seems like the main downside to me. Right. This method does require the topology map for cases where it probably wouldn't be required otherwise. However, the topology map is already used for other things (everywhere `vert_to_corner_map` is used currently) and I hope to use it more in the future for things like attribute interpolation. So I'd consider the cost amortized over more features. And overall it's less than the memory required for a UV map, for example. >I wanted to try integer quantization Sounds interesting! Though one thing I like about this solution is that it makes the normal calculation simpler, with no need for atomics or temporary arrays of intermediate values. It also works equally for any mesh topology. Obviously can't rule out integer quantization without trying it though! That could still be investigated as a second option in the future.
Hans Goudey added 2 commits 2023-09-11 18:23:15 +02:00
Hans Goudey changed title from Mesh: Make vertex normal calculation deterministic to WIP: Mesh: Make vertex normal calculation deterministic 2023-10-20 19:57:07 +02:00
Author
Member
	 75 - modifiers (Failed)
	 78 - physics_dynamic_paint (Failed)
	 94 - cycles_denoise_cpu (Failed)
	 96 - cycles_hair_cpu (Failed)
	113 - cycles_shadow_catcher_cpu (Failed)
	190 - geo_node_geometry_test_duplicate_elements_mesh_faces (Failed)
	272 - geo_node_mesh/extrude_test_vertex_extrude_and_propagate (Failed)
``` 75 - modifiers (Failed) 78 - physics_dynamic_paint (Failed) 94 - cycles_denoise_cpu (Failed) 96 - cycles_hair_cpu (Failed) 113 - cycles_shadow_catcher_cpu (Failed) 190 - geo_node_geometry_test_duplicate_elements_mesh_faces (Failed) 272 - geo_node_mesh/extrude_test_vertex_extrude_and_propagate (Failed) ```
Brecht Van Lommel approved these changes 2023-10-23 17:34:29 +02:00
Brecht Van Lommel left a comment
Owner

It's unfortunate about the memory usage, but I don't think that should hold this up.

It's unfortunate about the memory usage, but I don't think that should hold this up.
Hans Goudey added 3 commits 2023-11-09 10:25:44 +01:00
Hans Goudey changed title from WIP: Mesh: Make vertex normal calculation deterministic to Mesh: Make vertex normal calculation deterministic 2023-11-09 10:25:45 +01:00
Author
Member

@blender-bot build

@blender-bot build
Hans Goudey added 1 commit 2023-11-10 14:42:53 +01:00
buildbot/vexp-code-patch-coordinator Build done. Details
b9a40350b9
Merge branch 'main' into mesh-normals-deterministic
Author
Member

@blender-bot build

@blender-bot build
Hans Goudey merged commit 5052e0d407 into main 2023-11-10 15:19:13 +01:00
Hans Goudey deleted branch mesh-normals-deterministic 2023-11-10 15:19:15 +01:00
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
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
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
Overlay
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
Interest
Workbench
Interest: X11
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 project
No Assignees
3 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#111718
No description provided.