- Home /
Combining Quaternion Slerp tilt with Rotation around Y axis
I am trying to simulate the movement of a spinning top, with tilt and spin. I have this tilt rotation set up, and it works perfectly:
float maxVel = 20f;
float vel_X = Mathf.Clamp(rb.velocity.z, -maxVel, maxVel); //clamping the values
float vel_Z = Mathf.Clamp(-rb.velocity.x, -maxVel, maxVel); //for some reason, these values only work inverted like this
vel_X = vel_X / maxVel; //making it a percentage of the maxVelocity;
vel_Z = vel_Z / maxVel; //making it a percentage of the maxVelocity;
Quaternion target = Quaternion.Euler(vel_X * maxTilt, 0, vel_Z * maxTilt);
targetTilted.transform.rotation = Quaternion.Slerp(targetTilted.transform.rotation, target, Time.deltaTime * smooth);
The object tilts in the same direction as my analogue stick.
However, I also want to add a spin rotation, around the Y-axis. But I haven't been able to. One rotation breaks the other.
Thank you in advance for any help.
I meant that if I apply one rotation it breaks the other. I can't seem to make them both work at the same time. (I removed the "oddly" bit from the question to avoid further confusion)
That helps to differentiate what you're expecting but not seeing.
What I see is a slerp between targetTilted and target, and while that can be a valid calculation, it won't do what I think you're expecting. To imagine, consider if there was an exaggerated tile of 45 degrees (target) and a rotation spinning the object at any orientation in Y, but is otherwise 'straight up' at 0 degrees, the result of the Slerp would be an angle of tile somewhere between 0 and 45 degrees as defined by Time.deltaTime * smooth.
However, what I sense you're expecting to obtain is the spinning object tilted on an axis. Combining one rotation upon another is actually the result of Quaternion multiplication, not a slerp, and unlike simple multiplication the order of the operands matters (the result of multiplying a quaternion by a quaternion is not the same if the order is reversed).
You'll need to refashion your code with that point in $$anonymous$$d, that to apply a spin to a tilt is a quaternion multiplication.
Answer by telecaster · Sep 04, 2018 at 09:54 PM
Is this going in the direction you want?
void Update () {
float maxVel = 30f;
float vel_y = 40f;
float vel_X = Mathf.Clamp(rb.velocity.z, -maxVel, maxVel); //clamping the values
float vel_Z = Mathf.Clamp(-rb.velocity.x, -maxVel, maxVel); //for some reason, these values only work inverted like this
vel_X = vel_X / maxVel; //making it a percentage of the maxVelocity;
vel_Z = vel_Z / maxVel; //making it a percentage of the maxVelocity;
targetTilted.transform.Rotate(Vector3.up * 30);
vel_y = targetTilted.transform.rotation.y;
Quaternion target = Quaternion.Euler(vel_X * maxTilt, vel_y, vel_Z * maxTilt);
targetTilted.transform.rotation = Quaternion.Slerp(targetTilted.transform.rotation, target, Time.deltaTime);
targetTilted.transform.Rotate(Vector3.up, Time.deltaTime*30);
}
This shows spin at the local y axis assuming the centre of the objects is placed correctly. It worked for me using a deformed sphere. But maybe you are looking for something different?
This is definitely going in the right direction. I was able to get the effect that I desired, however, certain values in the method will break the spin, and sometimes even the tilt.
float maxVel = 30f; //the max velocity usually doesn't go above 20f
float vel_X = $$anonymous$$athf.Clamp(rb.velocity.z, -maxVel, maxVel); //clamping the values
float vel_Z = $$anonymous$$athf.Clamp(-rb.velocity.x, -maxVel, maxVel); //for some reason, these values only work inverted like this
vel_X = vel_X / maxVel; //making it a percentage of the maxVelocity;
vel_Z = vel_Z / maxVel; //making it a percentage of the maxVelocity;
targetTilted.transform.Rotate(Vector3.up * ((360*rotationSpeed)/ smooth)); //applying spin rotatiin
float vel_y = targetTilted.transform.rotation.y;
Quaternion target = Quaternion.Euler(vel_X * maxTilt, vel_y, vel_Z * maxTilt);
targetTilted.transform.rotation = Quaternion.Slerp(targetTilted.transform.rotation, target, Time.deltaTime * smooth);
If set "smooth = 5" and "rotationSpeed = 1", it works fine. But if I change these values, specially the smooth to, say 3 or 10, the spin stops working correctly. I suspect this has something to do with how unity calculates complete 360 degree rotations.
"I suspect this has something to do with how unity calculates complete 360 degree rotations."
That may not be Unity, but Quaternions in general. They don't accept input beyond 180 degrees either direction. Unity's documentation mentions this here, with this quote:
a Quaternion can represent either an orientation or a rotation - where the rotation is measured from the rotational “origin” or “Identity”. It because the rotation is measured in this way - from one orientation to another - that a quaternion can’t represent a rotation beyond 180 degrees.
That explains it. Do you have any ideas how, taking that into account, I might solve this?