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; } } }