فهرست منبع

Adds the following Public APIs to Transform:
- static void suspendTransformChanged();
- static void resumeTransformChanged();
- static bool isTransformChangedSuspended();
This provides a global mechanism for suspending calls to transformChanged().

Animation Optimization.
Significantly reduces the number of calls to transformChanged() during an AnimationController::update() call.
Calls Transform::suspendTransformChanged() before processing animations. This suspends all calls to transformChanged().
Calls Transform::resumeTransformChanged() after processing animations. This calls all the transformChanged() events after all animations are processed. This reduces the calls to transformChanged() (and on any children) every time there is a change to a Transform's scale, rotation or translation, which would happen quite frequently when animating a character.

Kieran Cunney 13 سال پیش
والد
کامیت
1df661a362
4فایلهای تغییر یافته به همراه123 افزوده شده و 21 حذف شده
  1. 4 0
      gameplay/src/AnimationController.cpp
  2. 13 2
      gameplay/src/Node.cpp
  3. 69 19
      gameplay/src/Transform.cpp
  4. 37 0
      gameplay/src/Transform.h

+ 4 - 0
gameplay/src/AnimationController.cpp

@@ -96,6 +96,8 @@ void AnimationController::update(long elapsedTime)
     if (_state != RUNNING)
         return;
 
+    Transform::suspendTransformChanged();
+
     // Loop through running clips and call update() on them.
     std::list<AnimationClip*>::iterator clipIter = _runningClips.begin();
     while (clipIter != _runningClips.end())
@@ -120,6 +122,8 @@ void AnimationController::update(long elapsedTime)
         }
     }
 
+    Transform::resumeTransformChanged();
+
     if (_runningClips.empty())
         _state = IDLE;
 }

+ 13 - 2
gameplay/src/Node.cpp

@@ -601,11 +601,22 @@ void Node::transformChanged()
     _dirtyBits |= NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS;
 
     // Notify our children that their transform has also changed (since transforms are inherited).
-    Joint* rootJoint = NULL;
     Node* n = getFirstChild();
     while (n)
     {
-        n->transformChanged();
+        if (Transform::isTransformChangedSuspended())
+        {
+            // If the DIRTY_NOTIFY bit is not set
+            if (!n->isDirty(Transform::DIRTY_NOTIFY))
+            {
+                n->transformChanged();
+                suspendTransformChange(n);
+            }
+        }
+        else
+        {
+            n->transformChanged();
+        }
         n = n->getNextSibling();
     }
 

+ 69 - 19
gameplay/src/Transform.cpp

@@ -6,6 +6,9 @@
 namespace gameplay
 {
 
+int Transform::_suspendTransformChanged(0);
+std::vector<Transform*> Transform::_transformsChanged;
+
 Transform::Transform()
     : _matrixDirtyBits(0), _listeners(NULL)
 {
@@ -39,6 +42,45 @@ Transform::~Transform()
     SAFE_DELETE(_listeners);
 }
 
+void Transform::suspendTransformChanged()
+{
+    _suspendTransformChanged++;
+}
+
+void Transform::resumeTransformChanged()
+{
+    if (_suspendTransformChanged == 0) // We haven't suspended transformChanged() calls, so do nothing.
+        return;
+    
+    if (--_suspendTransformChanged == 0)
+    {
+        // Call transformChanged() on all transforms in the list
+        unsigned int transformCount = _transformsChanged.size();
+        for (unsigned int i = 0; i < transformCount; i++)
+        {
+            Transform* t = _transformsChanged.at(i);
+            t->transformChanged();
+        }
+
+        // Go through list and reset DIRTY_NOTIFY bit. The list could potentially be larger here if the 
+        // transforms we were delaying calls to transformChanged() have any child nodes.
+        transformCount = _transformsChanged.size();
+        for (unsigned int i = 0; i < transformCount; i++)
+        {
+            Transform* t = _transformsChanged.at(i);
+            t->_matrixDirtyBits &= ~DIRTY_NOTIFY;
+        }
+
+        // empty list for next frame.
+        _transformsChanged.clear();
+    }
+}
+
+bool Transform::isTransformChangedSuspended()
+{
+    return (_suspendTransformChanged > 0);
+}
+
 const Matrix& Transform::getMatrix() const
 {
     if (_matrixDirtyBits)
@@ -74,7 +116,7 @@ const Matrix& Transform::getMatrix() const
             Matrix::createScale(_scale, &_matrix);
         }
 
-        _matrixDirtyBits = 0;
+        _matrixDirtyBits &= ~DIRTY_TRANSLATION & ~DIRTY_ROTATION & ~DIRTY_SCALE;
     }
 
     return _matrix;
@@ -692,7 +734,6 @@ void Transform::setAnimationPropertyValue(int propertyId, AnimationValue* value,
         case ANIMATE_ROTATE:
         {
             applyAnimationValueRotation(value, 0, blendWeight);
-            dirty(DIRTY_ROTATION);
             break;
         }
         case ANIMATE_TRANSLATE:
@@ -718,27 +759,14 @@ void Transform::setAnimationPropertyValue(int propertyId, AnimationValue* value,
         case ANIMATE_ROTATE_TRANSLATE:
         {
             applyAnimationValueRotation(value, 0, blendWeight);
-
-            _translation.x = Curve::lerp(blendWeight, _translation.x, value->getFloat(4));
-            _translation.y = Curve::lerp(blendWeight, _translation.y, value->getFloat(5));
-            _translation.z = Curve::lerp(blendWeight, _translation.z, value->getFloat(6));
-
-            dirty(DIRTY_ROTATION | DIRTY_TRANSLATION);
+            setTranslation(Curve::lerp(blendWeight, _translation.x, value->getFloat(4)), Curve::lerp(blendWeight, _translation.y, value->getFloat(5)), Curve::lerp(blendWeight, _translation.z, value->getFloat(6)));
             break;
         }
         case ANIMATE_SCALE_ROTATE_TRANSLATE:
         {
-            _scale.x = Curve::lerp(blendWeight, _scale.x, value->getFloat(0));
-            _scale.y = Curve::lerp(blendWeight, _scale.y, value->getFloat(1));
-            _scale.z = Curve::lerp(blendWeight, _scale.z, value->getFloat(2));
-            
+            setScale(Curve::lerp(blendWeight, _scale.x, value->getFloat(0)), Curve::lerp(blendWeight, _scale.y, value->getFloat(1)), Curve::lerp(blendWeight, _scale.z, value->getFloat(2)));
             applyAnimationValueRotation(value, 3, blendWeight);
-            
-            _translation.x = Curve::lerp(blendWeight, _translation.x, value->getFloat(7));
-            _translation.y = Curve::lerp(blendWeight, _translation.y, value->getFloat(8));
-            _translation.z = Curve::lerp(blendWeight, _translation.z, value->getFloat(9));
-
-            dirty(DIRTY_SCALE | DIRTY_ROTATION | DIRTY_TRANSLATION);
+            setTranslation(Curve::lerp(blendWeight, _translation.x, value->getFloat(7)), Curve::lerp(blendWeight, _translation.y, value->getFloat(8)), Curve::lerp(blendWeight, _translation.z, value->getFloat(9)));
             break;
         }
         default:
@@ -749,7 +777,28 @@ void Transform::setAnimationPropertyValue(int propertyId, AnimationValue* value,
 void Transform::dirty(char matrixDirtyBits)
 {
     _matrixDirtyBits |= matrixDirtyBits;
-    transformChanged();
+    if (isTransformChangedSuspended())
+    {
+        if (!isDirty(DIRTY_NOTIFY))
+        {
+            suspendTransformChange(this);
+        }
+    }
+    else
+    {
+        transformChanged();
+    }
+}
+
+bool Transform::isDirty(char matrixDirtyBits) const
+{
+    return (_matrixDirtyBits & matrixDirtyBits) == matrixDirtyBits;
+}
+
+void Transform::suspendTransformChange(Transform* transform)
+{
+    transform->_matrixDirtyBits |= DIRTY_NOTIFY;
+    _transformsChanged.push_back(transform);
 }
 
 void Transform::addListener(Transform::Listener* listener, long cookie)
@@ -802,6 +851,7 @@ void Transform::applyAnimationValueRotation(AnimationValue* value, unsigned int
 {
     Quaternion::slerp(_rotation.x, _rotation.y, _rotation.z, _rotation.w, value->getFloat(index), value->getFloat(index + 1), value->getFloat(index + 2), value->getFloat(index + 3), blendWeight, 
         &_rotation.x, &_rotation.y, &_rotation.z, &_rotation.w);
+    dirty(DIRTY_ROTATION);
 }
 
 }

+ 37 - 0
gameplay/src/Transform.h

@@ -91,6 +91,23 @@ public:
      */
     static const int ANIMATE_SCALE_ROTATE_TRANSLATE = 17;
 
+    /**
+     * Globally suspends all transform changed events.
+     */
+    static void suspendTransformChanged();
+
+    /**
+     * Globally resumes all transform changed events.
+     */
+    static void resumeTransformChanged();
+
+    /** 
+     * Gets whether all transform changed events are suspended.
+     *
+     * @return TRUE if transform changed events are suspended; FALSE if transform changed events are not suspended.
+     */
+    static bool isTransformChangedSuspended();
+
     /**
      * Listener interface for Transform events.
      */
@@ -760,6 +777,7 @@ protected:
         DIRTY_TRANSLATION = 0x01,
         DIRTY_SCALE = 0x02,
         DIRTY_ROTATION = 0x04,
+        DIRTY_NOTIFY = 0x08
     };
 
     /**
@@ -767,6 +785,20 @@ protected:
      */
     void dirty(char matrixDirtyBits);
 
+    /** 
+     * Determines if the specified matrix dirty bit is set.
+     *
+     * @param matrixDirtyBits the matrix dirty bit to check for dirtiness.
+     * @return TRUE if the specified matrix dirty bit is set; FALSE if the specified matrix dirty bit is unset.
+     */
+    bool isDirty(char matrixDirtyBits) const;
+
+    /** 
+     * Adds the specified transform to the list of transforms waiting to be notified of a change.
+     * Sets the DIRTY_NOTIFY bit on the transform.
+     */
+    static void suspendTransformChange(Transform* transform);
+
     /**
      * Called when the transform changes.
      */
@@ -811,7 +843,12 @@ protected:
     std::list<TransformListener>* _listeners;
 
 private:
+   
     void applyAnimationValueRotation(AnimationValue* value, unsigned int index, float blendWeight);
+
+    static int _suspendTransformChanged;
+    static std::vector<Transform*> _transformsChanged;
+    
 };
 
 }