Posts: 42
Threads: 20
Joined: May 2019
Hello
I Wonder if you have already a function who find the closest position from a Ray to your spline.
You have the curvySpline.GetNearestPointTF(worldPos, out closestPosition);
I could test every point on the Ray (or iterate randomly with more and more acuracy), but I a sure there is a better & opti way of doing it with Math.
How could I do with your plugin ?
Thanks
Posts: 2,124
Threads: 93
Joined: Jun 2017
07-31-2019, 11:30 AM
(This post was last modified: 10-22-2022, 05:44 PM by _Aka_.)
Hi,
Here is an implementation of the method you want. I need to work on it more before putting it in a release, but if this can save you some time, here it go:
In CurvySplineSegment.cs
Code: public float GetNearestPointF(Ray ray, out Vector3 nearestPointOnRay)
{
#if CURVY_SANITY_CHECKS
Assert.IsTrue(CacheSize >= 0, "[Curvy] CurvySplineSegment has unintialized cache. Call Refresh() on the CurvySpline it belongs to.");
#endif
int ui = CacheSize + 1;
float nearestDistSqr = float.MaxValue;
float distSqr;
int nearestIndex = 0;
// get the nearest index
for (int i = 0; i < ui; i++)
{
distSqr = DistanceToLine(ray, Approximation[i]);
if (distSqr <= nearestDistSqr)
{
nearestDistSqr = distSqr;
nearestIndex = i;
}
}
// collide p against the lines build by the index
int leftIdx = (nearestIndex > 0) ? nearestIndex - 1 : -1;
int rightIdx = (nearestIndex < CacheSize) ? nearestIndex + 1 : -1;
nearestPointOnRay = NearestPointOnRay(ray, Approximation[nearestIndex]);
float lfrag = 0;
float rfrag = 0;
float ldistSqr = float.MaxValue;
float rdistSqr = float.MaxValue;
if (leftIdx > -1)
ldistSqr = DTMath.LinePointDistanceSqr(Approximation[leftIdx], Approximation[nearestIndex], nearestPointOnRay, out lfrag);
if (rightIdx > -1)
rdistSqr = DTMath.LinePointDistanceSqr(Approximation[nearestIndex], Approximation[rightIdx], nearestPointOnRay, out rfrag);
float stepSize = 1f / CacheSize;
// return the nearest collision
if (ldistSqr < rdistSqr)
return getApproximationLocalF(leftIdx) + lfrag * stepSize;
else
return getApproximationLocalF(nearestIndex) + rfrag * stepSize;
}
public static float DistanceToLine(Ray ray, Vector3 point)
{
return Vector3.Cross(ray.direction, point - ray.origin).magnitude;
}
public static Vector3 NearestPointOnRay(Ray ray, Vector3 point)
{
Vector3 delta = point - ray.origin;
float distance = Mathf.Max(0, Vector3.Dot(delta, ray.direction));
return ray.origin + ray.direction * distance;
}
In CurvySpline.cs
Code: public float GetNearestPointTF(Ray ray, out Vector3 nearestPoint, [CanBeNull] out CurvySplineSegment nearestSegment, out float nearestSegmentF, int startSegmentIndex = 0, int stopSegmentIndex = -1)
{
#if CURVY_SANITY_CHECKS
DoSanityChecks();
#endif
nearestPoint = Vector3.zero;
if (Count == 0)
{
nearestSegment = null;
nearestSegmentF = -1;
return -1;
}
// for each segment, get the distance to it's approximation points
float distSqr = float.MaxValue;
float resF = 0;
CurvySplineSegment resSeg = null;
if (stopSegmentIndex == -1)
stopSegmentIndex = Count - 1;
startSegmentIndex = Mathf.Clamp(startSegmentIndex, 0, Count - 1);
stopSegmentIndex = Mathf.Clamp(stopSegmentIndex + 1, startSegmentIndex + 1, Count);
for (int i = startSegmentIndex; i < stopSegmentIndex; i++)
{
Vector3 nearestPointOnRay;
float f = this[i].GetNearestPointF(ray, out nearestPointOnRay);
Vector3 v = this[i].Interpolate(f);
float magSqr = (v - nearestPointOnRay).sqrMagnitude;
if (magSqr <= distSqr)
{
resSeg = this[i];
resF = f;
nearestPoint = v;
distSqr = magSqr;
}
//DrawPoint(v, Color.cyan);
//DrawPoint(nearestPointOnRay, Color.magenta);
}
nearestSegment = resSeg;
nearestSegmentF = resF;
// return the nearest
return resSeg.LocalFToTF(resF);
}
public float GetNearestPointTF(Ray ray, out Vector3 nearest, int startSegmentIndex = 0, int stopSegmentIndex = -1)
{
#if CURVY_SANITY_CHECKS
DoSanityChecks();
#endif
CurvySplineSegment segement;
float f;
return GetNearestPointTF(ray, out nearest, out segement, out f, startSegmentIndex, stopSegmentIndex);
}
public float GetNearestPointTF(Ray ray, int startSegmentIndex = 0, int stopSegmentIndex = -1)
{
#if CURVY_SANITY_CHECKS
DoSanityChecks();
#endif
Vector3 v;
return GetNearestPointTF(ray, out v, startSegmentIndex, stopSegmentIndex);
}
public float GetNearestPointTF(Ray ray, out Vector3 nearest)
{
#if CURVY_SANITY_CHECKS
DoSanityChecks();
#endif
return GetNearestPointTF(ray, out nearest, 0, -1);
}
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Posts: 42
Threads: 20
Joined: May 2019
Wow, honestly, that far from I excpected, you just give me the good method, without any compile error at the first implementation, in less than a day, and it work ! Wow you are amazing ! Sincerly !
Posts: 2,124
Threads: 93
Joined: Jun 2017
Thanks a lot, you are making me shy
But to be honest, I had that method already implemented. I just didn't take the time yet to test the s*** out of it, optimize it and document it. Once this is done, it will be included in the next Curvy update.
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Posts: 42
Threads: 20
Joined: May 2019
you're welcome
oh, you should add another out Vector3, if I want to have also the closest point in the line
Posts: 2,124
Threads: 93
Joined: Jun 2017
noted, thanks
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
|