Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

How can I align axis with quaternion.fromToRotation?

Discussion in 'Scripting' started by Reverend-Speed, Sep 17, 2019.

  1. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    181
    Hey folks, going somewhat crazy here. Trying to align two transforms, so that a prefab can be instantiated and made to stand at a particular parent empty, standing upwards along a particular axis of the parent empty.

    In the following image, I have a basic tree whose Y axis should aligned to the parent transform's -Z (minus z) axis.

    I desire that the tree should be standing with the trunk in line with the blue axis of the parent transform, but 'growing' in the opposite direction to the blue arrow (the green ball of the 'tree' should be away from the transform's origin in the opposite direction to the blue arrow).



    When the tree is instantiated, it is assigned the rotation of its parent transform and all axis of both objects are aligned.

    I identify the rotation between the axis and apply it to the tree's transform, following the example on this page. While that code works on a simple test project, I can't get it to work in my work scene. At the moment, my code reads as follows:

    Code (CSharp):
    1. tempTree.rotation = Quaternion.FromToRotation(tempTree.up, -treeArray[i].transform.forward);
    I have also attempted using the code so that the rotation from Quaternion.FromToRotation is applied to the transform.rotation through multiplication.

    Code (CSharp):
    1. tempTree.rotation *= Quaternion.FromToRotation(tempTree.up, -treeArray[i].transform.forward);
    In both cases, my result is as seen in the attached image - the tree is rotated to a seemingly arbitrary angle, entirely unsuitable for the project.

    Please, if you can, help me out with this one. Time is short, and I'm going out of my tree. =D
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    1,411
    Try

    tempTree.rotation = Quaternion.FromToRotation(Vector3.up, -treeArray[i].transform.forward);


    You are setting the tree's rotation in world space, so you want the rotation that would move world up to point in a certain direction, not the tree's current up (which you are overwriting).
     
  3. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    804
    That seems correct, but I'm not so sure about the explanation. (tempTree.up, .up) is the rotation from how it faces now, to how it should face. Clearly that should be _added_ to the current rotation. That would probably work, but it's pointlessly complex. You don't care about the tree's current rotation, so why even consider it in the formula?

    It's like writing n=4, except using: nMove=4-n; n+=nMove;
     
  4. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    181
    @Antistone - You saved my bacon. Thank you so much.

    Thanks also to @Owen-Reynolds - Honestly, I'm still really confused about quaternions. Up to just now I'd thought I knew enough to get through normal jobs, but this basically blew my mind.
     
  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    1,411
    @Owen-Reynolds in your post looks like it broke, probably because you tried to use an array index in square brackets and it got interpreted as a bbcode formatting tag.

    I agree that the last code snippet from the OP (using the *= operator) looks like it could work as a general approach, but debugging it seemed harder than just working out a new answer from first principles. My guess is that the multiplication is being done in the wrong order (i.e. that it would need to be FromToRotation * currentRotation rather than currentRotation * FromToRotation--remember, multiplication of Quaternions is not commutative!).
     
    Last edited: Sep 18, 2019
  6. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    804
    That's the one thing Unity Answers still beats Forums on -- underneath it gives you the "display" version of your reply, as you type it.

    Yes, that seems exactly the problem. RS figured out = wasn't correct, then figured out *= was the "add one rotation to another" command. That's pretty impressive. But didn't realize the entire approach of using tree.up wasn't good.

    To help out the OP, I'd rephrase that as "multiplication of ROTATIONS doesn't commute". Quaternions are the easiest way to handle rotations. But rotations themselves are a huge pain. I like to put it a different way: q1*R applies q1 as a global spin. R*q1 applies q1 in R's local axis. If you know how to use the Local/Global tool as a 3D modeler, you basically understand local vs. global rotations in a program.
     
  7. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    181
    Oh lord, I'd forgotten that order of multiplication was critical with Quaternions.

    Thanks so much to both of you, lots to try to internalize here.

    God, I spent so much time trying to get those trees to stand up straight...

    --Rev