From: Eunki, Hong Date: Tue, 28 Mar 2023 08:04:39 +0000 (+0900) Subject: [Tizen] LookAt API for actor X-Git-Tag: accepted/tizen/7.0/unified/20230608.164733^0 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-core.git;a=commitdiff_plain;h=6a9cc21128204463e8f1cd637fb284ba7aa4a11f [Tizen] LookAt API for actor Make LookAt API for common Actor. Note, this isn't follow target position. Just calculate Quaternion and apply instancely. Change-Id: I0fb107f954034fb5aa410cc607122b4e61988e9b Signed-off-by: Eunki, Hong --- diff --git a/automated-tests/src/dali/utc-Dali-Actor.cpp b/automated-tests/src/dali/utc-Dali-Actor.cpp index 06f0dd7..8294c99 100644 --- a/automated-tests/src/dali/utc-Dali-Actor.cpp +++ b/automated-tests/src/dali/utc-Dali-Actor.cpp @@ -11687,3 +11687,68 @@ int UtcDaliActorCalculateWorldColor04(void) END_TEST; } + +int UtcDaliActorCalculateLookAt(void) +{ + TestApplication application; + + tet_infoline("Test that actor rotate right value of orientation"); + + Actor actor = Actor::New(); + + actor[Actor::Property::POSITION] = Vector3(100.0f, 0.0f, 0.0f); + actor[Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER; + actor[Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER; + + application.GetScene().Add(actor); + + application.SendNotification(); + application.Render(0); + + Quaternion actorQuaternion; + + tet_printf("Test with target only\n"); + Dali::DevelActor::LookAt(actor, Vector3::ZERO); + actorQuaternion = actor.GetProperty(Actor::Property::ORIENTATION); + DALI_TEST_EQUALS(actorQuaternion, Quaternion(Radian(Degree(90.0f)), Vector3::NEGATIVE_YAXIS), TEST_LOCATION); + + tet_printf("Test with target + up\n"); + Dali::DevelActor::LookAt(actor, Vector3::ZERO, Vector3::ZAXIS); + actorQuaternion = actor.GetProperty(Actor::Property::ORIENTATION); + DALI_TEST_EQUALS(actorQuaternion, Quaternion(Radian(Degree(90.0f)), Vector3::XAXIS) * Quaternion(Radian(Degree(90.0f)), Vector3::NEGATIVE_YAXIS), TEST_LOCATION); + + tet_printf("Test with target + up + localForward\n"); + Dali::DevelActor::LookAt(actor, Vector3::ZERO, Vector3::NEGATIVE_YAXIS, Vector3::NEGATIVE_XAXIS); + actorQuaternion = actor.GetProperty(Actor::Property::ORIENTATION); + DALI_TEST_EQUALS(actorQuaternion, Quaternion(Radian(Degree(180.0f)), Vector3::XAXIS), TEST_LOCATION); + + tet_printf("Test with target + up + localForward + localUp\n"); + Dali::DevelActor::LookAt(actor, Vector3::ZERO, Vector3::NEGATIVE_YAXIS, Vector3::NEGATIVE_YAXIS, Vector3::XAXIS); + actorQuaternion = actor.GetProperty(Actor::Property::ORIENTATION); + DALI_TEST_EQUALS(actorQuaternion, Quaternion(Radian(Degree(90.0f)), Vector3::NEGATIVE_ZAXIS), TEST_LOCATION); + + // Reset quaternion + actor[Actor::Property::ORIENTATION] = Quaternion(); + + Actor actor2 = Actor::New(); + actor2[Actor::Property::POSITION] = Vector3(0.0f, 50.0f, -10.0f); + actor2[Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER; + actor2[Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER; + actor.Add(actor2); + + tet_printf("Test whether lookat calculate well by using event side values only\n"); + Dali::DevelActor::LookAt(actor2, Vector3(100.0f, 50.0f, 1.0f)); + actorQuaternion = actor2.GetProperty(Actor::Property::ORIENTATION); + DALI_TEST_EQUALS(actorQuaternion, Quaternion(), TEST_LOCATION); + + actor[Actor::Property::ORIENTATION] = Quaternion(Radian(Degree(90.0f)), Vector3::ZAXIS); + + DALI_TEST_EQUALS(Dali::DevelActor::GetWorldTransform(actor2).GetTranslation3(), Vector3(50.0f, 0.0f, -10.0f), TEST_LOCATION); + + tet_printf("Test whether lookat calculate well inherit by parent orientation\n"); + Dali::DevelActor::LookAt(actor2, Vector3(50.0f, 0.0f, 1.0f), Vector3::NEGATIVE_XAXIS); + actorQuaternion = actor2.GetProperty(Actor::Property::ORIENTATION); + DALI_TEST_EQUALS(actorQuaternion, Quaternion(), TEST_LOCATION); + + END_TEST; +} \ No newline at end of file diff --git a/dali/devel-api/actors/actor-devel.cpp b/dali/devel-api/actors/actor-devel.cpp index fc54e89..8289468 100644 --- a/dali/devel-api/actors/actor-devel.cpp +++ b/dali/devel-api/actors/actor-devel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,6 +79,12 @@ Vector4 GetWorldColor(Actor actor) return CalculateActorWorldColor(GetImplementation(actor)); } +void LookAt(Actor actor, Vector3 target, Vector3 up, Vector3 localForward, Vector3 localUp) +{ + auto orientation = CalculateActorLookAtOrientation(GetImplementation(actor), target, up, localForward, localUp); + GetImplementation(actor).SetOrientation(orientation); +} + } // namespace DevelActor } // namespace Dali diff --git a/dali/devel-api/actors/actor-devel.h b/dali/devel-api/actors/actor-devel.h index 7b985a0..02130de 100644 --- a/dali/devel-api/actors/actor-devel.h +++ b/dali/devel-api/actors/actor-devel.h @@ -2,7 +2,7 @@ #define DALI_ACTOR_DEVEL_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -413,6 +413,26 @@ DALI_CORE_API Matrix GetWorldTransform(Actor actor); */ DALI_CORE_API Vector4 GetWorldColor(Actor actor); +/** + * Rotate the actor look at specific position. + * It will change the actor's orientation property. + * + * This calculates the world transform from scratch using only event + * side properties - it does not rely on the update thread to have + * already calculated the transform. + * + * @note Target position should be setup by world coordinates. + * @note The result of invalid input is not determined. + * (ex : forward vector or actor-to-target vector has same direction with up, One of them is ZERO) + * + * @param[in] actor The actor for which to calculate the look at orientation. + * @param[in] target The target world position to look at. + * @param[in] up The up vector after target look at. Default is +Y axis. + * @param[in] localForward The forward vector of actor when it's orientation is not applied. Default is +Z axis. + * @param[in] localUp The up vector of actor when it's orientation is not applied. Default is +Y axis. + */ +DALI_CORE_API void LookAt(Actor actor, Vector3 target, Vector3 up = Vector3::YAXIS, Vector3 localForward = Vector3::ZAXIS, Vector3 localUp = Vector3::YAXIS); + } // namespace DevelActor } // namespace Dali diff --git a/dali/internal/event/actors/actor-coords.cpp b/dali/internal/event/actors/actor-coords.cpp index 2eb4042..91a0d9f 100644 --- a/dali/internal/event/actors/actor-coords.cpp +++ b/dali/internal/event/actors/actor-coords.cpp @@ -65,6 +65,36 @@ bool GetViewportExtentsFromRenderTask(const RenderTask& renderTask, Rect& } return true; } + +/** + * @brief Get the Orientation from Forward vector and Up vector + * If vectors are valid, return Quaternion to make forward direction as +Z, and up direction near as -Y axis. + * If some invalid vector inputed (like Zero length, or parallel vector), return identity quaternion + * + * @param[in] forward The vector that want to be +Z axis. + * @param[in] up The vector that want to be -Y axis. + * @return Quaternion to make forward direction as +Z, and up direction near as -Y axis. + */ +Quaternion GetOrientationFromForwardAndUpVector(Vector3 forward, Vector3 up) +{ + Vector3 vZ = forward; + vZ.Normalize(); + + Vector3 vX = up.Cross(vZ); + vX.Normalize(); + + // If something invalid input comes, vX length become zero. + if(DALI_UNLIKELY(Dali::EqualsZero(vX.Length()))) + { + DALI_LOG_ERROR("Invalid value inputed, forward : %f %f %f , up : %f %f %f\n", forward.x, forward.y, forward.z, up.x, up.y, up.z); + return Quaternion(); + } + + Vector3 vY = vZ.Cross(vX); + vY.Normalize(); + + return Quaternion(vX, vY, vZ); +} } // namespace bool ConvertScreenToLocal( const Matrix& viewMatrix, @@ -616,4 +646,29 @@ Vector4 CalculateActorWorldColor(const Actor& actor) return worldColor; } +Quaternion CalculateActorLookAtOrientation(const Actor& actor, Vector3 target, Vector3 up, Vector3 localForward, Vector3 localUp) +{ + Vector3 currentWorldPosition = CalculateActorWorldTransform(actor).GetTranslation3(); + + Quaternion worldToTarget = GetOrientationFromForwardAndUpVector(target - currentWorldPosition, up); + Quaternion worldToLocal = GetOrientationFromForwardAndUpVector(localForward, localUp); + + // Rotate by this order : Local --> World --> Target + Quaternion ret = worldToTarget / worldToLocal; + + // If we inherit orientation, get parent's world orientation, and revert it. + if(actor.IsOrientationInherited() && actor.GetParent()) + { + // Get Parent information. + Vector3 parentPosition, parentScale; + Quaternion parentOrientation; + const Matrix& parentMatrix = CalculateActorWorldTransform(*actor.GetParent()); + parentMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale); + + ret = ret / parentOrientation; + } + + return ret; +} + } // namespace Dali::Internal diff --git a/dali/internal/event/actors/actor-coords.h b/dali/internal/event/actors/actor-coords.h index af37dfa..a48f3f0 100644 --- a/dali/internal/event/actors/actor-coords.h +++ b/dali/internal/event/actors/actor-coords.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_EVENT_ACTORS_ACTOR_COORDS_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -249,6 +249,18 @@ Matrix CalculateActorWorldTransform(const Actor& actor); */ Vector4 CalculateActorWorldColor(const Actor& actor); +/** + * @brief Get the rotate of the actor look at specific position. + * + * @param[in] actor The actor for which to calculate the look at orientation. + * @param[in] target The target world position to look at. + * @param[in] up The up vector after target look at. + * @param[in] localForward The forward vector of actor when it's orientation is not applied. + * @param[in] localUp The up vector of actor when it's orientation is not applied. + * @return The orientation result of this lookAt result. + */ +Quaternion CalculateActorLookAtOrientation(const Actor& actor, Vector3 target, Vector3 up, Vector3 localForward, Vector3 localUp); + } // namespace Dali::Internal #endif // DALI_INTERNAL_EVENT_ACTORS_ACTOR_COORDS_H