Comb brush improvements #105722
Comb brushes currently don't work all that well. It takes several brush strokes to push hair into a different direction and align it. Curves tend to drift away from the brush, especially close to the tips.
A good combing brush should feel almost like a real, physical hair comb. It should "grip" the hair without letting it drift out of the brush region, while allowing slippage in the hair direction.
Goal positions for vertices are correctly computed by the brush and initially applied. But then segment length and collision constraints get solved, which moves points away from initial positions. Large brush strokes in particular cause large corrections for length constraints, which diminishes the brush effect.
Especially points at the tip tend get corrected so much that the initial displacement of the comb brush is quickly lost. That is because the length constraint works from the root upwards and only moves the end point of each segment. This "follow the leader" solution has the advantage that it only requires one iteration for a perfect length constraint, but the downside is that it artificially overcorrects curve tips. This issue has been described in section 3.1 of "Fast Simulation of Inextensible Hair and Fur." (Müller et al.).
Recently a correction factor was introduced (#104589) to make curve tips more responsive, but only partially solves the problem.
What is the desired behavior?
Combing should feel like a physical comb. Hairs between the teeth of a comb are constrained in their lateral movement, but can move (with some friction) along the direction of the hair.
This suggests that, rather than just an initial point offset, combing should be implemented as a constraint itself. This gives greater control over the priority and weighting of brush influence relative to other constraints. The solver can then try to satisfy segment lengths, collisions, and brush constraints at the same time, rather than overriding brush goals immediately.
Irrelevant aspects of real combs
Real physical combs are open to one side to make inserting hair easier. If that side faces down the hair will fall out. This is not a feature we need to replicate. Instead the hair should generally be restrained laterally, but move freely in the longitudinal direction.
Real combs also only work if held at a right angle to the hair direction. Brushes in Blender don’t usually have an orientation, so we can assume that this is always the case.
Combs are also generally planar, while Blender brushes are spheres or cylinders (depending on projection mode). We don’t need all hair constraints to lie in the same plane.
Real hair has some friction when dragged through a comb. This is a useful feature because it extends the influence of the brush beyond the immediate brush position. But we can simplify the brush and assume a moderate constant amount of friction with a simple tool setting (or disable friction altogether).
Formulating a comb brush constraint
All existing curve editing features can be understood as a simplified position-based constraint system. The goal now is to define an objective function that describes a suitable "comb constraint" and improve the curve constraint solver so that it supports this new constraint in addition to existing length and collision constraints.
An formulation of such a constraint can be found in section 5.1 Keyhole Constraint of "A robust and efficient Lagrangian Constraint Toolkit for the Simulation of 1D Structures" by Adrien Theetten.
The constraint minimizes the distance to a goal point. The goal is found at the beginning of the stroke by looking on each curve for the closest point to the brush center. The key difference to a simple "grab" constraint is that the point parameter
u along the curve is also a variable, meaning that the point can slide along the curve to minimize deformation, as long as the deformed curve still goes through the goal point.
It must be noted that the curve has to be differentiable for this to work properly. A simple cubic spline interpolation helps generate a smooth gradient to move the keyhole point in the right direction along the spline.
A few further improvements should be considered for a full feature:
- The constraint solver should be generalized to support additional constraints in the future.
- Length constraints should apply to both sides of a segment equally instead of the follow-the-leader approach (solving from the root up). This will require more iterations but make it more compatible with other constraints. Zero weights for root points ensure pinning to the surface.
- Some simplified stiffness constraints for segment angles can help avoid the "floppiness" of curves.
- Better collision handling is needed. Collision constraints should not attempt to solve length constraints simultaneously, since that only works for the last-solved segment and makes the solution very non-linear.
- The comb constraint is solved with a linear projection. A few iterations of gradient descent or a similar method for just this constraint type might improve convergence.
segment_lengthand similar constraint constants are recomputed at the start of each brush stroke. This is susceptible to drift over multiple brush strokes, as any residual error of the solver is carried over into the next stroke. While improving convergence of the solver alleviates this issue it shouldn't be expected to get a totally accurate solution every time.
segment_lengthand other (supposed) constants should be persistent as attributes and only change when e.g. grow/shrink brushes modify them.
Here's another test after replacing the root-first length constraints (aka. "follow-the-leader" method) with a more balanced length constraint implementation. Now points closer to the root are also reacting to the combing action, instead of just the tips.
The relative strength of constraints should become adjustable eventually, so the brush might have more or less "friction". Currently the brush falloff is also not taken into account.
Moved the main description to Hans' first comment.
Testing a bending constraint based on Bergou, Miklós, et al. "Discrete elastic rods."
Currently has unstable corner cases that need to be fixed. Especially when the brush affects the root points it tends to flip some segments and subsequently takes many iterations to solve.
This feature might be used in combination with the brush falloff, keeping the curves stiff outside of the comb brush influence. More experiments needed.
This woulde be a fantastic improvment! Any news on this?
@LukasTonne I think I missed your update on this. What is the status here? Should it be tested?
It's on hold, there were other priorities. Might come back to this or it might become part of the node tools project, no clear plans atm.
@SimonThommes no testing at this point, not sure if it still works at all
Deleting a branch is permanent. Although the deleted branch may exist for a short time before cleaning up, in most cases it CANNOT be undone. Continue?