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;
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);
//Weights
@ -225,20 +234,32 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset)
vertexIndex.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;
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)
{
weight[nextWeight] = tmpWeight[ind];
invTotalWeight += tmpWeight[ind];
vertexIndex[nextWeight] = tmpVertexIndex[ind];
boneIndex[nextWeight] = tmpBoneIndex[ind];
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 )

View file

@ -135,13 +135,13 @@ void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animS
{
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)
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))
else if ((curT >= t) || (key == nodeAnim->mNumPositionKeys - 1))
{
trans = curPos;
break;
@ -165,13 +165,13 @@ void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animS
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)
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))
else if ((curT >= t) || (key == nodeAnim->mNumRotationKeys - 1))
{
rot = curRot;
break;
@ -193,13 +193,13 @@ void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animS
{
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)
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))
else if ((curT >= t) || (key == nodeAnim->mNumScalingKeys - 1))
{
scale = curScale;
break;

View file

@ -19,6 +19,7 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) :
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;
@ -72,6 +73,7 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) :
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;
}

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
bool AssimpShapeLoader::canLoadCachedDTS(const Torque::Path& path)
{
return false;
// Generate the cached filename
Torque::Path cachedPath(path);
cachedPath.setExtension("cached.dts");
@ -339,13 +337,13 @@ bool AssimpShapeLoader::canLoadCachedDTS(const Torque::Path& path)
FileTime cachedModifyTime;
if (Platform::getFileTimes(cachedPath.getFullPath(), NULL, &cachedModifyTime))
{
bool forceLoadDAE = Con::getBoolVariable("$assimp::forceLoad", false);
bool forceLoad = Con::getBoolVariable("$assimp::forceLoad", false);
FileTime 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;
}
}