From BlenderWiki

Jump to: navigation, search
Note: This is an archived version of the Blender Developer Wiki. The current and active wiki is available on wiki.blender.org.

List of what's good about the original proposal

  1. Under-the-hood
    1. Speeding up shape key recalculations by avoiding doing total mesh recalculations if topology didn't change is probably good
    2. Memory undo optimizations via storing only the changed shape key if possible are hardly bad
    3. Compressing shapekey data by storing only the changed vertices (from the Key->refkey) can deflate the files by some percent
    4. Proportional editing for blending is good
  2. User Interface
    1. Scratch is a good concept by itself
    2. Improving Blend from Shape is a good thing, quick blending in editmode is a good thing

List of what's bad about the original proposal

  1. Over-engineered and complicated
    1. Too much checkboxes, need as few as possible
    2. Blending with sliders is inconsistent with other parts of Blener
    3. Scratch key doesn't have that many applications to be in the user's face
  2. Introduces some complicated local UI in one place
  3. Four-way slider is probably useless and not Blender-ish
    1. Modifier keys already taken and we don't want to break them, same with Y-dragging

List of things than aren't decided to be useful or not yet

  1. Having an alternative mix in Edit Mode in case there is animation
  2. Do we need a fast way to preview a shape key while working on top of a mix? -- seems there already is a way!
  3. Is Apply Shape Keys in Edit Mode worth getting rid of? -- this needs to be reverted back to master. The only thing we actually need is recalc speedup, not emulation of Shapekey Modifier. Why would I do it in the first place? :|

List of things considered useful that weren't in the original proposal

  1. Make shape keys that come from linked library animatable with a proxy (suggested by an artist via email)
  2. Add in a system to define custom evaluation routines for a shapekey (see this email)
  3. Allow local deformations to act as drivers for further deformations (see this other email)
  4. Make driving Shape Keys easier by adding a Value Range
  5. Add support for Shape Key grouping in the list - add support for groups in UILists in general. (these last ones are suggested in here by Derek Root)
  6. Add a "Shape Key Brush" brush that blends in the selected shape key in the active shape key (suggested by qurq on IRC)

What is going to make it and how?

Midterm

  1. Having an alternative animation-independent mix is a good idea
  2. Proportional editing and quick editmode blending can make it in form in a modal Blend from Shape operator conceptually doing the same as the slider (how do we choose the shape key to blend to/from here?)
  3. Shapekey compression on disk save
  4. Undo memory optimizations
  5. Value Ranges
  6. Scratch key can be internal and concealed from the user (minus one checkbox - Auto-Commit). If the user accidently edits the wrong key, we can have a special operator that reverts the current key and commits the edit into a new one. Commit to Different Shape Key or in the likes of that.
  7. Fix T40505
  8. Fix T35170 Kinda already fixed this (in patch tracker for a bunch of months), but still
  9. Make the added shape keys have value = 1.0 after adding in them Sculpt Mode (small thing, suggested by qurq)

Finals

  1. Make shape keys that come from linked library animatable with a proxy.
  2. Add a "Shape Key Brush" brush that blends in the selected shape key in the active shape key
  3. Add in a system to define custom evaluation routines for a shape key.
  4. Add support for groups in UILists in general.
  5.  ???

Midterm Deliverable Detials

Alternative anim-independent mix for editmode

The user, while sculpting on top of a mix in edit mode, can switch to an alternative mix values, in case the 'main' mix is already driven by animation.

This is already in the shapekey branch: 63a7fbe3a0

More efficient shapekey recalculation

In the master branch, switching between different shapekeys in editmode is internally re-entering editmode with a different shape key loaded. Offset propagation is done by a heavy-duty function from bmesh_mesh_conv.c. While this is a very safe method that accounts for topology and customdata changes, it's slow due to memory reallocations.

It is uncommon to edit topology while sculpting shape keys. It happens, of course, but not often, so it's rather pointless to run heavy-duty conversion functions each time (and reallocate everything) since

Most shape keys don't change in a deform-only edit, just the current one. Usually the number of basis shape keys is very small compared to the total number of keys. If the mesh topology can be assumed to be unchanged, we can avoid rebuilding the whole RealMesh, but only edit the affected shape keys. To help determine if the topology has been changed, a hash of the BMesh topology-related data is computed (see this commit. This is a cheat somewhat, as it doesn't check the topology itself, but the memory layout, so a copy of the current editmesh will be treated as a different mesh... but that doesn't seem to be a problem, editmesh reallocation doesn't happen much without real topology changes.

This is already in shapekey branch, though not really final. Benchmark results can be seen later on this page; it suggest it is a good idea!

PE for Blend from Shape and quick blending in editmode

Blend from Shape is to recieve Proportional Editing (all types of it) and modal behavior which will be reminiscent of the planned four-way slider: horizontal drag adjusts mix intensity; vertical drag -- falloff distance (can change that to Mousewheel for consistency with other Editmode operations...) The shapekey to blend from can be chosen on op invoke from a dropdown and then changed with some other key (maybe PgUp/PgDown or some other).

Shapekey compression on disk save

While saving shape keys, we're going to write only the vertices positions that are changed from the reference key (after a certain total vertex count). Store an int for the vertex index and a float for the vertex's position. Compressing is to be done on file write and uncompress on file read.

Optimization of mesh editmode undo memory usage

Currently mesh editmode undo stores the whole mesh after any edit, that includes full copy of all keyblocks. This is not very efficient. We're going to use editmesh topology hashing to check if there weren't topo changes and store only the affected keyblocks then. Just a bit more logic in undo push and pull.

Adding a Value Range for Shape Keys

As suggested in here, add a Value Range property to the keyblocks. The idea is that a shape's value can go anywhere in the user-defined range and then gets clamped to [0-1]. This allows for easier driver setup.

[I’m not sure at all about that… imho it’s not that hard to make clamping/mapping in drivers, don’t really see the point in adding that here? Just adds useless data and UI cluttering in my point of view., --Mont29 15:19, 15 June 2014 (UTC)]

Commit to New Shape Key

A small remain of the Scratch Shape Key, this operator is to revert the current shape to its original position and copy the edit coordinates to a new key. This is useful when you find out you've just edited the wrong shape key...

Bug fixes / TODOs

  1. T40505 - make the manipulator handles and constraint lines draw at the deformed (modifier) vertex position. In soc-2014-shapekey now: 516038c983e [I would suggest you add this as a patch asap, you can assign me and ideasman as reviewers - the soonest this goes to master, the better! :) --Mont29 15:18, 15 June 2014 (UTC)]
  2. T35170 - won't be needed after the undo system upgrades come into place, but poke people for review

Implementation notes

Shape key compression on disk save

It has been noted that usually when using shape keys to animate a character's face, only a bunch of vertices are changed from the rest position in each shape key. In the image below, only the vertices that change from the rest position are highlighted:

Gsoc-keys-shape-storage.png

It's obvious that the current system of storing each vertex's position in each shape key is not exactly space-effective. It has the important bonus of being able to access each vertex's position in O(1), but that isn't exactly needed while storing shape keys on disk (or for undo purposes).

The idea is to store only the changed vertices' positions in the file and in object mode undo. On a test file (4.5 kvert character head mesh with 157 shapes), the size reduction was almost 3x (compressed test file - open only with soc-2014-shapekey branch).

In a compressed shape key, a float3 for coordinates and and int for original vertex index is stored, so it's not a perfect win.

The compression logic checks if there will be a space gain from saving shape key in a compressed format and does that in case there is the gain.

Downside is that master Blender won't be able to open the compressed data correctly. A User Preference was added in File preferences to disable compression.


This is already in soc-2014-shapekey: 4c56a47730b93f4

T40505

What's the problem?

Fixing that is somewhat non-trivial since there can be different modifier situations that require us to use different DerivedMeshes, e. g.:

  1. If there're only deform modifiers, we just need to use the final cage, and the vertex indeces will be in sync to the editmesh
  2. If there're some generate modifiers, some vertices can be mapped back to editmesh ones by index (subdiv) or not (remesh).

Solution

  1. Setup:
    1. Determine the situation: if there're only deform modifiers, just use the final cage.
    2. If there're some generate modifiers, try to map new vertices to old vertices. If all vertices are mapped, use the final cage in proceeding calculations.
  2. Calculation:
    1. If there's a vert map, use it to get every selected vertex's derived position
    2. If no vert map, just use the current vertex's index to get the derived position

The setup phase must be a dedicated function since it's gonna be needed in manipulator draw and TransCon drawing too.

Mesh topology hashing

Comparison of execution times

The testfile I used is here.

Tests were done on i7 4770K + GTX 760 Win7 machine, built using VS 2013 in Release configuraions.

Master branch was at ce460c617, soc-2014-shapekey was at 31a1d1cad.

liz_head_rel is a 4.5 KVert mesh with 157 shape keys. liz_head_rel_40 is a 4.5 KVert mesh with 40 shape keys. liz_body_yound is a 4.8 KVert mesh without shapes.

Sampled a dozen values for each cell to avoid noise.

Table

Task Master branch exec time, in sec soc-2014-shapekey exec time, in sec
Editmesh-to-mesh (liz_head_rel), one shape affected
Timed OB_MESH case of ED_object_editmode_load_ex()
avg 0.0848
max 0.1164
min 0.0453
avg 0.0839
max 0.1447
min 0.0486
Editmesh-from-mesh (liz_head_rel)
Timed OB_MESH case of ED_object_editmode_enter().
avg 0.0471
max 0.0843
min 0.0268
avg 0.0532063
max 0.07304
min 0.026406
Editmesh-to-mesh (liz_body_young) avg 0.0849
max 0.1348
min 0.0344
avg 0.07498
max 0.1239
min 0.027
Editmesh-from-mesh (liz_body_young) avg 0.032
max 0.0383
min 0.0172
avg 0.0313
max 0.0407
min 0.0102
Shape switch, no topology change, no recalc (liz_head_rel).
Timed OB_MESH case in rna_Object_active_shape_update().
avg 0.1261
max 0.2462
min 0.088585
avg 0.0589
max 0.0750
min 0.0223
Shape switch, no topology change, no recalc (liz_head_rel_40). avg 0.0813
max 0.1147
min 0.055
avg 0.0426
max 0.0604
min 0.0335
Shape switch, no topology change, 157 shapes recalc (liz_head_rel) avg 0.139
max 0.2166
min 0.1076
avg 0.0665
max 0.0817
min 0.0525
Shape switch, topology change, no recalc (liz_head_rel). same as 'no topology change' same as 'no-topology-change' in master
Shape switch, topology change, 157 shapes recalc (liz_head_rel) same as 'no topology change' same as 'no-topology-change' in master
Extra: mesh hash (Murmur2) execution time, sampled from 100 runs, sepereated by 10 ms of sleeping.
Mesh exec time, in usec
liz_head_rel avg 970
max 1350
min 240
liz_body_young avg 1040
max 1740
min 560

Notes and conclusions

  1. On a mesh with shape keys, shape switch operations which happen without topology change are sped up 1.8-2.1 (40 shapes and 1by using the simpler recalculation routines in deform only cases.
  2. Hashing does not add a significant performance penalty; and there is room for even faster hashing, e. g. loop unrolling since the hash data sizes are constant

Conclusion: using hashing to determine if the mesh's topology hasn't changed and using 'lightweight' shape key recalculations in this case offers 2x speedup on shape key switching. Since most shapekey-related editing operations aren't changing the topology, this is a good thing.