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. Dismiss Notice

Question Rotating an object around a plane to look towards a point not on the plane

Discussion in 'Scripting' started by Chasenuva1, Jul 31, 2023.

  1. Chasenuva1

    Chasenuva1

    Joined:
    Mar 4, 2023
    Posts:
    9
    I'm having a hell of a time trying to wrap my head around how to handle this...... need suggestions.
    I have a set of wheels on an axel attached to a mock-vehicle (you can probably think of this kinda like a trailer) by a strut in the middle of the axel. This wheel assembly should rotate 'freely' along it's Y rotation.
    I have another gameobject, a leveraging bar, that attaches to the axel between the wheels. This bar should rotate 'freely' around it's attachment point on the Z and X axis.
    These objects can't be parented to one or the other as they each have separate rigidbodies.
    I also have a third gameobject, a player-controlled vehicle, that will be leveraging this bar around, but that might be unrelated to the solution.
    I need the wheel assembly to follow the attachment point along it's Y axis only, so the bar can position itself properly on the other two axis, but I can't find a working solution.

    I thought ProjectOnPlane and LookAt/LookRotation would be what I needed, but those gave me seemingly random rotations.
    I also tried a few variants of LocalEulerAngles, but those would inconsistently break with negative angles.
    RotateAroundPoint seemed good until I realized it was the inverse of that I needed.
    I feel like i'm missing something simple, but I have no idea what.

    This video shows the closest-working thing, but it's just a LookAt().
    I need the wheel on the left to rotate so the strut coming out of the top does not move, just rotate.

    This is the angle the strut should be at:
     
    Last edited: Jul 31, 2023
  2. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    Part of me wishes you'd abstract the whole idea and illustrate it better, simply name the pieces A, B, C, and ask a straightforward question. These geometry problems are trivial for some of us, but here I go wondering if I'm going to waste time with a wrong answer.

    and
    My question is how does one rotate around a plane?

    I'd argue that the vertical strut coming of the wheel doesn't move, it only rotates, albeit around local Z and Y. In either case you really have a hard time defining the problem, which is probably the reason why you can't define the solution as well.

    So let's see, it appears that you want to constrain the wheel rotation to happen only around the vertical axis (the strut), not around the wheel's rotational axis. To achieve this, consider that each rotation has a corresponding direction.

    If you imagine some vector being rotated around, what you basically want is for that vector to always stay on the plane, in this case it's the ground plane elevated a little to meet the center of the wheel.

    To build a direction from the wheel's center C to some arbitrary point P, you do
    Code (csharp):
    1. var dir = (p - c).normalized;
    This is the shortest way to it. To bring this back to the ground plane, simply ignore it's Y component. This will possibly turn in into a non-unit vector, so you need to normalize when this is done.

    Code (csharp):
    1. var delta = p - c;
    2. var dir = new Vector3(delta.x, 0f, delta.z).normalized;
    Now to build a quaternion out of this, use FromToRotation between the prefab's original forward and this newfound direction.

    Code (csharp):
    1. var rot = Quaternion.FromToRotation(Vector3.forward, dir);
    This rotation will always orient [an object that was originally oriented toward global forward] towards P, but only around Y axis.

    There are other ways to accomplish this, but this is one of the easiest when it comes to projecting to base planes.

    Btw, FromToRotation can fail if
    dir
    is directly opposite the left-hand side vector, in this case opposite forward.

    To prevent this you can do
    Code (csharp):
    1. var rot = dir == Vector3.back? Quaternion.AngleAxis(180f, Vector3.up)
    2.                              : Quaternion.FromToRotation(Vector3.forward, dir);
    Even though
    ==
    is to be avoided when comparing floats,
    dir == Vector3.back
    here works flawlessly because floats can be exactly compared if they are exactly 0 or 1 and
    Vector3.back
    is just (0, 0, -1)

    Finally assign this rotation to the wheel
    Code (csharp):
    1. wheel.transform.rotation = rot;
     
  3. Chasenuva1

    Chasenuva1

    Joined:
    Mar 4, 2023
    Posts:
    9
    Thank you! This is very close to what I'm trying to do, and I was able to jump what seems like 99.9% the rest of the way myself with this:
    Code (CSharp):
    1.     void Start() {
    2.         wheelStrutReferenceDirection = objFrontWheel.transform.forward.normalized;
    3.     }
    4.  
    5. // other code
    6.  
    7. // called once when the towbar connects, then every Update() that the connected towbar is in motion
    8.     public void OnMovementUpdate(GameObject towPoint) {
    9.         wheelToOffset = towPoint.transform.position - objFrontWheel.transform.position;
    10.         wheelToDirection = new Vector3(wheelToOffset.x, 0f, wheelToOffset.z).normalized;
    11.         if (wheelToDirection == Vector3.back) {
    12.             // other parts of the code will override this part long before we reach a 180 degree rotation
    13.             return;
    14.         }
    15.         wheelToRotation = Quaternion.FromToRotation(wheelStrutReferenceDirection, wheelToDirection);
    16.         objFrontWheel.transform.rotation = wheelToRotation;
    17.         // do movement stuff
    18.     }
    But there's just one small problem, the side of the wheel points at the towbar. (But keeps the proper strut angle, so yay! progress!)
    I was able to get the forward direction of the wheel to properly point toward the towbar by using objFrontWheel.transform.right.normalized but that gave the same results as the FromToRotation(Vector3.forward,dir), I assume because the .right reference direction is parallel to Vector3.forward.
    The brainless solution would be to find a 90 degree offset for the direction vector, but I feel like I'm still not quite grasping exactly how or why the expected result isn't happening with the objFrontWheel.transform.forward.normalized
    Anyone have some insight?



    My bad, I'll do better next time. I'll probably say something like
    "I need an object to rotate along an arbitrarily angled plane so it points at an arbitrary point that is not on that plane."
    Yes, much more abstract. Definitely won't get the 'not enough info, please explain exact use case' posts with that one........

    Well I'm sorry I'm lesser than you, I guess. I'll just become smarter. Easy Fix! :D

    Yes, Probably. That might, just maybe, be a small part of the reason I'm asking for help.
     
    Last edited: Jul 31, 2023