Prechádzať zdrojové kódy

[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 rokov pred
rodič
commit
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 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
             //! (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.
             //! @return  True if the ray intersects the mesh.
             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:
             void SetReady();

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

@@ -146,7 +146,9 @@ namespace AZ
                     AZ::Debug::Timer timer;
                     timer.Stamp();
 #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 (hit)
                     {

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

@@ -72,7 +72,8 @@ namespace AZ
         }
 
         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);
 
@@ -90,7 +91,7 @@ namespace AZ
                     BuildKdTree();
 
                     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
                 {

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

@@ -1214,11 +1214,12 @@ namespace UnitTest
 
         float distance = AZStd::numeric_limits<float>::max();
         AZ::Vector3 normal;
+        constexpr bool AllowBruteForce = false;
 
         EXPECT_THAT(
             mesh.GetModel()->LocalRayIntersectionAgainstModel(
                 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));
         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
         // happens at 1 in z)
+        constexpr bool AllowBruteForce = false;
         EXPECT_THAT(
             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));
         EXPECT_THAT(t, testing::FloatEq(0.4f));
     }
@@ -1275,9 +1277,10 @@ namespace UnitTest
         AZ::Vector3 normal = AZ::Vector3::CreateOne(); // invalid starting normal
 
         // ensure the intersection happens right at the end of the ray
+        constexpr bool AllowBruteForce = false;
         EXPECT_THAT(
             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));
         EXPECT_THAT(t, testing::FloatEq(1.0f));
         EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisY()));

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

@@ -28,7 +28,8 @@ namespace SurfaceData
 
         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
             outPosition = meshTransform.TransformPoint((rayStartLocal + (rayDirectionLocal * distance)) * clampedScale);

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

@@ -475,7 +475,8 @@ namespace UnitTest
         ~MockMeshAsset() override = default;
 
         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;
             return true;