|
|
@ -193,108 +193,116 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P |
|
|
|
if (!enabled) { |
|
|
|
if (!enabled) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
TempVars vars = TempVars.get(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if the ragdoll has the control of the skeleton, we update each bone with its position in physic world space.
|
|
|
|
|
|
|
|
if (mode == mode.Ragdoll && targetModel.getLocalTranslation().equals(modelPosition)) { |
|
|
|
|
|
|
|
ragDollUpdate(tpf); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
kinematicUpdate(tpf); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void ragDollUpdate(float tpf) { |
|
|
|
|
|
|
|
TempVars vars = TempVars.get(); |
|
|
|
Quaternion tmpRot1 = vars.quat1; |
|
|
|
Quaternion tmpRot1 = vars.quat1; |
|
|
|
Quaternion tmpRot2 = vars.quat2; |
|
|
|
Quaternion tmpRot2 = vars.quat2; |
|
|
|
|
|
|
|
|
|
|
|
//if the ragdoll has the control of the skeleton, we update each bone with its position in physic world space.
|
|
|
|
for (PhysicsBoneLink link : boneLinks.values()) { |
|
|
|
if (mode == mode.Ragdoll && targetModel.getLocalTranslation().equals(modelPosition)) { |
|
|
|
|
|
|
|
for (PhysicsBoneLink link : boneLinks.values()) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vector3f position = vars.vect1; |
|
|
|
Vector3f position = vars.vect1; |
|
|
|
|
|
|
|
|
|
|
|
//retrieving bone position in physic world space
|
|
|
|
//retrieving bone position in physic world space
|
|
|
|
Vector3f p = link.rigidBody.getMotionState().getWorldLocation(); |
|
|
|
Vector3f p = link.rigidBody.getMotionState().getWorldLocation(); |
|
|
|
//transforming this position with inverse transforms of the model
|
|
|
|
//transforming this position with inverse transforms of the model
|
|
|
|
targetModel.getWorldTransform().transformInverseVector(p, position); |
|
|
|
targetModel.getWorldTransform().transformInverseVector(p, position); |
|
|
|
|
|
|
|
|
|
|
|
//retrieving bone rotation in physic world space
|
|
|
|
//retrieving bone rotation in physic world space
|
|
|
|
Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat(); |
|
|
|
Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat(); |
|
|
|
|
|
|
|
|
|
|
|
//multiplying this rotation by the initialWorld rotation of the bone,
|
|
|
|
//multiplying this rotation by the initialWorld rotation of the bone,
|
|
|
|
//then transforming it with the inverse world rotation of the model
|
|
|
|
//then transforming it with the inverse world rotation of the model
|
|
|
|
tmpRot1.set(q).multLocal(link.initalWorldRotation); |
|
|
|
tmpRot1.set(q).multLocal(link.initalWorldRotation); |
|
|
|
tmpRot2.set(targetModel.getWorldRotation()).inverseLocal().mult(tmpRot1, tmpRot1); |
|
|
|
tmpRot2.set(targetModel.getWorldRotation()).inverseLocal().mult(tmpRot1, tmpRot1); |
|
|
|
tmpRot1.normalizeLocal(); |
|
|
|
tmpRot1.normalizeLocal(); |
|
|
|
|
|
|
|
|
|
|
|
//if the bone is the root bone, we apply the physic's transform to the model, so its position and rotation are correctly updated
|
|
|
|
//if the bone is the root bone, we apply the physic's transform to the model, so its position and rotation are correctly updated
|
|
|
|
if (link.bone.getParent() == null) { |
|
|
|
if (link.bone.getParent() == null) { |
|
|
|
|
|
|
|
|
|
|
|
//offsetting the physic's position/rotation by the root bone inverse model space position/rotaion
|
|
|
|
//offsetting the physic's position/rotation by the root bone inverse model space position/rotaion
|
|
|
|
modelPosition.set(p).subtractLocal(link.bone.getWorldBindPosition()); |
|
|
|
modelPosition.set(p).subtractLocal(link.bone.getWorldBindPosition()); |
|
|
|
targetModel.getParent().getWorldTransform().transformInverseVector(modelPosition, modelPosition); |
|
|
|
targetModel.getParent().getWorldTransform().transformInverseVector(modelPosition, modelPosition); |
|
|
|
modelRotation.set(q).multLocal(tmpRot2.set(link.bone.getWorldBindRotation()).inverseLocal()); |
|
|
|
modelRotation.set(q).multLocal(tmpRot2.set(link.bone.getWorldBindRotation()).inverseLocal()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//applying transforms to the model
|
|
|
|
//applying transforms to the model
|
|
|
|
targetModel.setLocalTranslation(modelPosition); |
|
|
|
targetModel.setLocalTranslation(modelPosition); |
|
|
|
|
|
|
|
|
|
|
|
targetModel.setLocalRotation(modelRotation); |
|
|
|
targetModel.setLocalRotation(modelRotation); |
|
|
|
|
|
|
|
|
|
|
|
//Applying computed transforms to the bone
|
|
|
|
//Applying computed transforms to the bone
|
|
|
|
link.bone.setUserTransformsWorld(position, tmpRot1); |
|
|
|
link.bone.setUserTransformsWorld(position, tmpRot1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
//if boneList is empty, this means that every bone in the ragdoll has a collision shape,
|
|
|
|
|
|
|
|
//so we just update the bone position
|
|
|
|
|
|
|
|
if (boneList.isEmpty()) { |
|
|
|
|
|
|
|
link.bone.setUserTransformsWorld(position, tmpRot1); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
//if boneList is empty, this means that every bone in the ragdoll has a collision shape,
|
|
|
|
//boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape.
|
|
|
|
//so we just update the bone position
|
|
|
|
//So we update them recusively
|
|
|
|
if (boneList.isEmpty()) { |
|
|
|
RagdollUtils.setTransform(link.bone, position, tmpRot1, false, boneList); |
|
|
|
link.bone.setUserTransformsWorld(position, tmpRot1); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
//boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape.
|
|
|
|
|
|
|
|
//So we update them recusively
|
|
|
|
|
|
|
|
RagdollUtils.setTransform(link.bone, position, tmpRot1, false, boneList); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} |
|
|
|
//the ragdoll does not have the controll, so the keyframed animation updates the physic position of the physic bonces
|
|
|
|
vars.release(); |
|
|
|
for (PhysicsBoneLink link : boneLinks.values()) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Vector3f position = vars.vect1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if blended control this means, keyframed animation is updating the skeleton,
|
|
|
|
|
|
|
|
//but to allow smooth transition, we blend this transformation with the saved position of the ragdoll
|
|
|
|
|
|
|
|
if (blendedControl) { |
|
|
|
|
|
|
|
Vector3f position2 = vars.vect2; |
|
|
|
|
|
|
|
//initializing tmp vars with the start position/rotation of the ragdoll
|
|
|
|
|
|
|
|
position.set(link.startBlendingPos); |
|
|
|
|
|
|
|
tmpRot1.set(link.startBlendingRot); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//interpolating between ragdoll position/rotation and keyframed position/rotation
|
|
|
|
|
|
|
|
tmpRot2.set(tmpRot1).nlerp(link.bone.getModelSpaceRotation(), blendStart / blendTime); |
|
|
|
|
|
|
|
position2.set(position).interpolate(link.bone.getModelSpacePosition(), blendStart / blendTime); |
|
|
|
|
|
|
|
tmpRot1.set(tmpRot2); |
|
|
|
|
|
|
|
position.set(position2); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//updating bones transforms
|
|
|
|
|
|
|
|
if (boneList.isEmpty()) { |
|
|
|
|
|
|
|
//we ensure we have the control to update the bone
|
|
|
|
|
|
|
|
link.bone.setUserControl(true); |
|
|
|
|
|
|
|
link.bone.setUserTransformsWorld(position, tmpRot1); |
|
|
|
|
|
|
|
//we give control back to the key framed animation.
|
|
|
|
|
|
|
|
link.bone.setUserControl(false); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
RagdollUtils.setTransform(link.bone, position, tmpRot1, true, boneList); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void kinematicUpdate(float tpf) { |
|
|
|
|
|
|
|
//the ragdoll does not have the controll, so the keyframed animation updates the physic position of the physic bonces
|
|
|
|
|
|
|
|
TempVars vars = TempVars.get(); |
|
|
|
|
|
|
|
Quaternion tmpRot1 = vars.quat1; |
|
|
|
|
|
|
|
Quaternion tmpRot2 = vars.quat2; |
|
|
|
|
|
|
|
Vector3f position = vars.vect1; |
|
|
|
|
|
|
|
for (PhysicsBoneLink link : boneLinks.values()) { |
|
|
|
|
|
|
|
//if blended control this means, keyframed animation is updating the skeleton,
|
|
|
|
|
|
|
|
//but to allow smooth transition, we blend this transformation with the saved position of the ragdoll
|
|
|
|
|
|
|
|
if (blendedControl) { |
|
|
|
|
|
|
|
Vector3f position2 = vars.vect2; |
|
|
|
|
|
|
|
//initializing tmp vars with the start position/rotation of the ragdoll
|
|
|
|
|
|
|
|
position.set(link.startBlendingPos); |
|
|
|
|
|
|
|
tmpRot1.set(link.startBlendingRot); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//interpolating between ragdoll position/rotation and keyframed position/rotation
|
|
|
|
|
|
|
|
tmpRot2.set(tmpRot1).nlerp(link.bone.getModelSpaceRotation(), blendStart / blendTime); |
|
|
|
|
|
|
|
position2.set(position).interpolate(link.bone.getModelSpacePosition(), blendStart / blendTime); |
|
|
|
|
|
|
|
tmpRot1.set(tmpRot2); |
|
|
|
|
|
|
|
position.set(position2); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//updating bones transforms
|
|
|
|
|
|
|
|
if (boneList.isEmpty()) { |
|
|
|
|
|
|
|
//we ensure we have the control to update the bone
|
|
|
|
|
|
|
|
link.bone.setUserControl(true); |
|
|
|
|
|
|
|
link.bone.setUserTransformsWorld(position, tmpRot1); |
|
|
|
|
|
|
|
//we give control back to the key framed animation.
|
|
|
|
|
|
|
|
link.bone.setUserControl(false); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
RagdollUtils.setTransform(link.bone, position, tmpRot1, true, boneList); |
|
|
|
} |
|
|
|
} |
|
|
|
//setting skeleton transforms to the ragdoll
|
|
|
|
|
|
|
|
matchPhysicObjectToBone(link, position, tmpRot1); |
|
|
|
|
|
|
|
modelPosition.set(targetModel.getLocalTranslation()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//setting skeleton transforms to the ragdoll
|
|
|
|
|
|
|
|
matchPhysicObjectToBone(link, position, tmpRot1); |
|
|
|
|
|
|
|
modelPosition.set(targetModel.getLocalTranslation()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//time control for blending
|
|
|
|
//time control for blending
|
|
|
|
if (blendedControl) { |
|
|
|
if (blendedControl) { |
|
|
|
blendStart += tpf; |
|
|
|
blendStart += tpf; |
|
|
|
if (blendStart > blendTime) { |
|
|
|
if (blendStart > blendTime) { |
|
|
|
blendedControl = false; |
|
|
|
blendedControl = false; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
vars.release(); |
|
|
|
vars.release(); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|