Skip to content

Instantly share code, notes, and snippets.

@insominx
Last active December 4, 2024 23:25
Show Gist options
  • Save insominx/eef82673c88c2b5f9224473bacf162c4 to your computer and use it in GitHub Desktop.
Save insominx/eef82673c88c2b5f9224473bacf162c4 to your computer and use it in GitHub Desktop.
Functions for getting and applying inverse transforms
using UnityEngine;
/// <summary>
/// Provides utility methods for inverting transforms in Unity.
/// </summary>
public static class TransformInverter
{
/// <summary>
/// Inverts the local transform of the target based on the source transform.
/// Equivalent to the LocalInvert method in the original MonoBehaviour.
/// </summary>
/// <param name="target">The Transform to apply the inversion to.</param>
/// <param name="source">The Transform to take the inverse from.</param>
public static void InvertLocal(Transform target, Transform source)
{
if (source == null || target == null)
{
Debug.LogWarning("InvertLocal: Source or target transform is null.");
return;
}
// Get the source's local transform components
Vector3 sourceLocalPosition = source.localPosition;
Quaternion sourceLocalRotation = source.localRotation;
Vector3 sourceLocalScale = source.localScale;
// Invert the scale
Vector3 inverseScale = new Vector3(
sourceLocalScale.x != 0 ? 1f / sourceLocalScale.x : 0,
sourceLocalScale.y != 0 ? 1f / sourceLocalScale.y : 0,
sourceLocalScale.z != 0 ? 1f / sourceLocalScale.z : 0
);
target.localScale = inverseScale;
// Invert the rotation
Quaternion inverseRotation = Quaternion.Inverse(sourceLocalRotation);
target.localRotation = inverseRotation;
// Invert the position
Vector3 scaledPosition = Vector3.Scale(inverseScale, sourceLocalPosition);
Vector3 rotatedPosition = inverseRotation * scaledPosition;
Vector3 inversePosition = -rotatedPosition;
target.localPosition = inversePosition;
}
/// <summary>
/// Inverts the global (world) transform of the target based on the source transform.
/// Equivalent to the GlobalInvert method in the original MonoBehaviour.
/// </summary>
/// <param name="target">The Transform to apply the inversion to.</param>
/// <param name="source">The Transform to take the inverse from.</param>
public static void InvertGlobal(Transform target, Transform source)
{
if (source == null || target == null)
{
Debug.LogWarning("InvertGlobal: Source or target transform is null.");
return;
}
// Get the source's world transform components
Vector3 sourceWorldPosition = source.position;
Quaternion sourceWorldRotation = source.rotation;
Vector3 sourceWorldScale = source.lossyScale;
// Invert the scale
Vector3 inverseScale = new Vector3(
sourceWorldScale.x != 0 ? 1f / sourceWorldScale.x : 0,
sourceWorldScale.y != 0 ? 1f / sourceWorldScale.y : 0,
sourceWorldScale.z != 0 ? 1f / sourceWorldScale.z : 0
);
target.localScale = inverseScale;
// Invert the rotation
Quaternion inverseRotation = Quaternion.Inverse(sourceWorldRotation);
target.rotation = inverseRotation;
// Invert the position
Vector3 scaledPosition = Vector3.Scale(inverseScale, sourceWorldPosition);
Vector3 rotatedPosition = inverseRotation * scaledPosition;
Vector3 inversePosition = -rotatedPosition;
target.position = inversePosition;
}
/// <summary>
/// Retrieves the inverse local transform components based on the source transform.
/// </summary>
/// <param name="source">The Transform to take the inverse from.</param>
/// <param name="inversePosition">Output inverse local position.</param>
/// <param name="inverseRotation">Output inverse local rotation.</param>
/// <param name="inverseScale">Output inverse local scale.</param>
public static void GetInverseLocal(Transform source, out Vector3 inversePosition, out Quaternion inverseRotation, out Vector3 inverseScale)
{
if (source == null)
{
Debug.LogWarning("GetInverseLocal: Source transform is null.");
inversePosition = Vector3.zero;
inverseRotation = Quaternion.identity;
inverseScale = Vector3.one;
return;
}
// Get the source's local transform components
Vector3 sourceLocalPosition = source.localPosition;
Quaternion sourceLocalRotation = source.localRotation;
Vector3 sourceLocalScale = source.localScale;
// Invert the scale
inverseScale = new Vector3(
sourceLocalScale.x != 0 ? 1f / sourceLocalScale.x : 0,
sourceLocalScale.y != 0 ? 1f / sourceLocalScale.y : 0,
sourceLocalScale.z != 0 ? 1f / sourceLocalScale.z : 0
);
// Invert the rotation
inverseRotation = Quaternion.Inverse(sourceLocalRotation);
// Invert the position
Vector3 scaledPosition = Vector3.Scale(inverseScale, sourceLocalPosition);
Vector3 rotatedPosition = inverseRotation * scaledPosition;
inversePosition = -rotatedPosition;
}
/// <summary>
/// Retrieves the inverse global (world) transform components based on the source transform.
/// </summary>
/// <param name="source">The Transform to take the inverse from.</param>
/// <param name="inversePosition">Output inverse world position.</param>
/// <param name="inverseRotation">Output inverse world rotation.</param>
/// <param name="inverseScale">Output inverse world scale.</param>
public static void GetInverseGlobal(Transform source, out Vector3 inversePosition, out Quaternion inverseRotation, out Vector3 inverseScale)
{
if (source == null)
{
Debug.LogWarning("GetInverseGlobal: Source transform is null.");
inversePosition = Vector3.zero;
inverseRotation = Quaternion.identity;
inverseScale = Vector3.one;
return;
}
// Get the source's world transform components
Vector3 sourceWorldPosition = source.position;
Quaternion sourceWorldRotation = source.rotation;
Vector3 sourceWorldScale = source.lossyScale;
// Invert the scale
inverseScale = new Vector3(
sourceWorldScale.x != 0 ? 1f / sourceWorldScale.x : 0,
sourceWorldScale.y != 0 ? 1f / sourceWorldScale.y : 0,
sourceWorldScale.z != 0 ? 1f / sourceWorldScale.z : 0
);
// Invert the rotation
inverseRotation = Quaternion.Inverse(sourceWorldRotation);
// Invert the position
Vector3 scaledPosition = Vector3.Scale(inverseScale, sourceWorldPosition);
Vector3 rotatedPosition = inverseRotation * scaledPosition;
inversePosition = -rotatedPosition;
}
/// <summary>
/// Retrieves the inverse local transform as a TransformData structure based on the source transform.
/// </summary>
/// <param name="source">The Transform to take the inverse from.</param>
/// <returns>A TransformData struct containing the inverse position, rotation, and scale.</returns>
public static TransformData GetInverseLocal(Transform source)
{
GetInverseLocal(source, out Vector3 inversePosition, out Quaternion inverseRotation, out Vector3 inverseScale);
return new TransformData(inversePosition, inverseRotation, inverseScale);
}
/// <summary>
/// Retrieves the inverse global (world) transform as a TransformData structure based on the source transform.
/// </summary>
/// <param name="source">The Transform to take the inverse from.</param>
/// <returns>A TransformData struct containing the inverse position, rotation, and scale.</returns>
public static TransformData GetInverseGlobal(Transform source)
{
GetInverseGlobal(source, out Vector3 inversePosition, out Quaternion inverseRotation, out Vector3 inverseScale);
return new TransformData(inversePosition, inverseRotation, inverseScale);
}
/// <summary>
/// Represents a set of transformation data: position, rotation, and scale.
/// </summary>
public struct TransformData
{
public Vector3 Position;
public Quaternion Rotation;
public Vector3 Scale;
/// <summary>
/// Initializes a new instance of the TransformData struct.
/// </summary>
/// <param name="position">The position component.</param>
/// <param name="rotation">The rotation component.</param>
/// <param name="scale">The scale component.</param>
public TransformData(Vector3 position, Quaternion rotation, Vector3 scale)
{
Position = position;
Rotation = rotation;
Scale = scale;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment