x


Using Quaternion.LookRotation( ) on y axis only, but keep x axis of transform the same?

The problem I have is a little different than what I have read about concerning the same issue. I found plenty of answers showing how to only rotate on 1 axis when using functions like 'Quaternion.LookRotation()', and I can achieve that just fine. My problem is that the object I am rotating towards the target is a motorcycle, which also rotates on the X axis for forward/backward pitch.

When I limit the rotation to the y axis only, and zero out the other 2, my motorcycle rotates towards the target on Y just fine, but it's X axis rotation is now locked to 0...so when going up-hill or down-hill, the bike doesn't rotate anymore.

If I don't zero out the X axis for the rotation, the the bike's X axis rotation is also following the target, so if my bike is going up-hill and the next waypoint is at y = 0 (on the ground), then the bike's X rotation tries to point towards the waypoint and rotates the opposite way of the up-hill, down-hill.

I have hit a roadblock trying to figure out how to leave the bike's X rotation alone while making its Y axis follow waypoints. Here's what I have so far:

void Update () 
{
    // Loop through waypoints
    if( currentWaypoint < waypoints.Length )
    {
        // Get direction of next waypoint
        Vector3 direction = waypoints[currentWaypoint].position - transform.position;

        // Check if we passed the current waypoint and get the next one if we did
        if( transform.position.x > waypoints[currentWaypoint].position.x )
        {
            currentWaypoint++;
        }
        else
        { 
            Quaternion newRotation = Quaternion.LookRotation( direction );
            Quaternion rot = Quaternion.Slerp( transform.rotation, newRotation, 
            transform.parent.rigidbody.velocity.magnitude * Time.deltaTime );

            transform.rotation = rot;

            // This version below gives me the bike's X rotation bike, but I gimbal lock problems...
            //transform.rotation = Quaternion.Euler( transform.eulerAngles.x, rot.eulerAngles.y, 0.0f );    
        }
    }
    else
    {
        Debug.LogWarning("NO MORE WAYPOINTS TO FOLLOW");
    }
}

Quaternions give me a headache :) I've been trying to get this to work for the past week, and although I am really close, it's still not stable enough to be used.

If any of you rotation gurus out there can give me some much needed help, I would really appreciate it! Thanks for your time,

Stephane

more ▼

asked Apr 30 '12 at 03:06 AM

ronronmx gravatar image

ronronmx
806 85 104 125

try updating your direction Vector3 before creating the "newRotation"..

Vector3 direction = waypoints[currentWaypoint].position - transform.position;

direction.x = (plug in the desired height here);

etc.

I suppose you may then need to multiply the desired height by the distance from the next waypoint, to keep it constant..

as in: direction.x = ((height * Vector3.Distance(waypoints[currentWaypoint].position,transform.position)) / someConstant);

Apr 30 '12 at 03:21 AM Seth Bergman

I'll give that a try and see if I can make it work. I wish there was a way to multiply my oldrotation by my new rotation, so that if my new rotation's x was 0, mutliplying it with the old rotation would only return the old roation's x. Is this possible?

Thanks for the example above Seth, I'll let you know if I can make this work!

Apr 30 '12 at 05:58 PM ronronmx
(comments are locked)
10|3000 characters needed characters left

2 answers: sort voted first

I got the rotation to work the way I needed it to work, so for future reference here it is below (I tried both solutions given above with no success for my particular situation, but thanks anyways guys):

// Get direction of next waypoint
Vector3 direction = waypoints[currentWaypoint].position - transform.position;

// Check if we passed the current waypoint and get the next one if we did
if( transform.position.x > waypoints[currentWaypoint].position.x )
{
    currentWaypoint++;
}
else
{ 
    Quaternion newRotation = Quaternion.LookRotation( direction.normalized );
    float yAngle = Mathf.LerpAngle( transform.eulerAngles.y,newRotation.eulerAngles.y - 90, rBody.velocity.magnitude * Time.deltaTime );

    rigidbody.MoveRotation( Quaternion.Euler( 0, yAngle, transform.eulerAngles.z ));
}

Hopefully this can help anyone else in the same situation :)

Stephane

more ▼

answered May 01 '12 at 05:42 AM

ronronmx gravatar image

ronronmx
806 85 104 125

(comments are locked)
10|3000 characters needed characters left

Usually you should use a parent/child hierarchy: the parent rotates around the Y axis and the child rotates locally around X - doing both rotations with the same object is complicated, because the first rotation also rotates the axes, and the second rotation gets tilted.
But in your specific case - a two wheel vehicle - there's a simpler and smarter solution: find the horizontal direction and cast two rays to the ground, one ahead and the other behind the bike; define a vector from back hit point to forward hit point and assign it to transform.forward:

  ...
  else {
    RaycastHit hitFwd;
    Physics.Raycast(transform.position + direction.normalized, -Vector3.up, out hitFwd);
    RaycastHit hitBck;
    Physics.Raycast(transform.position - direction.normalized, -Vector3.up, out hitBck);
    Vector3 dirXY = (hitFwd - hitBck).normalized;
    float speed = transform.parent.rigidbody.velocity.magnitude;
    transform.forward = Vector3.Lerp(transform.forward, dirXY, speed * Time.deltaTime);
  }
  ...

NOTE: this algorithm was suggested by @SirGive in the question http://answers.unity3d.com/questions/168097/orient-vehicle-to-ground-normal.html

more ▼

answered Apr 30 '12 at 03:50 AM

aldonaletto gravatar image

aldonaletto
42.5k 16 43 202

Aldo, thanks for the example code, this is a nice alternative, but I forgot to mention that I'm using a rigidbody to control the bike, and I'm doing all my current rotations (excluding the one I'm trying to add right now) on the rigidbody by adding torque to the Z axis to rotate the bike forward/backward with input, and the rigidbody takes care of pitching the bike when the terrain underneath changes.

Since the Quaternion.LookRotation() function points the transform's forward axis towards the target, and that my rigidbody's transform goes forward on the X axis (I'm using transform.right for all forward/backward movements), I had the create a child object and rotate it's Z axis so that it points the same way as my rigidbody's X axis, and childed all other transforms to that new object.

I am performing the turning code above on the new child object. Maybe I should change my code to perform all forward/backward movement on the Z axis instead of X, or maybe I can use a different method to turn the bike which doesn't rely on the Z axis to be pointing in the direction my bike is moving?!

Apr 30 '12 at 05:52 PM ronronmx
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x5273
x2245
x459
x142

asked: Apr 30 '12 at 03:06 AM

Seen: 2243 times

Last Updated: May 01 '12 at 05:42 AM