Fix transform matrix in case child actor didn't inherit some of its parent's transforms. 74/285174/7
authorseungho baek <sbsh.baek@samsung.com>
Wed, 7 Dec 2022 07:28:03 +0000 (16:28 +0900)
committerseungho baek <sbsh.baek@samsung.com>
Mon, 19 Dec 2022 08:57:06 +0000 (17:57 +0900)
Change-Id: Ib711eae4ca1a33872927a54e04c8228aabc1d256
Signed-off-by: seungho baek <sbsh.baek@samsung.com>
automated-tests/src/dali/utc-Dali-Actor.cpp
dali/internal/event/actors/actor-coords.cpp
dali/internal/update/manager/transform-manager.cpp

index 4ac16ea..a528eb3 100644 (file)
@@ -11662,6 +11662,76 @@ int UtcDaliActorCalculateWorldTransform07(void)
   END_TEST;
 }
 
+int UtcDaliActorCalculateWorldTransform08(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test that actor inheritance of scale produces right transform matrix");
+
+  Vector3 solutions[] = {Vector3(250, 0, 0), Vector3(0, 250, 0), Vector3(650, 0, 0), Vector3(0, 250, 0), Vector3(650, 0, 0), Vector3(400, 250, 0), Vector3(200, -50, 0), Vector3(500, 200, 0)};
+
+  struct TestCase
+  {
+    bool translation;
+    bool rotation;
+    bool scaling;
+  };
+  TestCase testCases[] = {
+    {false, false, true},
+    {false, true, false},
+    {true, false, false},
+    {false, true, true},
+    {true, false, true},
+    {true, true, false},
+    {false, false, false},
+    {true, true, true},
+  };
+
+  Actor rootActor = Actor::New();
+  Actor leafActor = Actor::New();
+
+  rootActor[Actor::Property::POSITION]      = Vector3(0.0f, 0.0f, 0.0f);
+  rootActor[Actor::Property::SCALE]         = Vector3(1.0f, 2.0f, 1.0f);
+  rootActor[Actor::Property::ORIENTATION]   = AngleAxis(Degree(90.0f), Vector3::ZAXIS);
+  rootActor[Actor::Property::SIZE]          = Vector2(200, 400);
+  rootActor[Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  rootActor[Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+
+  leafActor[Actor::Property::POSITION]                   = Vector3(0.0f, -50.0f, 0.0f);
+  leafActor[Actor::Property::SCALE]                      = Vector3(1.0f, 1.0f, 1.0f);
+  leafActor[Actor::Property::ORIENTATION]                = AngleAxis(Degree(90.0f), Vector3::ZAXIS);
+  leafActor[Actor::Property::SIZE]                       = Vector2(200, 400);
+  leafActor[Actor::Property::ANCHOR_POINT]               = AnchorPoint::BOTTOM_CENTER;
+  leafActor[Actor::Property::PARENT_ORIGIN]              = ParentOrigin::TOP_CENTER;
+  leafActor[Actor::Property::POSITION_USES_ANCHOR_POINT] = true;
+
+  application.GetScene().Add(rootActor);
+  rootActor.Add(leafActor);
+
+  for(uint32_t i = 0; i< 8; ++i)
+  {
+    leafActor[Actor::Property::INHERIT_POSITION]    = testCases[i].translation;
+    leafActor[Actor::Property::INHERIT_ORIENTATION] = testCases[i].rotation;
+    leafActor[Actor::Property::INHERIT_SCALE]       = testCases[i].scaling;
+
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+
+    Matrix m            = DevelActor::GetWorldTransform(leafActor);
+    Matrix actualMatrix = leafActor.GetCurrentProperty<Matrix>(Actor::Property::WORLD_MATRIX);
+
+    Vector3 worldPosition1 = Vector3(m.GetTranslation());
+    Vector3 worldPosition2 = Vector3(actualMatrix.GetTranslation());
+
+    DALI_TEST_EQUALS(solutions[i], worldPosition1, 0.001f, TEST_LOCATION);
+    DALI_TEST_EQUALS(solutions[i], worldPosition2, 0.001f, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliActorCalculateWorldColor01(void)
 {
   TestApplication application;
index d1a70db..9f1fefe 100644 (file)
@@ -533,39 +533,60 @@ Matrix CalculateActorWorldTransform(const Actor& actor)
       }
       else
       {
-        Vector3    parentPosition, parentScale;
-        Quaternion parentOrientation;
-        worldMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
-
+        // Get Parent information.
+        Vector3       parentPosition, parentScale;
+        Quaternion    parentOrientation;
+        const Matrix& parentMatrix = worldMatrix;
+        parentMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
+
+        // Compute intermediate Local information
+        centerPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, localScale, localOrientation);
+        Vector3 intermediateLocalPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
+        Matrix intermediateLocalMatrix;
+        intermediateLocalMatrix.SetTransformComponents(localScale, localOrientation, intermediateLocalPosition);
+
+        // Compute intermediate world information
+        Matrix intermediateWorldMatrix;
+        MatrixUtils::Multiply(intermediateWorldMatrix, intermediateLocalMatrix, parentMatrix);
+
+        Vector3       intermediateWorldPosition, intermediateWorldScale;
+        Quaternion    intermediateWorldOrientation;
+        intermediateWorldMatrix.GetTransformComponents(intermediateWorldPosition, intermediateWorldOrientation, intermediateWorldScale);
+
+        // Compute final world information
+        Vector3    finalWorldPosition    = intermediateWorldPosition;
+        Vector3    finalWorldScale       = intermediateWorldScale;
+        Quaternion finalWorldOrientation = intermediateWorldOrientation;
+        // worldScale includes the influence of local scale, local rotation, and parent scale.
+        // So, for the final world matrix, if this node inherits its parent scale, use worldScale.
+        // If not, use local scale for the final world matrix.
         if((inheritanceModeList[i] & INHERIT_SCALE) == 0)
         {
-          //Don't inherit scale
-          localScale /= parentScale;
+          finalWorldScale = localScale;
         }
 
+        // For the final world matrix, if this node inherits its parent orientation, use worldOrientation.
+        // If not, use local orientation for the final world matrix.
         if((inheritanceModeList[i] & INHERIT_ORIENTATION) == 0)
         {
-          //Don't inherit orientation
-          parentOrientation.Invert();
-          localOrientation = parentOrientation * localOrientation;
+          finalWorldOrientation = localOrientation;
         }
 
-        if((inheritanceModeList[i] & INHERIT_POSITION) == 0)
-        {
-          localMatrix.SetTransformComponents(localScale, localOrientation, Vector3::ZERO);
-          Matrix tempMatrix;
-          MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
-          worldMatrix = tempMatrix;
-          worldMatrix.SetTranslation(actorPosition + centerPosition);
-        }
-        else
+        // The final world position of this node is computed as a sum of
+        // parent origin position in world space and relative position of center from parent origin.
+        // If this node doesn't inherit its parent position, simply use the relative position as a final world position.
+        Vector3 localCenterPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, finalWorldScale, finalWorldOrientation);
+        finalWorldPosition = actorPosition * finalWorldScale;
+        finalWorldPosition *= finalWorldOrientation;
+        finalWorldPosition += localCenterPosition;
+        if((inheritanceModeList[i] & INHERIT_POSITION) != 0)
         {
-          localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
-          localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
-          Matrix tempMatrix;
-          MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
-          worldMatrix = tempMatrix;
+          Vector4 parentOriginPosition((parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize);
+          parentOriginPosition.w = 1.0f;
+          finalWorldPosition += Vector3(parentMatrix * parentOriginPosition);
         }
+
+        worldMatrix.SetTransformComponents(finalWorldScale, finalWorldOrientation, finalWorldPosition);
       }
     }
     else
index 342d820..452d272 100644 (file)
@@ -28,6 +28,8 @@
 #include <dali/internal/common/matrix-utils.h>
 #include <dali/public-api/common/constants.h>
 
+#include <dali/integration-api/debug.h>
+
 namespace Dali
 {
 namespace Internal
@@ -49,22 +51,24 @@ static_assert(sizeof(gDefaultTransformComponentStaticData) == sizeof(TransformCo
  * @brief Calculates the center position for the transform component
  * @param[out] centerPosition The calculated center-position of the transform component
  * @param[in] transformComponentStatic A const reference to the static component transform struct
- * @param[in] transformComponentAnimatable A const reference to the animatable component transform struct
+ * @param[in] scale scale factor to be applied to the center position.
+ * @param[in] orientation orientation factor to be applied to the center position.
  * @param[in] size The size of the current transform component
  * @param[in] half Halfway point of the transform
  * @param[in] topLeft The top-left coords of the transform
  */
 inline void CalculateCenterPosition(
-  Vector3&                            centerPosition,
-  const TransformComponentStatic&     transformComponentStatic,
-  const TransformComponentAnimatable& transformComponentAnimatable,
-  const Vector3&                      size,
-  const Vector3&                      half,
-  const Vector3&                      topLeft)
+  Vector3&                        centerPosition,
+  const TransformComponentStatic& transformComponentStatic,
+  const Vector3&                  scale,
+  const Quaternion&               orientation,
+  const Vector3&                  size,
+  const Vector3&                  half,
+  const Vector3&                  topLeft)
 {
   // Calculate the center-point by applying the scale and rotation on the anchor point.
-  centerPosition = (half - transformComponentStatic.mAnchorPoint) * size * transformComponentAnimatable.mScale;
-  centerPosition *= transformComponentAnimatable.mOrientation;
+  centerPosition = (half - transformComponentStatic.mAnchorPoint) * size * scale;
+  centerPosition *= orientation;
 
   // If the position is ignoring the anchor-point, then remove the anchor-point shift from the position.
   if(!transformComponentStatic.mPositionUsesAnchorPoint)
@@ -255,7 +259,7 @@ bool TransformManager::Update()
         {
           //Full transform inherited
           mLocalMatrixDirty[i] = true;
-          CalculateCenterPosition(centerPosition, mTxComponentStatic[i], mTxComponentAnimatable[i], mSize[i], half, topLeft);
+          CalculateCenterPosition(centerPosition, mTxComponentStatic[i], mTxComponentAnimatable[i].mScale, mTxComponentAnimatable[i].mOrientation, mSize[i], half, topLeft);
           localPosition = mTxComponentAnimatable[i].mPosition + centerPosition + (mTxComponentStatic[i].mParentOrigin - half) * mSize[parentIndex];
           mLocal[i].SetTransformComponents(mTxComponentAnimatable[i].mScale, mTxComponentAnimatable[i].mOrientation, localPosition);
         }
@@ -265,52 +269,76 @@ bool TransformManager::Update()
       }
       else
       {
-        //Some components are not inherited
+        // Keep previous localMatrix for comparison.
+        Matrix previousLocalMatrix = mLocal[i];
+
+        // Get Parent information.
         Vector3       parentPosition, parentScale;
         Quaternion    parentOrientation;
         const Matrix& parentMatrix = mWorld[parentIndex];
         parentMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
 
-        Vector3 localScale = mTxComponentAnimatable[i].mScale;
+        // Compute intermediate Local information
+        CalculateCenterPosition(centerPosition, mTxComponentStatic[i], mTxComponentAnimatable[i].mScale, mTxComponentAnimatable[i].mOrientation, mSize[i], half, topLeft);
+        Vector3 intermediateLocalPosition = mTxComponentAnimatable[i].mPosition + centerPosition + (mTxComponentStatic[i].mParentOrigin - half) * mSize[parentIndex];
+        Matrix intermediateLocalMatrix;
+        intermediateLocalMatrix.SetTransformComponents(mTxComponentAnimatable[i].mScale, mTxComponentAnimatable[i].mOrientation, intermediateLocalPosition);
+
+        // Compute intermediate world information
+        Matrix intermediateWorldMatrix;
+        MatrixUtils::Multiply(intermediateWorldMatrix, intermediateLocalMatrix, mWorld[parentIndex]);
+
+        Vector3       intermediateWorldPosition, intermediateWorldScale;
+        Quaternion    intermediateWorldOrientation;
+        intermediateWorldMatrix.GetTransformComponents(intermediateWorldPosition, intermediateWorldOrientation, intermediateWorldScale);
+
+        // Compute final world information
+        Vector3    finalWorldPosition    = intermediateWorldPosition;
+        Vector3    finalWorldScale       = intermediateWorldScale;
+        Quaternion finalWorldOrientation = intermediateWorldOrientation;
+        // worldScale includes the influence of local scale, local rotation, and parent scale.
+        // So, for the final world matrix, if this node inherits its parent scale, use worldScale.
+        // If not, use local scale for the final world matrix.
         if((mInheritanceMode[i] & INHERIT_SCALE) == 0)
         {
-          //Don't inherit scale
-          localScale /= parentScale;
+          finalWorldScale = mTxComponentAnimatable[i].mScale;
         }
 
-        Quaternion localOrientation(mTxComponentAnimatable[i].mOrientation);
+        // For the final world matrix, if this node inherits its parent orientation, use worldOrientation.
+        // If not, use local orientation for the final world matrix.
         if((mInheritanceMode[i] & INHERIT_ORIENTATION) == 0)
         {
-          //Don't inherit orientation
-          parentOrientation.Invert();
-          localOrientation = parentOrientation * mTxComponentAnimatable[i].mOrientation;
+          finalWorldOrientation = mTxComponentAnimatable[i].mOrientation;
         }
 
-        Matrix localMatrix = mLocal[i];
-
-        if((mInheritanceMode[i] & INHERIT_POSITION) == 0)
-        {
-          //Don't inherit position
-          CalculateCenterPosition(centerPosition, mTxComponentStatic[i], mTxComponentAnimatable[i], mSize[i], half, topLeft);
-          mLocal[i].SetTransformComponents(localScale, localOrientation, Vector3::ZERO);
-          MatrixUtils::Multiply(mWorld[i], mLocal[i], parentMatrix);
-          mWorld[i].SetTranslation(mTxComponentAnimatable[i].mPosition + centerPosition);
-        }
-        else
+        // The final world position of this node is computed as a sum of
+        // parent origin position in world space and relative position of center from parent origin.
+        // If this node doesn't inherit its parent position, simply use the relative position as a final world position.
+        Vector3 localCenterPosition;
+        CalculateCenterPosition(localCenterPosition, mTxComponentStatic[i], finalWorldScale, finalWorldOrientation, mSize[i], half, topLeft);
+        finalWorldPosition = mTxComponentAnimatable[i].mPosition * finalWorldScale;
+        finalWorldPosition *= finalWorldOrientation;
+        finalWorldPosition += localCenterPosition;
+        if((mInheritanceMode[i] & INHERIT_POSITION) != 0)
         {
-          CalculateCenterPosition(centerPosition, mTxComponentStatic[i], mTxComponentAnimatable[i], mSize[i], half, topLeft);
-          localPosition = mTxComponentAnimatable[i].mPosition + centerPosition + (mTxComponentStatic[i].mParentOrigin - half) * mSize[parentIndex];
-          mLocal[i].SetTransformComponents(localScale, localOrientation, localPosition);
-          MatrixUtils::Multiply(mWorld[i], mLocal[i], parentMatrix);
+          Vector4 parentOriginPosition((mTxComponentStatic[i].mParentOrigin - half) * mSize[parentIndex]);
+          parentOriginPosition.w = 1.0f;
+          finalWorldPosition += Vector3(parentMatrix * parentOriginPosition);
         }
 
-        mLocalMatrixDirty[i] = mComponentDirty[i] || (localMatrix != mLocal[i]);
+        mWorld[i].SetTransformComponents(finalWorldScale, finalWorldOrientation, finalWorldPosition);
+
+        Matrix inverseParentMatrix;
+        inverseParentMatrix.SetInverseTransformComponents(parentScale, parentOrientation, parentPosition);
+        mLocal[i] = inverseParentMatrix * mWorld[i];
+
+        mLocalMatrixDirty[i] = mComponentDirty[i] || (previousLocalMatrix != mLocal[i]);
       }
     }
     else //Component has no parent or doesn't inherit transform
     {
       Matrix localMatrix = mLocal[i];
-      CalculateCenterPosition(centerPosition, mTxComponentStatic[i], mTxComponentAnimatable[i], mSize[i], half, topLeft);
+      CalculateCenterPosition(centerPosition, mTxComponentStatic[i], mTxComponentAnimatable[i].mScale, mTxComponentAnimatable[i].mOrientation, mSize[i], half, topLeft);
       localPosition = mTxComponentAnimatable[i].mPosition + centerPosition;
       mLocal[i].SetTransformComponents(mTxComponentAnimatable[i].mScale, mTxComponentAnimatable[i].mOrientation, localPosition);
       mWorld[i]            = mLocal[i];