Hi everyone,
Is anybody using Ragdolls in production?
I am past the prototype stage and now system testing. Sharing some intitial findings:
-
No right-handed scene. Mostly use GLTF for bringing in 3d models. The only way (AI and me) got Babylon ragdolls to work is to force override the GLTF root node: rot(0,0,0) and scale(1,1,1). This will x-flip the model. That is the price you have to pay.
-
But, currently, I override the node shortly before starting the ragdoll and you often cannot tell. I might get away with it
Don’t forget material.sideOverride to fix normals. -
Promising alternative: Babylon has fbx support now
The Blender fbx exporter supports changing coordinate systems. After some quick testing, it seems Babylon sandbox loads these models just fine: no vertex explosion, animations play, normals good. -
It looks like you must instantiate the ragdoll class with your skeleton at rest and no rotations on the root node! Otherwise I see physics/mesh desyncing.
-
Unless you make a comedic game, you have to use 6DOF constraints and hack in the limits array. No way around it. The default constraints are too permissive making it look like the ragdoll mechanic is broken.
Now I was wondering have anyone of you got shareable config values? I do get good enough results with the following but I still too often see unnatural limb placements. I am 99% sure that this is a config issue because physics and mesh are in sync.
I use these for a Mixamo rig (this.engine == BABYLON); default humanoid, 1.78m.
[
{
bones: ["mixamorig:Hips"],
size: 0.2,
boxOffset: 0.01,
rotationAxis: this.engine.Axis.Z,
joint: this.engine.PhysicsConstraintType.HINGE,
mass: 30
},
{
bones: ["mixamorig:Spine2"],
size: 0.25,
boxOffset: 0.05,
boneOffsetAxis: this.engine.Axis.Y,
rotationAxis: this.engine.Axis.Z,
mass: 20,
joint: this.engine.PhysicsConstraintType.SIX_DOF,
limits: [
{axis: this.engine.PhysicsConstraintAxis.LINEAR_DISTANCE, minLimit: 0, maxLimit: 0},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_X, minLimit: -Math.PI/8, maxLimit: Math.PI/8},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Y, minLimit: -Math.PI/6, maxLimit: Math.PI/6},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Z, minLimit: -0.05, maxLimit: Math.PI/4}
]
},
// Arms.
{
bones: ["mixamorig:LeftArm", "mixamorig:RightArm"],
depth: 0.1,
size: 0.1,
width: 0.2,
rotationAxis: this.engine.Axis.Y,
boxOffset: 0.10,
boneOffsetAxis: this.engine.Axis.Y,
mass: 15,
joint: this.engine.PhysicsConstraintType.SIX_DOF,
limits: [
{axis: this.engine.PhysicsConstraintAxis.LINEAR_DISTANCE, minLimit: 0, maxLimit: 0},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_X, minLimit: -Math.PI/3, maxLimit: Math.PI/3},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Y, minLimit: 0, maxLimit: 0},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Z, minLimit: -Math.PI/3, maxLimit: Math.PI/3}
],
},
{
bones: ["mixamorig:LeftForeArm", "mixamorig:RightForeArm"],
depth: 0.1,
size: 0.1,
width: 0.2,
boxOffset: 0.12,
boneOffsetAxis: this.engine.Axis.Y,
rotationAxis: this.engine.Axis.Y,
joint: this.engine.PhysicsConstraintType.HINGE,
mass: 10 },
{
bones: ["mixamorig:LeftHand", "mixamorig:RightHand"],
depth: 0.12/2,
size: 0.12/2,
width: 0.12/2,
boxOffset: 0.1,
boneOffsetAxis: this.engine.Axis.Y,
rotationAxis: this.engine.Axis.Y,
joint: this.engine.PhysicsConstraintType.LOCK,
colliderShape: this.engine.PhysicsShapeType.SPHERE,
mass: 5
},
// Legs
{
bones: ["mixamorig:LeftUpLeg", "mixamorig:RightUpLeg"],
depth: 0.1,
size: 0.3,
width: 0.08,
boxOffset: 0.2,
boneOffsetAxis: this.engine.Axis.Y,
rotationAxis: this.engine.Axis.Y,
joint: this.engine.PhysicsConstraintType.SIX_DOF,
limits: [
{axis: this.engine.PhysicsConstraintAxis.LINEAR_DISTANCE, minLimit: 0, maxLimit: 0},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_X, minLimit: -Math.PI/5, maxLimit: Math.PI/2},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Y, minLimit: 0, maxLimit: 0},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Z, minLimit: -0.05, maxLimit: Math.PI/5}
],
mass: 15
},
{
bones: ["mixamorig:LeftLeg", "mixamorig:RightLeg"],
depth: 0.08,
size: 0.4,
width: 0.1,
boxOffset: 0.2,
boneOffsetAxis: this.engine.Axis.Y,
rotationAxis: this.engine.Axis.Z,
joint: this.engine.PhysicsConstraintType.SIX_DOF,
limits: [
{axis: this.engine.PhysicsConstraintAxis.LINEAR_DISTANCE, minLimit: 0, maxLimit: 0},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Z, minLimit: 0, maxLimit: Math.PI/2},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Y, minLimit: -0.05, maxLimit: 0.05},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_X, minLimit: -0.05, maxLimit: 0.05}
],
mass: 10
},
//head
{
bones: ["mixamorig:Head"],
size: 0.3/2.2,
boxOffset: 0.1,
boneOffsetAxis: this.engine.Axis.Y,
rotationAxis: this.engine.Axis.Z,
colliderShape: this.engine.PhysicsShapeType.SPHERE,
joint: this.engine.PhysicsConstraintType.SIX_DOF,
limits: [
{axis: this.engine.PhysicsConstraintAxis.LINEAR_DISTANCE, minLimit: 0, maxLimit: 0},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_X, minLimit: -Math.PI/3, maxLimit: Math.PI/3},
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Y, minLimit: -0, maxLimit: 0}, //looks weird; would need to drive neck bone to look up/down
{axis: this.engine.PhysicsConstraintAxis.ANGULAR_Z, minLimit: -Math.PI/3, maxLimit: Math.PI/3}
],
mass: 10
}
]
Best wishes
Joe