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

Quaternion Rotation Along Normal

Discussion in 'Scripting' started by liquidgraph, May 9, 2009.

Thread Status:
Not open for further replies.
  1. liquidgraph

    liquidgraph

    Joined:
    Feb 26, 2009
    Posts:
    324
    I have a tank object whose normal tracks my terrain, so when the tank moves up a mountain, it's X and Z rotation is flush with the terrain normal. Doing that was easy, but now I need to have the tank facing the proper direction as it moves. This means I need to rotate it along the terrain normal so that it faces where the player clicked. I'm using two sets of quaternion rotations (one to align to the terrain and another to align in the direction of travel) but they seem to be conflicting with one another. Take a look:

    Assuming I have the first part right -- terrain alignment -- how would I then add to it rotation along the local y-axis so as to align in the direction of motion (the x,z difference between where the player clicked and where the tank is now)?

    Code (csharp):
    1.  
    2. function MoveTo(movePos:Vector3) {
    3.     var startPos = transform.position;
    4.     var speed : float = 1;
    5.     var dist = Vector3.Distance (startPos, movePos);
    6.        
    7.     for (i = 0.0; i < 1.0; i += (speed * Time.deltaTime) / dist) {
    8.         var layerMask = 1 << 8;
    9.         var hit:RaycastHit;
    10.         var ray = Vector3(0,1,0);  // ray pointing upward
    11.         var castPosition = Vector3(transform.position.x,-100,transform.position.z);
    12.         Physics.Raycast (castPosition,ray,hit,100000,layerMask);
    13.         yyy = hit.point.y; // get the vertical position (y) of the terrain
    14.            
    15.         transform.rotation.x = Quaternion.FromToRotation(Vector3.up, hit.normal).x;
    16.         transform.rotation.z = Quaternion.FromToRotation(Vector3.up, hit.normal).z;
    17.        
    18.         var lerpedPosition = Vector3.Lerp(startPos, Vector3(movePos.x,0,movePos.z), i); // sets unit's horizontal movement (x and z)
    19.         transform.position = Vector3(lerpedPosition.x,yyy,lerpedPosition.z); // updates horizontal and vertical position
    20.        
    21.         yield;
    22.         if (Input.GetMouseButtonDown(1)  interfaceControllerScript.CheckIfInSelectionArray(this) == true) {
    23.             i = 1.0;
    24.         }
    25.     }
    26.  
    27. }
    28.    
    29.    
    30. function RotateTo(movePos:Vector3) {
    31.     var fromQuat = transform.rotation;
    32.     var posDifference = movePos - Vector3(transform.position.x,0,transform.position.z);
    33.        
    34.     var toQuat = Quaternion.LookRotation(posDifference);
    35.        
    36.     var speed : float = 50;
    37.     var dist = Quaternion.Angle(transform.rotation,toQuat);
    38.  
    39.  
    40.     for (i = 0.0; i < 1.0; i += (speed * Time.deltaTime) / dist) {
    41.         transform.rotation = Quaternion.Lerp (fromQuat,toQuat, i); // rotates unit in the direction of movement
    42.         yield;
    43.         if (Input.GetMouseButtonDown(1)  interfaceControllerScript.CheckIfInSelectionArray(this) == true) {
    44.             i = 1.0;
    45.         }
    46.         if (Quaternion.Angle(transform.rotation,toQuat) <= 1) {
    47.             i = 1.0;
    48.             MoveTo(movePos);
    49.         }
    50.     }
    51.        
    52. }
     
  2. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,877
    Just make the tank turn towards the desired point first and insert the code for terrain alignment after that.

    Also,

    You are setting the values of a quaternion here manually, which is most likely not what you want to do, unless you know quaternions inside out (all four x,y,z,w values in 4D space).

    Instead I would simply do:

    Code (csharp):
    1. transform.rotation = Quaternion.FromToRotation (transform.up, hit.normal) * transform.rotation;
    This rotates the tank by the amount required to align its local up axis with the normal of the hit point.

    Rune
     
  3. liquidgraph

    liquidgraph

    Joined:
    Feb 26, 2009
    Posts:
    324
    Thanks Rune.

    Yeah, I just figured out that using Quaternion components isn't smart.

    I was trying to set the direction of motion prior to aligning the normal, but the normal rotation always ended up overriding any direction the object was previously set in.

    I'm going to try doing what you say, but how would I got about animating this. Ideally I don't want the normal to snap when the tank drives over a hill -- the normal should animate smoothly, and while that's happening, it should also be possible to animate a change in direction.
     
  4. liquidgraph

    liquidgraph

    Joined:
    Feb 26, 2009
    Posts:
    324
    I've got it working pretty well now, but I can't figure out how to LERP between two quaternions along an axis. When I use this

    Code (csharp):
    1. transform.rotation = Quaternion.Lerp (fromQuat,toQuat, i);
    to change the direction of the tank, it doesn't rotate along its local y-axis like I want it to.
     
  5. Albazcythe

    Albazcythe

    Joined:
    Feb 21, 2013
    Posts:
    8
    Lol this post is kinda old.. But that line of code is just what I was looking for, thank you!
     
    Ignacii likes this.
  6. Loren-Logic

    Loren-Logic

    Joined:
    Jun 29, 2009
    Posts:
    6
    RuneVision's line of code is STILL perfectly helpful another four years later! Thank you! I've got my Spiderobot walking over the whole asteroid's surface! Great work, Rune!
     
  7. Akasharkxx

    Akasharkxx

    Joined:
    Sep 30, 2020
    Posts:
    2
    This works for ray gun system.
     
  8. BaraShiro

    BaraShiro

    Joined:
    Jul 10, 2017
    Posts:
    4
    Thanks, this fixed my missile impacts
     
  9. BobbyGunnels

    BobbyGunnels

    Joined:
    Nov 21, 2020
    Posts:
    1
    I've been saved by a line a code that is 13 years old. Exactly what I needed !
     
  10. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,573
    And why do you think it's a good idea to necro post again with a pretty pointless response 13 years later like the last four posts? Please read the code of conduct.
    I think this thread needs to be closed :)
     
  11. ayoubaelectro

    ayoubaelectro

    Joined:
    Feb 20, 2022
    Posts:
    1
    i will comment if this line of code is still helpful 5 years later
     
    Redellion and AnimalManUK like this.
Thread Status:
Not open for further replies.