Skip to content

Commit

Permalink
Rename to SplineDollyLookAtTargets
Browse files Browse the repository at this point in the history
  • Loading branch information
glabute committed May 15, 2024
1 parent 57451e1 commit 2374839
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# LookAt Data On Spline
# Cinemachine Spline Dolly LookAt Targets

This CinemachineCamera __Rotation Control__ behaviour lets you assign LookAt targets to points on a spline, so that as the camera arrives at the position on the spline, it looks at the specified place.

Expand All @@ -10,7 +10,7 @@ To use this behaviour, select it in the Rotation Control section of the Cinemach

When the LookAtDataOnSpline is selected in the inspector, a Scene View tool is provided to position the LookAt targets along the spline. The tool lets you add, remove, and reposition LookAt targets.

![LookAt Data On Spline Tool](images/LookAtDataOnSplineTool.png)
![Spline Dolly LookAt Targets Tool](images/CinemachineSplineDollyLookAtTargetsTool.png)


### Properties
Expand All @@ -20,7 +20,7 @@ When the LookAtDataOnSpline is selected in the inspector, a Scene View tool is p
| __Index Unit__ | | Defines how to interpret the _Index_ field for each data point. _Knot_ is the recommended value because it remains robust if the spline points change. |
| __Data Points__ | | The list of markup points on the spline. As the camera approaches these points, the corresponding fields will come into effect. |
| | _Index_ | The position on the Spline where the camera should look at the supplied point. The value is interpreted according to the _Index Unit_ setting. |
| | _Look At Target_ | The target object to look at. It may be None, in which case the LookAt pont will specify a point in world space. |
| | _Look At Target_ | The target object to look at. It may be None, in which case the LookAt point will specify a point in world space. |
| | _Offset_ | The offset (in local coords) from the LookAt target's origin. If LookAt target is None, this will specify a world-space point. |
| | _Easing_ | Controls how to ease in and out of this target. A value of 0 will linearly interpolate between LookAt points, while a value of 1 will slow down and briefly pause the rotation to look at the target. |

Expand Down
2 changes: 1 addition & 1 deletion com.unity.cinemachine/Documentation~/TableOfContents.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
* [Cinemachine Impulse Source](CinemachineImpulseSource.md)
* [Cinemachine Input Axis Controller](CinemachineInputAxisController.md)
* [Cinemachine Mixing Camera](CinemachineMixingCamera.md)
* [Cinemachine LookAt Data On Spline](CinemachineLookAtDataOnSpline.md)
* [Cinemachine Orbital Follow](CinemachineOrbitalFollow.md)
* [Cinemachine Pan Tilt](CinemachinePanTilt.md)
* [Cinemachine Pixel Perfect](CinemachinePixelPerfect.md)
Expand All @@ -74,6 +73,7 @@
* [Cinemachine Shot Quality Evaluator](CinemachineShotQualityEvaluator.md)
* [Cinemachine Spline Cart](CinemachineSplineCart.md)
* [Cinemachine Spline Dolly](CinemachineSplineDolly.md)
* [Cinemachine Spline Dolly LookAt Targets](CinemachineSplineDollyLookAtTargets.md)
* [Cinemachine Spline Roll](CinemachineSplineRoll.md)
* [Cinemachine State-Driven camera](CinemachineStateDrivenCamera.md)
* [Cinemachine Storyboard](CinemachineStoryboard.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Unity.Cinemachine.Editor
{
[CustomEditor(typeof(CinemachineLookAtDataOnSpline))]
[CustomEditor(typeof(CinemachineSplineDollyLookAtTargets))]
[CanEditMultipleObjects]
class CinemachineLookAtDataOnSplineEditor : CinemachineComponentBaseEditor
{
Expand All @@ -17,7 +17,7 @@ public override VisualElement CreateInspectorGUI()
var ux = new VisualElement();
this.AddMissingCmCameraHelpBox(ux);

var splineData = target as CinemachineLookAtDataOnSpline;
var splineData = target as CinemachineSplineDollyLookAtTargets;
var invalidHelp = new HelpBox(
"This component requires a CinemachineSplineDolly component referencing a nonempty Spline",
HelpBoxMessageType.Warning);
Expand All @@ -28,7 +28,7 @@ public override VisualElement CreateInspectorGUI()
{ text = "Edit Data Points in Scene View" });
ux.AddSpace();

var property = serializedObject.FindProperty(() => splineData.LookAtData);
var property = serializedObject.FindProperty(() => splineData.Targets);
ux.Add(new PropertyField(property.FindPropertyRelative("m_IndexUnit"))
{ tooltip = "Defines how to interpret the Index field for each data point. "
+ "Knot is the recommended value because it remains robust if the spline points change." });
Expand All @@ -41,21 +41,21 @@ public override VisualElement CreateInspectorGUI()
}

[DrawGizmo(GizmoType.Active | GizmoType.NotInSelectionHierarchy
| GizmoType.InSelectionHierarchy | GizmoType.Pickable, typeof(CinemachineLookAtDataOnSpline))]
static void DrawGizmos(CinemachineLookAtDataOnSpline splineData, GizmoType selectionType)
| GizmoType.InSelectionHierarchy | GizmoType.Pickable, typeof(CinemachineSplineDollyLookAtTargets))]
static void DrawGizmos(CinemachineSplineDollyLookAtTargets splineData, GizmoType selectionType)
{
// For performance reasons, we only draw a gizmo for the current active game object
if (Selection.activeGameObject == splineData.gameObject && splineData.LookAtData.Count > 0
if (Selection.activeGameObject == splineData.gameObject && splineData.Targets.Count > 0
&& splineData.GetTargets(out var spline, out _) && spline.Spline != null)
{
Gizmos.color = CinemachineCorePrefs.BoundaryObjectGizmoColour.Value;

var indexUnit = splineData.LookAtData.PathIndexUnit;
for (int i = 0; i < splineData.LookAtData.Count; i++)
var indexUnit = splineData.Targets.PathIndexUnit;
for (int i = 0; i < splineData.Targets.Count; i++)
{
var t = SplineUtility.GetNormalizedInterpolation(spline.Spline, splineData.LookAtData[i].Index, indexUnit);
var t = SplineUtility.GetNormalizedInterpolation(spline.Spline, splineData.Targets[i].Index, indexUnit);
spline.Evaluate(t, out var position, out _, out _);
var p = splineData.LookAtData[i].Value.WorldLookAt;
var p = splineData.Targets[i].Value.WorldLookAt;
Gizmos.DrawLine(position, p);
Gizmos.DrawSphere(p, HandleUtility.GetHandleSize(p) * 0.1f);

Expand All @@ -64,7 +64,7 @@ static void DrawGizmos(CinemachineLookAtDataOnSpline splineData, GizmoType selec
{
var oldColor = Gizmos.color;
Gizmos.color = Color.white;
var it = new CinemachineLookAtDataOnSpline.LerpItem();
var it = new CinemachineSplineDollyLookAtTargets.LerpItem();
for (float j = 0; j < 1f; j += 0.05f)
{
var item = it.Interpolate(splineData.LookAtData[i-1].Value, splineData.LookAtData[i].Value, j);
Expand All @@ -80,31 +80,30 @@ static void DrawGizmos(CinemachineLookAtDataOnSpline splineData, GizmoType selec
}
}

[CustomPropertyDrawer(typeof(DataPoint<CinemachineLookAtDataOnSpline.Item>))]
[CustomPropertyDrawer(typeof(DataPoint<CinemachineSplineDollyLookAtTargets.Item>))]
class CinemachineLookAtDataOnSplineItemPropertyDrawer : PropertyDrawer
{
Transform m_LastLookAtTarget;

public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
const string indexTooltip = "The position on the Spline at which this data point will take effect. "
+ "The value is interpreted according to the Index Unit setting.";

CinemachineLookAtDataOnSpline.Item def = new ();
CinemachineSplineDollyLookAtTargets.Item def = new ();
var indexProp = property.FindPropertyRelative("m_Index");
var valueProp = property.FindPropertyRelative("m_Value");
var lookAtProp = valueProp.FindPropertyRelative(() => def.LookAt);
var offsetProp = valueProp.FindPropertyRelative(() => def.Offset);

var overlay = new PropertyField(indexProp, "") { tooltip = indexTooltip, style = { flexGrow = 1, flexBasis = 100 }};
var overlay = new VisualElement () { style = { flexDirection = FlexDirection.Row, flexGrow = 1 }};
overlay.Add(new PropertyField(indexProp, "") { tooltip = indexTooltip, style = { flexGrow = 1, flexBasis = 50 }});
overlay.Add(new PropertyField(lookAtProp, "") { style = { flexGrow = 4, flexBasis = 50, marginLeft = 3 }});
var overlayLabel = new Label("Index") { tooltip = indexTooltip, style = { alignSelf = Align.Center }};
overlayLabel.AddDelayedFriendlyPropertyDragger(indexProp, overlay);

var foldout = new Foldout() { text = "Data Point" };
var foldout = new Foldout() { text = "Target" };
foldout.BindProperty(property);
foldout.Add(new PropertyField(indexProp) { tooltip = indexTooltip });

var lookAtProp = valueProp.FindPropertyRelative(() => def.LookAtTarget);
var offsetProp = valueProp.FindPropertyRelative(() => def.Offset);

var row = foldout.AddChild(InspectorUtility.PropertyRow(lookAtProp, out _));
row.Contents.Add(new Button(() =>
{
Expand All @@ -122,15 +121,15 @@ public override VisualElement CreatePropertyGUI(SerializedProperty property)
}
}

[EditorTool("LookAt Data On Spline Tool", typeof(CinemachineLookAtDataOnSpline))]
[EditorTool("Spline Dolly LookAt Targets Tool", typeof(CinemachineSplineDollyLookAtTargets))]
class LookAtDataOnSplineTool : EditorTool
{
GUIContent m_IconContent;
public override GUIContent toolbarIcon => m_IconContent;

bool GetTargets(out CinemachineLookAtDataOnSpline splineDataTarget, out SplineContainer spline, out CinemachineSplineDolly dolly)
bool GetTargets(out CinemachineSplineDollyLookAtTargets splineDataTarget, out SplineContainer spline, out CinemachineSplineDolly dolly)
{
splineDataTarget = target as CinemachineLookAtDataOnSpline;
splineDataTarget = target as CinemachineSplineDollyLookAtTargets;
if (splineDataTarget != null && splineDataTarget.GetTargets(out spline, out dolly))
return true;
spline = null;
Expand All @@ -144,8 +143,8 @@ void OnEnable()
{
image = AssetDatabase.LoadAssetAtPath<Texture2D>(
CinemachineCore.kPackageRoot + "/Editor/EditorResources/Icons/[email protected]"),
text = "LookAt Data On Spline Tool",
tooltip = "Assign LookAt points to points on the spline."
text = "Spline Dolly LookAt Targets Tool",
tooltip = "Assign LookAt targets to positions on the spline."
};
}

Expand All @@ -154,16 +153,16 @@ public override void OnToolGUI(EditorWindow window)
if (!GetTargets(out var splineDataTarget, out var spline, out _))
return;

Undo.RecordObject(splineDataTarget, "Modifying CinemachineLookAtDataOnSpline values");
Undo.RecordObject(splineDataTarget, "Modifying CinemachineSplineDollyLookAtTargets values");
using (new Handles.DrawingScope(Handles.selectedColor))
{
DrawDataPoints(splineDataTarget.LookAtData);
DrawDataPoints(splineDataTarget.Targets);
var nativeSpline = new NativeSpline(spline.Spline, spline.transform.localToWorldMatrix);
nativeSpline.DataPointHandles(splineDataTarget.LookAtData);
nativeSpline.DataPointHandles(splineDataTarget.Targets);
}
}

void DrawDataPoints(SplineData<CinemachineLookAtDataOnSpline.Item> splineData)
void DrawDataPoints(SplineData<CinemachineSplineDollyLookAtTargets.Item> splineData)
{
for (var r = 0; r < splineData.Count; ++r)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@
namespace Unity.Cinemachine
{
/// <summary>
/// CinemachineLookAtDataOnSpline is a component that allows the camera to look at
/// CinemachineSplineDollyLookAtTargets is a component that allows the camera to look at
/// specific points in the world as it moves along a spline.
/// </summary>
[ExecuteAlways, SaveDuringPlay]
[CameraPipeline(CinemachineCore.Stage.Aim)]
[AddComponentMenu("Cinemachine/Procedural/Rotation Control/Cinemachine Look At Data On Spline")]
[AddComponentMenu("Cinemachine/Procedural/Rotation Control/Cinemachine Spline Dolly LookAt Targets")]
[DisallowMultipleComponent]
[HelpURL(Documentation.BaseURL + "manual/CinemachineLookAtDataOnSpline.html")]
public class CinemachineLookAtDataOnSpline : CinemachineComponentBase
[HelpURL(Documentation.BaseURL + "manual/CinemachineSplineDollyLookAtTargets.html")]
public class CinemachineSplineDollyLookAtTargets : CinemachineComponentBase
{
/// <summary>LookAt targets for the camera at specific positions on the Spline</summary>
[Serializable]
public struct Item
{
/// <summary>The target object to look at. It may be None, in which case the LookAt pont will specify a point in world spac</summary>
[Tooltip("The target object to look at. It may be None, in which case the LookAt pont will specify a point in world space.")]
public Transform LookAtTarget;
/// <summary>The target object to look at. It may be None, in which case the LookAt point will specify a point in world spac</summary>
[Tooltip("The target object to look at. It may be None, in which case the LookAt point will specify a point in world space.")]
public Transform LookAt;

/// <summary>The offset (in local coords) from the LookAt target's origin. If LookAt target is None, this will specify a world-space point</summary>
[Tooltip("The offset (in local coords) from the LookAt target's origin. If LookAt target is None, this will specify a world-space point.")]
Expand All @@ -36,12 +36,12 @@ public struct Item
/// <summary>Get/set the LookAt point in world space.</summary>
public Vector3 WorldLookAt
{
readonly get => LookAtTarget == null ? Offset : LookAtTarget.TransformPoint(Offset);
set => Offset = LookAtTarget == null ? value : LookAtTarget.InverseTransformPoint(value);
readonly get => LookAt == null ? Offset : LookAt.TransformPoint(Offset);
set => Offset = LookAt == null ? value : LookAt.InverseTransformPoint(value);
}
}

/// <summary>Interpolator for the LookAtData</summary>
/// <summary>Interpolator for the Targets</summary>
internal struct LerpItem : IInterpolator<Item>
{
public Item Interpolate(Item a, Item b, float t)
Expand All @@ -56,12 +56,12 @@ public Item Interpolate(Item a, Item b, float t)

/// <summary>LookAt targets for the camera at specific positions on the Spline</summary>
[Tooltip("LookAt targets for the camera at specific positions on the Spline")]
public SplineData<Item> LookAtData = new () { DefaultValue = new Item { Easing = 1 } };
public SplineData<Item> Targets = new () { DefaultValue = new Item { Easing = 1 } };

void Reset() => LookAtData = new SplineData<Item> { DefaultValue = new Item { Easing = 1 } };
void Reset() => Targets = new SplineData<Item> { DefaultValue = new Item { Easing = 1 } };

/// <inheritdoc/>
public override bool IsValid => enabled && LookAtData != null && GetTargets(out _, out _);
public override bool IsValid => enabled && Targets != null && GetTargets(out _, out _);

/// <inheritdoc/>
public override CinemachineCore.Stage Stage => CinemachineCore.Stage.Aim;
Expand All @@ -76,7 +76,7 @@ public override void MutateCameraState(ref CameraState state, float deltaTime)
if (splinePath == null || splinePath.Count == 0)
return;

var item = LookAtData.Evaluate(splinePath, dolly.CameraPosition, dolly.PositionUnits, new LerpItem());
var item = Targets.Evaluate(splinePath, dolly.CameraPosition, dolly.PositionUnits, new LerpItem());
var dir = item.Offset - state.RawPosition;
if (dir.sqrMagnitude > UnityVectorExtensions.Epsilon)
{
Expand Down
2 changes: 1 addition & 1 deletion com.unity.cinemachine/Runtime/Core/CameraTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public struct CameraTarget

/// <summary>
/// If false, TrackingTarget will be used for all object tracking.
/// If true, then LookAtTarget is used for rotation tracking and
/// If true, then LookAt is used for rotation tracking and
/// TrackingTarget is used only for position tracking.
/// </summary>
public bool CustomLookAtTarget;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ static OnDomainReload()
public bool FollowTargetChanged { get; private set; }

/// <summary>
/// This property is true if the LookAtTarget was changed this frame.
/// This property is true if the LookAt was changed this frame.
/// </summary>
public bool LookAtTargetChanged { get; private set; }

Expand Down

0 comments on commit 2374839

Please sign in to comment.