Page MenuHome

Proposal for fast high poly mesh editing
Confirmed, NormalPublicDESIGN

Tokens
"Love" token, awarded by jshgdmn."Burninate" token, awarded by Idlero."Burninate" token, awarded by Dir-Surya."Like" token, awarded by daven."Like" token, awarded by 0o00o0oo."Burninate" token, awarded by Astiero."Like" token, awarded by Floatharr."Love" token, awarded by bnzs."Burninate" token, awarded by 616."Love" token, awarded by staughost."Burninate" token, awarded by cgeugene."Love" token, awarded by lcs_cavalheiro."Burninate" token, awarded by amonpaike."Love" token, awarded by symstract."Burninate" token, awarded by billreynish."Burninate" token, awarded by Zino."Love" token, awarded by Blendork."Like" token, awarded by Fracture128."Love" token, awarded by andruxa696."Burninate" token, awarded by shader."Love" token, awarded by wilBr."Like" token, awarded by xrg."Like" token, awarded by Frozen_Death_Knight."Love" token, awarded by Tetone."Love" token, awarded by ace_dragon."Like" token, awarded by YAFU."Yellow Medal" token, awarded by 1D_Inc."Love" token, awarded by dcvertice."Mountain of Wealth" token, awarded by TheRedWaxPolice.
Authored By

Description

Stage 1, Minimize Unnecessary Work

This should bring Blender's performance back to what we had in 2.7x.

The first step for this planning will be to perform benchmarks to
get an idea how much time these operations are taking,
so we can estimate how much of a speed improvement
we can expect to see for each proposed change.

This can help us prioritize changes.

Skip EditMesh to Mesh Conversion

Blender 2.7x supported edit-mesh without the creation of an "evaluation mesh".

For Blender 2.8x development it was convenient to always create this mesh
however this adds significant overhead, especially when making interactive mesh edits.

Exactly how to do this needs some design discussion with other module owners,
since it impacts the:

  • Depsgraph.
  • Modifier stack.
  • Render engine API.
  • Python API & file IO.

Exact details for this may change.

  • Support Delayed Mesh Creation: Initially this may mean locking the object upon request for an evaluation mesh, for common editing operations there would be no need to create this data.

    For cases where we know the evaluation mesh is needed, the depsgraph could create this.

    The end result should be that locking is avoided in common cases. Ideally we could avoid it entirely, however there may end up being some operations that require mesh data that we can't predict ahead of time.
  • Modifier Stack Support for EditMesh:

    Support deformations without converting to a "Mesh".
  • Support edit-mesh for tools & UI code: Currently which assume an evaluation mesh is present. Listing this here since it's going to take time to go over all uses of Object.runtime.mesh_eval and find cases which should account for the edit-mesh, for example stats_object checks this.
  • Multi-Thread EditMesh to Mesh Conversion

    This can use 3 threads, vertices/edges/faces.

    Splitting this up further could be done, I'd need to check if this would cause problems copying custom-data.

Minimize Data Send to the GPU

One part of this project is to minimize data sent to the GPU after each mesh edit.

  • Selection: When changing selection, only the selection state arrays need to be refreshed.
  • Deformation: When moving geometry, only vertex locations need be updated, along with derived data: Face centers, normals and possibly UV tangents.
  • Custom Data Layers: When editing a UV layer, the updates could be limited to that layer and it's (UV tangents when present). The same goes for Vertex colors and Weight Paint colors.

This could be achieved by tagging a mesh as requiring data to be updated.

Optimize Edit-mesh to GPU Conversion

Benchmark current code, identify any bottlenecks to improve the performance.

As far as I know, nobody has checked on edit-mesh conversion performance,
since for 2.80 release we were mainly concerned with it working correctly.

Stage 2, Further Optimizations

This is mainly to note possible improvements.

This is only a rough outline, we can re-evaluate this once stage one is done.

Partial Geometry Updates

Currently when moving a single vertex, all normals are recalculated and the entire mesh is updated.

This would avoid two expensive operations:

  • Recalculating all normals.
  • Sending all vertex coordinates and normals the the GPU.

We could support tagging geometry to update, while this would only work for deformations,
this could give a significant speedup in the common case of transforming geometry.

Although there are complications with having to update connected normals, custom-normals and UV-tangents
making this a less straightforward task.

BMesh Support in the Modifier Stack

Avoid unnecessary BMesh conversions by allowing modifiers to pass BMesh data between modifiers.

Multi-Object Edit-Mode

Currently there aren't many optimizations relating to multi-object edit-mode.

  • Every undo step includes all editable objects.

    This can be optimized only to include tagged objects.

Multi-Threaded Conversion

There are some difficulties with OpenGL and threading,
so the gains here might be limited, or better left until we move to Vulkan which handles this better.

The gains for edit-mesh aren't large unless the users is editing many meshes at once.

Listing this for completeness.

Event Timeline

Campbell Barton (campbellbarton) changed the subtype of this task from "Report" to "Design".Feb 25 2020, 1:35 AM
Campbell Barton (campbellbarton) updated the task description. (Show Details)
Campbell Barton (campbellbarton) updated the task description. (Show Details)

A question.
Will it be possible to develop a special cheapest heavy mesh viewport display mode, that contains no AA, no multisampling, edges shading and other features to increase performance?
We woul like to use such a mode.

YAFU (YAFU) added a subscriber: YAFU (YAFU).EditedFeb 25 2020, 2:19 AM

I'm afraid that the main bottleneck in edit mode is CPU related and not related to the GPU or viewport features. In my tests select the worst quality in viewport and a very small size of viewport/blender window does not make changes in fps while you move vertices in dense mesh.
Edit:
I mean, I'm not sure that what you ( Paul Kotelevets ) proposes changes the situation much.

I mean, I'm not sure that what you ( Paul Kotelevets ) proposes changes the situation much.

I suppose it depends on the implementation as well.

@Paul Kotelevets (1D_Inc), noted, although I think we should first look into making the default shader faster - if this is even a bottleneck.

This proposal seems broadly fine to me.

I also expect that EditMesh to Mesh Conversion can be multi-threaded? Depends how much it shows up in the profiles if it's worth to do this, but from what I remember this is largely single-threaded while there are some loops that might be trivially converted to run on multiple threads if there is a high number of verts/faces.

Also, our current multi-threaded normal computation algorithm does not scale well with many threads. The use of atomics for accumulation is too slow. A better algorithm is not trivial, but may be worth investigating if this shows up significantly in the profiles.

Support Delayed Mesh Creation: Initially this may mean locking the object upon request for an evaluation mesh, for common editing operations there would be no need to create this data.

I'm not sure what locking means here exactly? I would imagine the mesh to be created from the editmesh on demand, probably with a double-checked mutex lock, but there would no need for any thread to hold that lock once the mesh has been created?

No problem with mutli-threading EditMesh -> Mesh conversion. It's fairly localized code.

Although from memory, this ends up only being useful with quite high poly meshes.

As for locking, it depends if we want to keep the shared Object.runtime.mesh_eval, if this is lazily initialized - instead of always filled in, we'll have to lock it to avoid multiple users initializing it at once.

Or, an alternative could be to create the mesh from the bmesh as needed, then free it (leaving Object.runtime.mesh_eval NULL), the problem with this is it could end up being impractical for usage where the beginning/end isn't as clearly defined.

I think lazily initialized is fine. It's difficult to predict how many times this will be used, so if we free it everytime that might happen a lot and become a performance problem in itself. And to perform the lazy initialization you do indeed need a (probably double-checked) lock.

@Paul Kotelevets (1D_Inc), noted, although I think we should first look into making the default shader faster - if this is even a bottleneck.

Ok, just wanted to know the opinion of the developer. Thank you for the answer.

for the future optimizations- sculpting and painting very high poly meshes

using 1 mesh for physics and for graphics is a bad design when we cross a certain model complexity.

we need to take the mesh and break it up like voxel remesh does - but break a mesh into islands - each island(physics patch) vertex 'ownes' a gfx vertex - and can own up to 3 other physics patch vertex.

we can sculpt on the physics patches and have them update the draw mesh vertex - and rebuild the very small physics patch bvhtree .

  1. getting hit position on big meshes becomes faster
  2. rebulding small bvhtree that change is much faster than rebuilding the whole tree.
  3. - room is left for adaptive subdivision too.