Add a ray cast API to the terrain system, implement it, and use it so entities can be placed on top of terrain. (#6895)

* Add a ray cast API to the terrain system, implement it, and use it so entities can be placed on top of terrain.

Still to do:
- Unit tests
- Profiling/benchmarks
- Optimization (if needed, may not be now after updating to use the iterative approach, but one option could be to use SIMD to ray cast against both triangles at once)

Signed-off-by: bosnichd <bosnichd@amazon.com>

* Fix typos.

Signed-off-by: bosnichd <bosnichd@amazon.com>

* Added a FindNearestIntersectionIterative to use in place of the first-pass FindnearestIntersectionRecursive attempt.

Signed-off-by: bosnichd <bosnichd@amazon.com>

* Remove some functions that are no longer being used.

Signed-off-by: bosnichd <bosnichd@amazon.com>

* Remove a unicode character from a comment to fix the validation build.

Signed-off-by: bosnichd <bosnichd@amazon.com>

* Remove another unicode character from a comment to fix the validation build.

Signed-off-by: bosnichd <bosnichd@amazon.com>

* Update to bail out as soon as t > 1.0f

Signed-off-by: bosnichd <bosnichd@amazon.com>
This commit is contained in:
bosnichd
2022-01-24 13:47:44 -07:00
committed by GitHub
parent f8ac3071a3
commit f34d3a822e
9 changed files with 494 additions and 5 deletions
@@ -24,7 +24,7 @@ namespace AzFramework
//! IntersectorBus::EventResult(result, editorContextId, &IntersectorInterface::RayIntersect, ray);
//!
//! Raycast against all entities
//! RayResultAggregator rayResult;
//! AZ::EBusReduceResult<RayResult, RayResultClosestAggregator> rayResult;
//! IntersectorBus::BroadCastResult(rayResult, &IntersectorInterface::RayIntersect, ray);
//
class IntersectorInterface
@@ -12,6 +12,8 @@
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/std/containers/span.h>
#include <AzFramework/Entity/EntityContextBus.h>
#include <AzFramework/Render/GeometryIntersectionStructures.h>
#include <AzFramework/SurfaceData/SurfaceData.h>
namespace AzFramework
@@ -185,6 +187,11 @@ namespace AzFramework
SurfacePointRegionFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
//! Get the terrain raycast entity context id.
virtual EntityContextId GetTerrainRaycastEntityContextId() const = 0;
//! Given a ray, return the closest intersection with terrain.
virtual RenderGeometry::RayResult GetClosestIntersection(const RenderGeometry::RayRequest& ray) const = 0;
private:
// Private variations of the GetSurfacePoint API exposed to BehaviorContext that returns a value instead of
@@ -102,5 +102,9 @@ namespace UnitTest
ProcessSurfaceWeightsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler));
MOCK_CONST_METHOD4(
ProcessSurfacePointsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler));
MOCK_CONST_METHOD0(
GetTerrainRaycastEntityContextId, AzFramework::EntityContextId());
MOCK_CONST_METHOD1(
GetClosestIntersection, AzFramework::RenderGeometry::RayResult(const AzFramework::RenderGeometry::RayRequest&));
};
} // namespace UnitTest
@@ -7,6 +7,7 @@
*/
#include <AzFramework/Render/IntersectorInterface.h>
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
namespace AzToolsFramework
@@ -66,15 +67,19 @@ namespace AzToolsFramework
AZ::Vector3 FindClosestPickIntersection(const AzFramework::RenderGeometry::RayRequest& rayRequest, const float defaultDistance)
{
AzFramework::RenderGeometry::RayResult renderGeometryIntersectionResult;
// attempt a ray intersection with any visible mesh or terrain and return the intersection position if successful
AZ::EBusReduceResult<AzFramework::RenderGeometry::RayResult, AzFramework::RenderGeometry::RayResultClosestAggregator> renderGeometryIntersectionResult;
AzFramework::RenderGeometry::IntersectorBus::EventResult(
renderGeometryIntersectionResult, AzToolsFramework::GetEntityContextId(),
&AzFramework::RenderGeometry::IntersectorBus::Events::RayIntersect, rayRequest);
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
renderGeometryIntersectionResult,
&AzFramework::Terrain::TerrainDataRequests::GetClosestIntersection,
rayRequest);
// attempt a ray intersection with any visible mesh and return the intersection position if successful
if (renderGeometryIntersectionResult)
if (renderGeometryIntersectionResult.value)
{
return renderGeometryIntersectionResult.m_worldPosition;
return renderGeometryIntersectionResult.value.m_worldPosition;
}
else
{