- Home /
Replicating the rotation of one game object on another game object using Quaternions.
Good day everybody. I have been bashing my head over this problem for a while now. I'm trying to create a script that can be applied to a game object. The purpose of the script is to take another game objects transform in and replicate the difference in rotations of that transform on the game object the script is attached too.
The script needs to be able to follow each independent axis rotation solely, or two of axes, or even all three. The code below works if all three of the axes are monitored, when the x and z axis are solely monitored, when the y and z axis are solely monitored, but NOT when the x and y axis are solely monitored (The game object that's following (with the script attached)) generates a value for the z axis when trying to rotate just the x and y axis.
It becomes clear that whenever I'm trying to replicate the rotation of two of the axes and the z axis is not one of those axes I'm running into issues. I have done this with quaternions to avoid gimbal lock. I do believe there is an issue with the implementation of my w axis when creating the Quaternion (Which represents the rotation I want to apply to the Game object).
If anyone may provide some insight I'd be very grateful, I am a junior developer and have only started working with unity this year.
Please find the code below
[ExecuteInEditMode]
public class RotationSync2 : MonoBehaviour
{
[SerializeField]
public Transform ExternalTransform;
private Quaternion PreviousExternalTransform;
private Quaternion RotationDifference;
private Quaternion Temp = new Quaternion();
private Quaternion PreviousTemp;
private float xToUse;
private float yToUse;
private float zToUse;
private bool RotationComplete = false;
[HideInInspector] public bool rotateX;
[HideInInspector] public bool rotateY;
[HideInInspector] public bool rotateZ;
[HideInInspector] [InspectorName("Invert")] public bool InvertX;
[HideInInspector] [InspectorName("Invert")] public bool InvertY;
[HideInInspector] [InspectorName("Invert")] public bool InvertZ;
[HideInInspector] public float percentageOfRotationToFollowX = 1f;
[HideInInspector] public float percentageOfRotationToFollowY = 1f;
[HideInInspector] public float percentageOfRotationToFollowZ = 1f;
private float rotationToSetX;
private float rotationToSetY;
private float rotationToSetZ;
// Start is called before the first frame update
void Start()
{
PreviousExternalTransform = ExternalTransform.rotation;
}
// Update is called once per frame
void Update()
{
ClearPreviousRotationValues();
BuildQuarternion();
FindRotateDifference();
SetRotationValues();
SetRotations();
}
public void ClearPreviousRotationValues()
{
rotationToSetX = 0;
rotationToSetY = 0;
rotationToSetZ = 0;
}
private void BuildQuarternion()
{
if (ExternalTransform.rotation.x == PreviousExternalTransform.x && rotateX)
{
Temp.x = 0f;
}
else
{
Temp.x = ExternalTransform.rotation.x;
}
if (ExternalTransform.rotation.y == PreviousExternalTransform.y && rotateY)
{
Temp.y = 0f;
}
else
{
Temp.y = ExternalTransform.rotation.y;
}
if (ExternalTransform.rotation.z == PreviousExternalTransform.z && rotateZ)
{
Temp.z = 0f;
}
else
{
Temp.z = ExternalTransform.rotation.z;
}
Temp.w = ExternalTransform.rotation.w;
}
private void FindRotateDifference()
{
Quaternion a = Quaternion.identity * Quaternion.Inverse(Temp);
Quaternion b = Quaternion.identity * Quaternion.Inverse(PreviousTemp);
if (ExternalTransform.rotation != PreviousExternalTransform && PreviousTemp != null)
{
RotationDifference = b * Quaternion.Inverse(a);
RotationComplete = false;
}
PreviousTemp = Temp;
PreviousExternalTransform = ExternalTransform.rotation;
if (PreviousTemp == null)
{
return;
}
}
public void SetRotationValues()
{
if (rotateX) //Checks if this axis is being used
{
if (InvertX)
{
rotationToSetX = (RotationDifference.x * percentageOfRotationToFollowX) * -1; // set the rotation to the value of the given transform * the percentage to follow * -1 to invert it
}
else
{
rotationToSetX = RotationDifference.x * percentageOfRotationToFollowX; // set the rotation to the value of the given transform * the percentage to follow
}
}
if (rotateY)
{
if (InvertY)
{
rotationToSetY = (RotationDifference.y * percentageOfRotationToFollowY) * -1;
}
else
{
rotationToSetY = RotationDifference.y * percentageOfRotationToFollowY;
}
}
if (rotateZ)
{
if (InvertZ)
{
rotationToSetZ = (RotationDifference.z * percentageOfRotationToFollowZ) * -1;
}
else
{
rotationToSetZ = RotationDifference.z * percentageOfRotationToFollowZ;
}
}
}
public void SetRotations() //Checks which of axis' rotation the transform should follow of the given transform and applies the respective rotations.
{
if (RotationComplete == false)
{
if (rotateX && rotateY && rotateZ)
{
transform.rotation *= new Quaternion(rotationToSetX, rotationToSetY, rotationToSetZ, RotationDifference.w);
}
else if (rotateX && rotateY)
{
transform.rotation *= new Quaternion(rotationToSetX, rotationToSetY, 0f, RotationDifference.w);
}
else if (rotateX && rotateZ)
{
transform.rotation *= new Quaternion(rotationToSetX,0f, rotationToSetZ, RotationDifference.w);
}
else if (rotateY && rotateZ)
{
transform.rotation *= new Quaternion(0f, rotationToSetY, rotationToSetZ, RotationDifference.w);
}
else if (rotateX)
{
transform.rotation *= new Quaternion(rotationToSetX, 0f, 0f, RotationDifference.w);
}
else if (rotateY)
{
transform.rotation *= new Quaternion(0f, rotationToSetY, 0f, RotationDifference.w);
}
else if (rotateZ)
{
transform.rotation *= new Quaternion(0f, 0f, rotationToSetZ, RotationDifference.w);
}
RotationComplete = true;
}
}
}