static PxTransform computeBoneTransform(PxTransform &rootTransform, Acclaim::Bone &bone, PxVec3* boneFrameData) { using namespace Acclaim; //PxTransform rootTransform(PxVec3(0.0f), PxQuat(PxIdentity)); PxTransform parentTransform = (bone.mParent) ? computeBoneTransform(rootTransform, *bone.mParent, boneFrameData) : rootTransform; PxQuat qWorld = EulerAngleToQuat(bone.mAxis); PxVec3 offset = bone.mLength * bone.mDirection; PxQuat qDelta = PxQuat(PxIdentity); PxVec3 boneData = boneFrameData[bone.mID-1]; if (bone.mDOF & BoneDOFFlag::eRX) qDelta = PxQuat(Ps::degToRad(boneData.x), PxVec3(1.0f, 0.0f, 0.0f)) * qDelta; if (bone.mDOF & BoneDOFFlag::eRY) qDelta = PxQuat(Ps::degToRad(boneData.y), PxVec3(0.0f, 1.0f, 0.0f)) * qDelta; if (bone.mDOF & BoneDOFFlag::eRZ) qDelta = PxQuat(Ps::degToRad(boneData.z), PxVec3(0.0f, 0.0f, 1.0f)) * qDelta; PxQuat boneOrientation = qWorld * qDelta * qWorld.getConjugate(); PxTransform boneTransform(boneOrientation.rotate(offset), boneOrientation); return parentTransform.transform(boneTransform); }
bool Character::buildMotion(Acclaim::AMCData &amcData, Motion &motion, PxU32 start, PxU32 end) { using namespace Acclaim; if (mASFData == NULL) return false; motion.mNbFrames = end - start + 1; motion.mMotionData = SAMPLE_NEW(MotionData)[motion.mNbFrames]; // compute bounds of all the motion data on normalized frame PxBounds3 bounds = PxBounds3::empty(); for (PxU32 i = start; i < end; i++) { Acclaim::FrameData &frameData = amcData.mFrameData[i]; PxTransform rootTransform(PxVec3(0.0f), EulerAngleToQuat(frameData.mRootOrientation)); for (PxU32 j = 0; j < mASFData->mNbBones; j++) { PxTransform t = computeBoneTransform(rootTransform, mASFData->mBones[j], frameData.mBoneFrameData); bounds.include(t.p); } } Acclaim::FrameData& firstFrame = amcData.mFrameData[0]; Acclaim::FrameData& lastFrame = amcData.mFrameData[amcData.mNbFrames-1]; // compute direction vector motion.mDistance = mCharacterScale * (lastFrame.mRootPosition - firstFrame.mRootPosition).magnitude(); PxVec3 firstPosition = firstFrame.mRootPosition; PX_UNUSED(firstPosition); PxVec3 firstAngles = firstFrame.mRootOrientation; PxQuat firstOrientation = EulerAngleToQuat(PxVec3(0, firstAngles.y, 0)); for (PxU32 i = 0; i < motion.mNbFrames; i++) { Acclaim::FrameData& frameData = amcData.mFrameData[i+start]; MotionData &motionData = motion.mMotionData[i]; // normalize y-rot by computing inverse quat from first frame // this makes all the motion aligned in the same (+ z) direction. PxQuat currentOrientation = EulerAngleToQuat(frameData.mRootOrientation); PxQuat qdel = firstOrientation.getConjugate() * currentOrientation; PxTransform rootTransform(PxVec3(0.0f), qdel); for (PxU32 j = 0; j < mNbBones; j++) { PxTransform boneTransform = computeBoneTransform(rootTransform, mASFData->mBones[j], frameData.mBoneFrameData); motionData.mBoneTransform[j] = boneTransform; } //PxReal y = mCharacterScale * (frameData.mRootPosition.y - firstPosition.y) - bounds.minimum.y; motionData.mRootTransform = PxTransform(PxVec3(0.0f, -bounds.minimum.y, 0.0f), PxQuat(PxIdentity)); } // now make the motion cyclic by linear interpolating root position and joint angles const PxU32 windowSize = 10; for (PxU32 i = 0; i <= windowSize; i++) { PxU32 j = motion.mNbFrames - 1 - windowSize + i; PxReal t = PxReal(i) / PxReal(windowSize); MotionData& motion_i = motion.mMotionData[0]; MotionData& motion_j = motion.mMotionData[j]; // lerp root translation PxVec3 blendedRootPos = (1.0f - t) * motion_j.mRootTransform.p + t * motion_i.mRootTransform.p; for (PxU32 k = 0; k < mNbBones; k++) { PxVec3 pj = motion_j.mRootTransform.p + motion_j.mBoneTransform[k].p; PxVec3 pi = motion_i.mRootTransform.p + motion_i.mBoneTransform[k].p; PxVec3 p = (1.0f - t) * pj + t * pi; motion_j.mBoneTransform[k].p = p - blendedRootPos; } motion_j.mRootTransform.p = blendedRootPos; } return true; }