- Home /
Eulers from normal into rotation sometimes wrong.
Hi, what I'm basically doing is using this piece of code, to rotate my room so that whatever the collision hits becomes the "floor":
function OnCollisionEnter(collisionInfo : Collision) {
myQuaternionFTR = Quaternion.FromToRotation(collisionInfo.contacts[0].normal, Vector3.up);
Map.transform.Rotate(myQuaternionFTR.eulerAngles);
}
But sometimes it just gets it wrong for some reason, after a few spins it might get something like 345/345/305 xyz where it should've been 0(or360)/345/315 in a single step (where up until then it has worked perfectly), and after getting a wrong rotation I can usually hit the same surface again with its new normals to make it correct.
The room I'm using for the tests is a rhombicuboctahedron that I'm fairly sure I managed to get with all the proper angles- if it makes any difference.
Any ideas?
Not sure if this is your problem, but you might check the caveat here about setting angles over 360: http://unity3d.com/support/documentation/ScriptReference/Transform-eulerAngles.html
Yeah, I'm pretty sure that page specifically states that what you're trying to do here won't work.
I changed it to "$$anonymous$$ap.transform.Rotate(myQuaternonLook.eulerAngles);" and I get the exact same behaviour.
Apparently taking eulerAngles from my FromToRotation Quaternion isnt what I'm looking for "when you convert a quaternion to euler angles, the quaternion gives you no gurantuee out of which euler angle you will get out".
$$anonymous$$aybe I just need to convert my direction to eulerangles manually? Any math-wizards around? The normal should have all I need as compared to Vector3.up...
The whole deal with that line you quoted out of the Quaternion class is that you can't get a specific set of euler angles out of a given quaternion- the whole point of quaternions is that they can accurately describe a rotation, in a way that euler angles alone cannot. Hence, you are losing information when you convert a quaternion to a euler angle representation (similar to converting a double to a float).
Answer by Wisearn · May 04, 2012 at 04:23 PM
Thanks @Bunny83 and @syclamoth
It hadnt occured to me that the pivot point was the issue considering my test shape was symmetric but it makes sense now because the pivot point of the model is actually in the center >bottom< of the model (I just had "center" on in the view without realizing it) which explains why it started becoming less and less accurate.
Using temporary parenting with an empty gameobject solved my issue entierly.
Answer by Paulius-Liekis · May 02, 2012 at 12:15 PM
Wait, Transform.Rotate is incremental rotation, don't you want to set the rotation instead (transform.localEulerAngles = myQuaternonLook.eulerAngles)?
You don't need conversion to euler angles, you can simply assign quaternions: transform.localRotation = myQuaternonLook;
Having said that I have no opinion about this math in general :) Assuming that ContactPoint.normal is in world space - it makes sense.
You're absolutely right, however if you set the rotation fix to the one you calculates you can't rotate your player anymore ;) But the incremental note is correct.
Sorry, just realized he rotates the $$anonymous$$ap and not the player ^^. Then you're right, however i don't think this would work since the map rotation happens around the maps origin and not around the contact point.
Answer by aldonaletto · May 02, 2012 at 01:55 PM
Opposite to what it may seem (this fooled me at first too), using Rotate is correct: the room is already at some rotation when the collision occurs, thus it should be rotated from that orientation to the new one. The problem is the precision loss in quaternion-euler conversions - and there are two of them each collision. It would be better to just multiply the from-to rotation by the current rotation:
function OnCollisionEnter(collisionInfo : Collision) { newRotation = Quaternion.FromToRotation(collisionInfo.contacts[0].normal, Vector3.up); Map.transform.rotation *= newRotation; }But even this approach may accumulate errors, and rotate to weird positions after several collisions. To avoid this, you may try to force the eulerAngles to allowed angles after each rotation.
According to the sapient Wikipedia, this is a rhombi-whatever solid:
From this image (borrowed from wikipedia and Leonardo da Vinci), I suppose the eulerAngles xyz must all be integral multiples of 45 degrees. If this is true, you could try this:
function OnCollisionEnter(collisionInfo : Collision) { var newRot = Quaternion.FromToRotation(collisionInfo.contacts[0].normal, Vector3.up); newRot = newRot * Map.transform.rotation; // find the new rotation var euler = newRot.eulerAngles; // get the corresponding euler angles... euler.x = Mathf.Round(euler.x / 45) * 45; // force them to be multiples of 45 euler.y = Mathf.Round(euler.y / 45) * 45; euler.z = Mathf.Round(euler.z / 45) * 45; Map.transform.eulerAngles = euler; // then assign the new absolute rotation }By the way, this angle fixing could be applied to your approach as well (use Rotate, then fix the eulerAngles).
The room will rotate around its own pivot, as @Bunny83 said, but this may be a desired behaviour in your case. If not, @syclamoth's suggestion is good: place an empty object at the hit point, child the room to it, apply the new rotation to the empty object and assign null to the room's parent.
Your answer
Follow this Question
Related Questions
Problem snapping object to different normals, but maintaining x axis orientation 0 Answers
Problem snapping object to different normals, but maintaining x axis orientation 1 Answer
Rotating cube with quaternion angles 0 Answers
Why changing the normal affects the viewDir? 1 Answer
Gun not rotating with the camera? 1 Answer