Judging from some of the commits, it appears to be related to the brand new Dyntopo code Pablo talked about, but this is being worked on by Joseph Eager and not Pablo (to note, Joseph was the original architect of Bmesh, it looks like he is back in a big way).
The commit logs here showed all of those commits appearing just today, so something is up in this area (if not only to bring it in as a base for future Dyntopo work).
I already read about Joseph wanting to get involved again to improve BMesh / Dyntopo, I believe it was in one of the recent Developer Meeting Notes. Didn’t expect it to happen this soon.
As I understood it, Joseph has said that he used Bmesh as the basis for developing DynTopo, which was apparently not the intended purpose of Bmesh, and DynTopo should have never used it in the first place. This is also why it has been a nightmare to develop for since it is using a code base which is fundamentally flawed for what DynTopo is supposed to achieve.
So since Joseph is the architect of the feature he knows best what is causing these slowdowns and will use a stronger base that is hopefully easier for developers like Pablo to improve upon by supporting the tools Pablo has added.
It’s not so much that the code is more difficult because of BMesh, it’s that BMesh’s data structures don’t lend themselves to the type of quick iteration that’s needed for dynamic sculpting, and each vert/edge/face in the BMesh structure holds a lot of data that’s not needed for such an operation, which adds a lot of overhead to every stroke calculation.
# Introduction to TriMesh
TriMesh is a triangle mesh kernel loosely modelled on the BMesh API and designed to be
multithreaded. It has its own memory pool implementation for that purpose.
# Topological Lists
TriMesh stores topological links in simple pointer arrays instead of linked lists.
So the edges around a vertex is stored in v->edges, which is (initially) pool-allocated.
These pointer arrays have the following public api:
<pre>
struct simplelist {
void **items;
int length;
};
</ptr>
Note that, like BMesh, no topological constraints is enforced, which is why
TriMesh is not a half-edge data structure (in many ways I would have preferred to use half-edge,
but oh well).
# SafePool
TriMesh uses a new (hopefully) thread-safe memory pool allocator, BLI_safepool. It stores one pool per thread
and uses a bare minimum of read-write locks to synchronize the structure. The following rules apply:
# Iterating over the entire pool is allowed only in single-threaded code.
# Freed elements go into the freelist of the thread pool that freed them not the one that allocated them.
# Locks are kept to an absolute bare minimum--un-thread-safe code will crash or deadlock.
# Unlike mempool, elements have a single pointer header that points back at the original allocating pool (if in use)
or the freeing pool if freed.
# Threaded Mesh Kernel
The concurrent api works like this:
Step 1: Mesh is split into independent islands
Step 2: Geometry along the boundaries of each islands are marked, and will be procesed
single-threaded after all threads exit.
Step 3: The islands are fed to a bunch of threads
Step 4: Once all threads exist, the boundary elements are processed on the main thread.
Note that this has not been tested yet because of all the performance bugs I've been finding
in the single-threaded dyntopo code.
The high-level function for this is:
<pre>
typedef void (*OptTriMeshJob)(TM_TriMesh *tm, void **elements, int totelem, int threadnr, void *userdata);
void TM_foreach_tris(TM_TriMesh *tm, TMFace **tris, int tottri, OptTriMeshJob job, int maxthread, void *userdata);
</pre>
# TMElemSet
This is a simple wrapper around GHash that stores a flat pointer array. It doesn't provide much of
a performance boost--in this branch, where I've basically inlined all of GHash into BLI_ghash.h. TMElemSet
should allow me to revert that. It would be nice if I could also do away with BLI_hashmap.
# BLI_hashmap
I did not write this because I wanted to. BLI_hashmap wraps a thread-safe, SIMD C++ hashmap class in C.
It's extremely finicky code; I ended up doing templates-via-C-macros (gross), and the entire endeavor is
highly dependent on the compiler sucessfully inlining some extremely sphagetti-like C++ template code.
GCC and Clang do; msvc does not.
Hopefully I won't end up needing this library. If not I may try porting some of the features I want
into my old BLI_smallhash library.
# CustomData
I'm thinking of adding extremely basic support for customdata interpolation, basically UVs and vertex colors.
These would live in a single function, like so:
<pre>
static void trimesh_customdata_interp(TMElement *e, TMElement *ins, float *ws, int *types, int *offsets, int totelem, int totlayer) {
for (int i=0; i<totlayer; i++, types++, offsets++) {
int type = *types;
int offset = *offsets;
int size = 0;
void *dst = TM_elem_cd_get(e, offset);
switch (type) {
case CD_UV: {
for (int j=0; j<totelem; j++) {
//interpolate uv
}
break;
}
case CD_MCOL: {
//interpolate mcol
break;
}
case CD_PROP_FLOAT: {
//interpolate mask
break;
}
}
}
}
</pre>
It might be worth investigating whether one can tell a C or C++ compiler to take an external C function
and inline it into a switch jump table.
Anyway, this would be extremely (extremely) basic.
# Sculpt Indices
Generic vertex index in the sculpt code now use intptr_t, allowing me to eliminate much of the overhead
assocated with keeping vertex/face pointer arrays up to date (profiling revealed this to be a major
bottleneck).
# Log
The log code is unfinished. The key performance improvement I made was to store original
coordinates/normals in TMVert. This will have to be updated as undo steps happen.
I really like that voxel remesher gets improved as it is quite fine thing for iterating before launching sculpt for smoothing and other post processing touches. Even my 3D printer likes this commit
I’m toying with the Lasso Trim’s new Use Cursor For Depth option (in Union and Join mode). Nice! But in my tests, the cursor location doesn’t seem to matter. The thickness of the generated shape is just a lot lower than when the cursor option is not activated, and the position of the shape depends on where you start the lasso.
I actually like it this way: the auto-positioning on the surface.
A few more options would be nice:
An adjustable Thickness value.
Option to create a new, separate object with each Lasso Trim.
An adjustable (rounded) bevel for the hard edges of the generated shapes, preferably adjustable using a gesture right after the shape is established (e.g. move left = hard edge, move right = increase bevel).
Some geometric form options, such as square, rectangle, circle, ellipse.