VR4Medical/ICI/Library/PackageCache/com.unity.xr.interaction.toolkit@42ef3600567b/Runtime/Locomotion/XRBodyTransformations.cs
2025-07-29 13:45:50 +03:00

179 lines
7.6 KiB
C#

using System;
using Unity.XR.CoreUtils;
namespace UnityEngine.XR.Interaction.Toolkit.Locomotion
{
/// <summary>
/// Body transformation that invokes a delegate when applied.
/// </summary>
public class DelegateXRBodyTransformation : IXRBodyTransformation
{
/// <summary>
/// Invoked when <see cref="Apply"/> is called. Use this to perform the actual transformation.
/// </summary>
public event Action<XRMovableBody> transformation;
/// <summary>
/// Constructs a new transformation.
/// </summary>
public DelegateXRBodyTransformation()
{
}
/// <summary>
/// Constructs a new transformation with the specified delegate.
/// </summary>
/// <param name="transformation">The delegate to be invoked when <see cref="Apply"/> is called.</param>
public DelegateXRBodyTransformation(Action<XRMovableBody> transformation)
{
this.transformation = transformation;
}
/// <inheritdoc/>
public void Apply(XRMovableBody body)
{
transformation?.Invoke(body);
}
}
/// <summary>
/// Transformation that translates the target's <see cref="XRMovableBody.originTransform"/> by the specified amount.
/// </summary>
public class XROriginMovement : IXRBodyTransformation
{
/// <summary>
/// Amount of translation to apply to the <see cref="XRMovableBody.originTransform"/>.
/// </summary>
public Vector3 motion { get; set; }
/// <summary>
/// Whether to ignore <see cref="XRMovableBody.constrainedManipulator"/> even if it is set.
/// Defaults to <see langword="false"/> to use the movement constraints if configured to.
/// </summary>
/// <remarks>
/// Setting this to <see langword="true"/> will mean the body will always be moved using the Transform component directly.
/// Setting this to <see langword="false"/> will use <see cref="IConstrainedXRBodyManipulator.MoveBody"/> to move the Origin
/// if the <see cref="XRMovableBody.constrainedManipulator"/> is not <see langword="null"/>, and otherwise use the Transform component.
/// </remarks>
public bool forceUnconstrained { get; set; }
/// <inheritdoc/>
public virtual void Apply(XRMovableBody body)
{
if (body.constrainedManipulator != null && !forceUnconstrained)
body.constrainedManipulator.MoveBody(motion);
else
body.originTransform.position += motion;
}
}
/// <summary>
/// Transformation that moves the target's <see cref="XRMovableBody.originTransform"/> such that the world position
/// of where the user's body is grounded matches the specified position. The body ground position is determined by
/// the target's <see cref="XRMovableBody.bodyPositionEvaluator"/>.
/// </summary>
public class XRBodyGroundPosition : IXRBodyTransformation
{
/// <summary>
/// World position that the user's body ground position should be at.
/// </summary>
public Vector3 targetPosition { get; set; }
/// <inheritdoc/>
public virtual void Apply(XRMovableBody body)
{
var origin = body.originTransform;
origin.position = targetPosition + origin.position - body.GetBodyGroundWorldPosition();
}
}
/// <summary>
/// Transformation that rotates the target's <see cref="XRMovableBody.originTransform"/> such that its up vector
/// matches the specified vector. Note that this does not maintain the world position of the user's body.
/// </summary>
public class XROriginUpAlignment : IXRBodyTransformation
{
/// <summary>
/// Vector that the <see cref="XRMovableBody.originTransform"/>'s up vector should match.
/// </summary>
public Vector3 targetUp { get; set; }
/// <inheritdoc/>
public virtual void Apply(XRMovableBody body)
{
body.xrOrigin.MatchOriginUp(targetUp);
}
}
/// <summary>
/// Transformation that rotates the target's <see cref="XRMovableBody.originTransform"/> by the specified amount
/// about the axis aligned with the Origin's up vector and passing through the world position of where the user's
/// body is grounded. The body ground position is determined by the target's <see cref="XRMovableBody.bodyPositionEvaluator"/>.
/// </summary>
public class XRBodyYawRotation : IXRBodyTransformation
{
/// <summary>
/// Amount in degrees to rotate the <see cref="XRMovableBody.originTransform"/>.
/// </summary>
public float angleDelta { get; set; }
/// <inheritdoc/>
public virtual void Apply(XRMovableBody body)
{
var origin = body.originTransform;
origin.RotateAround(body.GetBodyGroundWorldPosition(), origin.up, angleDelta);
}
}
/// <summary>
/// Transformation that rotates the target's <see cref="XRMovableBody.originTransform"/> about the axis aligned with
/// the Origin's up vector and passing through the world position of the <see cref="XROrigin.Camera"/>, such that
/// the projection of the camera's forward vector onto the Origin's XZ plane matches the projection of the specified
/// vector onto the Origin's XZ plane.
/// </summary>
public class XRCameraForwardXZAlignment : IXRBodyTransformation
{
/// <summary>
/// Vector that the forward vector of the <see cref="XROrigin.Camera"/> should match when both are projected
/// onto the XZ plane of the <see cref="XRMovableBody.originTransform"/>.
/// </summary>
public Vector3 targetDirection { get; set; }
/// <inheritdoc/>
public virtual void Apply(XRMovableBody body)
{
var xrOrigin = body.xrOrigin;
var originUp = body.originTransform.up;
var projectedCamForward = Vector3.ProjectOnPlane(xrOrigin.Camera.transform.forward, originUp).normalized;
var projectedTargetForward = Vector3.ProjectOnPlane(targetDirection, originUp).normalized;
var signedAngle = Vector3.SignedAngle(projectedCamForward, projectedTargetForward, originUp);
xrOrigin.RotateAroundCameraPosition(originUp, signedAngle);
}
}
/// <summary>
/// Transformation that sets the uniform local scale of the target's <see cref="XRMovableBody.originTransform"/> to
/// the specified value, and then repositions the Origin such that the world position of where the user's body is
/// grounded remains the same. The body ground position is determined by the target's
/// <see cref="XRMovableBody.bodyPositionEvaluator"/>.
/// </summary>
public class XRBodyScale : IXRBodyTransformation
{
/// <summary>
/// Uniform value to scale the <see cref="XRMovableBody.originTransform"/> to. The local scale of the Origin
/// will be set to <see cref="Vector3.one"/> multiplied by this value.
/// </summary>
public float uniformScale { get; set; }
/// <inheritdoc/>
public virtual void Apply(XRMovableBody body)
{
var bodyGroundPositionBeforeScale = body.GetBodyGroundWorldPosition();
var origin = body.originTransform;
origin.localScale = Vector3.one * uniformScale;
var bodyGroundPositionAfterScale = body.GetBodyGroundWorldPosition();
origin.position = bodyGroundPositionBeforeScale + origin.position - bodyGroundPositionAfterScale;
}
}
}