Hair physics/simulation

I have made a hair physics/simulation using bullet physics engine. This approach is usually called spring bones, jiggle bones, wiggle bones (common names) or dynamic bones (Unity engine).


This is how I did it:

  1. I have parsed a chain of bones from glTF which I want to make dynamic. Bone’s tail position could be retrieved from the next bone’s head position, but this would require adding an extra leaf bones at the end of chain.
  2. I have created a Rigid Body for each bone using 80% of the bone’s length to keep some space for the springs. I have set a mass for each Rigid Body, so they would not be static.
  3. I have created an extra Rigid Body for the root of the chain and marked is as kinematic. The mass is 0 by default, so it would be static+kinematic.
  4. I have created Spring Constraints between Rigid Bodies to connect them together.
    Spring Constraints are part of my Physics module - KITSUNETSUKI-SDK/conda/kphys at master · kitsune-ONE-team/KITSUNETSUKI-SDK · GitHub
    This is the Spring Constraint class - KITSUNETSUKI-SDK/spring.cxx at master · kitsune-ONE-team/KITSUNETSUKI-SDK · GitHub
    It’s based on btGeneric6DofSpring2Constraint. It’s also possible to switch to the btGeneric6DofSpringConstraint (which have a little bit different behavior) and rebuild the module.
  5. I have set the following settings for the springs:
spring.set_limit(kphys.DOF_TX, 0, 0)
spring.set_limit(kphys.DOF_TY, 0, 0)
spring.set_limit(kphys.DOF_TZ, 0, 0)

spring.set_limit(kphys.DOF_RX, -90, 90)
spring.set_limit(kphys.DOF_RY, 0, 0)
spring.set_limit(kphys.DOF_RZ, -90, 90)


for dof in (kphys.DOF_RX, kphys.DOF_RZ,):
    spring.set_spring(dof, True)
    spring.set_stiffness(dof, STIFFNESS)
    spring.set_damping(dof, DAMPING)

So I have disabled translation (TX, TY, TZ), enabled rotation for 2 axis only (RX, RZ) and changed rotation order to make the locked axis the last one. Then I have enabled spring behavior for the 2 unlocked axis and set stiffness and damping params.
6. For the simulation of 1 single frame I’m copying the initial world-space position and rotation of the first bone (it needs to be saved somewhere, because the bone will be moved in the next step) to the root rigid body. Then I’m running the bullet physics simulation and copying each non-static rigid body world-space rotation to the bones.