fix: Change DtRaycastHit class to struct to resolve SOH issue. step2

This commit is contained in:
ikpil 2024-01-31 00:59:48 +09:00 committed by Ikpil
parent 5bba84883e
commit aaff85b229
4 changed files with 91 additions and 24 deletions

View File

@ -187,20 +187,19 @@ namespace DotRecast.Detour.Crowd
return; return;
} }
// Overshoot a little. This helps to optimize open fields in tiled // Overshoot a little. This helps to optimize open fields in tiled meshes.
// meshes.
dist = Math.Min(dist + 0.01f, pathOptimizationRange); dist = Math.Min(dist + 0.01f, pathOptimizationRange);
// Adjust ray length. // Adjust ray length.
var delta = RcVec3f.Subtract(next, m_pos); var delta = RcVec3f.Subtract(next, m_pos);
RcVec3f goal = RcVecUtils.Mad(m_pos, delta, pathOptimizationRange / dist); RcVec3f goal = RcVecUtils.Mad(m_pos, delta, pathOptimizationRange / dist);
var status = navquery.Raycast(m_path[0], m_pos, goal, filter, 0, 0, out var rayHit); var status = navquery.Raycast(m_path[0], m_pos, goal, filter, out var t, out var norm, out var path);
if (status.Succeeded()) if (status.Succeeded())
{ {
if (rayHit.path.Count > 1 && rayHit.t > 0.99f) if (path.Count > 1 && t > 0.99f)
{ {
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, rayHit.path); m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, path);
} }
} }
} }

View File

@ -892,8 +892,9 @@ namespace DotRecast.Detour
List<long> shortcut = null; List<long> shortcut = null;
if (tryLOS) if (tryLOS)
{ {
var rayHit = new DtRaycastHit(0);
var rayStatus = Raycast(parentRef, parentNode.pos, neighbourPos, filter, var rayStatus = Raycast(parentRef, parentNode.pos, neighbourPos, filter,
DtRaycastOptions.DT_RAYCAST_USE_COSTS, grandpaRef, out var rayHit); DtRaycastOptions.DT_RAYCAST_USE_COSTS, ref rayHit, grandpaRef);
if (rayStatus.Succeeded()) if (rayStatus.Succeeded())
{ {
foundShortCut = rayHit.t >= 1.0f; foundShortCut = rayHit.t >= 1.0f;
@ -1213,8 +1214,9 @@ namespace DotRecast.Detour
List<long> shortcut = null; List<long> shortcut = null;
if (tryLOS) if (tryLOS)
{ {
var rayHit = new DtRaycastHit(0);
status = Raycast(parentRef, parentNode.pos, neighbourPos, m_query.filter, status = Raycast(parentRef, parentNode.pos, neighbourPos, m_query.filter,
DtRaycastOptions.DT_RAYCAST_USE_COSTS, grandpaRef, out var rayHit); DtRaycastOptions.DT_RAYCAST_USE_COSTS, ref rayHit, grandpaRef);
if (status.Succeeded()) if (status.Succeeded())
{ {
foundShortCut = rayHit.t >= 1.0f; foundShortCut = rayHit.t >= 1.0f;
@ -2113,6 +2115,62 @@ namespace DotRecast.Detour
return DtStatus.DT_SUCCESS; return DtStatus.DT_SUCCESS;
} }
/// @par
///
/// This method is meant to be used for quick, short distance checks.
///
/// If the path array is too small to hold the result, it will be filled as
/// far as possible from the start postion toward the end position.
///
/// <b>Using the Hit Parameter (t)</b>
///
/// If the hit parameter is a very high value (FLT_MAX), then the ray has hit
/// the end position. In this case the path represents a valid corridor to the
/// end position and the value of @p hitNormal is undefined.
///
/// If the hit parameter is zero, then the start position is on the wall that
/// was hit and the value of @p hitNormal is undefined.
///
/// If 0 < t < 1.0 then the following applies:
///
/// @code
/// distanceToHitBorder = distanceToEndPosition * t
/// hitPoint = startPos + (endPos - startPos) * t
/// @endcode
///
/// <b>Use Case Restriction</b>
///
/// The raycast ignores the y-value of the end position. (2D check.) This
/// places significant limits on how it can be used. For example:
///
/// Consider a scene where there is a main floor with a second floor balcony
/// that hangs over the main floor. So the first floor mesh extends below the
/// balcony mesh. The start position is somewhere on the first floor. The end
/// position is on the balcony.
///
/// The raycast will search toward the end position along the first floor mesh.
/// If it reaches the end position's xz-coordinates it will indicate FLT_MAX
/// (no wall hit), meaning it reached the end position. This is one example of why
/// this method is meant for short distance checks.
///
public DtStatus Raycast(long startRef, RcVec3f startPos, RcVec3f endPos,
IDtQueryFilter filter,
out float t, out RcVec3f hitNormal, out List<long> path)
{
DtRaycastHit hit = new DtRaycastHit(0);
// hit.path = path;
// hit.maxPath = maxPath;
DtStatus status = Raycast(startRef, startPos, endPos, filter, 0, ref hit, 0);
t = hit.t;
hitNormal = hit.hitNormal;
path = hit.path;
// if (pathCount)
// *pathCount = hit.pathCount;
return status;
}
/// @par /// @par
/// ///
@ -2166,11 +2224,10 @@ namespace DotRecast.Detour
/// @param[out] pathCount The number of visited polygons. [opt] /// @param[out] pathCount The number of visited polygons. [opt]
/// @param[in] maxPath The maximum number of polygons the @p path array can hold. /// @param[in] maxPath The maximum number of polygons the @p path array can hold.
/// @returns The status flags for the query. /// @returns The status flags for the query.
public DtStatus Raycast(long startRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter, int options, public DtStatus Raycast(long startRef, RcVec3f startPos, RcVec3f endPos,
long prevRef, out DtRaycastHit hit) IDtQueryFilter filter, int options,
ref DtRaycastHit hit, long prevRef)
{ {
hit = null;
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !startPos.IsFinite() || !endPos.IsFinite() if (!m_nav.IsValidPolyRef(startRef) || !startPos.IsFinite() || !endPos.IsFinite()
|| null == filter || (prevRef != 0 && !m_nav.IsValidPolyRef(prevRef))) || null == filter || (prevRef != 0 && !m_nav.IsValidPolyRef(prevRef)))
@ -2178,7 +2235,9 @@ namespace DotRecast.Detour
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
} }
hit = new DtRaycastHit(); hit.t = 0;
hit.path.Clear();
hit.pathCost = 0;
RcVec3f[] verts = new RcVec3f[m_nav.GetMaxVertsPerPoly() + 1]; RcVec3f[] verts = new RcVec3f[m_nav.GetMaxVertsPerPoly() + 1];
@ -2186,7 +2245,8 @@ namespace DotRecast.Detour
RcVec3f lastPos = RcVec3f.Zero; RcVec3f lastPos = RcVec3f.Zero;
curPos = startPos; curPos = startPos;
var dir = RcVec3f.Subtract(endPos, startPos); RcVec3f dir = RcVec3f.Subtract(endPos, startPos);
hit.hitNormal = RcVec3f.Zero;
DtMeshTile prevTile, tile, nextTile; DtMeshTile prevTile, tile, nextTile;
DtPoly prevPoly, poly, nextPoly; DtPoly prevPoly, poly, nextPoly;

View File

@ -26,22 +26,30 @@ namespace DotRecast.Detour
/// Provides information about raycast hit /// Provides information about raycast hit
/// filled by dtNavMeshQuery::raycast /// filled by dtNavMeshQuery::raycast
/// @ingroup detour /// @ingroup detour
public class DtRaycastHit public struct DtRaycastHit
{ {
/// The hit parameter. (FLT_MAX if no wall hit.) /// The hit parameter. (FLT_MAX if no wall hit.)
public float t; public float t;
/// hitNormal The normal of the nearest wall hit. [(x, y, z)] /// hitNormal The normal of the nearest wall hit. [(x, y, z)]
public RcVec3f hitNormal = new RcVec3f(); public RcVec3f hitNormal;
/// The index of the edge on the final polygon where the wall was hit. /// The index of the edge on the final polygon where the wall was hit.
public int hitEdgeIndex; public int hitEdgeIndex;
/// Pointer to an array of reference ids of the visited polygons. [opt] /// Pointer to an array of reference ids of the visited polygons. [opt]
public readonly List<long> path = new List<long>(); public readonly List<long> path;
/// The cost of the path until hit. /// The cost of the path until hit.
public float pathCost; public float pathCost;
public DtRaycastHit(int s)
{
t = 0;
hitEdgeIndex = 0;
hitNormal = RcVec3f.Zero;
path = new List<long>();
pathCost = 0;
}
} }
} }

View File

@ -257,16 +257,16 @@ namespace DotRecast.Recast.Toolset.Tools
return DtStatus.DT_FAILURE; return DtStatus.DT_FAILURE;
} }
var status = navQuery.Raycast(startRef, startPos, endPos, filter, 0, 0, out var rayHit); var status = navQuery.Raycast(startRef, startPos, endPos, filter, out var t, out var hitNormal2, out var path);
if (!status.Succeeded()) if (!status.Succeeded())
{ {
return status; return status;
} }
// results ... // results ...
polys = rayHit.path; polys = path;
if (rayHit.t > 1) if (t > 1)
{ {
// No hit // No hit
hitPos = endPos; hitPos = endPos;
@ -275,15 +275,15 @@ namespace DotRecast.Recast.Toolset.Tools
else else
{ {
// Hit // Hit
hitPos = RcVec3f.Lerp(startPos, endPos, rayHit.t); hitPos = RcVec3f.Lerp(startPos, endPos, t);
hitNormal = rayHit.hitNormal; hitNormal = hitNormal2;
hitResult = true; hitResult = true;
} }
// Adjust height. // Adjust height.
if (rayHit.path.Count > 0) if (path.Count > 0)
{ {
var result = navQuery.GetPolyHeight(rayHit.path[rayHit.path.Count - 1], hitPos, out var h); var result = navQuery.GetPolyHeight(path[path.Count - 1], hitPos, out var h);
if (result.Succeeded()) if (result.Succeeded())
{ {
hitPos.Y = h; hitPos.Y = h;