From 05960e4d255f07dfdb2d4e5a56a3a69abc0f8b2b Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 10 Feb 2024 20:01:52 +0000 Subject: [PATCH] extra fixes Torque sees the seqEnd in appSequence as a time in seconds whereas in Assimp this is in frames. This is then converted to frames in generateSequences. --- Engine/source/ts/assimp/assimpAppNode.cpp | 169 ++++++++++-------- Engine/source/ts/assimp/assimpAppSequence.cpp | 71 ++++++-- Engine/source/ts/assimp/assimpAppSequence.h | 2 +- Engine/source/ts/assimp/assimpShapeLoader.cpp | 23 ++- 4 files changed, 171 insertions(+), 94 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppNode.cpp b/Engine/source/ts/assimp/assimpAppNode.cpp index 093101521..2b06b58b8 100644 --- a/Engine/source/ts/assimp/assimpAppNode.cpp +++ b/Engine/source/ts/assimp/assimpAppNode.cpp @@ -122,100 +122,115 @@ MatrixF AssimpAppNode::getTransform(F32 time) void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animSeq) { // Find the channel for this node - for (U32 i = 0; i < animSeq->mNumChannels; ++i) + for (U32 k = 0; k < animSeq->mNumChannels; ++k) { - if (strcmp(mName, animSeq->mChannels[i]->mNodeName.C_Str()) == 0) + if (dStrcmp(mName, animSeq->mChannels[k]->mNodeName.C_Str()) == 0) { - aiNodeAnim *nodeAnim = animSeq->mChannels[i]; + aiNodeAnim *nodeAnim = animSeq->mChannels[k]; Point3F trans(Point3F::Zero); Point3F scale(Point3F::One); QuatF rot; rot.identity(); + // T is in seconds, convert to frames. + F32 frame = t * animSeq->mTicksPerSecond; - // Transform - if (nodeAnim->mNumPositionKeys == 1) - trans.set(nodeAnim->mPositionKeys[0].mValue.x, nodeAnim->mPositionKeys[0].mValue.y, nodeAnim->mPositionKeys[0].mValue.z); + // interpolate scaling. + if (nodeAnim->mNumScalingKeys > 1) { + U32 scaleIndex = 0; + + for (U32 i = 0; i < nodeAnim->mNumScalingKeys-1; i++) + { + if (frame < nodeAnim->mScalingKeys[i + 1].mTime) { + scaleIndex = i; + break; + } + } + + const Point3F& scalingStart = Point3F( nodeAnim->mScalingKeys[scaleIndex].mValue.x, + nodeAnim->mScalingKeys[scaleIndex].mValue.y, + nodeAnim->mScalingKeys[scaleIndex].mValue.z); + + const Point3F& scalingEnd = Point3F(nodeAnim->mScalingKeys[scaleIndex + 1].mValue.x, + nodeAnim->mScalingKeys[scaleIndex + 1].mValue.y, + nodeAnim->mScalingKeys[scaleIndex + 1].mValue.z); + + F32 deltaTime = nodeAnim->mScalingKeys[scaleIndex + 1].mTime - nodeAnim->mScalingKeys[scaleIndex].mTime; + F32 factor = (frame - nodeAnim->mScalingKeys[scaleIndex].mTime) / deltaTime; + + scale = scalingStart + factor * (scalingEnd - scalingStart); + } else { - Point3F curPos, lastPos; - F32 lastT = 0.0; - for (U32 key = 0; key < nodeAnim->mNumPositionKeys; ++key) - { - F32 curT = sTimeMultiplier * (F32)nodeAnim->mPositionKeys[key].mTime; - curPos.set(nodeAnim->mPositionKeys[key].mValue.x, nodeAnim->mPositionKeys[key].mValue.y, nodeAnim->mPositionKeys[key].mValue.z); - if ((curT > t) && (key > 0)) - { - F32 factor = (t - lastT) / (curT - lastT); - trans.interpolate(lastPos, curPos, factor); - break; - } - else if ((curT >= t) || (key == nodeAnim->mNumPositionKeys - 1)) - { - trans = curPos; - break; - } - - lastT = curT; - lastPos = curPos; - } + scale.set( nodeAnim->mScalingKeys[0].mValue.x, + nodeAnim->mScalingKeys[0].mValue.y, + nodeAnim->mScalingKeys[0].mValue.z); } - // Rotation - if (nodeAnim->mNumRotationKeys == 1) - rot.set(nodeAnim->mRotationKeys[0].mValue.x, nodeAnim->mRotationKeys[0].mValue.y, - nodeAnim->mRotationKeys[0].mValue.z, nodeAnim->mRotationKeys[0].mValue.w); + // interpolate rotation. + if (nodeAnim->mNumRotationKeys > 1) { + U32 rotationIndex = 0; + + for (U32 i = 0; i < nodeAnim->mNumRotationKeys - 1; i++) + { + if (frame < nodeAnim->mRotationKeys[i + 1].mTime) { + rotationIndex = i; + break; + } + } + + const QuatF& rotStart = QuatF(nodeAnim->mRotationKeys[rotationIndex].mValue.x, + nodeAnim->mRotationKeys[rotationIndex].mValue.y, + nodeAnim->mRotationKeys[rotationIndex].mValue.z, + nodeAnim->mRotationKeys[rotationIndex].mValue.w); + + const QuatF& rotEnd = QuatF(nodeAnim->mRotationKeys[rotationIndex + 1].mValue.x, + nodeAnim->mRotationKeys[rotationIndex + 1].mValue.y, + nodeAnim->mRotationKeys[rotationIndex + 1].mValue.z, + nodeAnim->mRotationKeys[rotationIndex + 1].mValue.w); + + F32 deltaTime = nodeAnim->mRotationKeys[rotationIndex + 1].mTime - nodeAnim->mRotationKeys[rotationIndex].mTime; + F32 factor = (frame - nodeAnim->mRotationKeys[rotationIndex].mTime) / deltaTime; + + rot.interpolate(rotStart, rotEnd, factor); + } else { - QuatF curRot, lastRot; - F32 lastT = 0.0; - for (U32 key = 0; key < nodeAnim->mNumRotationKeys; ++key) - { - F32 curT = sTimeMultiplier * (F32)nodeAnim->mRotationKeys[key].mTime; - curRot.set(nodeAnim->mRotationKeys[key].mValue.x, nodeAnim->mRotationKeys[key].mValue.y, - nodeAnim->mRotationKeys[key].mValue.z, nodeAnim->mRotationKeys[key].mValue.w); - if ((curT > t) && (key > 0)) - { - F32 factor = (t - lastT) / (curT - lastT); - rot.interpolate(lastRot, curRot, factor); - break; - } - else if ((curT >= t) || (key == nodeAnim->mNumRotationKeys - 1)) - { - rot = curRot; - break; - } - - lastT = curT; - lastRot = curRot; - } + rot.set( nodeAnim->mRotationKeys[0].mValue.x, + nodeAnim->mRotationKeys[0].mValue.y, + nodeAnim->mRotationKeys[0].mValue.z, + nodeAnim->mRotationKeys[0].mValue.w); } - // Scale - if (nodeAnim->mNumScalingKeys == 1) - scale.set(nodeAnim->mScalingKeys[0].mValue.x, nodeAnim->mScalingKeys[0].mValue.y, nodeAnim->mScalingKeys[0].mValue.z); + // interpolate position. + if (nodeAnim->mNumPositionKeys > 1) { + U32 posIndex = 0; + + for (U32 i = 0; i < nodeAnim->mNumPositionKeys - 1; i++) + { + if (frame < nodeAnim->mPositionKeys[i + 1].mTime) { + posIndex = i; + break; + } + } + + const Point3F& posStart = Point3F( nodeAnim->mPositionKeys[posIndex].mValue.x, + nodeAnim->mPositionKeys[posIndex].mValue.y, + nodeAnim->mPositionKeys[posIndex].mValue.z); + + const Point3F& posEnd = Point3F(nodeAnim->mPositionKeys[posIndex + 1].mValue.x, + nodeAnim->mPositionKeys[posIndex + 1].mValue.y, + nodeAnim->mPositionKeys[posIndex + 1].mValue.z); + + F32 deltaTime = nodeAnim->mPositionKeys[posIndex + 1].mTime - nodeAnim->mPositionKeys[posIndex].mTime; + F32 factor = (frame - nodeAnim->mPositionKeys[posIndex].mTime) / deltaTime; + + trans = posStart + factor * (posEnd - posStart); + } else { - Point3F curScale, lastScale; - F32 lastT = 0.0; - for (U32 key = 0; key < nodeAnim->mNumScalingKeys; ++key) - { - F32 curT = sTimeMultiplier * (F32)nodeAnim->mScalingKeys[key].mTime; - curScale.set(nodeAnim->mScalingKeys[key].mValue.x, nodeAnim->mScalingKeys[key].mValue.y, nodeAnim->mScalingKeys[key].mValue.z); - if ((curT > t) && (key > 0)) - { - F32 factor = (t - lastT) / (curT - lastT); - scale.interpolate(lastScale, curScale, factor); - break; - } - else if ((curT >= t) || (key == nodeAnim->mNumScalingKeys - 1)) - { - scale = curScale; - break; - } - - lastT = curT; - lastScale = curScale; - } + trans.set( nodeAnim->mPositionKeys[0].mValue.x, + nodeAnim->mPositionKeys[0].mValue.y, + nodeAnim->mPositionKeys[0].mValue.z); } rot.setMatrix(&mat); diff --git a/Engine/source/ts/assimp/assimpAppSequence.cpp b/Engine/source/ts/assimp/assimpAppSequence.cpp index 88652fa69..69587fe85 100644 --- a/Engine/source/ts/assimp/assimpAppSequence.cpp +++ b/Engine/source/ts/assimp/assimpAppSequence.cpp @@ -14,30 +14,75 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) : seqStart(0.0f), - mAnim(a) + seqEnd(0.0f) { + mAnim = new aiAnimation(*a); + + // Deep copy channels + mAnim->mChannels = new aiNodeAnim * [a->mNumChannels]; + for (U32 i = 0; i < a->mNumChannels; ++i) { + mAnim->mChannels[i] = new aiNodeAnim(*a->mChannels[i]); + } + + // Deep copy meshes + mAnim->mMeshChannels = new aiMeshAnim * [a->mNumMeshChannels]; + for (U32 i = 0; i < a->mNumMeshChannels; ++i) { + mAnim->mMeshChannels[i] = new aiMeshAnim(*a->mMeshChannels[i]); + } + + // Deep copy name + mAnim->mName = a->mName; + mSequenceName = mAnim->mName.C_Str(); if (mSequenceName.isEmpty()) mSequenceName = "ambient"; Con::printf("\n[Assimp] Adding %s animation", mSequenceName.c_str()); - fps = (mAnim->mTicksPerSecond > 0) ? mAnim->mTicksPerSecond : 30.0f; + fps = (a->mTicksPerSecond > 0) ? a->mTicksPerSecond : 30.0f; - U32 maxKeys = 0; - F32 maxEndTime = 0; - F32 minFrameTime = 100000.0f; - // Detect the frame rate (minimum time between keyframes) and max sequence time - for (U32 i = 0; i < mAnim->mNumChannels; ++i) + if (a->mDuration > 0) { - aiNodeAnim *nodeAnim = mAnim->mChannels[i]; - maxKeys = getMax(maxKeys, nodeAnim->mNumPositionKeys); - maxKeys = getMax(maxKeys, nodeAnim->mNumRotationKeys); - maxKeys = getMax(maxKeys, nodeAnim->mNumScalingKeys); + // torques seqEnd is in seconds, this then gets generated into frames in generateSequences() + seqEnd = (F32)a->mDuration / fps; + } + else + { + for (U32 i = 0; i < a->mNumChannels; ++i) + { + aiNodeAnim* nodeAnim = a->mChannels[i]; + // Determine the maximum keyframe time for this animation + F32 maxKeyTime = 0.0f; + for (U32 k = 0; k < nodeAnim->mNumPositionKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mPositionKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumRotationKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mRotationKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumScalingKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mScalingKeys[k].mTime); + } - maxEndTime = getMax(maxEndTime, (F32)maxKeys); + seqEnd = getMax(seqEnd, maxKeyTime); + } } - seqEnd = maxEndTime; + mTimeMultiplier = 1.0f; + + //S32 timeFactor = ColladaUtils::getOptions().animTiming; + //S32 fpsRequest = (S32)a->mTicksPerSecond; + //if (timeFactor == 0) + //{ // Timing specified in frames + // fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate); + // mTimeMultiplier = 1.0f / fps; + //} + //else + //{ // Timing specified in seconds or ms depending on format + // if (seqEnd > 1000.0f || a->mDuration > 1000.0f) + // timeFactor = 1000.0f; // If it's more than 1000 seconds, assume it's ms. + + // timeFactor = mClamp(timeFactor, 1, 1000); + // mTimeMultiplier = 1.0f / timeFactor; + //} } diff --git a/Engine/source/ts/assimp/assimpAppSequence.h b/Engine/source/ts/assimp/assimpAppSequence.h index be5c11025..467aeb4a2 100644 --- a/Engine/source/ts/assimp/assimpAppSequence.h +++ b/Engine/source/ts/assimp/assimpAppSequence.h @@ -48,4 +48,4 @@ public: virtual U32 getFlags() const; virtual F32 getPriority() const; virtual F32 getBlendRefTime() const; -}; \ No newline at end of file +}; diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index c7cf7d751..908e186f2 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -260,22 +260,39 @@ void AssimpShapeLoader::processAnimations() ambientSeq->mName = "ambient"; Vector ambientChannels; + F32 duration = 0.0f; for (U32 i = 0; i < mScene->mNumAnimations; ++i) { aiAnimation* anim = mScene->mAnimations[i]; for (U32 j = 0; j < anim->mNumChannels; j++) { - ambientChannels.push_back(anim->mChannels[j]); + aiNodeAnim* nodeAnim = anim->mChannels[j]; + // Determine the maximum keyframe time for this animation + F32 maxKeyTime = 0.0f; + for (U32 k = 0; k < nodeAnim->mNumPositionKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mPositionKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumRotationKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mRotationKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumScalingKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mScalingKeys[k].mTime); + } + + ambientChannels.push_back(nodeAnim); + + duration = getMax(duration, maxKeyTime); } } - + ambientSeq->mNumChannels = ambientChannels.size(); ambientSeq->mChannels = ambientChannels.address(); + ambientSeq->mDuration = duration; + ambientSeq->mTicksPerSecond = 24.0; AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); appSequences.push_back(defaultAssimpSeq); - } void AssimpShapeLoader::computeBounds(Box3F& bounds)