- Home /
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
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);
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!
Answer by ronronmx · May 01, 2012 at 05:42 AM
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
Answer by aldonaletto · Apr 30, 2012 at 03:50 AM
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
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 perfor$$anonymous$$g the turning code above on the new child object. $$anonymous$$aybe I should change my code to perform all forward/backward movement on the Z axis ins$$anonymous$$d 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?!
@aldonaletto How would you do this with three axis? I am trying to create a rotation button in my game with three seperate axis. Is is best to have a heirchy tree with a parent, child and grandparent with each gameobject for a seperate axis rotation?
Yes, make a 3 level hierarchy where each level rotates about its local axis (X, Y or Z), like this:
AxisX // Rotate(x,0,0)
AxisY // Rotate(0,y,0)
AxisZ // Rotate(0,0,z)
Rotate assumes local axes by default (Space.Self)