Optimizing the remesh modifier

The past couple days I’ve been looking into the performance of the remesh modifier. Although I’m committed to getting dynamic-topology sculpting working, the remesh modifier is also a useful approach to clay-like sculpting. Ideally it should support quite high density levels at fast speeds. Below I’ll get very detailed about what I’ve found, but spoiler alert: it turns out there’s quite a lot we can do to make remesh faster.

Continue reading Optimizing the remesh modifier

Two new options and a brush for dynamic topology

I’ve pushed a few updates for dyntopo:

  • As a follow-up to yesterday’s post about better flat-shaded drawing for regular sculpt mode, you can now toggle between smooth and flat shading in dyntopo. This is just a display setting for now, doesn’t alter the actual mesh at all.
  • Edge collapse is now available again, but disabled by default. When making large alterations to the mesh (e.g. with the snake hook brush), you can enable the “Collapse Short Edges” toggle to get smoother and more regular topology. The trade-off is that, while enabled, brushes will tend to erase fine details. For example, if you use the crease brush to define a sharp indent in the mesh, you probably don’t want to collapse short edges in that area.
  • Added a “Simplify” brush that only modifies topology. It’s pretty much the same as using a regular brush with zero strength and Collapse Short Edges enabled. (Note that as this is a new brush it won’t show up in your brush list by default, you have to add a simplify brush manually.)

Flat shading in sculpt mode

Spent a little time today looking at improving one small aspect of sculpt drawing: flat-shaded faces in solid view mode with VBO enabled.

In current trunk, flat shading in sculpt mode looks quite different depending on whether VBO is enabled or not. When VBO is not enabled, and immediate mode is used to draw the mesh, each face (triangle or quad) gets drawn separately. Before drawing the face, a single averaged normal and mask value is calculated. The normal and mask values are used for each vertex of the face. In contrast, VBO drawing uses a shared vertex normal and mask value for every face that uses the vertex. This behavior is correct for smooth shading, but looks strange for flat shading.

The benefit to using a shared vertex value is lower storage requirements; the mesh’s faces can simply reference vertices with an index (and the index can usually be a short, so two bytes per index.) When flat shading is enabled, however, OpenGL uses only a single vertex’s value for the entire face. On any particular face this generally looks OK, but the problem is evident when adjacent quads appear to have the same normal despite facing different directions.

Flat shading in sculpt mode
Click to embiggen
Left: current trunk. Middle: averaged normals and interpolated mask. Right: averaged normals and averaged mask.

I’ve implemented a simple fix for this, available from the sculpt-flat-shading branch on Github. If the mesh is flat shaded, the index buffer is scrapped in favor of duplicating vertex values. The GPU storage requirements are in general slightly higher, but the output looks much more correct.

In the image above you can see two variations of the fix. Both have flat-shaded normals, but the middle uses interpolated mask values while the right uses a single average mask value. Using an averaged mask value seems to look a bit better, although it’s technically a bit inaccurate as sculpt brushes operate on vertex mask values, not the average.

One further issue which affects smooth shading is that interpolation over quads doesn’t look very good with OpenGL. Mask values and normals don’t look smooth because OpenGL tessellates quads into two triangles. The vertex values are interpolated within each triangle, without regard to the missing corner. It’s technically possible to solve this with shaders. Instead of using regular vertex attributes, the vertices just get texture coordinates and the attributes are put into a texture. A bilinear (or even bicubic) interpolation can then be coded in the shader. Such fanciness is probably of questionable usefulness though, and at the very least will have to wait on the completion of other improvements to the various drawing systems in Blender.

My current plan is to wait until 2.64 is released, then commit the flat-shading fix (with averaged mask values.)

Localized subdivision for dynamic topology

OK, time for some updates. Based in part of some useful feedback on BlenderArtists, I’ve spent the past week experimenting with various approaches to the topological update step. I think it’s now getting much closer to what people want to see; in particular the subdivision is localized to the area directly around the brush.

Localized dynamic subdivision
A sphere with varying levels of detail. The small clay stroke in the center has edge lengths a couple orders of magnitude smaller than the large edges to the right.

Until now, the topological updates were based on the paper “Freestyle: Sculpting meshes with self-adaptive topology”. This paper assumes that the entire mesh will have a consistent detail size. Note that since the algorithm collapses short edges, you can lose detail if you change your brush to a coarser detail size.

In contrast, the approach I am using now is to only do edge splits. If you create very dense topology and then set a coarse detail size, the dense topology will remain and not be collapsed. To handle situations where you want to make the topology less dense, a separate simplify brush will be added. (I haven’t done that yet, but the code is largely already written.)

In order to get a good boundary between a dense portion of the mesh and larger polygons, I used a trick that Farsthary described in his unlimited clay research: identify nearby pole vertices (in this case, defined as having nine or more adjacent edges) and split the adjacent edges. This isolates the pole vertex and prevents it from distorting the mesh. This wasn’t an issue with edge collapses, which implicitly force triangles to be relatively regular, but in a subdivision-only approach it turns out this is a really critical step. Without it the mesh quickly develops degenerate triangles that can’t be smoothed away.

Some other changes: the topology update now occurs before each sculpt step, so the result should match the brush shape a bit better. The brush also avoids the accumulation problem now, so repeatedly brushing over an area won’t continually build the surface up (unless the brush accumulate option is on, of course.)

I’m still looking into surface relaxation; I suspect a smoother result can be achieved while still maintaining detail, but haven’t found a good way to do it yet. My current short-term goal is to do some brush work: add the reduce/simplify mentioned earlier and fix the guaranteed-crash brushes like grab.

As usual, the code is available from the dyntopo branch on Github.

Emacs notes

I spent some time today cleanup up my Emacs configuration directory. The files are now up in a new repository on Github: emacs-conf.

Emacs in action, including a compilation buffer, debugging (GDB) buffer, Org buffer with the README for the emacs-conf repository, IRC for #blendercoders, and a shell.

Most of the stuff in there should be quite easy to copy and paste into your own configuration if you don’t want the whole thing. If you do want to try all of it, simply replace your .emacs.el with this:

(add-to-list 'load-path "/path/to/emacs-conf/")
(load "top")

I also append this to my .emacs.el.

(cd "/d/src/blender/git-trunk")

Of course, you will want to replace the path with something more useful on your own system.

General advice, some of it Emacs-specific:

  • Rebind your capslock key to a control key. I do this system wide. In Ubuntu it can be done easily from System Settings (Keyboard Layout > Options > Ctrl key position > Caps Lock as Ctrl. It can also be done with XModMap. In Windows you’ll need to make a small registry edit. See also this overview of various techniques.
  • Related to the control key, be careful with your hands. If you find some action is causing your hands/wrists/arms to hurt, find a different way to do it. Or take more breaks. Or buy a different keyboard. Basically, don’t let programming damage your hands!
  • Make sure your Alt (Meta) key isn’t tied up with something annoying. In Ubuntu you probably want to disable or rebind the HUD.
  • Look at how other people do things. For example, some of my configuration (like C-x C-m as a replacement for M-x) comes from Steve Yegge. Emacs has been around for a long time, so it’s quite likely that someone else has already found a solution for most problems you encounter.
  • Use a big screen, or multiple screens. I use an HP ZR30w (30 inches, IPS panel.) Especially when refactoring a large piece of source, being able to see a lot of things at once is very helpful.
  • Related to the above, if you split your Emacs window into a lot of smaller sections (in Emacs terminology that’s splitting a frame into lots of windows), it’s important to be able to switch between them rapidly. I use C-M-j and C-M-k for this (that’s Ctrl+Alt+J and Ctrl+Alt+k).
  • Keep everything inside Emacs, where possible. You don’t need to run a separate terminal for compilation, debugging, or general shell commands. These can be done inside Emacs with commands like “compile”, “gud-gdb”, and “shell”.
  • Identify patterns in your own work and automate them with a key binding. In Emacs, everything can be scripted.

Undo (for dynamic topology) is working

The latest code in the dyntopo branch now does undo/redo in sculpt mode with dynamic topology enabled.

The bmesh-undo branch on which this is based has gained a simple unit-test framework, although only one test is enabled currently.

The last major change that was needed to get undo working was rewriting the edge-collapse function in dyntopo. Originally it was coded using the vertex/edge splicing euler operators. The two vertices of the edge were spliced (merged), then duplicate edges were spliced, and various cleanups on faces were performed. This was already tricky and error-prone, and getting undo working for splice was not going too well. As a workaround, I replaced all the splicing code by simply creating new faces and deleting the original vertex/edge. Simpler code and the undo code was already working for that case. That said, proper logging of splicing is something that will need to be revisited if the BMLog were considered as a replacement for editmesh-undo.

There are of course still bugs to work through, but this is a good validation of the logging technique.