[Tizen] Use BoundingBox for 3D model hit test 78/324978/2 tizen_9.0
authorSeungho Baek <sbsh.baek@samsung.com>
Thu, 29 May 2025 12:42:24 +0000 (21:42 +0900)
committerSeungho Baek <sbsh.baek@samsung.com>
Thu, 29 May 2025 12:45:35 +0000 (21:45 +0900)
Change-Id: I2403a03598628025d03130d0e75417af614fc52b
Signed-off-by: Seungho Baek <sbsh.baek@samsung.com>
dali/internal/event/events/hit-test-algorithm-impl.cpp
dali/internal/event/events/ray-test.cpp
dali/internal/event/events/ray-test.h

index ab5d59f9d5f234772bc3d83cf7bbdfb8d3b288f3..aba4d5a7f123ac69fe4cde711d1c1f33c2fcb81c 100644 (file)
@@ -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::Behavior>(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<Dali::Internal::Actor*>&             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))
   {
index a78cc614534d903b0d9e6ab581d0a56a99c49704..269863c18fe33c23462e13d5e71ef9370f5931c1 100644 (file)
@@ -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<float>::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
index 911ba159511d2320f2952da982f69983a8126c52..17ff38f3cd17422a4cbac47cdb62d587d2450327 100644 (file)
@@ -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