Rotate an object to a position only through one axis
I'm about to rip my hair out trying to do something that should be relatively simple.
I have an Vehicle A, which when upside-down I want to rotate slowly so it aligns back to the ground, but only through the X-asis and Z-Axis (Player is able to steer the object left and right, and I don't want to lock them out of controlling the Y axis while it rotates). The problem, of course, is that angles in Unity is bananas. Instead of going from 0-360, angles goes from 0 to 90 and back down to 0, then jumps to 360, down to 270, and back up to 360 again. And Quaternions requires a ph.d.
Is there a simple solution to this I'm just not seeing?
edit: This replicated pretty closely what I want:
Quaternion rt = Quaternion.RotateTowards(transform.rotation, new Quaternion(0, 0, 0, 1), rotateSpeed * Time.fixedDeltaTime);
transform.rotation = new Quaternion(rt.x, transform.rotation.y, rt.z, rt.w);
And if you're looking at this in horror going "what in the he..?"; you and me both. The problem with this is that it still grips the Y axis a little bit, making steering slower, and when the rotation is done it starts rotating around the Y-axis ever so slightly. Due to my complete lack of knowledge about Quaternions, I have no idea why.
Answer by Scribe · Jun 01, 2018 at 06:38 PM
I might be able to give you a hand with your PhD if you need!
public float timeTaken = 5f;
private bool standingUp = false;
void Update()
{
// Usual turning
transform.rotation *= Quaternion.AngleAxis(Input.GetAxis("Horizontal"), transform.InverseTransformDirection(Vector3.up));
// Flip up
if (Input.GetKeyDown(KeyCode.Q) && !standingUp && isFlipped())
{
standingUp = true;
StartCoroutine(StandUp(timeTaken));
}
// Flip over
if (Input.GetKeyDown(KeyCode.W))
{
transform.rotation = Quaternion.AngleAxis(180, Vector3.forward) * Quaternion.AngleAxis(Random.Range(-180, 180), Vector3.up);
}
}
private bool isFlipped()
{
return transform.up.y < 0.1f;
}
private IEnumerator StandUp(float timeToTake)
{
float t = 0;
while(t < timeToTake)
{
Quaternion target = findTargetRotation(transform);
// Try to keep the 'degreesToChange' as constant as possible whilst realising that it may go up or down
// if other rotations are applied whilst this happens
float timeLeft = timeToTake - t;
float leftOverDegrees = Quaternion.Angle(transform.rotation, target);
float degreesToChange = Time.deltaTime * (leftOverDegrees / timeLeft);
transform.rotation = Quaternion.RotateTowards(transform.rotation, target, degreesToChange);
t += Time.deltaTime;
yield return null;
}
transform.rotation = findTargetRotation(transform);
standingUp = false;
}
public Quaternion findTargetRotation(Transform t)
{
// Project the current forward axis onto the horizontal plane (hence the normal axis is Vector3.up)
Vector3 proj = Vector3.ProjectOnPlane(t.forward, Vector3.up);
// Use lovely built in methods to get a rotation such that we point the forward axis along the
// closest axis on the horizontal plane. We also want our up vector to be the world up vector
// once we've finished rotating.
return Quaternion.LookRotation(proj, Vector3.up);
}
Check the in-code comments for some pointers but let me know if you need any parts explained in more detail!
Scribe
It's almost working. The issue with this is that it mainly rotates around the Z axis, while I would want it to rotate more along the X axis (It doesn't look reasonable that my hovering vehicle decides to do a forward or backwards flip when it finds itself upside down, as opposed to a roll.) It also points in a complete different direction when it's done (If it's upside down, it's going to flip itself backwards and end up looking backwards). I want to be able to preserve the direction in the y axis, while letting it roll in the x axis to get itself upright and level the Z axis.
Your answer
Follow this Question
Related Questions
Having two objects Y axis parallel rotating around local Z axis. 0 Answers
Rotate y-axis of child object following a rigidbody sphere parent 0 Answers
Turret rotating on a z axis 2 Answers
3 Axis Camera Rotation 0 Answers
How can I clamp a target rotation within the rotation limits of a character joint? 0 Answers