- Home /
How to fix flipping Euler anlges?
Hi folks,
I created a script that links transform channels criss-cross to another object. This enables me e.g. to drive some transform channel (like rotation x, y or z) with the transform channel of some other object.
This is working all good so far with the exception of rotation. Every 180 degrees the rotation direction of the driven rotation channel gets inverted and every 360 degrees ist abruptly flips (this only happens in "Play" mode, not in Editor mode). I assume the problem is that I am using Euler angles instead of Quaternions to link the rotations. If this is indeed my problem, how can I fix my script to deal with this issue?
I know that transform.Rotate doesn't have this problem, but since I am doing a 1:1 link every frame between rotation channel, I see no way to use transform.Rotate.
Here is my script (you can ignore the parts that deal with linking the position and scale channels!):
using UnityEngine;
using System.Collections;
public enum Channel
{
TransX,
TransY,
TransZ,
RotX,
RotY,
RotZ,
ScaleX,
ScaleY,
ScaleZ,
None
}
[ExecuteInEditMode]
public class WireParams : MonoBehaviour
{
public GameObject Source;
private Transform ThisTransform = null;
public Channel TransX = Channel.None;
public float TransXFactor = 1.0f;
public Channel TransY = Channel.None;
public float TransYFactor = 1.0f;
public Channel TransZ = Channel.None;
public float TransZFactor = 1.0f;
public Channel RotX = Channel.None;
public float RotXFactor = 1.0f;
public Channel RotY = Channel.None;
public float RotYFactor = 1.0f;
public Channel RotZ = Channel.None;
public float RotZFactor = 1.0f;
public Channel ScaleX = Channel.None;
public float ScaleXFactor = 1.0f;
public Channel ScaleY = Channel.None;
public float ScaleYFactor = 1.0f;
public Channel ScaleZ = Channel.None;
public float ScaleZFactor = 1.0f;
public void Start()
{
ThisTransform = transform;
}
public void LinkTransX (Channel TransX)
{
if(TransX != Channel.None)
{
Vector3 oldPosition = ThisTransform.position;
float newPositionX;
newPositionX = SourceTransform (TransX) * TransXFactor;
ThisTransform.position = new Vector3(newPositionX, oldPosition.y, oldPosition.z);
}
}
public void LinkTransY (Channel TransY)
{
if(TransY != Channel.None)
{
Vector3 oldPosition = ThisTransform.position;
float newPositionY;
newPositionY = SourceTransform (TransY) * TransYFactor;
ThisTransform.position = new Vector3(oldPosition.x, newPositionY, oldPosition.z);
}
}
public void LinkTransZ (Channel TransZ)
{
if(TransZ != Channel.None)
{
Vector3 oldPosition = ThisTransform.position;
float newPositionZ;
newPositionZ = SourceTransform (TransZ) * TransZFactor;
ThisTransform.position = new Vector3(oldPosition.x, oldPosition.y, newPositionZ);
}
}
public void LinkRotX (Channel RotX)
{
if(RotX != Channel.None)
{
Vector3 oldRotation = ThisTransform.localEulerAngles;
float newRotationX;
newRotationX = SourceTransform (RotX) * RotXFactor;
ThisTransform.localEulerAngles = new Vector3(newRotationX, oldRotation.y, oldRotation.z);
}
}
public void LinkRotY (Channel RotY)
{
if(RotY != Channel.None)
{
Vector3 oldRotation = ThisTransform.localEulerAngles;
float newRotationY;
newRotationY = SourceTransform (RotY) * RotYFactor;
ThisTransform.localEulerAngles = new Vector3(oldRotation.x, newRotationY, oldRotation.z);
}
}
public void LinkRotZ (Channel RotZ)
{
if(RotZ != Channel.None)
{
Vector3 oldRotation = ThisTransform.localEulerAngles;
float newRotationZ;
newRotationZ = SourceTransform (RotZ) * RotZFactor;
ThisTransform.localEulerAngles = new Vector3(oldRotation.x, oldRotation.y, newRotationZ);
}
}
public void LinkScaleX (Channel ScaleX)
{
if(ScaleX != Channel.None)
{
Vector3 oldScale = ThisTransform.localScale;
float newScaleX;
newScaleX = SourceTransform (ScaleX) * ScaleXFactor;
ThisTransform.localScale = new Vector3(newScaleX, oldScale.y, oldScale.z);
}
}
public void LinkScaleY (Channel ScaleY)
{
if(ScaleY != Channel.None)
{
Vector3 oldScale = ThisTransform.localScale;
float newScaleY;
newScaleY = SourceTransform (ScaleY) * ScaleYFactor;
ThisTransform.localScale = new Vector3(oldScale.x, newScaleY, oldScale.z);
}
}
public void LinkScaleZ (Channel ScaleZ)
{
if(ScaleZ != Channel.None)
{
Vector3 oldScale = ThisTransform.localScale;
float newScaleZ;
newScaleZ = SourceTransform (ScaleZ) * ScaleZFactor;
ThisTransform.localScale = new Vector3(oldScale.x, oldScale.y, newScaleZ);
}
}
float SourceTransform(Channel channel)
{
if (channel == Channel.TransX)
return Source.transform.position.x;
else if (channel == Channel.TransY)
return Source.transform.position.y;
else if (channel == Channel.TransZ)
return Source.transform.position.z;
else if (channel == Channel.RotX)
return Source.transform.localEulerAngles.x;
else if (channel == Channel.RotY)
return Source.transform.localEulerAngles.y;
else if (channel == Channel.RotZ)
return Source.transform.localEulerAngles.z;
else if (channel == Channel.ScaleX)
return Source.transform.localScale.x;
else if (channel == Channel.ScaleY)
return Source.transform.localScale.y;
else if (channel == Channel.ScaleZ)
return Source.transform.localScale.z;
else
return 0f;
}
public void Update()
{
LinkTransX(TransX);
LinkTransY(TransY);
LinkTransZ(TransZ);
LinkRotX(RotX);
LinkRotY(RotY);
LinkRotZ(RotZ);
LinkScaleX(ScaleX);
LinkScaleY(ScaleY);
LinkScaleZ(ScaleZ);
}
}
Thanks a lot for any help!
Sean
basically use Rotate
, don't actually set any angles. That's it
(Don't use Quaternions at all, for any reason, ever)
Why don't use Quaternion? it's cool. You don't have to fully understand how those 4 numbers works. You just need to create Quaternion with those static functions, and use it as a whole thing
But how to exactely use transform.Rotate? To my knowledge transform.Rotate is not meant to be used to set rotations to absolute values, but rather to rotate an object a certain delta per frame.