Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Angle detection by tangent
#1
Hello ! First of all thanks for this package, i really enjoy working with it Smile 

So i'm currently working on a game of slot car were i want to give a fake drift to my spline follower (by rotating the view) based on the curvature of the spline. So i'm building a CustomSplineController that inherits from SplineController

To get the curvature of the spline i use the following approach:

1. Get 2 tangent
Code:
Vector3 currentTangent = GetTangent(relativePosition);       
Vector3 aheadTangent = GetTangent(relativePosition + _normalizedAheadOffset); // Small offset ahead for curvature approximation

2. I want to ignore my vertical variation because I'm only interested in the XZ curvature angle
Code:
// Flatten tangents by setting the y-component to zero, ignoring vertical variations.
currentTangent.y = 0;
aheadTangent.y = 0;
       
// Re-normalize the vectors to prevent any magnitude issues after zeroing out y.
currentTangent.Normalize();
aheadTangent.Normalize();
3. Then finally i can compute my curvature
Code:
// Calculate curvature strength by the angle between current and future tangents.
float xzCurvatureAngle = Vector3.Angle(currentTangent, aheadTangent);
I'm pretty happy with this approach it's works very well when there is no vertical curvature in my spline (when the Y component of my tangent are 0 or near 0) in a standard flat turn.
However, when the splines exhibit vertical variation in the Y direction, the xzCurvatureAngle is significantly larger than it should be. It happen when the car take a looping for example.

My first thought is that my approach to flatten the tangent is not functional.
Do you have maybe an idea why ? Or a better approach to determine the XZ Curvature Angle of a spline ?
Also the physic in a looping become very complicated so maybe I'm not taking in account an inversion of sign in one the tangent component ? I'm not sure I'm a bit overwhelmed here ^^
PS: The red sphere in front of the car in the pictures is the ahead tracker (relativePosition + _normalizedAheadOffset).
Thanks in advance, great day to you !


Attached Files Thumbnail(s)
       
Reply
#2
Hi,

Is your project anything like Micro Machines? It looks cool, and I would like to learn more about it.

Regarding your code, there might be different sources for the issue:
  1. I would recommend using Vector3.Project to project vectors instead of manipulating their individual components. You can project your vectors on plane which normal is the spline's orientation, given by CurvySpline.GetOrientationUpFast
  2. Vector3.Angle returns an unsigned angle; you might want to use Vector3.SignedAngle a signed one.
  3. Know that the GetTangent and GetOrientationUpFast methods have an optional parameter allowing you to retrieve the tangents either in local space or global space.

With this information, I hope that you will be able to debug your code. If needed feel free to ask for more clarification.
Have a nice day
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Reply
#3
Hello thanks for your answer !

Yes it take inspiration from Slot Car race ! For now it's only a small prototype, but if it goes further i can keep you updated Smile 

So, I've tried to change my code using your approach sadly the result is not has expected.

First of all I'm not so sure that the projection on the spline normal was a good idea. No matter what i get the same results without the projection.

So here's my updated code using SignedAngle wich I agree with is more adapted to the situation:

Code:
        // Get current and future tangents on the spline to estimate curvature
        Vector3 currentTangent = GetTangent(relativePosition);
       
        _normalizedAheadOffset = (200 * _aheadTangentOffset) / Spline.Length;
        _aheadRelativePosition = relativePosition + _normalizedAheadOffset;
        _aheadTarget.RelativePosition = _aheadRelativePosition;
       
        Vector3 aheadTangent = GetTangent(relativePosition + _normalizedAheadOffset); // Small offset ahead for curvature approximation
       
        // For inspector debug purpose
        _tangent = currentTangent;
        _aheadTangent = aheadTangent;

        if (_projectTangentOnSpline)
        {
            // Ignoring vertical variations by projecting the tangent on a plane which normal is the spline's orientation.
            currentTangent = Vector3.Project(currentTangent, Spline.GetOrientationUpFast(relativePosition));
            aheadTangent = Vector3.Project(aheadTangent, Spline.GetOrientationUpFast(relativePosition + _normalizedAheadOffset));
        }
       
        // Calculate curvature strength by the angle between current and future tangents.
        float xzCurvatureAngle = Vector3.SignedAngle(currentTangent, aheadTangent, transform.up);
       
        // For inspector debug purpose
        _XZCurvatureAngle = xzCurvatureAngle;
        _XYCurvatureAngle = Vector3.SignedAngle(currentTangent, aheadTangent, transform.forward);
        _YZCurvatureAngle = Vector3.SignedAngle(currentTangent, aheadTangent, transform.right);

As you can see i compute the angles based on the local axis of my follower. So i expect to have different value for the different curvature angle.

In the screenshots bellow i have the same value for all my angle, and this value is the ZY angle that you can see in this picture.    

But the XZ angle that can be view in this picture is not correctly computed.    

I really don't understand what i do wrong here. Do you see why all my curvature angle are equal to the ZY angle ?

For reference this is the code i use for drawing the rays:

Code:
    private void OnDrawGizmos()
    {
        DrawDirectionArrow(transform.position, GetTangent(RelativePosition) * 5, Color.red);
        DrawDirectionArrow(transform.position, GetTangent(RelativePosition + _normalizedAheadOffset) * 5, Color.green);
    }

    private void DrawDirectionArrow(Vector3 start, Vector3 direction, Color color)
    {
        Gizmos.color = color;

        // Draw the ray
        Gizmos.DrawRay(start, direction);
        Gizmos.DrawWireSphere(start + direction, 0.2f);
    }

Thanks in advance !
Reply
#4
I have finally found a solution ! 

The issue was that my y component in my tangent dominated the angle computation, so the projection was indeed necessary, so here the final implementation: 

Code:
        // Explicit projection to XZ transform local plane
        currentTangent = Vector3.ProjectOnPlane(currentTangent, transform.up).normalized;
        aheadTangent = Vector3.ProjectOnPlane(aheadTangent, transform.up).normalized;

        // Calculate XZ curvature angle
        float xzCurvatureAngle = Vector3.SignedAngle(currentTangent, aheadTangent, transform.up);

It's working like a charm !

Nice day to you Smile
Reply
#5
Glad to read that.
If and when you feel like it, please leave a review for the asset, that helps a lot.
Nice day to you too.
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Reply
#6
Hello again !

I'm sorry but i have another interrogation, this time is about my ahead target.
I seem to notify that the distance with my ahead target is not constant and I'm not sure to understand why.

Here my code to compute my ahead offset relative position with a _aheadFixedOffset = 1:
Code:
 
private float AheadRelativePosition => RelativePosition + _aheadOffset;

protected override void OnValidate()
    {   
        _aheadOffset = _aheadFixedOffset / Spline.Length;
    }
 

Then i tried a simple exercise to test my hypothesis with this debug code:
Code:
   
private void OnDrawGizmos()
    {
        Gizmos.color = Color.magenta;
        Gizmos.DrawWireSphere(GetInterpolatedSourcePosition(AheadRelativePosition), 0.5f);

        var distance = Vector3.Distance(GetInterpolatedSourcePosition(RelativePosition), GetInterpolatedSourcePosition(AheadRelativePosition));
        Debug.Log($"Distance with ahead target: {distance} at Relative pos: {RelativePosition} with ahead relative pos: {AheadRelativePosition}");
}

As you can see in the picture bellow, the distance between the tracker is variable for different relative positions.
In my understanding of the situation it should be the same, since the  _aheadOffset is a constant value.

My assumption is that this difference come from the fact that the points on the spline are not equally spread.

Have you an idea of how i can have an ahead target at a constant distance from my spline follower ?

Thanks again !


Attached Files Thumbnail(s)
           
Reply
#7
Hi

Your assumption is correct. It is fully explained here:
https://www.youtube.com/watch?v=rP0zuAEoVJw

Instead of using RelativePosition and RelativePosition + _aheadOffset, you should use AbsolutePosition and AbsolutePosition + _fixedAheadDistance. Then use AbsoluteToRelative to get back the relative position to be used by GetInterpolatedSourcePosition

I hope this helped.
Have a nice day
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Reply
#8
Hello it's working very well with this approach ! Thanks a lot Smile
Reply
#9
You are welcome.
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Bug Corner Angle Revisited SAMYTHEBIGJUICY 10 243 01-02-2024, 10:12 AM
Last Post: _Aka_
  How can I find the point on the spline after applying with offset angle+radius? Chanon 1 63 10-01-2022, 11:50 AM
Last Post: _Aka_
  Tangent incorrect. tairoark 3 115 06-28-2022, 06:31 PM
Last Post: _Aka_
  Make hard angle cll3m 5 1,506 07-01-2021, 04:06 PM
Last Post: _Aka_

Forum Jump: