using System;
using Unity.XR.CoreUtils;
namespace UnityEngine.XR.Interaction.Toolkit.Locomotion
{
///
/// Body transformation that invokes a delegate when applied.
///
public class DelegateXRBodyTransformation : IXRBodyTransformation
{
///
/// Invoked when is called. Use this to perform the actual transformation.
///
public event Action transformation;
///
/// Constructs a new transformation.
///
public DelegateXRBodyTransformation()
{
}
///
/// Constructs a new transformation with the specified delegate.
///
/// The delegate to be invoked when is called.
public DelegateXRBodyTransformation(Action transformation)
{
this.transformation = transformation;
}
///
public void Apply(XRMovableBody body)
{
transformation?.Invoke(body);
}
}
///
/// Transformation that translates the target's by the specified amount.
///
public class XROriginMovement : IXRBodyTransformation
{
///
/// Amount of translation to apply to the .
///
public Vector3 motion { get; set; }
///
/// Whether to ignore even if it is set.
/// Defaults to to use the movement constraints if configured to.
///
///
/// Setting this to will mean the body will always be moved using the Transform component directly.
/// Setting this to will use to move the Origin
/// if the is not , and otherwise use the Transform component.
///
public bool forceUnconstrained { get; set; }
///
public virtual void Apply(XRMovableBody body)
{
if (body.constrainedManipulator != null && !forceUnconstrained)
body.constrainedManipulator.MoveBody(motion);
else
body.originTransform.position += motion;
}
}
///
/// Transformation that moves the target's 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 .
///
public class XRBodyGroundPosition : IXRBodyTransformation
{
///
/// World position that the user's body ground position should be at.
///
public Vector3 targetPosition { get; set; }
///
public virtual void Apply(XRMovableBody body)
{
var origin = body.originTransform;
origin.position = targetPosition + origin.position - body.GetBodyGroundWorldPosition();
}
}
///
/// Transformation that rotates the target's such that its up vector
/// matches the specified vector. Note that this does not maintain the world position of the user's body.
///
public class XROriginUpAlignment : IXRBodyTransformation
{
///
/// Vector that the 's up vector should match.
///
public Vector3 targetUp { get; set; }
///
public virtual void Apply(XRMovableBody body)
{
body.xrOrigin.MatchOriginUp(targetUp);
}
}
///
/// Transformation that rotates the target's 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 .
///
public class XRBodyYawRotation : IXRBodyTransformation
{
///
/// Amount in degrees to rotate the .
///
public float angleDelta { get; set; }
///
public virtual void Apply(XRMovableBody body)
{
var origin = body.originTransform;
origin.RotateAround(body.GetBodyGroundWorldPosition(), origin.up, angleDelta);
}
}
///
/// Transformation that rotates the target's about the axis aligned with
/// the Origin's up vector and passing through the world position of the , 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.
///
public class XRCameraForwardXZAlignment : IXRBodyTransformation
{
///
/// Vector that the forward vector of the should match when both are projected
/// onto the XZ plane of the .
///
public Vector3 targetDirection { get; set; }
///
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);
}
}
///
/// Transformation that sets the uniform local scale of the target's 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
/// .
///
public class XRBodyScale : IXRBodyTransformation
{
///
/// Uniform value to scale the to. The local scale of the Origin
/// will be set to multiplied by this value.
///
public float uniformScale { get; set; }
///
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;
}
}
}