refactor: RcVec3f.Mad, IsFinite, Lerp

This commit is contained in:
ikpil 2023-10-26 00:05:00 +09:00
parent 18a195404f
commit 9a62fbf9f4
10 changed files with 91 additions and 98 deletions

View File

@ -263,62 +263,6 @@ namespace DotRecast.Core.Numerics
(vector1.Z * vector2.Z); (vector1.Z * vector2.Z);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float PerpXZ(RcVec3f a, RcVec3f b)
{
return (a.X * b.Z) - (a.Z * b.X);
}
/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
/// @param[out] dest The result vector. [(x, y, z)]
/// @param[in] v1 The base vector. [(x, y, z)]
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RcVec3f Mad(RcVec3f v1, RcVec3f v2, float s)
{
return new RcVec3f()
{
X = v1.X + (v2.X * s),
Y = v1.Y + (v2.Y * s),
Z = v1.Z + (v2.Z * s),
};
}
/// Performs a linear interpolation between two vectors. (@p v1 toward @p
/// v2)
/// @param[out] dest The result vector. [(x, y, x)]
/// @param[in] v1 The starting vector.
/// @param[in] v2 The destination vector.
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RcVec3f Lerp(float[] verts, int v1, int v2, float t)
{
return new RcVec3f(
verts[v1 + 0] + (verts[v2 + 0] - verts[v1 + 0]) * t,
verts[v1 + 1] + (verts[v2 + 1] - verts[v1 + 1]) * t,
verts[v1 + 2] + (verts[v2 + 2] - verts[v1 + 2]) * t
);
}
/// Checks that the specified vector's components are all finite.
/// @param[in] v A point. [(x, y, z)]
/// @return True if all of the point's components are finite, i.e. not NaN
/// or any of the infinities.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsFinite(RcVec3f v)
{
return float.IsFinite(v.X) && float.IsFinite(v.Y) && float.IsFinite(v.Z);
}
/// Checks that the specified vector's 2D components are finite.
/// @param[in] v A point. [(x, y, z)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsFinite2D(RcVec3f v)
{
return float.IsFinite(v.X) && float.IsFinite(v.Z);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly void CopyTo(float[] array) public readonly void CopyTo(float[] array)
{ {

View File

@ -219,5 +219,61 @@ namespace DotRecast.Core.Numerics
{ {
return u.Z * v.X - u.X * v.Z; return u.Z * v.X - u.X * v.Z;
} }
/// Checks that the specified vector's components are all finite.
/// @param[in] v A point. [(x, y, z)]
/// @return True if all of the point's components are finite, i.e. not NaN
/// or any of the infinities.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsFinite(RcVec3f v)
{
return float.IsFinite(v.X) && float.IsFinite(v.Y) && float.IsFinite(v.Z);
}
/// Checks that the specified vector's 2D components are finite.
/// @param[in] v A point. [(x, y, z)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsFinite2D(RcVec3f v)
{
return float.IsFinite(v.X) && float.IsFinite(v.Z);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float PerpXZ(RcVec3f a, RcVec3f b)
{
return (a.X * b.Z) - (a.Z * b.X);
}
/// Performs a linear interpolation between two vectors. (@p v1 toward @p
/// v2)
/// @param[out] dest The result vector. [(x, y, x)]
/// @param[in] v1 The starting vector.
/// @param[in] v2 The destination vector.
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RcVec3f Lerp(float[] verts, int v1, int v2, float t)
{
return new RcVec3f(
verts[v1 + 0] + (verts[v2 + 0] - verts[v1 + 0]) * t,
verts[v1 + 1] + (verts[v2 + 1] - verts[v1 + 1]) * t,
verts[v1 + 2] + (verts[v2 + 2] - verts[v1 + 2]) * t
);
}
/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
/// @param[out] dest The result vector. [(x, y, z)]
/// @param[in] v1 The base vector. [(x, y, z)]
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RcVec3f Mad(RcVec3f v1, RcVec3f v2, float s)
{
return new RcVec3f()
{
X = v1.X + (v2.X * s),
Y = v1.Y + (v2.Y * s),
Z = v1.Z + (v2.Z * s),
};
}
} }
} }

View File

@ -1094,14 +1094,14 @@ namespace DotRecast.Detour.Crowd
float dist = MathF.Sqrt(distSqr); float dist = MathF.Sqrt(distSqr);
float weight = separationWeight * (1.0f - RcMath.Sqr(dist * invSeparationDist)); float weight = separationWeight * (1.0f - RcMath.Sqr(dist * invSeparationDist));
disp = RcVec3f.Mad(disp, diff, weight / dist); disp = RcVecUtils.Mad(disp, diff, weight / dist);
w += 1.0f; w += 1.0f;
} }
if (w > 0.0001f) if (w > 0.0001f)
{ {
// Adjust desired velocity. // Adjust desired velocity.
dvel = RcVec3f.Mad(dvel, disp, 1.0f / w); dvel = RcVecUtils.Mad(dvel, disp, 1.0f / w);
// Clamp desired velocity to desired speed. // Clamp desired velocity to desired speed.
float speedSqr = dvel.LengthSquared(); float speedSqr = dvel.LengthSquared();
float desiredSqr = RcMath.Sqr(ag.desiredSpeed); float desiredSqr = RcMath.Sqr(ag.desiredSpeed);
@ -1254,7 +1254,7 @@ namespace DotRecast.Detour.Crowd
pen = (1.0f / dist) * (pen * 0.5f) * _config.collisionResolveFactor; pen = (1.0f / dist) * (pen * 0.5f) * _config.collisionResolveFactor;
} }
ag.disp = RcVec3f.Mad(ag.disp, diff, pen); ag.disp = RcVecUtils.Mad(ag.disp, diff, pen);
w += 1.0f; w += 1.0f;
} }

View File

@ -121,7 +121,7 @@ namespace DotRecast.Detour.Crowd
// Integrate // Integrate
if (vel.Length() > 0.0001f) if (vel.Length() > 0.0001f)
npos = RcVec3f.Mad(npos, vel, dt); npos = RcVecUtils.Mad(npos, vel, dt);
else else
vel = RcVec3f.Zero; vel = RcVec3f.Zero;
} }

View File

@ -193,7 +193,7 @@ namespace DotRecast.Detour.Crowd
// Adjust ray length. // Adjust ray length.
var delta = RcVec3f.Subtract(next, m_pos); var delta = RcVec3f.Subtract(next, m_pos);
RcVec3f goal = RcVec3f.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, 0, 0, out var rayHit);
if (status.Succeeded()) if (status.Succeeded())

View File

@ -205,7 +205,7 @@ namespace DotRecast.Detour
randomPt = centerPos; randomPt = centerPos;
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !RcVec3f.IsFinite(centerPos) || maxRadius < 0 if (!m_nav.IsValidPolyRef(startRef) || !RcVecUtils.IsFinite(centerPos) || maxRadius < 0
|| !float.IsFinite(maxRadius) || null == filter || null == frand) || !float.IsFinite(maxRadius) || null == filter || null == frand)
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
@ -406,7 +406,7 @@ namespace DotRecast.Detour
closest = pos; closest = pos;
posOverPoly = false; posOverPoly = false;
if (!m_nav.IsValidPolyRef(refs) || !RcVec3f.IsFinite(pos)) if (!m_nav.IsValidPolyRef(refs) || !RcVecUtils.IsFinite(pos))
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
} }
@ -441,7 +441,7 @@ namespace DotRecast.Detour
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
} }
if (tile == null || !RcVec3f.IsFinite(pos)) if (tile == null || !RcVecUtils.IsFinite(pos))
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
} }
@ -476,7 +476,7 @@ namespace DotRecast.Detour
int va = imin * 3; int va = imin * 3;
int vb = ((imin + 1) % nv) * 3; int vb = ((imin + 1) % nv) * 3;
closest = RcVec3f.Lerp(verts, va, vb, edget[imin]); closest = RcVecUtils.Lerp(verts, va, vb, edget[imin]);
} }
return DtStatus.DT_SUCCSESS; return DtStatus.DT_SUCCSESS;
@ -502,7 +502,7 @@ namespace DotRecast.Detour
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
} }
if (!RcVec3f.IsFinite2D(pos)) if (!RcVecUtils.IsFinite2D(pos))
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
} }
@ -673,7 +673,7 @@ namespace DotRecast.Detour
*/ */
public DtStatus QueryPolygons(RcVec3f center, RcVec3f halfExtents, IDtQueryFilter filter, IDtPolyQuery query) public DtStatus QueryPolygons(RcVec3f center, RcVec3f halfExtents, IDtQueryFilter filter, IDtPolyQuery query)
{ {
if (!RcVec3f.IsFinite(center) || !RcVec3f.IsFinite(halfExtents) || null == filter) if (!RcVecUtils.IsFinite(center) || !RcVecUtils.IsFinite(halfExtents) || null == filter)
{ {
return DtStatus.DT_INVALID_PARAM; return DtStatus.DT_INVALID_PARAM;
} }
@ -694,7 +694,7 @@ namespace DotRecast.Detour
*/ */
public IList<DtMeshTile> QueryTiles(RcVec3f center, RcVec3f halfExtents) public IList<DtMeshTile> QueryTiles(RcVec3f center, RcVec3f halfExtents)
{ {
if (!RcVec3f.IsFinite(center) || !RcVec3f.IsFinite(halfExtents)) if (!RcVecUtils.IsFinite(center) || !RcVecUtils.IsFinite(halfExtents))
{ {
return RcImmutableArray<DtMeshTile>.Empty; return RcImmutableArray<DtMeshTile>.Empty;
} }
@ -744,7 +744,7 @@ namespace DotRecast.Detour
path.Clear(); path.Clear();
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !m_nav.IsValidPolyRef(endRef) || !RcVec3f.IsFinite(startPos) || !RcVec3f.IsFinite(endPos) || null == filter) if (!m_nav.IsValidPolyRef(startRef) || !m_nav.IsValidPolyRef(endRef) || !RcVecUtils.IsFinite(startPos) || !RcVecUtils.IsFinite(endPos) || null == filter)
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
} }
@ -1020,7 +1020,7 @@ namespace DotRecast.Detour
m_query.raycastLimitSqr = RcMath.Sqr(raycastLimit); m_query.raycastLimitSqr = RcMath.Sqr(raycastLimit);
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !m_nav.IsValidPolyRef(endRef) || !RcVec3f.IsFinite(startPos) || !RcVec3f.IsFinite(endPos) || null == filter) if (!m_nav.IsValidPolyRef(startRef) || !m_nav.IsValidPolyRef(endRef) || !RcVecUtils.IsFinite(startPos) || !RcVecUtils.IsFinite(endPos) || null == filter)
{ {
return DtStatus.DT_INVALID_PARAM; return DtStatus.DT_INVALID_PARAM;
} }
@ -1514,7 +1514,7 @@ namespace DotRecast.Detour
ref List<DtStraightPath> straightPath, ref List<DtStraightPath> straightPath,
int maxStraightPath, int options) int maxStraightPath, int options)
{ {
if (!RcVec3f.IsFinite(startPos) || !RcVec3f.IsFinite(endPos) || null == straightPath if (!RcVecUtils.IsFinite(startPos) || !RcVecUtils.IsFinite(endPos) || null == straightPath
|| null == path || 0 == path.Count || path[0] == 0 || maxStraightPath <= 0) || null == path || 0 == path.Count || path[0] == 0 || maxStraightPath <= 0)
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
@ -1779,8 +1779,8 @@ namespace DotRecast.Detour
visited.Clear(); visited.Clear();
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !RcVec3f.IsFinite(startPos) if (!m_nav.IsValidPolyRef(startRef) || !RcVecUtils.IsFinite(startPos)
|| !RcVec3f.IsFinite(endPos) || null == filter) || !RcVecUtils.IsFinite(endPos) || null == filter)
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
} }
@ -1883,7 +1883,7 @@ namespace DotRecast.Detour
if (distSqr < bestDist) if (distSqr < bestDist)
{ {
// Update nearest distance. // Update nearest distance.
bestPos = RcVec3f.Lerp(verts, vj, vi, tseg); bestPos = RcVecUtils.Lerp(verts, vj, vi, tseg);
bestDist = distSqr; bestDist = distSqr;
bestNode = curNode; bestNode = curNode;
} }
@ -2062,8 +2062,8 @@ namespace DotRecast.Detour
float s = 1.0f / 255.0f; float s = 1.0f / 255.0f;
float tmin = link.bmin * s; float tmin = link.bmin * s;
float tmax = link.bmax * s; float tmax = link.bmax * s;
left = RcVec3f.Lerp(fromTile.data.verts, v0 * 3, v1 * 3, tmin); left = RcVecUtils.Lerp(fromTile.data.verts, v0 * 3, v1 * 3, tmin);
right = RcVec3f.Lerp(fromTile.data.verts, v0 * 3, v1 * 3, tmax); right = RcVecUtils.Lerp(fromTile.data.verts, v0 * 3, v1 * 3, tmax);
} }
} }
@ -2165,7 +2165,7 @@ namespace DotRecast.Detour
hit = null; hit = null;
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !RcVec3f.IsFinite(startPos) || !RcVec3f.IsFinite(endPos) if (!m_nav.IsValidPolyRef(startRef) || !RcVecUtils.IsFinite(startPos) || !RcVecUtils.IsFinite(endPos)
|| null == filter || (prevRef != 0 && !m_nav.IsValidPolyRef(prevRef))) || null == filter || (prevRef != 0 && !m_nav.IsValidPolyRef(prevRef)))
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
@ -2340,7 +2340,7 @@ namespace DotRecast.Detour
// compute the intersection point at the furthest end of the polygon // compute the intersection point at the furthest end of the polygon
// and correct the height (since the raycast moves in 2d) // and correct the height (since the raycast moves in 2d)
lastPos = curPos; lastPos = curPos;
curPos = RcVec3f.Mad(startPos, dir, hit.t); curPos = RcVecUtils.Mad(startPos, dir, hit.t);
var e1 = verts[segMax]; var e1 = verts[segMax];
var e2 = verts[(segMax + 1) % nv]; var e2 = verts[(segMax + 1) % nv];
var eDir = RcVec3f.Subtract(e2, e1); var eDir = RcVec3f.Subtract(e2, e1);
@ -2434,7 +2434,7 @@ namespace DotRecast.Detour
} }
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !RcVec3f.IsFinite(centerPos) || radius < 0 if (!m_nav.IsValidPolyRef(startRef) || !RcVecUtils.IsFinite(centerPos) || radius < 0
|| !float.IsFinite(radius) || null == filter) || !float.IsFinite(radius) || null == filter)
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
@ -2777,7 +2777,7 @@ namespace DotRecast.Detour
ref List<long> resultRef, ref List<long> resultParent) ref List<long> resultRef, ref List<long> resultParent)
{ {
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !RcVec3f.IsFinite(centerPos) || radius < 0 if (!m_nav.IsValidPolyRef(startRef) || !RcVecUtils.IsFinite(centerPos) || radius < 0
|| !float.IsFinite(radius) || null == filter || !float.IsFinite(radius) || null == filter
|| null == resultRef || null == resultParent) || null == resultRef || null == resultParent)
{ {
@ -3055,8 +3055,8 @@ namespace DotRecast.Detour
float tmin = ints[k].tmin / 255.0f; float tmin = ints[k].tmin / 255.0f;
float tmax = ints[k].tmax / 255.0f; float tmax = ints[k].tmax / 255.0f;
var seg = new RcSegmentVert(); var seg = new RcSegmentVert();
seg.vmin = RcVec3f.Lerp(tile.data.verts, vj, vi, tmin); seg.vmin = RcVecUtils.Lerp(tile.data.verts, vj, vi, tmin);
seg.vmax = RcVec3f.Lerp(tile.data.verts, vj, vi, tmax); seg.vmax = RcVecUtils.Lerp(tile.data.verts, vj, vi, tmax);
segmentVerts.Add(seg); segmentVerts.Add(seg);
segmentRefs.Add(ints[k].refs); segmentRefs.Add(ints[k].refs);
} }
@ -3069,8 +3069,8 @@ namespace DotRecast.Detour
float tmin = imin / 255.0f; float tmin = imin / 255.0f;
float tmax = imax / 255.0f; float tmax = imax / 255.0f;
var seg = new RcSegmentVert(); var seg = new RcSegmentVert();
seg.vmin = RcVec3f.Lerp(tile.data.verts, vj, vi, tmin); seg.vmin = RcVecUtils.Lerp(tile.data.verts, vj, vi, tmin);
seg.vmax = RcVec3f.Lerp(tile.data.verts, vj, vi, tmax); seg.vmax = RcVecUtils.Lerp(tile.data.verts, vj, vi, tmax);
segmentVerts.Add(seg); segmentVerts.Add(seg);
segmentRefs.Add(0L); segmentRefs.Add(0L);
} }
@ -3109,7 +3109,7 @@ namespace DotRecast.Detour
hitNormal = RcVec3f.Zero; hitNormal = RcVec3f.Zero;
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !RcVec3f.IsFinite(centerPos) || maxRadius < 0 if (!m_nav.IsValidPolyRef(startRef) || !RcVecUtils.IsFinite(centerPos) || maxRadius < 0
|| !float.IsFinite(maxRadius) || null == filter) || !float.IsFinite(maxRadius) || null == filter)
{ {
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;

View File

@ -425,14 +425,14 @@ namespace DotRecast.Detour
RcVec3f u = RcVec3f.Subtract(aq, ap); RcVec3f u = RcVec3f.Subtract(aq, ap);
RcVec3f v = RcVec3f.Subtract(bq, bp); RcVec3f v = RcVec3f.Subtract(bq, bp);
RcVec3f w = RcVec3f.Subtract(ap, bp); RcVec3f w = RcVec3f.Subtract(ap, bp);
float d = RcVec3f.PerpXZ(u, v); float d = RcVecUtils.PerpXZ(u, v);
if (MathF.Abs(d) < 1e-6f) if (MathF.Abs(d) < 1e-6f)
{ {
return false; return false;
} }
s = RcVec3f.PerpXZ(v, w) / d; s = RcVecUtils.PerpXZ(v, w) / d;
t = RcVec3f.PerpXZ(u, w) / d; t = RcVecUtils.PerpXZ(u, w) / d;
return true; return true;
} }

View File

@ -508,10 +508,10 @@ public class TestNavmeshSampleTool : ISampleTool
} }
RcVec3f delta = RcVec3f.Subtract(s3, s.vmin); RcVec3f delta = RcVec3f.Subtract(s3, s.vmin);
RcVec3f p0 = RcVec3f.Mad(s.vmin, delta, 0.5f); RcVec3f p0 = RcVecUtils.Mad(s.vmin, delta, 0.5f);
RcVec3f norm = new RcVec3f(delta.Z, 0, -delta.X); RcVec3f norm = new RcVec3f(delta.Z, 0, -delta.X);
norm = RcVec3f.Normalize(norm); norm = RcVec3f.Normalize(norm);
RcVec3f p1 = RcVec3f.Mad(p0, norm, agentRadius * 0.5f); RcVec3f p1 = RcVecUtils.Mad(p0, norm, agentRadius * 0.5f);
// Skip backfacing segments. // Skip backfacing segments.
if (segmentRefs[j] != 0) if (segmentRefs[j] != 0)
{ {

View File

@ -85,7 +85,7 @@ namespace DotRecast.Recast.Toolset.Tools
len = STEP_SIZE / len; len = STEP_SIZE / len;
} }
RcVec3f moveTgt = RcVec3f.Mad(iterPos, delta, len); RcVec3f moveTgt = RcVecUtils.Mad(iterPos, delta, len);
// Move // Move
navQuery.MoveAlongSurface(polys[0], iterPos, moveTgt, filter, out var result, ref visited); navQuery.MoveAlongSurface(polys[0], iterPos, moveTgt, filter, out var result, ref visited);

View File

@ -172,13 +172,6 @@ public class Vector3Tests
// IsFinite // IsFinite
} }
[Test]
[Repeat(100000)]
public void TestVectorPerp2D()
{
// Perp2D
}
// [Test] // [Test]
// [Repeat(100000)] // [Repeat(100000)]
// public void TestVectorLerp() // public void TestVectorLerp()