Browse Source

Merge branch 'master' into issue_2693

Kim Kulling 5 years ago
parent
commit
78cfec41ec

+ 21 - 0
code/Common/SceneCombiner.cpp

@@ -1196,6 +1196,7 @@ void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src ) {
 
     // and reallocate all arrays
     CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels );
+    CopyPtrArray( dest->mMorphMeshChannels, src->mMorphMeshChannels, dest->mNumMorphMeshChannels );
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -1215,6 +1216,26 @@ void SceneCombiner::Copy(aiNodeAnim** _dest, const aiNodeAnim* src) {
     GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys );
 }
 
+void SceneCombiner::Copy(aiMeshMorphAnim** _dest, const aiMeshMorphAnim* src) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
+
+    aiMeshMorphAnim* dest = *_dest = new aiMeshMorphAnim();
+
+    // get a flat copy
+    ::memcpy(dest,src,sizeof(aiMeshMorphAnim));
+
+    // and reallocate all arrays
+    GetArrayCopy( dest->mKeys, dest->mNumKeys );
+    for (ai_uint i = 0; i < dest->mNumKeys;++i) {
+        dest->mKeys[i].mValues = new unsigned int[dest->mKeys[i].mNumValuesAndWeights];
+        dest->mKeys[i].mWeights = new double[dest->mKeys[i].mNumValuesAndWeights];
+        ::memcpy(dest->mKeys[i].mValues, src->mKeys[i].mValues, dest->mKeys[i].mNumValuesAndWeights * sizeof(unsigned int));
+        ::memcpy(dest->mKeys[i].mWeights, src->mKeys[i].mWeights, dest->mKeys[i].mNumValuesAndWeights * sizeof(double));
+    }
+}
+
 // ------------------------------------------------------------------------------------------------
 void SceneCombiner::Copy( aiCamera** _dest,const  aiCamera* src) {
     if ( nullptr == _dest || nullptr == src ) {

+ 58 - 3
code/PostProcessing/ValidateDataStructure.cpp

@@ -538,13 +538,17 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
 {
     Validate(&pAnimation->mName);
 
-    // validate all materials
-    if (pAnimation->mNumChannels)
+    // validate all animations
+    if (pAnimation->mNumChannels || pAnimation->mNumMorphMeshChannels)
     {
-        if (!pAnimation->mChannels) {
+        if (!pAnimation->mChannels && pAnimation->mNumChannels) {
             ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)",
                 pAnimation->mNumChannels);
         }
+        if (!pAnimation->mMorphMeshChannels && pAnimation->mNumMorphMeshChannels) {
+            ReportError("aiAnimation::mMorphMeshChannels is NULL (aiAnimation::mNumMorphMeshChannels is %i)",
+                pAnimation->mNumMorphMeshChannels);
+        }
         for (unsigned int i = 0; i < pAnimation->mNumChannels;++i)
         {
             if (!pAnimation->mChannels[i])
@@ -554,6 +558,15 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
             }
             Validate(pAnimation, pAnimation->mChannels[i]);
         }
+        for (unsigned int i = 0; i < pAnimation->mNumMorphMeshChannels;++i)
+        {
+            if (!pAnimation->mMorphMeshChannels[i])
+            {
+                ReportError("aiAnimation::mMorphMeshChannels[%i] is NULL (aiAnimation::mNumMorphMeshChannels is %i)",
+                    i, pAnimation->mNumMorphMeshChannels);
+            }
+            Validate(pAnimation, pAnimation->mMorphMeshChannels[i]);
+        }
     }
     else {
     	ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there.");
@@ -903,6 +916,48 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
     }
 }
 
+void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
+     const aiMeshMorphAnim* pMeshMorphAnim)
+{
+    Validate(&pMeshMorphAnim->mName);
+
+    if (!pMeshMorphAnim->mNumKeys) {
+        ReportError("Empty mesh morph animation channel");
+    }
+
+    // otherwise check whether one of the keys exceeds the total duration of the animation
+    if (pMeshMorphAnim->mNumKeys)
+    {
+        if (!pMeshMorphAnim->mKeys)
+        {
+            ReportError("aiMeshMorphAnim::mKeys is NULL (aiMeshMorphAnim::mNumKeys is %i)",
+                pMeshMorphAnim->mNumKeys);
+        }
+        double dLast = -10e10;
+        for (unsigned int i = 0; i < pMeshMorphAnim->mNumKeys;++i)
+        {
+            // ScenePreprocessor will compute the duration if still the default value
+            // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration,
+            //  seems to be due the compilers register usage/width.
+            if (pAnimation->mDuration > 0. && pMeshMorphAnim->mKeys[i].mTime > pAnimation->mDuration+0.001)
+            {
+                ReportError("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is larger "
+                    "than aiAnimation::mDuration (which is %.5f)",i,
+                    (float)pMeshMorphAnim->mKeys[i].mTime,
+                    (float)pAnimation->mDuration);
+            }
+            if (i && pMeshMorphAnim->mKeys[i].mTime <= dLast)
+            {
+                ReportWarning("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is smaller "
+                    "than aiMeshMorphAnim::mKeys[%i] (which is %.5f)",i,
+                    (float)pMeshMorphAnim->mKeys[i].mTime,
+                    i-1, (float)dLast);
+            }
+            dLast = pMeshMorphAnim->mKeys[i].mTime;
+        }
+    }
+}
+
 // ------------------------------------------------------------------------------------------------
 void ValidateDSProcess::Validate( const aiNode* pNode)
 {

+ 8 - 0
code/PostProcessing/ValidateDataStructure.h

@@ -55,6 +55,7 @@ struct aiBone;
 struct aiMesh;
 struct aiAnimation;
 struct aiNodeAnim;
+struct aiMeshMorphAnim;
 struct aiTexture;
 struct aiMaterial;
 struct aiNode;
@@ -150,6 +151,13 @@ protected:
     void Validate( const aiAnimation* pAnimation,
         const aiNodeAnim* pBoneAnim);
 
+    /** Validates a mesh morph animation channel.
+     * @param pAnimation Input animation.
+     * @param pMeshMorphAnim Mesh morph animation channel.
+     * */
+    void Validate( const aiAnimation* pAnimation,
+        const aiMeshMorphAnim* pMeshMorphAnim);
+
     // -------------------------------------------------------------------
     /** Validates a node and all of its subnodes
      * @param Node Input node*/

+ 84 - 4
code/glTF2/glTF2Importer.cpp

@@ -1005,13 +1005,15 @@ struct AnimationSamplers {
     AnimationSamplers()
     : translation(nullptr)
     , rotation(nullptr)
-    , scale(nullptr) {
+    , scale(nullptr)
+    , weight(nullptr) {
         // empty
     }
 
     Animation::Sampler* translation;
     Animation::Sampler* rotation;
     Animation::Sampler* scale;
+    Animation::Sampler* weight;
 };
 
 aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers)
@@ -1094,6 +1096,43 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl
     return anim;
 }
 
+aiMeshMorphAnim* CreateMeshMorphAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers)
+{
+    aiMeshMorphAnim* anim = new aiMeshMorphAnim();
+    anim->mName = GetNodeName(node);
+
+    static const float kMillisecondsFromSeconds = 1000.f;
+
+    if (nullptr != samplers.weight) {
+        float* times = nullptr;
+        samplers.weight->input->ExtractData(times);
+        float* values = nullptr;
+        samplers.weight->output->ExtractData(values);
+        anim->mNumKeys = static_cast<uint32_t>(samplers.weight->input->count);
+
+        const unsigned int numMorphs = samplers.weight->output->count / anim->mNumKeys;
+
+        anim->mKeys = new aiMeshMorphKey[anim->mNumKeys];
+        unsigned int k = 0u;
+        for (unsigned int i = 0u; i < anim->mNumKeys; ++i) {
+            anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
+            anim->mKeys[i].mNumValuesAndWeights = numMorphs;
+            anim->mKeys[i].mValues = new unsigned int[numMorphs];
+            anim->mKeys[i].mWeights = new double[numMorphs];
+
+            for (unsigned int j = 0u; j < numMorphs; ++j, ++k) {
+                anim->mKeys[i].mValues[j] = j;
+                anim->mKeys[i].mWeights[j] = ( 0.f > values[k] ) ? 0.f : values[k];
+            }
+        }
+
+        delete[] times;
+        delete[] values;
+    }
+
+    return anim;
+}
+
 std::unordered_map<unsigned int, AnimationSamplers> GatherSamplers(Animation& anim)
 {
     std::unordered_map<unsigned int, AnimationSamplers> samplers;
@@ -1112,6 +1151,8 @@ std::unordered_map<unsigned int, AnimationSamplers> GatherSamplers(Animation& an
             sampler.rotation = &anim.samplers[channel.sampler];
         } else if (channel.target.path == AnimationPath_SCALE) {
             sampler.scale = &anim.samplers[channel.sampler];
+        } else if (channel.target.path == AnimationPath_WEIGHTS) {
+            sampler.weight = &anim.samplers[channel.sampler];
         }
     }
 
@@ -1138,13 +1179,39 @@ void glTF2Importer::ImportAnimations(glTF2::Asset& r)
 
         std::unordered_map<unsigned int, AnimationSamplers> samplers = GatherSamplers(anim);
 
-        ai_anim->mNumChannels = static_cast<uint32_t>(samplers.size());
+        uint32_t numChannels = 0u;
+        uint32_t numMorphMeshChannels = 0u;
+
+        for (auto& iter : samplers) {
+            if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) {
+                ++numChannels;
+            }
+            if (nullptr != iter.second.weight) {
+                ++numMorphMeshChannels;
+            }
+        }
+
+        ai_anim->mNumChannels = numChannels;
         if (ai_anim->mNumChannels > 0) {
             ai_anim->mChannels = new aiNodeAnim*[ai_anim->mNumChannels];
             int j = 0;
             for (auto& iter : samplers) {
-                ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second);
-                ++j;
+                if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) {
+                    ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second);
+                    ++j;
+                }
+            }
+        }
+
+        ai_anim->mNumMorphMeshChannels = numMorphMeshChannels;
+        if (ai_anim->mNumMorphMeshChannels > 0) {
+            ai_anim->mMorphMeshChannels = new aiMeshMorphAnim*[ai_anim->mNumMorphMeshChannels];
+            int j = 0;
+            for (auto& iter : samplers) {
+                if (nullptr != iter.second.weight) {
+                  ai_anim->mMorphMeshChannels[j] = CreateMeshMorphAnim(r, r.nodes[iter.first], iter.second);
+                  ++j;
+                }
             }
         }
 
@@ -1175,6 +1242,19 @@ void glTF2Importer::ImportAnimations(glTF2::Asset& r)
                 maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumScalingKeys);
             }
         }
+
+        for (unsigned int j = 0; j < ai_anim->mNumMorphMeshChannels; ++j) {
+            const auto* const chan = ai_anim->mMorphMeshChannels[j];
+
+            if (0u != chan->mNumKeys) {
+                const auto& lastKey = chan->mKeys[chan->mNumKeys - 1u];
+                if (lastKey.mTime > maxDuration) {
+                    maxDuration = lastKey.mTime;
+                }
+                maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumKeys);
+            }
+        }
+
         ai_anim->mDuration = maxDuration;
         ai_anim->mTicksPerSecond = 1000.0;
 

+ 2 - 0
include/assimp/SceneCombiner.h

@@ -68,6 +68,7 @@ struct aiMesh;
 struct aiAnimMesh;
 struct aiAnimation;
 struct aiNodeAnim;
+struct aiMeshMorphAnim;
 
 namespace Assimp    {
 
@@ -372,6 +373,7 @@ public:
     static void Copy  (aiBone** dest, const aiBone* src);
     static void Copy  (aiLight** dest, const aiLight* src);
     static void Copy  (aiNodeAnim** dest, const aiNodeAnim* src);
+    static void Copy  (aiMeshMorphAnim** dest, const aiMeshMorphAnim* src);
     static void Copy  (aiMetadata** dest, const aiMetadata* src);
 
     // recursive, of course