Bladeren bron

Removed the autosyncsource feature from AnimatedModel as it is difficult to ensure that animation LOD updates line up correctly. Manual sync should be used instead.
Added local animation flag for AnimatedModel. When enabled, animation and morph updates will not be sent over network.
Added missing registration of syncAnimation() & syncMorphs() to script.

Lasse Öörni 15 jaren geleden
bovenliggende
commit
09644088b8
3 gewijzigde bestanden met toevoegingen van 27 en 83 verwijderingen
  1. 4 2
      Engine/Engine/RegisterRenderer.cpp
  2. 15 65
      Engine/Renderer/AnimatedModel.cpp
  3. 8 16
      Engine/Renderer/AnimatedModel.h

+ 4 - 2
Engine/Engine/RegisterRenderer.cpp

@@ -660,8 +660,10 @@ static void registerAnimatedModel(asIScriptEngine* engine)
     engine->RegisterObjectMethod("AnimatedModel", "void setAnimationLodBias(float)", asMETHOD(AnimatedModel, setAnimationLodBias), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void setAnimationLodBias(float)", asMETHOD(AnimatedModel, setAnimationLodBias), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void setMorphWeight(uint, float)", asMETHODPR(AnimatedModel, setMorphWeight, (unsigned, float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void setMorphWeight(uint, float)", asMETHODPR(AnimatedModel, setMorphWeight, (unsigned, float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void setMorphWeight(const string& in, float)", asMETHODPR(AnimatedModel, setMorphWeight, (const std::string&, float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void setMorphWeight(const string& in, float)", asMETHODPR(AnimatedModel, setMorphWeight, (const std::string&, float), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod("AnimatedModel", "void setAutoSyncSource(AnimatedModel@+)", asMETHOD(AnimatedModel, setAutoSyncSource), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void resetMorphWeights()", asMETHOD(AnimatedModel, resetMorphWeights), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void resetMorphWeights()", asMETHOD(AnimatedModel, resetMorphWeights), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedModel", "void syncAnimation(AnimatedModel@+)", asMETHOD(AnimatedModel, syncAnimation), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedModel", "void syncMorphs(AnimatedModel@+)", asMETHOD(AnimatedModel, syncMorphs), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedModel", "void setLocalAnimation(bool)", asMETHOD(AnimatedModel, setLocalAnimation), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "Skeleton@+ getSkeleton() const", asMETHOD(AnimatedModel, getSkeleton), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "Skeleton@+ getSkeleton() const", asMETHOD(AnimatedModel, getSkeleton), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "AnimationState@+ getAnimationState(Animation@+) const", asMETHODPR(AnimatedModel, getAnimationState, (Animation*) const, AnimationState*), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "AnimationState@+ getAnimationState(Animation@+) const", asMETHODPR(AnimatedModel, getAnimationState, (Animation*) const, AnimationState*), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "AnimationState@+ getAnimationState(const string& in) const", asMETHODPR(AnimatedModel, getAnimationState, (const std::string&) const, AnimationState*), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "AnimationState@+ getAnimationState(const string& in) const", asMETHODPR(AnimatedModel, getAnimationState, (const std::string&) const, AnimationState*), asCALL_THISCALL);
@@ -669,7 +671,7 @@ static void registerAnimatedModel(asIScriptEngine* engine)
     engine->RegisterObjectMethod("AnimatedModel", "uint getNumMorphs() const", asMETHOD(AnimatedModel, getNumMorphs), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "uint getNumMorphs() const", asMETHOD(AnimatedModel, getNumMorphs), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "float getMorphWeight(uint) const", asMETHODPR(AnimatedModel, getMorphWeight, (unsigned) const, float), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "float getMorphWeight(uint) const", asMETHODPR(AnimatedModel, getMorphWeight, (unsigned) const, float), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "float getMorphWeight(const string& in) const", asMETHODPR(AnimatedModel, getMorphWeight, (const std::string&) const, float), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "float getMorphWeight(const string& in) const", asMETHODPR(AnimatedModel, getMorphWeight, (const std::string&) const, float), asCALL_THISCALL);
-    engine->RegisterObjectMethod("AnimatedModel", "AnimatedModel@+ getAutoSyncSource() const", asMETHOD(AnimatedModel, getAutoSyncSource), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedModel", "bool getLocalAnimation() const", asMETHOD(AnimatedModel, getLocalAnimation), asCALL_THISCALL);
     registerRefCasts<Component, AnimatedModel>(engine, "Component", "AnimatedModel");
     registerRefCasts<Component, AnimatedModel>(engine, "Component", "AnimatedModel");
     registerRefCasts<Node, AnimatedModel>(engine, "Node", "AnimatedModel");
     registerRefCasts<Node, AnimatedModel>(engine, "Node", "AnimatedModel");
 }
 }

+ 15 - 65
Engine/Renderer/AnimatedModel.cpp

@@ -57,7 +57,8 @@ AnimatedModel::AnimatedModel(Octant* octant, const std::string& name) :
     mAnimationLodTimer(0.0f),
     mAnimationLodTimer(0.0f),
     mAnimationDirty(true),
     mAnimationDirty(true),
     mAnimationOrderDirty(true),
     mAnimationOrderDirty(true),
-    mMorphsDirty(true)
+    mMorphsDirty(true),
+    mLocalAnimation(false)
 {
 {
 }
 }
 
 
@@ -91,10 +92,6 @@ void AnimatedModel::save(Serializer& dest)
     dest.writeVLE(mMorphs.size());
     dest.writeVLE(mMorphs.size());
     for (unsigned i = 0; i < mMorphs.size(); ++i)
     for (unsigned i = 0; i < mMorphs.size(); ++i)
         dest.writeFloat(mMorphs[i].mWeight);
         dest.writeFloat(mMorphs[i].mWeight);
-    
-    // Write autosyncsource reference
-    ComponentRef autoSyncSourceRef(mAutoSyncSource.getPtr());
-    autoSyncSourceRef.write(dest);
 }
 }
 
 
 void AnimatedModel::load(Deserializer& source, ResourceCache* cache)
 void AnimatedModel::load(Deserializer& source, ResourceCache* cache)
@@ -127,9 +124,6 @@ void AnimatedModel::load(Deserializer& source, ResourceCache* cache)
     unsigned numMorphs = source.readVLE();
     unsigned numMorphs = source.readVLE();
     for (unsigned i = 0; i < numMorphs; ++i)
     for (unsigned i = 0; i < numMorphs; ++i)
         setMorphWeight(i, source.readFloat());
         setMorphWeight(i, source.readFloat());
-    
-    // Read autosyncsource reference
-    mAutoSyncSourceRef.read(source);
 }
 }
 
 
 void AnimatedModel::saveXML(XMLElement& dest)
 void AnimatedModel::saveXML(XMLElement& dest)
@@ -164,14 +158,6 @@ void AnimatedModel::saveXML(XMLElement& dest)
         morphElem.setInt("index", i);
         morphElem.setInt("index", i);
         morphElem.setFloat("weight", mMorphs[i].mWeight);
         morphElem.setFloat("weight", mMorphs[i].mWeight);
     }
     }
-    
-    // Write autosyncsource reference
-    ComponentRef autoSyncSourceRef(mAutoSyncSource.getPtr(), true);
-    if (autoSyncSourceRef.mEntityID)
-    {
-        XMLElement syncSourceElem = dest.createChildElement("syncsource");
-        autoSyncSourceRef.writeXML(syncSourceElem);
-    }
 }
 }
 
 
 void AnimatedModel::loadXML(const XMLElement& source, ResourceCache* cache)
 void AnimatedModel::loadXML(const XMLElement& source, ResourceCache* cache)
@@ -212,22 +198,6 @@ void AnimatedModel::loadXML(const XMLElement& source, ResourceCache* cache)
         setMorphWeight(index, morphElem.getFloat("weight"));
         setMorphWeight(index, morphElem.getFloat("weight"));
         morphElem = morphElem.getNextElement("morph");
         morphElem = morphElem.getNextElement("morph");
     }
     }
-    
-    // Read autosyncsource reference
-    XMLElement syncSourceElem = source.getChildElement("syncsource", false);
-    if (syncSourceElem.notNull())
-        mAutoSyncSourceRef.readXML(syncSourceElem);
-}
-
-void AnimatedModel::postLoad(ResourceCache* cache)
-{
-    Node::postLoad(cache);
-    
-    if (mAutoSyncSourceRef.mDirty)
-    {
-        mAutoSyncSource = static_cast<AnimatedModel*>(mEntity->getScene()->getComponent(mAutoSyncSourceRef));
-        mAutoSyncSourceRef.mDirty = false;
-    }
 }
 }
 
 
 bool AnimatedModel::writeNetUpdate(Serializer& dest, Serializer& destRevision, Deserializer& baseRevision, const NetUpdateInfo& info)
 bool AnimatedModel::writeNetUpdate(Serializer& dest, Serializer& destRevision, Deserializer& baseRevision, const NetUpdateInfo& info)
@@ -322,11 +292,10 @@ bool AnimatedModel::writeNetUpdate(Serializer& dest, Serializer& destRevision, D
         else
         else
             baseRevision.readUByte();
             baseRevision.readUByte();
     }
     }
-    // Autosyncsource
-    ComponentRef autoSyncSourceRef(mAutoSyncSource);
-    checkComponentRef(autoSyncSourceRef, baseRevision, bits, 32);
-    // If autosyncsource exists, do not send animation or morph data
-    if (mAutoSyncSource)
+    
+    // If local animation, do not send even if changed. It is slightly unoptimal to first check, then disable, but it ensures
+    // that the base revision data stays the same (otherwise out of bounds reads might result when toggling local animation)
+    if (mLocalAnimation)
         bits &= ~(8 | 16);
         bits &= ~(8 | 16);
     
     
     // Update replication state fully, and network stream by delta
     // Update replication state fully, and network stream by delta
@@ -374,7 +343,6 @@ bool AnimatedModel::writeNetUpdate(Serializer& dest, Serializer& destRevision, D
     writeVLEDelta(mMorphs.size(), dest, destRevision, bits & 16);
     writeVLEDelta(mMorphs.size(), dest, destRevision, bits & 16);
     for (unsigned i = 0; i < mMorphs.size(); ++i)
     for (unsigned i = 0; i < mMorphs.size(); ++i)
         writeUByteDelta((unsigned char)(mMorphs[i].mWeight * 255.0f), dest, destRevision, bits & 16);
         writeUByteDelta((unsigned char)(mMorphs[i].mWeight * 255.0f), dest, destRevision, bits & 16);
-    writeComponentRefDelta(autoSyncSourceRef, dest, destRevision, bits & 32);
     
     
     return prevBits || (bits != 0);
     return prevBits || (bits != 0);
 }
 }
@@ -454,12 +422,6 @@ void AnimatedModel::readNetUpdate(Deserializer& source, ResourceCache* cache, co
         for (unsigned i = 0; i < numMorphs; ++i)
         for (unsigned i = 0; i < numMorphs; ++i)
             setMorphWeight(i, source.readUByte() / 255.0f);
             setMorphWeight(i, source.readUByte() / 255.0f);
     }
     }
-    readComponentRefDelta(mAutoSyncSourceRef, source, bits & 32);
-}
-
-void AnimatedModel::postNetUpdate(ResourceCache* cache)
-{
-    postLoad(cache);
 }
 }
 
 
 void AnimatedModel::interpolate(bool snapToEnd)
 void AnimatedModel::interpolate(bool snapToEnd)
@@ -472,14 +434,6 @@ void AnimatedModel::interpolate(bool snapToEnd)
         (*i)->interpolate(snapToEnd, t);
         (*i)->interpolate(snapToEnd, t);
 }
 }
 
 
-void AnimatedModel::getComponentRefs(std::vector<ComponentRef>& dest)
-{
-    if (mParent)
-        dest.push_back(ComponentRef(mParent));
-    if (mAutoSyncSource)
-        dest.push_back(ComponentRef(mAutoSyncSource));
-}
-
 void AnimatedModel::processRayQuery(RayOctreeQuery& query, float initialDistance)
 void AnimatedModel::processRayQuery(RayOctreeQuery& query, float initialDistance)
 {
 {
     // If no bones or no bone-level testing, use the GeometryNode test
     // If no bones or no bone-level testing, use the GeometryNode test
@@ -600,13 +554,6 @@ void AnimatedModel::updateDistance(const FrameInfo& frame)
 
 
 void AnimatedModel::updateGeometry(const FrameInfo& frame, Renderer* renderer)
 void AnimatedModel::updateGeometry(const FrameInfo& frame, Renderer* renderer)
 {
 {
-    // Update animation from sync source if one is defined
-    if (!mAutoSyncSource.isExpired())
-    {
-        syncAnimation(mAutoSyncSource);
-        syncMorphs(mAutoSyncSource);
-    }
-    
     if (mLodLevelsDirty)
     if (mLodLevelsDirty)
         calculateLodLevels();
         calculateLodLevels();
     
     
@@ -835,11 +782,6 @@ void AnimatedModel::setMorphWeight(StringHash nameHash, float weight)
     }
     }
 }
 }
 
 
-void AnimatedModel::setAutoSyncSource(AnimatedModel* source)
-{
-    mAutoSyncSource = source;
-}
-
 void AnimatedModel::resetMorphWeights()
 void AnimatedModel::resetMorphWeights()
 {
 {
     for (std::vector<ModelMorph>::iterator i = mMorphs.begin(); i != mMorphs.end(); ++i)
     for (std::vector<ModelMorph>::iterator i = mMorphs.begin(); i != mMorphs.end(); ++i)
@@ -853,7 +795,10 @@ void AnimatedModel::syncAnimation(AnimatedModel* srcNode)
     if (!srcNode)
     if (!srcNode)
         return;
         return;
     
     
-    setAnimationLodBias(srcNode->getAnimationLodBias());
+    // Make sure the animation proceeds at the same rate as in the source
+    mAnimationLodBias = srcNode->mAnimationLodBias;
+    mAnimationLodDistance = srcNode->mAnimationLodDistance;
+    mAnimationLodFrameNumber = srcNode->mAnimationLodFrameNumber;
     
     
     const std::vector<AnimationState*>& srcStates = srcNode->getAnimationStates();
     const std::vector<AnimationState*>& srcStates = srcNode->getAnimationStates();
     std::set<Animation*> srcAnimations;
     std::set<Animation*> srcAnimations;
@@ -891,6 +836,11 @@ void AnimatedModel::syncMorphs(AnimatedModel* srcNode)
     }
     }
 }
 }
 
 
+void AnimatedModel::setLocalAnimation(bool enable)
+{
+    mLocalAnimation = enable;
+}
+
 float AnimatedModel::getMorphWeight(unsigned index) const
 float AnimatedModel::getMorphWeight(unsigned index) const
 {
 {
     if (index >= mMorphs.size())
     if (index >= mMorphs.size())

+ 8 - 16
Engine/Renderer/AnimatedModel.h

@@ -54,18 +54,12 @@ public:
     virtual void saveXML(XMLElement& dest);
     virtual void saveXML(XMLElement& dest);
     //! Read component state from an XML element
     //! Read component state from an XML element
     virtual void loadXML(const XMLElement& source, ResourceCache* cache);
     virtual void loadXML(const XMLElement& source, ResourceCache* cache);
-    //! Resolve component references after loading
-    virtual void postLoad(ResourceCache* cache);
     //! Write a network update
     //! Write a network update
     virtual bool writeNetUpdate(Serializer& dest, Serializer& destRevision, Deserializer& baseRevision, const NetUpdateInfo& info);
     virtual bool writeNetUpdate(Serializer& dest, Serializer& destRevision, Deserializer& baseRevision, const NetUpdateInfo& info);
     //! Read a network update
     //! Read a network update
     virtual void readNetUpdate(Deserializer& source, ResourceCache* cache, const NetUpdateInfo& info);
     virtual void readNetUpdate(Deserializer& source, ResourceCache* cache, const NetUpdateInfo& info);
-    //! Resolve component references after a network update
-    virtual void postNetUpdate(ResourceCache* cache);
     //! Perform client-side visual smoothing
     //! Perform client-side visual smoothing
     virtual void interpolate(bool snapToEnd);
     virtual void interpolate(bool snapToEnd);
-    //! Return component references
-    virtual void getComponentRefs(std::vector<ComponentRef>& refs);
     
     
     //! Process renderer raycast
     //! Process renderer raycast
     virtual void processRayQuery(RayOctreeQuery& query, float initialDistance);
     virtual void processRayQuery(RayOctreeQuery& query, float initialDistance);
@@ -100,14 +94,14 @@ public:
     void setMorphWeight(const std::string& name, float weight);
     void setMorphWeight(const std::string& name, float weight);
     //! Set vertex morph weight by name hash
     //! Set vertex morph weight by name hash
     void setMorphWeight(StringHash nameHash, float weight);
     void setMorphWeight(StringHash nameHash, float weight);
-    //! Enable automatic animation and morph sync from another animated model
-    void setAutoSyncSource(AnimatedModel* source);
     //! Reset all vertex morphs to zero
     //! Reset all vertex morphs to zero
     void resetMorphWeights();
     void resetMorphWeights();
-    //! Sync animation manually from another animated model
+    //! Sync animation from another animated model
     void syncAnimation(AnimatedModel* srcNode);
     void syncAnimation(AnimatedModel* srcNode);
-    //! Sync morphs manually from another animated model
+    //! Sync morphs from another animated model
     void syncMorphs(AnimatedModel* srcNode);
     void syncMorphs(AnimatedModel* srcNode);
+    //! Set animation & morphs local mode. If enabled, they are not sent over network even if the node is otherwise replicated
+    void setLocalAnimation(bool enable);
     
     
     //! Return skeleton
     //! Return skeleton
     const Skeleton& getSkeleton() const { return mSkeleton; }
     const Skeleton& getSkeleton() const { return mSkeleton; }
@@ -133,8 +127,8 @@ public:
     float getMorphWeight(const std::string& name) const;
     float getMorphWeight(const std::string& name) const;
     //! Return vertex morph weight by name hash
     //! Return vertex morph weight by name hash
     float getMorphWeight(StringHash nameHash) const;
     float getMorphWeight(StringHash nameHash) const;
-    //! Return automatic animation sync source
-    AnimatedModel* getAutoSyncSource() const { return mAutoSyncSource; }
+    //! Return whether animation is local
+    bool getLocalAnimation() const { return mLocalAnimation; }
     
     
 protected:
 protected:
     //! Update world-space bounding box
     //! Update world-space bounding box
@@ -185,8 +179,6 @@ private:
     std::vector<std::vector<Matrix4x3> > mGeometrySkinMatrices;
     std::vector<std::vector<Matrix4x3> > mGeometrySkinMatrices;
     //! Subgeometry skinning matrix pointers, if more bones than skinning shader can manage
     //! Subgeometry skinning matrix pointers, if more bones than skinning shader can manage
     std::vector<std::vector<Matrix4x3*> > mGeometrySkinMatrixPtrs;
     std::vector<std::vector<Matrix4x3*> > mGeometrySkinMatrixPtrs;
-    //! Automatic animation sync source
-    WeakPtr<AnimatedModel> mAutoSyncSource;
     //! Animation LOD bias
     //! Animation LOD bias
     float mAnimationLodBias;
     float mAnimationLodBias;
     //! Animation LOD timer
     //! Animation LOD timer
@@ -197,8 +189,8 @@ private:
     bool mAnimationOrderDirty;
     bool mAnimationOrderDirty;
     //! Vertex morphs dirty flag
     //! Vertex morphs dirty flag
     bool mMorphsDirty;
     bool mMorphsDirty;
-    //! Automatic animation sync source component reference
-    ComponentRef mAutoSyncSourceRef;
+    //! Local animation flag
+    bool mLocalAnimation;
 };
 };
 
 
 #endif // RENDERER_ANIMATEDMODEL_H
 #endif // RENDERER_ANIMATEDMODEL_H