Fix for importing animated skinned meshes.

Scale is negated in inverse bind matrices.
Vertex weights are normalized (glTF importer is limited to 4 weights per vert).
Fixed interpolation for animations where the first frame is not at 0.0.
Allows cached.dts version of assimp imported shapes to be loaded.
This commit is contained in:
OTHGMars 2019-04-25 16:02:22 -04:00
parent 6be2989bbc
commit 6660f253b5
4 changed files with 35 additions and 14 deletions

View file

@ -202,6 +202,15 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset)
MatrixF boneTransform; MatrixF boneTransform;
AssimpAppNode::assimpToTorqueMat(mMeshData->mBones[b]->mOffsetMatrix, boneTransform); AssimpAppNode::assimpToTorqueMat(mMeshData->mBones[b]->mOffsetMatrix, boneTransform);
Point3F boneScale = boneTransform.getScale();
if (boneScale != Point3F::One)
{
Point3F scaleMult = Point3F::One / boneScale;
Point3F scalePos = boneTransform.getPosition();
boneTransform.scale(scaleMult);
scalePos /= scaleMult;
boneTransform.setPosition(scalePos);
}
initialTransforms.push_back(boneTransform); initialTransforms.push_back(boneTransform);
//Weights //Weights
@ -225,20 +234,32 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset)
vertexIndex.setSize(nonZeroWeights); vertexIndex.setSize(nonZeroWeights);
boneIndex.setSize(nonZeroWeights); boneIndex.setSize(nonZeroWeights);
// Copy the weights to our vectors in vertex order // Copy the weights to our vectors in vertex order and
// normalize vertex weights (force weights for each vert to sum to 1)
U32 nextWeight = 0; U32 nextWeight = 0;
for (U32 i = 0; i < mMeshData->mNumVertices; i++) for (U32 i = 0; i < mMeshData->mNumVertices; ++i)
{ {
for (U32 ind = 0; ind < nonZeroWeights; ind++) U32 vertStart = nextWeight;
F32 invTotalWeight = 0;
for (U32 ind = 0; ind < nonZeroWeights; ++ind)
{ {
if (tmpVertexIndex[ind] == i) if (tmpVertexIndex[ind] == i)
{ {
weight[nextWeight] = tmpWeight[ind]; weight[nextWeight] = tmpWeight[ind];
invTotalWeight += tmpWeight[ind];
vertexIndex[nextWeight] = tmpVertexIndex[ind]; vertexIndex[nextWeight] = tmpVertexIndex[ind];
boneIndex[nextWeight] = tmpBoneIndex[ind]; boneIndex[nextWeight] = tmpBoneIndex[ind];
nextWeight++; nextWeight++;
} }
} }
// Now normalize the vertex weights
if (invTotalWeight > 0.0)
{
invTotalWeight = 1.0f / invTotalWeight;
for (U32 ind = vertStart; ind < nextWeight; ++ind)
weight[ind] *= invTotalWeight;
}
} }
if ( noUVFound ) if ( noUVFound )

View file

@ -135,13 +135,13 @@ void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animS
{ {
F32 curT = sTimeMultiplier * (F32)nodeAnim->mPositionKeys[key].mTime; 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); curPos.set(nodeAnim->mPositionKeys[key].mValue.x, nodeAnim->mPositionKeys[key].mValue.y, nodeAnim->mPositionKeys[key].mValue.z);
if (curT > t) if ((curT > t) && (key > 0))
{ {
F32 factor = (t - lastT) / (curT - lastT); F32 factor = (t - lastT) / (curT - lastT);
trans.interpolate(lastPos, curPos, factor); trans.interpolate(lastPos, curPos, factor);
break; break;
} }
else if ((curT == t) || (key == nodeAnim->mNumPositionKeys - 1)) else if ((curT >= t) || (key == nodeAnim->mNumPositionKeys - 1))
{ {
trans = curPos; trans = curPos;
break; break;
@ -165,13 +165,13 @@ void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animS
F32 curT = sTimeMultiplier * (F32)nodeAnim->mRotationKeys[key].mTime; F32 curT = sTimeMultiplier * (F32)nodeAnim->mRotationKeys[key].mTime;
curRot.set(nodeAnim->mRotationKeys[key].mValue.x, nodeAnim->mRotationKeys[key].mValue.y, curRot.set(nodeAnim->mRotationKeys[key].mValue.x, nodeAnim->mRotationKeys[key].mValue.y,
nodeAnim->mRotationKeys[key].mValue.z, nodeAnim->mRotationKeys[key].mValue.w); nodeAnim->mRotationKeys[key].mValue.z, nodeAnim->mRotationKeys[key].mValue.w);
if (curT > t) if ((curT > t) && (key > 0))
{ {
F32 factor = (t - lastT) / (curT - lastT); F32 factor = (t - lastT) / (curT - lastT);
rot.interpolate(lastRot, curRot, factor); rot.interpolate(lastRot, curRot, factor);
break; break;
} }
else if ((curT == t) || (key == nodeAnim->mNumRotationKeys - 1)) else if ((curT >= t) || (key == nodeAnim->mNumRotationKeys - 1))
{ {
rot = curRot; rot = curRot;
break; break;
@ -193,13 +193,13 @@ void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animS
{ {
F32 curT = sTimeMultiplier * (F32)nodeAnim->mScalingKeys[key].mTime; 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); curScale.set(nodeAnim->mScalingKeys[key].mValue.x, nodeAnim->mScalingKeys[key].mValue.y, nodeAnim->mScalingKeys[key].mValue.z);
if (curT > t) if ((curT > t) && (key > 0))
{ {
F32 factor = (t - lastT) / (curT - lastT); F32 factor = (t - lastT) / (curT - lastT);
scale.interpolate(lastScale, curScale, factor); scale.interpolate(lastScale, curScale, factor);
break; break;
} }
else if ((curT == t) || (key == nodeAnim->mNumScalingKeys - 1)) else if ((curT >= t) || (key == nodeAnim->mNumScalingKeys - 1))
{ {
scale = curScale; scale = curScale;
break; break;

View file

@ -19,6 +19,7 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) :
mSequenceName = mAnim->mName.C_Str(); mSequenceName = mAnim->mName.C_Str();
if (mSequenceName.isEmpty()) if (mSequenceName.isEmpty())
mSequenceName = "ambient"; mSequenceName = "ambient";
Con::printf("\n[Assimp] Adding %s animation", mSequenceName.c_str());
fps = (mAnim->mTicksPerSecond > 0) ? mAnim->mTicksPerSecond : 30.0f; fps = (mAnim->mTicksPerSecond > 0) ? mAnim->mTicksPerSecond : 30.0f;
@ -72,6 +73,7 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) :
minFrameTime /= (F32)timeFactor; minFrameTime /= (F32)timeFactor;
maxEndTime /= (F32)timeFactor; maxEndTime /= (F32)timeFactor;
fps = (minFrameTime > 0.0f) ? 1.0f / minFrameTime : fps; fps = (minFrameTime > 0.0f) ? 1.0f / minFrameTime : fps;
fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate);
seqEnd = maxEndTime; seqEnd = maxEndTime;
mTimeMultiplier = 1.0f / timeFactor; mTimeMultiplier = 1.0f / timeFactor;
} }

View file

@ -329,8 +329,6 @@ void AssimpShapeLoader::updateMaterialsScript(const Torque::Path &path)
/// Check if an up-to-date cached DTS is available for this DAE file /// Check if an up-to-date cached DTS is available for this DAE file
bool AssimpShapeLoader::canLoadCachedDTS(const Torque::Path& path) bool AssimpShapeLoader::canLoadCachedDTS(const Torque::Path& path)
{ {
return false;
// Generate the cached filename // Generate the cached filename
Torque::Path cachedPath(path); Torque::Path cachedPath(path);
cachedPath.setExtension("cached.dts"); cachedPath.setExtension("cached.dts");
@ -339,13 +337,13 @@ bool AssimpShapeLoader::canLoadCachedDTS(const Torque::Path& path)
FileTime cachedModifyTime; FileTime cachedModifyTime;
if (Platform::getFileTimes(cachedPath.getFullPath(), NULL, &cachedModifyTime)) if (Platform::getFileTimes(cachedPath.getFullPath(), NULL, &cachedModifyTime))
{ {
bool forceLoadDAE = Con::getBoolVariable("$assimp::forceLoad", false); bool forceLoad = Con::getBoolVariable("$assimp::forceLoad", false);
FileTime daeModifyTime; FileTime daeModifyTime;
if (!Platform::getFileTimes(path.getFullPath(), NULL, &daeModifyTime) || if (!Platform::getFileTimes(path.getFullPath(), NULL, &daeModifyTime) ||
(!forceLoadDAE && (Platform::compareFileTimes(cachedModifyTime, daeModifyTime) >= 0) )) (!forceLoad && (Platform::compareFileTimes(cachedModifyTime, daeModifyTime) >= 0) ))
{ {
// DAE not found, or cached DTS is newer // Original file not found, or cached DTS is newer
return true; return true;
} }
} }