diff --git a/engine/src/bullet-common/com/jme3/bullet/control/KinematicRagdollControl.java b/engine/src/bullet-common/com/jme3/bullet/control/KinematicRagdollControl.java index 367c44c76..73cbba18f 100644 --- a/engine/src/bullet-common/com/jme3/bullet/control/KinematicRagdollControl.java +++ b/engine/src/bullet-common/com/jme3/bullet/control/KinematicRagdollControl.java @@ -193,108 +193,116 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P if (!enabled) { 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 tmpRot2 = vars.quat2; + + for (PhysicsBoneLink link : boneLinks.values()) { - //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)) { - for (PhysicsBoneLink link : boneLinks.values()) { + Vector3f position = vars.vect1; - Vector3f position = vars.vect1; + //retrieving bone position in physic world space + Vector3f p = link.rigidBody.getMotionState().getWorldLocation(); + //transforming this position with inverse transforms of the model + targetModel.getWorldTransform().transformInverseVector(p, position); - //retrieving bone position in physic world space - Vector3f p = link.rigidBody.getMotionState().getWorldLocation(); - //transforming this position with inverse transforms of the model - targetModel.getWorldTransform().transformInverseVector(p, position); + //retrieving bone rotation in physic world space + Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat(); - //retrieving bone rotation in physic world space - Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat(); + //multiplying this rotation by the initialWorld rotation of the bone, + //then transforming it with the inverse world rotation of the model + tmpRot1.set(q).multLocal(link.initalWorldRotation); + tmpRot2.set(targetModel.getWorldRotation()).inverseLocal().mult(tmpRot1, tmpRot1); + tmpRot1.normalizeLocal(); - //multiplying this rotation by the initialWorld rotation of the bone, - //then transforming it with the inverse world rotation of the model - tmpRot1.set(q).multLocal(link.initalWorldRotation); - tmpRot2.set(targetModel.getWorldRotation()).inverseLocal().mult(tmpRot1, tmpRot1); - 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 (link.bone.getParent() == null) { - //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) { + //offsetting the physic's position/rotation by the root bone inverse model space position/rotaion + modelPosition.set(p).subtractLocal(link.bone.getWorldBindPosition()); + targetModel.getParent().getWorldTransform().transformInverseVector(modelPosition, modelPosition); + modelRotation.set(q).multLocal(tmpRot2.set(link.bone.getWorldBindRotation()).inverseLocal()); - //offsetting the physic's position/rotation by the root bone inverse model space position/rotaion - modelPosition.set(p).subtractLocal(link.bone.getWorldBindPosition()); - targetModel.getParent().getWorldTransform().transformInverseVector(modelPosition, modelPosition); - modelRotation.set(q).multLocal(tmpRot2.set(link.bone.getWorldBindRotation()).inverseLocal()); + //applying transforms to the model + targetModel.setLocalTranslation(modelPosition); - //applying transforms to the model - targetModel.setLocalTranslation(modelPosition); + targetModel.setLocalRotation(modelRotation); - targetModel.setLocalRotation(modelRotation); + //Applying computed transforms to the bone + link.bone.setUserTransformsWorld(position, tmpRot1); - //Applying computed transforms to the bone + } 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 { - //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 { - //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); - } + //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 - 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); - } + } + vars.release(); + } + 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 - if (blendedControl) { - blendStart += tpf; - if (blendStart > blendTime) { - blendedControl = false; - } + //time control for blending + if (blendedControl) { + blendStart += tpf; + if (blendStart > blendTime) { + blendedControl = false; } } vars.release(); - } /**