From: Seungho Baek Date: Thu, 29 May 2025 12:42:24 +0000 (+0900) Subject: [Tizen] Use BoundingBox for 3D model hit test X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Ftizen_9.0;p=platform%2Fcore%2Fuifw%2Fdali-core.git [Tizen] Use BoundingBox for 3D model hit test Change-Id: I2403a03598628025d03130d0e75417af614fc52b Signed-off-by: Seungho Baek --- diff --git a/dali/internal/event/events/hit-test-algorithm-impl.cpp b/dali/internal/event/events/hit-test-algorithm-impl.cpp index ab5d59f9d..aba4d5a7f 100644 --- a/dali/internal/event/events/hit-test-algorithm-impl.cpp +++ b/dali/internal/event/events/hit-test-algorithm-impl.cpp @@ -201,7 +201,7 @@ bool HitTestActor(const RenderTask& renderTask, const float& nearClippingPlane, const float& farClippingPlane, HitTestInterface& hitCheck, - const RayTest& rayTest, + RayTest& rayTest, const Integration::Point& point, const uint32_t eventTime, bool clippingActor, @@ -224,8 +224,21 @@ bool HitTestActor(const RenderTask& renderTask, Vector2 hitPointLocal; float distance; + Vector3 hitPointLocal3D; + Dali::Layer::Behavior layerBehavior = actor.GetLayer().GetProperty(Dali::Layer::Property::BEHAVIOR); + + bool isHitted = false; + if(layerBehavior == Dali::Layer::Behavior::LAYER_3D) + { + isHitted = rayTest.ActorBoundingBoxTest(actor, rayOrigin, rayDir, hitPointLocal3D, distance); + } + else + { + isHitted = rayTest.ActorTest(actor, rayOrigin, rayDir, hitPointLocal, distance); + } + // Finally, perform a more accurate ray test to see if our ray actually hits the actor. - if(rayTest.ActorTest(actor, rayOrigin, rayDir, hitPointLocal, distance)) + if(isHitted) { // Calculate z coordinate value in Camera Space. const Matrix& viewMatrix = renderTask.GetCameraActor()->GetViewMatrix(); @@ -341,7 +354,7 @@ HitActor HitTestWithinLayer(Actor& actor const bool& overlayed, bool& overlayHit, bool layerIs3d, - const RayTest& rayTest, + RayTest& rayTest, const Integration::Point& point, const uint32_t eventTime, std::list& actorLists, @@ -533,7 +546,7 @@ void GeoHitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives, Vector2 screenCoordinates, Results& results, HitTestInterface& hitCheck, - const RayTest& rayTest) + RayTest& rayTest) { if(renderTask.IsHittable(screenCoordinates)) { @@ -648,7 +661,7 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives, Vector2 screenCoordinates, Results& results, HitTestInterface& hitCheck, - const RayTest& rayTest) + RayTest& rayTest) { if(renderTask.IsHittable(screenCoordinates)) { diff --git a/dali/internal/event/events/ray-test.cpp b/dali/internal/event/events/ray-test.cpp index a78cc6145..269863c18 100644 --- a/dali/internal/event/events/ray-test.cpp +++ b/dali/internal/event/events/ray-test.cpp @@ -194,6 +194,84 @@ bool RayTest::ActorTest(const Internal::Actor& actor, const Vector4& rayOrigin, return hit; } +bool RayTest::ActorBoundingBoxTest(const Internal::Actor& actor, const Vector4& rayOrigin, const Vector4& rayDir, Vector3& hitPointLocal, float& distance) +{ + bool hit = false; + + if(actor.OnScene()) + { + const Node& node = actor.GetNode(); + + // Transforms the ray to the local reference system. + // Calculate the inverse of Model matrix + Matrix modelMatrix(false /*don't init*/); + modelMatrix = node.GetWorldMatrix(0); + Matrix invModelMatrix = modelMatrix; + invModelMatrix.Invert(); + + Vector4 rayOriginLocal(invModelMatrix * rayOrigin); + Vector4 rayDirVector = rayDir; + rayDirVector.w = 0.0f; // Make it Vector. + Vector4 rayDirLocal(invModelMatrix * rayDirVector); + rayDirLocal.Normalize(); + + Vector3 currentSize = node.GetSize(EventThreadServices::Get().GetEventBufferIndex()); + Vector3 AABBMin = Vector3(-currentSize.width * 0.5f, -currentSize.height * 0.5f, -currentSize.depth * 0.5f); + Vector3 AABBMax = Vector3(currentSize.width * 0.5f, currentSize.height * 0.5f, currentSize.depth * 0.5f); + + float distanceMin = 0.0f; + float distanceMax = std::numeric_limits::infinity(); + for(uint32_t i = 0; i < 3u; ++i) + { + float rayOriginScalar = (i == 0) ? rayOriginLocal.x : ((i == 1) ? rayOriginLocal.y : rayOriginLocal.z); + float rayDirectionScalar = (i == 0) ? rayDirLocal.x : ((i == 1) ? rayDirLocal.y : rayDirLocal.z); + float boxMin = (i == 0) ? AABBMin.x : ((i == 1) ? AABBMin.y : AABBMin.z); + float boxMax = (i == 0) ? AABBMax.x : ((i == 1) ? AABBMax.y : AABBMax.z); + + // Check the ray is parallel to an axis. + if(std::abs(rayDirectionScalar) < Math::MACHINE_EPSILON_1) + { + // If the ray is parallel to an axis and the ray's origin along that axis lies outside the + // corresponding minimum and maximum bounds of the AABB, there can be no intersection + // between the ray and the AABB. + if(rayOriginScalar < boxMin || rayOriginScalar > boxMax) + { + return false; + } + } + else + { + float hit1 = (boxMin - rayOriginScalar) / rayDirectionScalar; + float hit2 = (boxMax - rayOriginScalar) / rayDirectionScalar; + + if(hit1 > hit2) + { + std::swap(hit1, hit2); + } + + distanceMin = std::max(distanceMin, hit1); + distanceMax = std::min(distanceMax, hit2); + + if(distanceMin > distanceMax) + { + return false; + } + } + } + + Vector4 hitPointLocalVector4 = rayOriginLocal + rayDirLocal * distanceMin; + hitPointLocalVector4.w = 1.0f; // Make it Position + distance = Vector3(rayOrigin - (modelMatrix * hitPointLocalVector4)).Length(); + hitPointLocal = Vector3(hitPointLocalVector4); + hitPointLocal.x += currentSize.x * 0.5f; + hitPointLocal.y = currentSize.y * 0.5f - hitPointLocal.y; + + hit = true; + } + + return hit; +} + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/events/ray-test.h b/dali/internal/event/events/ray-test.h index 911ba1595..17ff38f3c 100644 --- a/dali/internal/event/events/ray-test.h +++ b/dali/internal/event/events/ray-test.h @@ -71,6 +71,20 @@ public: * @note The actor coordinates are relative to the top-left (0.0, 0.0, 0.5) */ bool ActorTest(const Internal::Actor& actor, const Vector4& rayOrigin, const Vector4& rayDir, Vector2& hitPointLocal, float& distance) const; + + /** + * Performs a ray-actor test with the given pick-ray and the given actor's Bounding Box. + * + * @param[in] actor The actor to perform the ray-sphere test on + * @param[in] rayOrigin The ray origin in the world's reference system. + * @param[in] rayDir The ray director vector in the world's reference system. + * @param[out] hitPointLocal The hit point in the Actor's local reference system. + * @param[out] distance The distance from the hit point to the camera. + * @return True if the ray intersects the actor's Bounding Box. + * + * @note The actor coordinates are relative to the top-left (0.0, 0.0, 0.5) + */ + bool ActorBoundingBoxTest(const Internal::Actor& actor, const Vector4& rayOrigin, const Vector4& rayDir, Vector3& hitPointLocal, float& distance); }; } // namespace Internal