Body/CameraHardLock.cs
namespace MANIFOLD.Camera {
/// <summary>
/// Locks the <see cref="VirtualCamera"/> to it's <see cref="VirtualCamera.TrackingTarget"/>.
/// </summary>
[Title(LibraryData.TITLE_SPLIT + "Hard Lock"), Category(LibraryData.CATEGORY), Icon("lock")]
public sealed class CameraHardLock : CameraExtension {
public enum OrientMode {
/// <summary>
/// The target's orientation is not taken into account.
/// </summary>
None,
/// <summary>
/// The target's orientation only affects the position.
/// </summary>
[Title("Position Only")]
NoRotation,
/// <summary>
/// The target's orientation affects both position and rotation.
/// </summary>
[Title("Position and Rotation")]
Full
}
/// <summary>
/// How should the Target's orientation be handled?
/// </summary>
[Property, Title("Orientation Handling")]
public OrientMode Orient { get; set; } = OrientMode.Full;
private GameObject lastTarget;
private Vector3 targetBindRelativePos;
private Vector3 targetBindLocalPos;
private Rotation targetBindLocalRot;
protected internal override void OnCameraInitialize() {
if (!Camera.TrackingTarget.IsValid()) return;
BindValues();
}
protected internal override void OnCameraUpdate(ref Vector3 localPosition, ref Rotation localRotation) {
if (!Camera.TrackingTarget.IsValid()) return;
if (Camera.TrackingTarget != lastTarget) {
BindValues();
}
GameObject target = Camera.TrackingTarget;
switch (Orient) {
case OrientMode.None: {
Camera.WorldPosition = target.WorldPosition + targetBindRelativePos;
break;
}
case OrientMode.NoRotation: {
Camera.WorldPosition = target.WorldPosition + (targetBindLocalPos * target.WorldRotation);
break;
}
case OrientMode.Full: {
Camera.WorldPosition = target.WorldPosition + (targetBindLocalPos * target.WorldRotation);
Camera.WorldRotation = target.WorldRotation * targetBindLocalRot;
break;
}
}
}
private void BindValues() {
lastTarget = Camera.TrackingTarget;
targetBindRelativePos = WorldPosition - Camera.TrackingTarget.WorldPosition;
Rotation inverse = Camera.TrackingTarget.WorldRotation.Inverse;
targetBindLocalRot = WorldRotation * inverse;
targetBindLocalPos = (WorldPosition - Camera.TrackingTarget.WorldPosition) * inverse;
}
}
}