浏览代码

[ATOM-4343] Temporary fix for vegetation raycasts until full solution is implemented. (#1572)

Currently, the first time a raycast is attempted for a model, the raycast will fail and the model's kdtree will asynchronously get built.  This breaks the vegetation system, which expects the queries to always work.  This adds in a brute-force fallback for use while the kdtree is building.  However, other use cases like the Editor mouse cursor selection raycast still should get the current "silent failure" behavior, because otherwise the Editor will lock up for several seconds the first time the mouse moves over an extremely complex model.
Mike Balfour 4 年之前
父节点
当前提交
567156b85a

+ 3 - 1
Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h

@@ -60,12 +60,14 @@ namespace AZ
             //!
             //!
             //! @param rayStart  The starting point of the ray.
             //! @param rayStart  The starting point of the ray.
             //! @param rayDir  The direction and length of the ray (magnitude is encoded in the direction).
             //! @param rayDir  The direction and length of the ray (magnitude is encoded in the direction).
+            //! @param allowBruteForce  Allow for brute force queries while the mesh is baking (remove when ATOM-4343 is complete)
             //! @param[out] distanceNormalized  If an intersection is found, will be set to the normalized distance of the intersection
             //! @param[out] distanceNormalized  If an intersection is found, will be set to the normalized distance of the intersection
             //! (in the range 0.0-1.0) - to calculate the actual distance, multiply distanceNormalized by the magnitude of rayDir.
             //! (in the range 0.0-1.0) - to calculate the actual distance, multiply distanceNormalized by the magnitude of rayDir.
             //! @param[out] normal If an intersection is found, will be set to the normal at the point of collision.
             //! @param[out] normal If an intersection is found, will be set to the normal at the point of collision.
             //! @return  True if the ray intersects the mesh.
             //! @return  True if the ray intersects the mesh.
             virtual bool LocalRayIntersectionAgainstModel(
             virtual bool LocalRayIntersectionAgainstModel(
-                const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const;
+                const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, bool allowBruteForce,
+                float& distanceNormalized, AZ::Vector3& normal) const;
 
 
         private:
         private:
             void SetReady();
             void SetReady();

+ 3 - 1
Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp

@@ -146,7 +146,9 @@ namespace AZ
                     AZ::Debug::Timer timer;
                     AZ::Debug::Timer timer;
                     timer.Stamp();
                     timer.Stamp();
 #endif
 #endif
-                    const bool hit = modelAssetPtr->LocalRayIntersectionAgainstModel(rayStart, rayDir, distanceNormalized, normal);
+                    constexpr bool AllowBruteForce = false;
+                    const bool hit = modelAssetPtr->LocalRayIntersectionAgainstModel(
+                        rayStart, rayDir, AllowBruteForce, distanceNormalized, normal);
 #if defined(AZ_RPI_PROFILE_RAYCASTING_AGAINST_MODELS)
 #if defined(AZ_RPI_PROFILE_RAYCASTING_AGAINST_MODELS)
                     if (hit)
                     if (hit)
                     {
                     {

+ 3 - 2
Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp

@@ -72,7 +72,8 @@ namespace AZ
         }
         }
 
 
         bool ModelAsset::LocalRayIntersectionAgainstModel(
         bool ModelAsset::LocalRayIntersectionAgainstModel(
-            const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
+            const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, bool allowBruteForce,
+            float& distanceNormalized, AZ::Vector3& normal) const
         {
         {
             AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender);
             AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender);
 
 
@@ -90,7 +91,7 @@ namespace AZ
                     BuildKdTree();
                     BuildKdTree();
 
 
                     AZ_WarningOnce("Model", false, "ray intersection against a model that is still creating spatial information");
                     AZ_WarningOnce("Model", false, "ray intersection against a model that is still creating spatial information");
-                    return false;
+                    return allowBruteForce ? BruteForceRayIntersect(rayStart, rayDir, distanceNormalized, normal) : false;
                 }
                 }
                 else
                 else
                 {
                 {

+ 6 - 3
Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp

@@ -1214,11 +1214,12 @@ namespace UnitTest
 
 
         float distance = AZStd::numeric_limits<float>::max();
         float distance = AZStd::numeric_limits<float>::max();
         AZ::Vector3 normal;
         AZ::Vector3 normal;
+        constexpr bool AllowBruteForce = false;
 
 
         EXPECT_THAT(
         EXPECT_THAT(
             mesh.GetModel()->LocalRayIntersectionAgainstModel(
             mesh.GetModel()->LocalRayIntersectionAgainstModel(
                 AZ::Vector3(GetParam().xpos, GetParam().ypos, GetParam().zpos),
                 AZ::Vector3(GetParam().xpos, GetParam().ypos, GetParam().zpos),
-                AZ::Vector3(GetParam().xdir, GetParam().ydir, GetParam().zdir), distance, normal),
+                AZ::Vector3(GetParam().xdir, GetParam().ydir, GetParam().zdir), AllowBruteForce, distance, normal),
             testing::Eq(GetParam().expectedShouldIntersect));
             testing::Eq(GetParam().expectedShouldIntersect));
         EXPECT_THAT(distance, testing::FloatEq(GetParam().expectedDistance));
         EXPECT_THAT(distance, testing::FloatEq(GetParam().expectedDistance));
     }
     }
@@ -1262,9 +1263,10 @@ namespace UnitTest
 
 
         // firing down the negative z axis, positioned 5 units from cube (cube is 2x2x2 so intersection
         // firing down the negative z axis, positioned 5 units from cube (cube is 2x2x2 so intersection
         // happens at 1 in z)
         // happens at 1 in z)
+        constexpr bool AllowBruteForce = false;
         EXPECT_THAT(
         EXPECT_THAT(
             m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
             m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
-                AZ::Vector3::CreateAxisZ(5.0f), -AZ::Vector3::CreateAxisZ(10.0f), t, normal),
+                AZ::Vector3::CreateAxisZ(5.0f), -AZ::Vector3::CreateAxisZ(10.0f), AllowBruteForce, t, normal),
             testing::Eq(true));
             testing::Eq(true));
         EXPECT_THAT(t, testing::FloatEq(0.4f));
         EXPECT_THAT(t, testing::FloatEq(0.4f));
     }
     }
@@ -1275,9 +1277,10 @@ namespace UnitTest
         AZ::Vector3 normal = AZ::Vector3::CreateOne(); // invalid starting normal
         AZ::Vector3 normal = AZ::Vector3::CreateOne(); // invalid starting normal
 
 
         // ensure the intersection happens right at the end of the ray
         // ensure the intersection happens right at the end of the ray
+        constexpr bool AllowBruteForce = false;
         EXPECT_THAT(
         EXPECT_THAT(
             m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
             m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
-                AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(9.0f), t, normal),
+                AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(9.0f), AllowBruteForce, t, normal),
             testing::Eq(true));
             testing::Eq(true));
         EXPECT_THAT(t, testing::FloatEq(1.0f));
         EXPECT_THAT(t, testing::FloatEq(1.0f));
         EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisY()));
         EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisY()));

+ 2 - 1
Gems/SurfaceData/Code/Source/SurfaceDataUtility.cpp

@@ -28,7 +28,8 @@ namespace SurfaceData
 
 
         AZ::Vector3 normalLocal;
         AZ::Vector3 normalLocal;
 
 
-        if (meshAsset.LocalRayIntersectionAgainstModel(rayStartLocal, rayDirectionLocal, distance, normalLocal))
+        constexpr bool AllowBruteForce = true;
+        if (meshAsset.LocalRayIntersectionAgainstModel(rayStartLocal, rayDirectionLocal, AllowBruteForce, distance, normalLocal))
         {
         {
             // Transform everything back to world space
             // Transform everything back to world space
             outPosition = meshTransform.TransformPoint((rayStartLocal + (rayDirectionLocal * distance)) * clampedScale);
             outPosition = meshTransform.TransformPoint((rayStartLocal + (rayDirectionLocal * distance)) * clampedScale);

+ 2 - 1
Gems/Vegetation/Code/Tests/VegetationMocks.h

@@ -475,7 +475,8 @@ namespace UnitTest
         ~MockMeshAsset() override = default;
         ~MockMeshAsset() override = default;
 
 
         bool LocalRayIntersectionAgainstModel(
         bool LocalRayIntersectionAgainstModel(
-            [[maybe_unused]] const AZ::Vector3& rayStart, [[maybe_unused]] const AZ::Vector3& dir, [[maybe_unused]] float& distance, [[maybe_unused]] AZ::Vector3& normal) const override
+            [[maybe_unused]] const AZ::Vector3& rayStart, [[maybe_unused]] const AZ::Vector3& dir, [[maybe_unused]] bool allowBruteForce,
+            [[maybe_unused]] float& distance, [[maybe_unused]] AZ::Vector3& normal) const override
         {
         {
             distance = 0.1f;
             distance = 0.1f;
             return true;
             return true;