Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question How would you go on about making a Physics based Steering Wheel?

Discussion in 'Scripting' started by SKULLgaming8777, Sep 9, 2023.

  1. SKULLgaming8777

    SKULLgaming8777

    Joined:
    Dec 11, 2021
    Posts:
    15
    By physics based i mean that the steering wheel is a rigidbody attached by a rotational hinge. This is because its for a VR game. Im trying to make a steering wheel that is able to turn more than 180 degrees because all solutions ive found just allowed me to move the wheel about 180 degrees before it breaks.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    37,210
    Sounds like they're using .eulerAngles.

    Don't use .eulerAngles.

    Track your own notion of how much the steering is rotated and then drive the rotation explicitly according to whatever ratio you want the steering wheel to drive the wheel angle.

    All about Euler angles and rotations, by StarManta:

    https://starmanta.gitbooks.io/unitytipsredux/content/second-question.html
     
    Last edited: Sep 9, 2023
    PraetorBlue likes this.
  3. SKULLgaming8777

    SKULLgaming8777

    Joined:
    Dec 11, 2021
    Posts:
    15
    What would be the best way to notion my own steering wheel value?
    The way i tried it is by subtracting the x rotation by an older frames x rotation and then constantly adding the frame's result to a variable. I feel like this "should" work but i think by the way quaternions are set up it doesnt.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    37,210
    Attached is a simple "dial with your finger" demo.

    Around about line 56 is where it rotates the transform by angleDelta.

    Modify the above to keep your own float steer angle and update it by angleDelta.

    Code (csharp):
    1. private float mySteerDirection;
    like so:

    Code (csharp):
    1. mySteerDirection += angleDelta;
    and use mySteerDirection however you want to turn your wheel collider or your hinge, probably by scaling it way down, perhaps dividing it by 10 or something.
     

    Attached Files:

  5. SKULLgaming8777

    SKULLgaming8777

    Joined:
    Dec 11, 2021
    Posts:
    15
    i cant express how thankfull i am for this help, but what i was needing help with is getting the rotational value in sort of a specific way, since the rotation itself is already gonna be handeled by the rigidbody and the players hand i only need the rotation in such way where when i for example turn the wheel 360 degrees to the right it would return 360 and if i spin it once more to the right its gonna return 720, third one would be 1080 and it would just keep going like that. when you would start turning left again and lets say you do a whole 360 degree turn, the value would now reverse and go back to 720. i hope that makes sense and i apologize for not explaining correctly.
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    37,210
    I'm sorry, the assertion I made above was incorrect. The number does not fully accumulate.




    See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.









    DISREGARD THE BELOW!!

    I fixed it so that it accumulates forever as you turn the dial. Here it is in action.



    Use the above package I posted, but replace the script with this:

    (changes have been flagged with
    // related to degree accumulation
    )

    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. // by @kurtdekker
    6. // simple example of rotating something like a dial on a safe
    7. //
    8. // EDIT: this has been tweaked to sum and report total degrees turned.
    9. //
    10.  
    11. public class RotateZViaDrag : MonoBehaviour
    12. {
    13.     public bool RotateAroundAxis;
    14.  
    15.     Vector3 lastPosition;
    16.  
    17.     // related to degree accumulation
    18.     private float mySteerDirection;
    19.     public UnityEngine.UI.Text DegreeOutput;
    20.  
    21.     void OnMouseDown()
    22.     {
    23.         lastPosition = Input.mousePosition;
    24.     }
    25.  
    26.     void PerformLinearRotation()
    27.     {
    28.         Vector3 currPosition = Input.mousePosition;
    29.  
    30.         Vector3 difference = currPosition - lastPosition;
    31.  
    32.         lastPosition = currPosition;
    33.  
    34.         // now choose what axis to care about... this adds X and Y
    35.         float change = difference.x + difference.y;
    36.  
    37.         // and it rotates it around the Z (forward)
    38.         transform.Rotate(new Vector3(0, 0, change));
    39.     }
    40.  
    41.     void PerformCircularRotation()
    42.     {
    43.         // where is our center on screen?
    44.         Vector3 center = Camera.main.WorldToScreenPoint(transform.position);
    45.  
    46.         // angle to previous finger
    47.         float anglePrevious = Mathf.Atan2(center.x - lastPosition.x, lastPosition.y - center.y);
    48.  
    49.         // related to degree accumulation
    50.         Vector2 arm1 = new Vector2(center.x - lastPosition.x, lastPosition.y - center.y);
    51.  
    52.         Vector3 currPosition = Input.mousePosition;
    53.  
    54.         // angle in radians to current finger
    55.         float angleNow = Mathf.Atan2(center.x - currPosition.x, currPosition.y - center.y);
    56.  
    57.         // related to degree accumulation
    58.         Vector2 arm2 = new Vector2(center.x - currPosition.x, currPosition.y - center.y);
    59.  
    60.         lastPosition = currPosition;
    61.  
    62.         // how different are those angles?
    63.         float angleDelta = angleNow - anglePrevious;
    64.  
    65.         // scale up to degrees (everything above is in radians!)
    66.         angleDelta *= Mathf.Rad2Deg;
    67.  
    68.         // related to degree accumulation
    69.         // compare the arms and accumulate distance
    70.         float steerDelta = Mathf.Asin( Vector3.Cross( arm1.normalized, arm2.normalized).z) * Mathf.Rad2Deg;
    71.         mySteerDirection += steerDelta;
    72.         Debug.Log( ((int)mySteerDirection).ToString());
    73.         if (DegreeOutput) DegreeOutput.text = ((int)mySteerDirection).ToString();
    74.  
    75.         // rotate by that much
    76.         transform.Rotate(new Vector3(0, 0, angleDelta));
    77.     }
    78.  
    79.     void OnMouseDrag()
    80.     {
    81.         if (RotateAroundAxis)
    82.         {
    83.             PerformCircularRotation();
    84.         }
    85.         else
    86.         {
    87.             PerformLinearRotation();
    88.         }
    89.     }
    90. }
    Where the mouse input happens (the position and previous position that feed into
    arm1
    and
    arm2
    vectors) can be replaced with just any arbitrary Transform parented below your steering wheel.

    NOTE: this works as rotations around the Z+ axis.
     
    Last edited: Sep 10, 2023
  7. SKULLgaming8777

    SKULLgaming8777

    Joined:
    Dec 11, 2021
    Posts:
    15
    Thank you so much! The accumulation is exactly what i needed, but how would i convert this to 3D? My steering wheel does not use player inputs like the mouse since its a vr game. it uses hands that will rotate the wheel. So the whole Rotating part i already got settled. I only need this accumilation mechanism that tracks how much the wheel rotated and if possible would this also work for the X Axis?
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    37,210
    See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.




    I think my original statement might have been a bit strong.

    Nothing about the computation on line 70 is tied to any axis.

    It does however presume that the axis of the wheel is not changing over its course. That would introduce error.

    The dependence on +Z axis is simply from the creation of arm1 and arm2, which are x/y Vector2s.

    I suspect it would work fine in another orientation as long as you were consistently tracking a rotating part of the wheel.
     
    Last edited: Sep 10, 2023
  9. SKULLgaming8777

    SKULLgaming8777

    Joined:
    Dec 11, 2021
    Posts:
    15
    what about the script should i exactly be changing to make it work with my case? For reference my wheel is a child of a pirate ship model. it has a hingejoint component to attach it to the ship and a rigidbody. I want to know what I can change, remove, not remove, etc
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    37,210
    See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.



    Instead of computing arm1 / arm2 the way I did above, compute it as the Vector difference between the center (hub) and a single fixed point on the wheel. Doesn't matter where the point is, it just can't be at the center.

    The code above will observe that point's rotation in the same way that it observes the mouse motion above.
     
    Last edited: Sep 10, 2023
  11. SKULLgaming8777

    SKULLgaming8777

    Joined:
    Dec 11, 2021
    Posts:
    15
    Could you please give me an example?
     
  12. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    37,210
    See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.




    I've told you everything. Get the vector from the hub of your wheel and a point on the wheel (this frame and last) and feed that into the computations at line 70 above. That's it, honest.
     
    Last edited: Sep 10, 2023
  13. SKULLgaming8777

    SKULLgaming8777

    Joined:
    Dec 11, 2021
    Posts:
    15
    Thank you very much for the help I appreciate it. I'll give it a try
     
  14. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    37,210
    See several posts below (presently Post #16) for a true RevolutionCounter script. Nothing else in this post is guaranteed.


    I tried to replicate this based on what I told you above and there is still one assumption of +Z in line 70: the use of the .z component of the computed cross product.

    I'm sorry but I don't have time to dig further into it right now. I suggest perhaps using the Transform of your actual steering wheel to compute the inverse position of an observed point so that once it feeds into the arm1 / arm2 calculation, it is normalized to the global +Z axis.
     
    Last edited: Sep 10, 2023
  15. SKULLgaming8777

    SKULLgaming8777

    Joined:
    Dec 11, 2021
    Posts:
    15
    No problem man. Thank you for the help.
     
  16. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    37,210
    Heh, you're very welcome... I think I was getting tangled up in my "Rotate Z" demo code.

    It was bugging me so much I pushed into it and solved it.

    This is WAY simplified: just place this script on a Transform anywhere in any orientation.

    It will read out the accumulated degrees rotated around the Transform's local +Z

    https://gist.github.com/kurtdekker/ad051f56462f72a7e184269d9bece32f

    You just get a reference to this script and read it out of the
    TotalDegrees
    field.