From f846d63f1252b52de5d745ab8044cd1f3f5ea029 Mon Sep 17 00:00:00 2001 From: seungho baek Date: Wed, 7 Dec 2022 16:28:03 +0900 Subject: [PATCH] Fix transform matrix in case child actor didn't inherit some of its parent's transforms. Change-Id: Ib711eae4ca1a33872927a54e04c8228aabc1d256 Signed-off-by: seungho baek --- automated-tests/src/dali/utc-Dali-Actor.cpp | 70 ++++++++++++++++ dali/internal/event/actors/actor-coords.cpp | 67 ++++++++++----- dali/internal/update/manager/transform-manager.cpp | 98 ++++++++++++++-------- 3 files changed, 177 insertions(+), 58 deletions(-) diff --git a/automated-tests/src/dali/utc-Dali-Actor.cpp b/automated-tests/src/dali/utc-Dali-Actor.cpp index 4ac16ea..a528eb3 100644 --- a/automated-tests/src/dali/utc-Dali-Actor.cpp +++ b/automated-tests/src/dali/utc-Dali-Actor.cpp @@ -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(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; diff --git a/dali/internal/event/actors/actor-coords.cpp b/dali/internal/event/actors/actor-coords.cpp index d1a70db..9f1fefe 100644 --- a/dali/internal/event/actors/actor-coords.cpp +++ b/dali/internal/event/actors/actor-coords.cpp @@ -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 diff --git a/dali/internal/update/manager/transform-manager.cpp b/dali/internal/update/manager/transform-manager.cpp index 342d820..452d272 100644 --- a/dali/internal/update/manager/transform-manager.cpp +++ b/dali/internal/update/manager/transform-manager.cpp @@ -28,6 +28,8 @@ #include #include +#include + 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]; -- 2.7.4