From 37dd58dca45e27f0feab20193f303a7cfddfa5eb Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 9 Feb 2024 22:06:11 +0000 Subject: [PATCH 1/6] Update assimpShapeLoader.cpp non destructive fixes for assimp loader -this creates an ambient sequence if 1 does not exist. -adds a bounds node if 1 does not exist. --- Engine/source/ts/assimp/assimpShapeLoader.cpp | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index 2a3735243..fd56bb2a1 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -229,6 +229,18 @@ void AssimpShapeLoader::enumerateScene() if (!processNode(node)) delete node; + // add bounds node. + if (!boundsNode) + { + aiNode* req[1]; + req[0] = new aiNode("bounds"); + mScene->mRootNode->addChildren(1, req); + + AssimpAppNode* appBounds = new AssimpAppNode(mScene, req[0]); + if (!processNode(appBounds)) + delete appBounds; + } + // Check for animations and process those. processAnimations(); } @@ -243,13 +255,42 @@ void AssimpShapeLoader::enumerateScene() void AssimpShapeLoader::processAnimations() { + bool ambient = false; for(U32 n = 0; n < mScene->mNumAnimations; ++n) { Con::printf("[ASSIMP] Animation Found: %s", mScene->mAnimations[n]->mName.C_Str()); + if (mScene->mAnimations[n]->mName.C_Str() == "ambient") + ambient = true; + AssimpAppSequence* newAssimpSeq = new AssimpAppSequence(mScene->mAnimations[n]); appSequences.push_back(newAssimpSeq); } + + // dont have ambient, lets just add everything to an ambient sequence. + // we should probably just do this as default. + if (!ambient) + { + aiAnimation* ambientSeq = new aiAnimation(); + ambientSeq->mName = "ambient"; + + Vector ambientChannels; + + 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]); + } + } + + ambientSeq->mChannels = ambientChannels.address(); + + AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); + appSequences.push_back(defaultAssimpSeq); + } + } void AssimpShapeLoader::computeBounds(Box3F& bounds) @@ -369,12 +410,16 @@ bool AssimpShapeLoader::fillGuiTreeView(const char* sourceShapePath, GuiTreeView tree->insertItem(matItem, String::ToString("%s", name.c_str()), String::ToString("%s", texName.c_str())); } - for (U32 i = 0; i < shapeScene->mNumAnimations; i++) + if (shapeScene->mNumAnimations == 0) { - String sequenceName = shapeScene->mAnimations[i]->mName.C_Str(); - if (sequenceName.isEmpty()) - sequenceName = "ambient"; - tree->insertItem(animItem, sequenceName.c_str()); + tree->insertItem(animItem, "ambient", "animation", "", 0, 0); + } + else + { + for (U32 i = 0; i < shapeScene->mNumAnimations; i++) + { + tree->insertItem(animItem, shapeScene->mAnimations[i]->mName.C_Str(), "animation", "", 0, 0); + } } U32 numNodes = 0; From 7115d9bcc6ed92edf7bdbb7667f53fb146a8daed Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 9 Feb 2024 22:12:52 +0000 Subject: [PATCH 2/6] Update assimpShapeLoader.cpp --- Engine/source/ts/assimp/assimpShapeLoader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index fd56bb2a1..2e8070091 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -284,7 +284,8 @@ void AssimpShapeLoader::processAnimations() ambientChannels.push_back(anim->mChannels[j]); } } - + + ambientSeq->mNumChannels = ambientChannels.size(); ambientSeq->mChannels = ambientChannels.address(); AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); From 144e1bcc60a33f7bb2be4b30c02b80a00a50673b Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 10 Feb 2024 04:25:48 +0000 Subject: [PATCH 3/6] Update assimpShapeLoader.cpp --- Engine/source/ts/assimp/assimpShapeLoader.cpp | 48 +++++++------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index 2e8070091..c7cf7d751 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -255,42 +255,26 @@ void AssimpShapeLoader::enumerateScene() void AssimpShapeLoader::processAnimations() { - bool ambient = false; - for(U32 n = 0; n < mScene->mNumAnimations; ++n) + // add all animations into 1 ambient animation. + aiAnimation* ambientSeq = new aiAnimation(); + ambientSeq->mName = "ambient"; + + Vector ambientChannels; + + for (U32 i = 0; i < mScene->mNumAnimations; ++i) { - Con::printf("[ASSIMP] Animation Found: %s", mScene->mAnimations[n]->mName.C_Str()); - - if (mScene->mAnimations[n]->mName.C_Str() == "ambient") - ambient = true; - - AssimpAppSequence* newAssimpSeq = new AssimpAppSequence(mScene->mAnimations[n]); - appSequences.push_back(newAssimpSeq); - } - - // dont have ambient, lets just add everything to an ambient sequence. - // we should probably just do this as default. - if (!ambient) - { - aiAnimation* ambientSeq = new aiAnimation(); - ambientSeq->mName = "ambient"; - - Vector ambientChannels; - - for (U32 i = 0; i < mScene->mNumAnimations; ++i) + aiAnimation* anim = mScene->mAnimations[i]; + for (U32 j = 0; j < anim->mNumChannels; j++) { - aiAnimation* anim = mScene->mAnimations[i]; - for (U32 j = 0; j < anim->mNumChannels; j++) - { - ambientChannels.push_back(anim->mChannels[j]); - } + ambientChannels.push_back(anim->mChannels[j]); } - - ambientSeq->mNumChannels = ambientChannels.size(); - ambientSeq->mChannels = ambientChannels.address(); - - AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); - appSequences.push_back(defaultAssimpSeq); } + + ambientSeq->mNumChannels = ambientChannels.size(); + ambientSeq->mChannels = ambientChannels.address(); + + AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); + appSequences.push_back(defaultAssimpSeq); } From e2550ed5258a30ae2b85eab0c4c90035369e2cdd Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 10 Feb 2024 04:49:57 +0000 Subject: [PATCH 4/6] Update assimpAppSequence.cpp --- Engine/source/ts/assimp/assimpAppSequence.cpp | 49 ++----------------- 1 file changed, 4 insertions(+), 45 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppSequence.cpp b/Engine/source/ts/assimp/assimpAppSequence.cpp index e0a78175e..88652fa69 100644 --- a/Engine/source/ts/assimp/assimpAppSequence.cpp +++ b/Engine/source/ts/assimp/assimpAppSequence.cpp @@ -34,52 +34,11 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) : maxKeys = getMax(maxKeys, nodeAnim->mNumRotationKeys); maxKeys = getMax(maxKeys, nodeAnim->mNumScalingKeys); - if (nodeAnim->mNumPositionKeys) - maxEndTime = getMax(maxEndTime, (F32) nodeAnim->mPositionKeys[nodeAnim->mNumPositionKeys-1].mTime); - if (nodeAnim->mNumRotationKeys) - maxEndTime = getMax(maxEndTime, (F32) nodeAnim->mRotationKeys[nodeAnim->mNumRotationKeys-1].mTime); - if (nodeAnim->mNumScalingKeys) - maxEndTime = getMax(maxEndTime, (F32) nodeAnim->mScalingKeys[nodeAnim->mNumScalingKeys-1].mTime); - - for (U32 key = 1; key < nodeAnim->mNumPositionKeys; ++key) - { - F32 deltaT = nodeAnim->mPositionKeys[key].mTime - nodeAnim->mPositionKeys[key-1].mTime; - minFrameTime = getMin(minFrameTime, deltaT); - } - for (U32 key = 1; key < nodeAnim->mNumRotationKeys; ++key) - { - F32 deltaT = nodeAnim->mRotationKeys[key].mTime - nodeAnim->mRotationKeys[key-1].mTime; - minFrameTime = getMin(minFrameTime, deltaT); - } - for (U32 key = 1; key < nodeAnim->mNumScalingKeys; ++key) - { - F32 deltaT = nodeAnim->mScalingKeys[key].mTime - nodeAnim->mScalingKeys[key-1].mTime; - minFrameTime = getMin(minFrameTime, deltaT); - } + maxEndTime = getMax(maxEndTime, (F32)maxKeys); } - S32 timeFactor = ColladaUtils::getOptions().animTiming; - S32 fpsRequest = ColladaUtils::getOptions().animFPS; - if (timeFactor == 0) - { // Timing specified in frames - fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate); - maxKeys = getMax(maxKeys, (U32)maxEndTime); // Keys won't be assigned for every frame. - seqEnd = maxKeys / fps; - mTimeMultiplier = 1.0f / fps; - } - else - { // Timing specified in seconds or ms depending on format - if (maxEndTime > 1000.0f || mAnim->mDuration > 1000.0f) - timeFactor = 1000.0f; // If it's more than 1000 seconds, assume it's ms. + seqEnd = maxEndTime; - timeFactor = mClamp(timeFactor, 1, 1000); - minFrameTime /= (F32)timeFactor; - maxEndTime /= (F32)timeFactor; - fps = (minFrameTime > 0.0f) ? 1.0f / minFrameTime : fps; - fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate); - seqEnd = maxEndTime; - mTimeMultiplier = 1.0f / timeFactor; - } } AssimpAppSequence::~AssimpAppSequence() @@ -102,7 +61,7 @@ void AssimpAppSequence::setActive(bool active) U32 AssimpAppSequence::getFlags() const { - return TSShape::Blend; + return TSShape::Cyclic; } F32 AssimpAppSequence::getPriority() const { @@ -111,4 +70,4 @@ F32 AssimpAppSequence::getPriority() const F32 AssimpAppSequence::getBlendRefTime() const { return -1.0f; -} \ No newline at end of file +} From 05960e4d255f07dfdb2d4e5a56a3a69abc0f8b2b Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 10 Feb 2024 20:01:52 +0000 Subject: [PATCH 5/6] 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) From 58bcea770c735b1956631596a5b28d0e90a7e960 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 10 Feb 2024 21:57:08 +0000 Subject: [PATCH 6/6] Node interp Fix node interpolation to remove the jittered (reverted back to previous get node transform) --- Engine/source/ts/assimp/assimpAppNode.cpp | 161 ++++++++---------- Engine/source/ts/assimp/assimpAppSequence.cpp | 31 ++-- 2 files changed, 89 insertions(+), 103 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppNode.cpp b/Engine/source/ts/assimp/assimpAppNode.cpp index 2b06b58b8..024186255 100644 --- a/Engine/source/ts/assimp/assimpAppNode.cpp +++ b/Engine/source/ts/assimp/assimpAppNode.cpp @@ -132,105 +132,92 @@ void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animS QuatF rot; rot.identity(); // T is in seconds, convert to frames. - F32 frame = t * animSeq->mTicksPerSecond; + F32 frame = (t * animSeq->mTicksPerSecond + 0.5f) + 1.0f; - // 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); - } + // Transform + if (nodeAnim->mNumPositionKeys == 1) + trans.set(nodeAnim->mPositionKeys[0].mValue.x, nodeAnim->mPositionKeys[0].mValue.y, nodeAnim->mPositionKeys[0].mValue.z); else { - scale.set( nodeAnim->mScalingKeys[0].mValue.x, - nodeAnim->mScalingKeys[0].mValue.y, - nodeAnim->mScalingKeys[0].mValue.z); - } - - // interpolate rotation. - if (nodeAnim->mNumRotationKeys > 1) { - U32 rotationIndex = 0; - - for (U32 i = 0; i < nodeAnim->mNumRotationKeys - 1; i++) + Point3F curPos, lastPos; + F32 lastT = 0.0; + for (U32 key = 0; key < nodeAnim->mNumPositionKeys; ++key) { - if (frame < nodeAnim->mRotationKeys[i + 1].mTime) { - rotationIndex = i; + 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 > frame) && (key > 0)) + { + F32 factor = (frame - lastT) / (curT - lastT); + trans.interpolate(lastPos, curPos, factor); 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 - { - rot.set( nodeAnim->mRotationKeys[0].mValue.x, - nodeAnim->mRotationKeys[0].mValue.y, - nodeAnim->mRotationKeys[0].mValue.z, - nodeAnim->mRotationKeys[0].mValue.w); - } - - // 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; + else if ((curT >= frame) || (key == nodeAnim->mNumPositionKeys - 1)) + { + trans = curPos; break; } + + lastT = curT; + lastPos = curPos; } - - 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); } + + // 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); else { - trans.set( nodeAnim->mPositionKeys[0].mValue.x, - nodeAnim->mPositionKeys[0].mValue.y, - nodeAnim->mPositionKeys[0].mValue.z); + 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 > frame) && (key > 0)) + { + F32 factor = (frame - lastT) / (curT - lastT); + rot.interpolate(lastRot, curRot, factor); + break; + } + else if ((curT >= frame) || (key == nodeAnim->mNumRotationKeys - 1)) + { + rot = curRot; + break; + } + + lastT = curT; + lastRot = curRot; + } + } + + // Scale + if (nodeAnim->mNumScalingKeys == 1) + scale.set(nodeAnim->mScalingKeys[0].mValue.x, nodeAnim->mScalingKeys[0].mValue.y, nodeAnim->mScalingKeys[0].mValue.z); + 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 > frame) && (key > 0)) + { + F32 factor = (frame - lastT) / (curT - lastT); + scale.interpolate(lastScale, curScale, factor); + break; + } + else if ((curT >= frame) || (key == nodeAnim->mNumScalingKeys - 1)) + { + scale = curScale; + break; + } + + lastT = curT; + lastScale = curScale; + } } rot.setMatrix(&mat); diff --git a/Engine/source/ts/assimp/assimpAppSequence.cpp b/Engine/source/ts/assimp/assimpAppSequence.cpp index 69587fe85..496d1fb09 100644 --- a/Engine/source/ts/assimp/assimpAppSequence.cpp +++ b/Engine/source/ts/assimp/assimpAppSequence.cpp @@ -17,7 +17,6 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *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) { @@ -68,21 +67,21 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) : 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. + 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; - //} + timeFactor = mClamp(timeFactor, 1, 1000); + mTimeMultiplier = 1.0f / timeFactor; + } } @@ -114,5 +113,5 @@ F32 AssimpAppSequence::getPriority() const } F32 AssimpAppSequence::getBlendRefTime() const { - return -1.0f; + return 0.0f; }