From aaff85b2295a5e268723761bc59383bcc470f15f Mon Sep 17 00:00:00 2001 From: ikpil Date: Wed, 31 Jan 2024 00:59:48 +0900 Subject: [PATCH] fix: Change DtRaycastHit class to struct to resolve SOH issue. step2 --- src/DotRecast.Detour.Crowd/DtPathCorridor.cs | 9 +-- src/DotRecast.Detour/DtNavMeshQuery.cs | 76 +++++++++++++++++-- src/DotRecast.Detour/DtRaycastHit.cs | 16 +++- .../Tools/RcTestNavMeshTool.cs | 14 ++-- 4 files changed, 91 insertions(+), 24 deletions(-) diff --git a/src/DotRecast.Detour.Crowd/DtPathCorridor.cs b/src/DotRecast.Detour.Crowd/DtPathCorridor.cs index 866b373..8ceaf5b 100644 --- a/src/DotRecast.Detour.Crowd/DtPathCorridor.cs +++ b/src/DotRecast.Detour.Crowd/DtPathCorridor.cs @@ -187,20 +187,19 @@ namespace DotRecast.Detour.Crowd return; } - // Overshoot a little. This helps to optimize open fields in tiled - // meshes. + // Overshoot a little. This helps to optimize open fields in tiled meshes. dist = Math.Min(dist + 0.01f, pathOptimizationRange); // Adjust ray length. var delta = RcVec3f.Subtract(next, m_pos); 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 (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); } } } diff --git a/src/DotRecast.Detour/DtNavMeshQuery.cs b/src/DotRecast.Detour/DtNavMeshQuery.cs index 871d098..d581a4b 100644 --- a/src/DotRecast.Detour/DtNavMeshQuery.cs +++ b/src/DotRecast.Detour/DtNavMeshQuery.cs @@ -892,8 +892,9 @@ namespace DotRecast.Detour List shortcut = null; if (tryLOS) { + var rayHit = new DtRaycastHit(0); 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()) { foundShortCut = rayHit.t >= 1.0f; @@ -1213,8 +1214,9 @@ namespace DotRecast.Detour List shortcut = null; if (tryLOS) { + var rayHit = new DtRaycastHit(0); 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()) { foundShortCut = rayHit.t >= 1.0f; @@ -2113,6 +2115,62 @@ namespace DotRecast.Detour 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. + /// + /// Using the Hit Parameter (t) + /// + /// 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 + /// + /// Use Case Restriction + /// + /// 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 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 /// @@ -2166,11 +2224,10 @@ namespace DotRecast.Detour /// @param[out] pathCount The number of visited polygons. [opt] /// @param[in] maxPath The maximum number of polygons the @p path array can hold. /// @returns The status flags for the query. - public DtStatus Raycast(long startRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter, int options, - long prevRef, out DtRaycastHit hit) + public DtStatus Raycast(long startRef, RcVec3f startPos, RcVec3f endPos, + IDtQueryFilter filter, int options, + ref DtRaycastHit hit, long prevRef) { - hit = null; - // Validate input if (!m_nav.IsValidPolyRef(startRef) || !startPos.IsFinite() || !endPos.IsFinite() || null == filter || (prevRef != 0 && !m_nav.IsValidPolyRef(prevRef))) @@ -2178,7 +2235,9 @@ namespace DotRecast.Detour 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]; @@ -2186,7 +2245,8 @@ namespace DotRecast.Detour RcVec3f lastPos = RcVec3f.Zero; curPos = startPos; - var dir = RcVec3f.Subtract(endPos, startPos); + RcVec3f dir = RcVec3f.Subtract(endPos, startPos); + hit.hitNormal = RcVec3f.Zero; DtMeshTile prevTile, tile, nextTile; DtPoly prevPoly, poly, nextPoly; diff --git a/src/DotRecast.Detour/DtRaycastHit.cs b/src/DotRecast.Detour/DtRaycastHit.cs index bc52bb6..3e68e3d 100644 --- a/src/DotRecast.Detour/DtRaycastHit.cs +++ b/src/DotRecast.Detour/DtRaycastHit.cs @@ -26,22 +26,30 @@ namespace DotRecast.Detour /// Provides information about raycast hit /// filled by dtNavMeshQuery::raycast /// @ingroup detour - public class DtRaycastHit + public struct DtRaycastHit { /// The hit parameter. (FLT_MAX if no wall hit.) public float t; /// 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. public int hitEdgeIndex; - + /// Pointer to an array of reference ids of the visited polygons. [opt] - public readonly List path = new List(); + public readonly List path; /// The cost of the path until hit. public float pathCost; + public DtRaycastHit(int s) + { + t = 0; + hitEdgeIndex = 0; + hitNormal = RcVec3f.Zero; + path = new List(); + pathCost = 0; + } } } \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/RcTestNavMeshTool.cs b/src/DotRecast.Recast.Toolset/Tools/RcTestNavMeshTool.cs index b8dac40..96d1dee 100644 --- a/src/DotRecast.Recast.Toolset/Tools/RcTestNavMeshTool.cs +++ b/src/DotRecast.Recast.Toolset/Tools/RcTestNavMeshTool.cs @@ -257,16 +257,16 @@ namespace DotRecast.Recast.Toolset.Tools 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()) { return status; } // results ... - polys = rayHit.path; + polys = path; - if (rayHit.t > 1) + if (t > 1) { // No hit hitPos = endPos; @@ -275,15 +275,15 @@ namespace DotRecast.Recast.Toolset.Tools else { // Hit - hitPos = RcVec3f.Lerp(startPos, endPos, rayHit.t); - hitNormal = rayHit.hitNormal; + hitPos = RcVec3f.Lerp(startPos, endPos, t); + hitNormal = hitNormal2; hitResult = true; } // 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()) { hitPos.Y = h;