(unity) Working out Eulers between objects

edited in General
Hiiiiii

I've googled and googled and I can't figure this out :/ It seems simple enough, but uhhh how do I work out angles among 3D objects? I'm looking for the blue ?? degrees! In Unity!

image

Comments

  • edited
    This is a really useful equation. It's a relationship between two vectors and the angle between them.
    image

    Using that, you can find the angle between any vector and any other one.

    So working backwards (and untested, so possible typos or whatever)
    Vector3 vector = objB.transform.position - objA.transform.position;
    float angle = Mathf.Acos(Vector3.Dot(vector, Vector3.down) / vector.magnitude);


    In this case, we only divide by the magnitude of your other vector, because the global up/down vector has a magnitude of 1.

    Keep in mind that the angle that it gives you is probably in radians, but you can multiply by Mathf.Rad2Deg to convert it if necessary.

    [edit] Oooh, I've never used the method @Rigormortis posted before. It would make sense that there's a built in method for this... :P Looks like Vector3.Angle(from, to) is a thing too.
  • I'll test, but on a simple way to do it, I tried Vector3.AngleBetween but for reasons unknown I can't get it to work. Weirdly I give the function transform.positions and the error tells me it cannot explicitly convert between float and Vector3. And I'm like EH?!

    https://answers.unity.com/questions/591879/rotation-angle-from-one-object-to-another.html
  • edited
    @elyaradone what's "vector" in that equation?

    Vector3 vector = objB.transform.position - objA.transform.position;
    float angle = Mathf.Acos(Vector3.Dot(vector, Vector3.down) / vector.magnitude);
  • edited
    It's this:
    Vector3 vector = objB.transform.position - objA.transform.position;

    @Elyaradine, that method didn't always exist. I can't recall which patch it came in, but I believe it basically does the dot product calculation internally.
  • RIGHT DOH >_<

    Will report back soon >_<
  • @elyaradine So I plugged this in and it does work but not exactly... It gets the angle from the up/down axis to the object, but without regarding the left-right and forward axis - so if the object is off from the blue plane (in my diagram not in Unity axis colours which I can't remember right now), the angle remains the same. Is there a way to take the forward axis into consideration so that when objB is off plane, the angle is different?
  • Um. It'll get the angle between any two vectors. They don't have to be on any particular plane. If you want other angles, then you can compare your vector with one of the other axes (if that's what you want), or with some other reference vector. It's hard to recommend which, not really knowing what you're trying to do.
  • edited
    @Tuism What do you actually want to use the angle result for? (there may be other Unity built in methods that do this easier).

    Like @Elyaradine says, what you can do is test the axis's individually, like first how far off on the X axis it the vectors are and then how far off on the Y axis it is, because it sounds like you want to use the angles individually, i.e. calculating the X Angle and the Y angle, and then using the X and Y angles for your Euler Angle on a transform.
  • Man, angles are HARD to understand.

    Okay let me try my best to explain what I want:

    - I have three points. In VR. So there's the head point, and the two hand points.
    - The head is pointing where the head is pointing. The hands are where the hands are.
    - I have a long "bone" object that has its origin at the head point, pointing directly towards the left hand point.
    - I want to rotate the one bone, let's take the left, x degrees away from the facing of the head point. So more x, the further up/away from where the head is looking. Effectively, creating a backward-bending leg. The less x, the straighter it is back to the original "pointing at the hand" position.
    - After that I'll do a second bone jointed to the first bone at the bottom that mirrors the first bone's rotation and together they'll be a physics enabled leg. Hopefully :)

    image

    Hope that makes sense?

    Just as I draw this I realise there might be a problem with this approach but let me get it working first to see if it.... indeed doesn't work :/ HOPE IT DOES!!!
    Screenshot 2019-02-11 at 22.18.01.png
    598 x 519 - 39K
  • Well, what did you do?
    Thanked by 1Chakiri
  • Good comment, my friend (no)
  • If it wasn't clear, I haven't done anything yet because I don't know how to get that angle turning in 3D away from a forward :/
  • edited
    Don't psych yourself out thinking about 3D maths. You just need to think about the stuff you know and how something rotates around something else. The key thing here is "rotates around", you need to know what the axis of the rotation of the bone is and that's what's stumping you because you're focusing on rotating around the x or y or z axes.

    There's a nifty function called the cross product that finds the perpendicular vector (a vector is just a direction in 3D space) given two other vectors, that's how we're going to find the axis to rotate the bone around. You already have the two vectors you need: The head_forward vector and the vector from the head to the hand:

    (Also, I'm going to assume you want to do everything in world space - things could be easier in object space if you set up your gameobject hierarchy in certain ways, but you said two hands and world space is the best way to make that stable)

    relativeRotation = //(float) however many degrees you want the bone to be "away" from the hand.
    headForwardVector = //(Vector3) the forward vector from the head
      // I assume you're getting this from the camera? Make sure it's in world space!
    headToHandVector = hand.transform.position - head.transform.position;
    
    rotationAxisVector = Vector3.Cross(headForwardVector, headToHandVector);
    rotationAroundAxis = Quaternion.AngleAxis(rotationAngle, rotationAxisVector);
    //Think of this as an instruction to rotate a vector this many degrees around this axis
    
    //Now you apply that rotation to the bone... Assuming the bone has its pivot point at the head.
    bone.transform.rotation = Quaternion.FromToRotation(headForwardVector, headToHandVector); //Point bone at hand.
    bone.transform.rotation *= rotationAroundAxis; //rotate the "extra" degrees away from the hand


    That should work in most cases. All you need to do is animate the relativeRotation value over time and it'll shift the bone around by that many degrees around the axis perpendicular to the hand. If you run it in the update loop it'll even shift the bone relative to hand motion...

    Some things that might go wrong:
    You might have to make the rotation be -30 degrees instead of 30 degrees, because the direction that the "hinge" axis is pointing might be opposite to what you want for a clockwise rotation to work.
    If the hand goes above the head that hinge axis might flip as well. But if that happens all you need to do is check to see which is higher and change the order you pass the vectors into the Vector3.Cross function.
  • edited
    @dislekcia I've been trying to get your solution to work but it doesn't really seem to, it feels like it comes out the same way when I tried to do Quaternion.RotateTowards... I tried to strip back and just use your solution up to this point without adding rotation, and it didn't work - the object just pointed forward.

    bone.transform.rotation = Quaternion.FromToRotation(headForwardVector, headToHandVector); //Point bone at hand.


    Then I tried to debug the values and saw that the forward vector (head.forward or head.transform.forward) were coming out with -1 to 1 values instead of my direction vectors which are 360 values. After some googling, seems transform.forward's values are not the same as a vector derived from this, which is how I'm working out the line/angle from the head point to the arm point:

    Quaternion headToHandVector = (Quaternion.LookRotation(handTransform.position - headTransform.position));


    So my understanding is that if I multiply the rotation of my arm by the the rotation that I want to influence it by (x degrees in the direction of the head's forward (or minus that, whatever)), it should work. BUT THE TWO VALUES ARE DIFFERENT SYSTEMS! How do I convert transform.forward's normalised value to a Vector3 direction? I've googled the living beep out of this and it doesn't seem to be a thing that people even think about. What's up with that????
  • If you're still struggling with this and wish to drive through all this abysmal Joburg rain (assuming you're still around here), feel free to stop by our (new) office and I can help you. It honestly just looks like there's a lot more that can be achieved with your project in front of us.
    Thanked by 2Rigormortis Tuism
  • @Chippit thanks for the offer! (What's the new address?) I'll try and make the drive to visit the new fort at some point :) Would do me a world of good...!!!
  • @Tuism: I will DM you the deets.
  • edited
    @Tuism, hope this helps

    Quaternion targetRotation = Quaternion.LookRotation(target.poistion - origin.position);
    
    origin.rotation = Quaternion.RotateTowards(origin.rotation, targetRotation, rotateSpeed * Time.deltaTime);
Sign In or Register to comment.