Physics simulation for character hair

Ah, ok. A nice simple solution, though.

Now that you described that, I think Dragon’s Dogma behaves as if it does something like this :stuck_out_tongue:

I see.

My approach is somewhere between: I have a discrete mathematical model built out of point masses, massless rigid (inextensible, straight) rods and bending springs. This produces a sort of a “discretized rope”, where straight segments are connected by ball-constrained joints.

The joints are programmed to push toward their neutral position by a configurable strength, creating bending rigidity. This causes the hair to bend in a natural fashion when subjected to gravity; without bending rigidity the equilibrium position would point straight down. There is also friction in the joints, modeled as a simple damping factor for the velocity, so that the motion gradually dies away (instead of oscillating ad infinitum as a purely elastic system would (not accounting for numerical error in time integration, which typically introduces additional dissipation)).

What I’m essentially wondering is whether there is an efficient way to tell Bullet to do something similar (using ball constraints and something?), or whether it is better to manually implement a small custom physics code for this special purpose, as I’ve been doing so far.

I’ve been thinking about this. I agree that the head is essential. It is also easy to model, as you suggest, as a sphere. A spherical head approximation should be enough for anime-style characters.

If the hair parent joint in the character model is placed exactly at the center of the head, then it is possible to automatically determine an appropriate radius for the collision sphere by taking the smallest (or average, or largest) distance from this joint to any hair chain root joint. These distances can be computed by Panda - the head center must be an exposed joint anyway in order to connect the hair and body submodels of the multipart actor, and by some selective NodePath parenting trickery, it is possible to read the default global transformation of controlled joints, too.

For more realistic models (such as those from MakeHuman), I’m thinking an ellipsoid could be a good match for the head. It’s almost as simple and cheap to detect collisions with (as a sphere), and it allows for oblong shapes. It might be possible to automatically determine best fit x/y/z axis lengths by solving some simple optimization problem (given the positions of the head center and the hair chain roots), but I haven’t thought about this in any detail yet. (Maybe least-squares fit the sum of distances from each hair chain root to the surface of the collision solid, parametrized by the axis lengths?)

As for the rest, what is required I think depends on the hairstyle. Ideally, I would like to have some characters with e.g. really long braids, which requires collision detection at least with the arms and the torso in addition to neck and shoulders. Maybe with the legs, too, for completeness - but here this already runs into a problem, because skirts present a special case. Capes, too.

On the technical side, spheres, ellipsoids and capsules should be sufficient as collision shapes. Sphere or ellipsoid for the head, and capsules for everything else. Capsules are nice in that they are not much more complicated to check collisions with than spheres, and they avoid the complicated handling of the end faces of cylinders (see e.g. https://www10.informatik.uni-erlangen.de/Publications/Theses/2010/Suenkel_BA_10.pdf).

I think the speed is probably not a concern, given a few assumptions. Namely: this must be done in C++; we should keep the collision shapes simple by design; use only a handful of them per character; and keep collisions local to each character. Also, ignore collisions between hair segments; almost all of the time, the motion is such that these won’t occur. Then each joint needs to do only a small constant number of collision checks (against the targets on the body side), making this scale as O(n) in terms of number of hair segments in the character.

The physics simulation already requires some math, so it shouldn’t be much heavier (in the relative sense) if it runs a few collision checks. This could of course also be made configurable. It may also be possible to automatically switch some checks off (e.g. torso and legs), if the hair is determined to be short enough (by summing segment lengths in the chains).

Some speed optimization should be possible by assuming that for the purposes of collisions, the mass points in the simulation can be represented by spheres. The sizes of these collision spheres can be automatically approximated as the average of the half-distances to the next point in each direction along the chain. (I.e. for point n, look at the distances to points n-1 and n+1, divide each by 2, and average the results.) The sphere shape is advantageous here, because it is the cheapest one to check collisions with, and there may be potentially dozens of hair segments per character in more complex hairstyles.

The most difficult part, I think, is setting up the collision geometry on the body side automatically. It is difficult to determine the appropriate placement and size of the collision solids without any external help, because the joints themselves are just transforms, and thus have no “bone thickness” information.

This would need using some information from the actual character mesh - e.g. for a capsule, find the endpoints of the axis, and to determine the radius, compute the average (or smallest, or largest) distance of vertices affected by the corresponding joint, as measured in the direction perpendicular to the axis of the capsule. I’m pretty sure Panda has the necessary infrastructure for this, but the technical details may become a bit hairy (no pun intended). :slight_smile:

(This is of course ignoring vertex morphs. Based on my experiments, it seems Panda applies joint (bone) transforms on the CPU, but vertex morphs are applied on the GPU. In any case, their effects to vertex positions cannot be retrieved by just examining the deformed mesh geometry as Panda sees it.)

I haven’t cared much about which gen I’m aiming at - basically, for now I’m just solving interesting technical problems and slowly building my character creator while at it. The project will take some time so it’s better to plan ahead :stuck_out_tongue: