Add ultimate xr

This commit is contained in:
2024-08-06 21:58:35 +02:00
parent 864033bf10
commit 7165bacd9d
3952 changed files with 2162037 additions and 35 deletions

View File

@@ -0,0 +1,243 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrAxis.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core.Settings;
using UnityEngine;
namespace UltimateXR.Core.Math
{
/// <summary>
/// Class that allows to have formatted axes (A combo box with X, Y, Z strings) instead of numerical fields.
/// It also allows conversion from and to integers and <see cref="Vector3" /> types.
/// See the UxrAxisPropertyDrawer editor class for the integration with Unity Editor.
/// </summary>
[Serializable]
public class UxrAxis : IEquatable<UxrAxis>
{
#region Inspector Properties/Serialized Fields
[SerializeField] private int _axis;
#endregion
#region Public Types & Data
public const int X = 0;
public const int Y = 1;
public const int Z = 2;
/// <summary>
/// Returns a perpendicular axis.
/// </summary>
public UxrAxis Perpendicular => (_axis + 1) % 3;
/// <summary>
/// Returns the other perpendicular axis.
/// </summary>
public UxrAxis OtherPerpendicular => (_axis + 2) % 3;
#endregion
#region Constructors & Finalizer
/// <summary>
/// Constructor.
/// </summary>
/// <param name="axis">Axis as an integer value</param>
public UxrAxis(int axis)
{
#if UNITY_EDITOR
if (axis < 0 || axis > 3)
{
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Errors)
{
Debug.LogError($"{UxrConstants.CoreModule} Assigning invalid value to axis: {axis}");
}
}
#endif
_axis = Mathf.Clamp(axis, 0, 2);
}
#endregion
#region Implicit IEquatable<UxrAxis>
/// <inheritdoc />
public bool Equals(UxrAxis other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return _axis == other._axis;
}
#endregion
#region Public Overrides object
/// <inheritdoc />
public override string ToString()
{
return _axis switch
{
0 => "Right",
1 => "Up",
_ => "Forward"
};
}
/// <inheritdoc />
public override bool Equals(object obj)
{
return Equals(obj as UxrAxis);
}
/// <inheritdoc />
public override int GetHashCode()
{
return _axis.GetHashCode();
}
#endregion
#region Public Methods
/// <summary>
/// Returns the remaining axis which is not axis1 nor axis2.
/// </summary>
/// <param name="axis1">Axis 1</param>
/// <param name="axis2">Axis 2</param>
/// <returns>The remaining axis which is not axis1 nor axis2</returns>
public static UxrAxis OtherThan(UxrAxis axis1, UxrAxis axis2)
{
if (axis1 == axis2)
{
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Errors)
{
Debug.LogError($"{UxrConstants.CoreModule} {nameof(UxrAxis)}: Got same axis for {nameof(OtherThan)} (axis1)");
}
return axis1.Perpendicular;
}
int smaller = axis1._axis < axis2._axis ? axis1._axis : axis2._axis;
int bigger = axis1._axis > axis2._axis ? axis1._axis : axis2._axis;
if (smaller == 0 && bigger == 1)
{
return 2;
}
if (smaller == 0 && bigger == 2)
{
return 1;
}
return 0;
}
/// <summary>
/// Gets the color representing
/// </summary>
/// <param name="alpha"></param>
/// <returns></returns>
public Color GetColor(float alpha)
{
Vector3 axis = this;
return new Color(Mathf.Abs(axis.x), Mathf.Abs(axis.y), Mathf.Abs(axis.z), alpha);
}
#endregion
#region Operators
/// <summary>
/// Unary minus operator. Negates the axis value.
/// </summary>
/// <param name="axis">Axis to negate</param>
/// <returns>Negated axis</returns>
public static Vector3 operator -(UxrAxis axis)
{
return -(Vector3)axis;
}
/// <summary>
/// Implicit conversion from an <see cref="UxrAxis" /> to a <see cref="Vector3" />.
/// </summary>
/// <param name="axis">Axis to convert</param>
/// <returns>Converted <see cref="Vector3" /> value</returns>
public static implicit operator Vector3(UxrAxis axis)
{
return axis._axis switch
{
0 => Vector3.right,
1 => Vector3.up,
_ => Vector3.forward
};
}
/// <summary>
/// Implicit conversion from an integer to an <see cref="UxrAxis" />.
/// </summary>
/// <param name="axis">Integer to convert</param>
/// <returns>Converted <see cref="UxrAxis" /> value</returns>
public static implicit operator UxrAxis(int axis)
{
return new UxrAxis(axis);
}
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="a">Operand A</param>
/// <param name="b">Operand B</param>
/// <returns>Whether the two operands are equal</returns>
public static bool operator ==(UxrAxis a, UxrAxis b)
{
if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
{
return true;
}
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
{
return false;
}
return a.Equals(b);
}
/// <summary>
/// Inequality operator.
/// </summary>
/// <param name="a">Operand A</param>
/// <param name="b">Operand B</param>
/// <returns>Whether the two operands are different</returns>
public static bool operator !=(UxrAxis a, UxrAxis b)
{
return !(a == b);
}
/// <summary>
/// Implicit conversion from an <see cref="UxrAxis" /> to an integer.
/// </summary>
/// <param name="axis">Axis to convert</param>
/// <returns>Int value (0 = right, 1 = up, 2 = forward)</returns>
public static implicit operator int(UxrAxis axis)
{
return axis._axis;
}
#endregion
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 79ee905395498e5428d29fba7ef65416
timeCreated: 1538564096
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,193 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrMathUtils.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Extensions.Unity.Math;
using UnityEngine;
namespace UltimateXR.Core.Math
{
/// <summary>
/// Contains math computations involving elements that do not belong to a specific class.
/// Most math is available through extensions classes in namespaces such as
/// <see cref="UltimateXR.Extensions.System.Math">UltimateXR.Extensions.System.Math</see> or
/// <see cref="UltimateXR.Extensions.Unity.Math">UltimateXR.Extensions.Unity.Math</see>.
/// Math related to animation is also available through classes in namespaces such as
/// <see cref="UltimateXR.Animation.IK">UltimateXR.Animation.IK</see>,
/// <see cref="UltimateXR.Animation.Interpolation">UltimateXRAnimation.Interpolation</see> or
/// <see cref="UltimateXR.Animation.Splines">UltimateXR.Animation.Splines</see>.
/// This class will contain math functionality that cannot be assigned to any extensions class.
/// </summary>
public static class UxrMathUtils
{
#region Public Methods
/// <summary>
/// Tries to find the intersection(s) between a 2D line and a 2D circle
/// Code from: http://csharphelper.com/blog/2014/09/determine-where-a-line-intersects-a-circle-in-c/
/// </summary>
/// <param name="linePoint1">Point A in the line</param>
/// <param name="linePoint2">Point B in the line</param>
/// <param name="circlePos">Circle position</param>
/// <param name="radius">Circle radius</param>
/// <param name="intersection1">Intersection 1 result, if it exists</param>
/// <param name="intersection2">Intersection 2 result, if it exists</param>
/// <returns>Number of intersections found (0, 1 or 2)</returns>
public static int FindLineCircleIntersections2D(Vector2 linePoint1, Vector2 linePoint2, Vector2 circlePos, float radius, out Vector2 intersection1, out Vector2 intersection2)
{
float t;
float dx = linePoint2.x - linePoint1.x;
float dy = linePoint2.y - linePoint1.y;
float a = dx * dx + dy * dy;
float b = 2 * (dx * (linePoint1.x - circlePos.x) + dy * (linePoint1.y - circlePos.y));
float c = (linePoint1.x - circlePos.x) * (linePoint1.x - circlePos.x) + (linePoint1.y - circlePos.y) * (linePoint1.y - circlePos.y) - radius * radius;
float det = b * b - 4 * a * c;
if (a <= 0.0000001 || det < 0)
{
// No real solutions.
intersection1 = new Vector3(float.NaN, float.NaN);
intersection2 = new Vector3(float.NaN, float.NaN);
return 0;
}
if (det == 0)
{
// One solution.
t = -b / (2 * a);
intersection1 = new Vector3(linePoint1.x + t * dx, linePoint1.y + t * dy);
intersection2 = new Vector3(float.NaN, float.NaN);
return 1;
}
// Two solutions.
t = (-b + Mathf.Sqrt(det)) / (2 * a);
intersection1 = new Vector3(linePoint1.x + t * dx, linePoint1.y + t * dy);
t = (-b - Mathf.Sqrt(det)) / (2 * a);
intersection2 = new Vector3(linePoint1.x + t * dx, linePoint1.y + t * dy);
return 2;
}
/// <summary>
/// Applies to <paramref name="position" /> and <paramref name="rotation" /> the transformation to make a transform
/// defined by <paramref name="sourcePosition" /> and <paramref name="sourceRotation" /> move and rotate to
/// <paramref name="targetPosition" /> and <paramref name="targetRotation" />.
/// </summary>
/// <param name="position">Position to apply the transformation to</param>
/// <param name="rotation">Rotation to apply the transformation to</param>
/// <param name="sourcePosition">Source position that will try to match <paramref name="targetPosition" /></param>
/// <param name="sourceRotation">Source rotation that will try to match <paramref name="targetRotation" /></param>
/// <param name="targetPosition">Target position</param>
/// <param name="targetRotation">Target rotation</param>
/// <param name="rotate">Allows to control whether to rotate or not</param>
/// <param name="translate">Allows to control whether to translate or not</param>
/// <param name="t">Optional interpolation value [0.0, 1.0]</param>
public static void ApplyAlignment(ref Vector3 position,
ref Quaternion rotation,
Vector3 sourcePosition,
Quaternion sourceRotation,
Vector3 targetPosition,
Quaternion targetRotation,
bool rotate,
bool translate,
float t = 1.0f)
{
if (rotate)
{
rotation.ApplyAlignment(sourceRotation, targetRotation, t);
}
if (translate)
{
position += (targetPosition - sourcePosition) * t;
}
}
/// <summary>
/// Checks if a box is completely (all corners) inside a BoxCollider
/// </summary>
/// <param name="boxPosition">Position of the box to test if it is inside the BoxCollider</param>
/// <param name="boxRotation">Rotation of the box to test if it is inside the BoxCollider</param>
/// <param name="boxScale">Scale of the box to test if it is inside the BoxCollider</param>
/// <param name="boxCenter">Center of the box (in local coordinates) to test if it is inside the BoxCollider</param>
/// <param name="boxSize">Size of the box (in local coordinates) to test if it is inside the BoxCollider</param>
/// <param name="boxVolume">BoxCollider to test against</param>
/// <param name="margin">Allowed margin for each x, y, z component</param>
/// <returns>True if all corners are inside the BoxCollider plus margin</returns>
public static bool IsBoxInsideBox(Vector3 boxPosition, Quaternion boxRotation, Vector3 boxScale, Vector3 boxCenter, Vector3 boxSize, BoxCollider boxVolume, Vector3 margin = default)
{
Matrix4x4 boxMatrix = Matrix4x4.TRS(boxPosition, boxRotation, boxScale);
Vector3[] corners = new Vector3[8];
corners[0] = boxMatrix.MultiplyPoint(boxCenter + new Vector3(+boxSize.x, +boxSize.y, +boxSize.z) * 0.5f);
corners[1] = boxMatrix.MultiplyPoint(boxCenter + new Vector3(+boxSize.x, +boxSize.y, -boxSize.z) * 0.5f);
corners[2] = boxMatrix.MultiplyPoint(boxCenter + new Vector3(+boxSize.x, -boxSize.y, +boxSize.z) * 0.5f);
corners[3] = boxMatrix.MultiplyPoint(boxCenter + new Vector3(+boxSize.x, -boxSize.y, -boxSize.z) * 0.5f);
corners[4] = boxMatrix.MultiplyPoint(boxCenter + new Vector3(-boxSize.x, +boxSize.y, +boxSize.z) * 0.5f);
corners[5] = boxMatrix.MultiplyPoint(boxCenter + new Vector3(-boxSize.x, +boxSize.y, -boxSize.z) * 0.5f);
corners[6] = boxMatrix.MultiplyPoint(boxCenter + new Vector3(-boxSize.x, -boxSize.y, +boxSize.z) * 0.5f);
corners[7] = boxMatrix.MultiplyPoint(boxCenter + new Vector3(-boxSize.x, -boxSize.y, -boxSize.z) * 0.5f);
for (int i = 0; i < 8; ++i)
{
if (!corners[i].IsInsideBox(boxVolume, margin))
{
return false;
}
}
return true;
}
/// <summary>
/// Checks if box1 is completely (all corners) inside box2
/// </summary>
/// <param name="box1Position">Position of box1</param>
/// <param name="box1Rotation">Rotation of box1</param>
/// <param name="box1Scale">Scale of box1</param>
/// <param name="box1Center">Center of box1 in its own local coordinates</param>
/// <param name="box1Size">Size of box1 in its own local coordinates</param>
/// <param name="box2Position">Position of box2</param>
/// <param name="box2Rotation">Rotation of box2</param>
/// <param name="box2Scale">Scale of box2</param>
/// <param name="box2Center">Center of box2 in its own local coordinates</param>
/// <param name="box2Size">Size of box2 in its own local coordinates</param>
/// <param name="margin">Allowed margin for each x, y, z component</param>
/// <returns>True if all corners of box1 are inside box2 plus margin</returns>
public static bool IsBoxInsideBox(Vector3 box1Position,
Quaternion box1Rotation,
Vector3 box1Scale,
Vector3 box1Center,
Vector3 box1Size,
Vector3 box2Position,
Quaternion box2Rotation,
Vector3 box2Scale,
Vector3 box2Center,
Vector3 box2Size,
Vector3 margin = default)
{
Matrix4x4 boxMatrix = Matrix4x4.TRS(box1Position, box1Rotation, box1Scale);
Vector3[] corners = new Vector3[8];
corners[0] = boxMatrix.MultiplyPoint(box1Center + new Vector3(+box1Size.x, +box1Size.y, +box1Size.z) * 0.5f);
corners[1] = boxMatrix.MultiplyPoint(box1Center + new Vector3(+box1Size.x, +box1Size.y, -box1Size.z) * 0.5f);
corners[2] = boxMatrix.MultiplyPoint(box1Center + new Vector3(+box1Size.x, -box1Size.y, +box1Size.z) * 0.5f);
corners[3] = boxMatrix.MultiplyPoint(box1Center + new Vector3(+box1Size.x, -box1Size.y, -box1Size.z) * 0.5f);
corners[4] = boxMatrix.MultiplyPoint(box1Center + new Vector3(-box1Size.x, +box1Size.y, +box1Size.z) * 0.5f);
corners[5] = boxMatrix.MultiplyPoint(box1Center + new Vector3(-box1Size.x, +box1Size.y, -box1Size.z) * 0.5f);
corners[6] = boxMatrix.MultiplyPoint(box1Center + new Vector3(-box1Size.x, -box1Size.y, +box1Size.z) * 0.5f);
corners[7] = boxMatrix.MultiplyPoint(box1Center + new Vector3(-box1Size.x, -box1Size.y, -box1Size.z) * 0.5f);
for (int i = 0; i < 8; ++i)
{
if (!corners[i].IsInsideBox(box2Position, box2Rotation, box2Scale, box2Center, box2Size, margin))
{
return false;
}
}
return true;
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 94fda00f50a40c245b7a2825b2448da9
timeCreated: 1501489697
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,317 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrUniversalLocalAxes.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Extensions.Unity.Math;
using UnityEngine;
namespace UltimateXR.Core.Math
{
/// <summary>
/// <para>
/// Different parts of the framework need to deal with axes. These algorithms like IK solvers or avatar
/// components need to know exactly where 'forward' is or which axis points to the right in avatar-space.
/// Since modelling packages and artists may rig objects using arbitrary coordinate systems we need a way to
/// perform operations in a way that takes this into account. The code also needs to remain readable since many
/// math operations may increase complexity. Readability is favoured here over performance.
/// </para>
/// <para>
/// This class allows to transform from arbitrary coordinate systems to a universal one where different rotations
/// can then be performed and vice versa.
/// One example would be a finger bone curl. We create the convention that forward is the axis from one bone to
/// the next, up points upwards and right would be the axis around which the bone should rotate to curl. This is OK
/// but now we face the problem that different modelling packages or artists rig fingers in completely different
/// ways using all varieties of axis systems. The purpose of this class is to help creating a system where
/// operations can be performed in this universal system to follow our conventions and then rotated "back" to any
/// kind of coordinate system afterwards.
/// </para>
/// <para>
/// tl;dr A class that helps us operate with rotations and angles of an object no matter which convention the
/// 3D assets use. We call 'Universal' the coordinate system we use as convention for our computations, we then
/// can use <see cref="UniversalToActualAxesRotation" /> to transform the object back to its actual axes.
/// This way our computations do not care which coordinate system the assets use, and is essential to simplify
/// operations like inverse kinematics or angle computations.
/// </para>
/// </summary>
[Serializable]
public class UxrUniversalLocalAxes
{
#region Inspector Properties/Serialized Fields
[SerializeField] private Transform _transform;
[SerializeField] private Vector3 _localRight = Vector3.right;
[SerializeField] private Vector3 _localUp = Vector3.up;
[SerializeField] private Vector3 _localForward = Vector3.forward;
[SerializeField] private Quaternion _universalToActualAxesRotation = Quaternion.identity;
[SerializeField] private Quaternion _initialRotation = Quaternion.identity;
[SerializeField] private Quaternion _initialLocalRotation = Quaternion.identity;
[SerializeField] private Quaternion _initialLocalReferenceRotation = Quaternion.identity;
[SerializeField] private Quaternion _initialUniversalLocalReferenceRotation = Quaternion.identity;
[SerializeField] private Vector3 _initialPosition = Vector3.zero;
[SerializeField] private Vector3 _initialLocalPosition = Vector3.zero;
#endregion
#region Public Types & Data
/// <summary>
/// Gets the universal 'right' direction in world space.
/// </summary>
public Vector3 WorldRight => _transform.TransformDirection(LocalRight);
/// <summary>
/// Gets the universal 'up' direction in world space.
/// </summary>
public Vector3 WorldUp => _transform.TransformDirection(LocalUp);
/// <summary>
/// Gets the universal 'forward' direction in world space.
/// </summary>
public Vector3 WorldForward => _transform.TransformDirection(LocalForward);
/// <summary>
/// Gets the local object rotation in universal convention
/// </summary>
public Quaternion UniversalLocalRotation => _transform.localRotation * Quaternion.Inverse(UniversalToActualAxesRotation);
/// <summary>
/// Gets the object rotation in universal convention
/// </summary>
public Quaternion UniversalRotation => _transform.rotation * Quaternion.Inverse(UniversalToActualAxesRotation);
/// <summary>
/// Gets the universal 'right' direction in transform's local space.
/// </summary>
public Vector3 LocalRight
{
get => _localRight;
private set => _localRight = value;
}
/// <summary>
/// Gets the universal 'up' direction in transform's local space.
/// </summary>
public Vector3 LocalUp
{
get => _localUp;
private set => _localUp = value;
}
/// <summary>
/// Gets the universal 'forward' direction in transform's local space.
/// </summary>
public Vector3 LocalForward
{
get => _localForward;
private set => _localForward = value;
}
/// <summary>
/// Gets the rotation that transforms from the universal axes to the convention that the transform follows.
/// <example>
/// <code>
/// // universalRotation may be a rotation around the y axis, where we know
/// // exactly that y points upwards in that space.
/// // This rotation will rotate an object around the "universal" y axis no
/// // matter where his actual axes point to.
/// transform.rotation = universalRotation * UniversalToActualAxesRotation;
/// </code>
/// </example>
/// </summary>
public Quaternion UniversalToActualAxesRotation
{
get => _universalToActualAxesRotation;
private set => _universalToActualAxesRotation = value;
}
/// <summary>
/// Gets the transform's rotation at the time of setting the object up.
/// </summary>
public Quaternion InitialRotation
{
get => _initialRotation;
private set => _initialRotation = value;
}
/// <summary>
/// Gets the transform's local rotation at the time of setting the object up.
/// </summary>
public Quaternion InitialLocalRotation
{
get => _initialLocalRotation;
private set => _initialLocalRotation = value;
}
/// <summary>
/// Gets the transform's rotation with respect to the reference transform at the time of setting the object up.
/// This will only contain a rotation when the constructor using a reference transform was used.
/// </summary>
public Quaternion InitialLocalReferenceRotation
{
get => _initialLocalReferenceRotation;
private set => _initialLocalReferenceRotation = value;
}
/// <summary>
/// Gets the transform's rotation (in universal coordinates) with respect to the reference transform at the time of
/// setting the object up.
/// This will only contain a rotation when the constructor using a reference transform was used.
/// </summary>
public Quaternion InitialUniversalLocalReferenceRotation
{
get => _initialUniversalLocalReferenceRotation;
private set => _initialUniversalLocalReferenceRotation = value;
}
/// <summary>
/// Gets the transform's position at the time of setting the object up.
/// </summary>
public Vector3 InitialPosition
{
get => _initialPosition;
private set => _initialPosition = value;
}
/// <summary>
/// Gets the transform's local position at the time of setting the object up.
/// </summary>
public Vector3 InitialLocalPosition
{
get => _initialLocalPosition;
private set => _initialLocalPosition = value;
}
#endregion
#region Constructors & Finalizer
/// <summary>
/// Constructor.
/// Uses universalReference to check which axes of a transform are actually the ones
/// that are right, up and forward. For example, universalReference may be the avatar
/// root where we know that right, up and forward point to these actual directions and
/// we want to know which axes of an upper body part point to these directions too.
/// These may be completely different depending on the modelling package or artist.
/// Using this class we can easily check which one points upwards and create a small
/// chest torsion by rotating around this axis.
/// </summary>
/// <param name="transform">Transform to create the universal axes for</param>
/// <param name="universalReference">
/// The transform to use as a reference for the universal right, up and forward directions.
/// </param>
public UxrUniversalLocalAxes(Transform transform, Transform universalReference)
{
_transform = transform;
LocalRight = transform.InverseTransformDirection(universalReference != null ? universalReference.right : Vector3.right).GetClosestAxis();
LocalUp = transform.InverseTransformDirection(universalReference != null ? universalReference.up : Vector3.up).GetClosestAxis();
LocalForward = transform.InverseTransformDirection(universalReference != null ? universalReference.forward : Vector3.forward).GetClosestAxis();
UniversalToActualAxesRotation = GetUniversalToActualAxesRotation();
InitialRotation = transform.rotation;
InitialLocalRotation = transform.localRotation;
InitialLocalReferenceRotation = Quaternion.Inverse(universalReference.rotation) * transform.rotation;
InitialUniversalLocalReferenceRotation = InitialLocalReferenceRotation * Quaternion.Inverse(UniversalToActualAxesRotation);
InitialPosition = transform.position;
InitialLocalPosition = transform.localPosition;
}
/// <summary>
/// Default constructor is private to make it inaccessible.
/// </summary>
private UxrUniversalLocalAxes()
{
}
#endregion
#region Public Methods
/// <summary>
/// Creates a UniversalLocalAxes object describing the universal local axes for the given transform.
/// </summary>
/// <param name="transform">The transform the UniversalLocalAxes object is for</param>
/// <param name="universalLocalRight">
/// Which vector in the transform local coordinates points to the 'right' direction in the universal convention
/// </param>
/// <param name="universalLocalUp">
/// Which vector in the transform local coordinates points to the 'up' direction in the universal convention
/// </param>
/// <param name="universalLocalForward">
/// Which vector in the transform local coordinates points to the 'forward' direction in the universal convention
/// </param>
/// <returns>
/// UniversalLocalAxes object that allows us to compute object rotations in a universal
/// space and then apply it to a transform that can have any kind of axis convention
/// (x may point up, z down...)
/// </returns>
public static UxrUniversalLocalAxes FromAxes(Transform transform, Vector3 universalLocalRight, Vector3 universalLocalUp, Vector3 universalLocalForward)
{
UxrUniversalLocalAxes localAxes = new UxrUniversalLocalAxes();
localAxes._transform = transform;
localAxes.LocalRight = universalLocalRight;
localAxes.LocalUp = universalLocalUp;
localAxes.LocalForward = universalLocalForward;
localAxes.InitialRotation = transform.rotation;
localAxes.InitialLocalRotation = transform.localRotation;
localAxes.InitialLocalReferenceRotation = Quaternion.identity;
localAxes.InitialUniversalLocalReferenceRotation = Quaternion.identity;
localAxes.InitialPosition = transform.position;
localAxes.InitialLocalPosition = transform.localPosition;
localAxes.UniversalToActualAxesRotation = localAxes.GetUniversalToActualAxesRotation();
return localAxes;
}
/// <summary>
/// See <see cref="FromAxes" />.
/// </summary>
public static UxrUniversalLocalAxes FromRightUp(Transform transform, Vector3 universalLocalRight, Vector3 universalLocalUp)
{
return FromAxes(transform, universalLocalRight, universalLocalUp, Vector3.Cross(universalLocalRight, universalLocalUp));
}
/// <summary>
/// See <see cref="FromAxes" />.
/// </summary>
public static UxrUniversalLocalAxes FromRightForward(Transform transform, Vector3 universalLocalRight, Vector3 universalLocalForward)
{
return FromAxes(transform, universalLocalRight, Vector3.Cross(universalLocalForward, universalLocalRight), universalLocalForward);
}
/// <summary>
/// See <see cref="FromAxes" />.
/// </summary>
public static UxrUniversalLocalAxes FromUpForward(Transform transform, Vector3 universalLocalUp, Vector3 universalLocalForward)
{
return FromAxes(transform, Vector3.Cross(universalLocalUp, universalLocalForward), universalLocalUp, universalLocalForward);
}
#endregion
#region Private Methods
/// <summary>
/// Computes the rotation that transforms from the universal coordinate system to the convention that the transform
/// follows.
/// </summary>
private Quaternion GetUniversalToActualAxesRotation()
{
Matrix4x4 matrix = new Matrix4x4();
matrix.SetColumn(0, LocalRight);
matrix.SetColumn(1, LocalUp);
matrix.SetColumn(2, LocalForward);
matrix.SetColumn(3, new Vector4(0, 0, 0, 1));
return Quaternion.Inverse(matrix.rotation);
}
#endregion
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 92dff33db2971124397cffe499bf092a
timeCreated: 1549525217
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: