Skip to content
Open
5 changes: 5 additions & 0 deletions com.unity.cinemachine/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [3.1.7-pre.1] - 2026-02-24

### Changed
- Added support for fast enter play mode.

## [3.1.6] - 2026-02-23

### Bugfixes
Expand Down
112 changes: 57 additions & 55 deletions com.unity.cinemachine/Editor/Obsolete/CinemachineFreeLookEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,65 +172,67 @@ void UpdateRigEditor()
}
}

/// <summary>
/// Register with CinemachineFreeLook to create the pipeline in an undo-friendly manner
/// </summary>
[InitializeOnLoad]
class CreateRigWithUndo
static CinemachineVirtualCamera CreateRigOverride(CinemachineFreeLook vcam, string name, CinemachineVirtualCamera copyFrom)
{
static CreateRigWithUndo()
// Recycle the game object if it exists
GameObject go = null;
foreach (Transform child in vcam.transform)
{
CinemachineFreeLook.CreateRigOverride
= (CinemachineFreeLook vcam, string name, CinemachineVirtualCamera copyFrom) =>
{
// Recycle the game object if it exists
GameObject go = null;
foreach (Transform child in vcam.transform)
{
if (child.gameObject.name == name)
{
go = child.gameObject;
break;
}
}

CinemachineVirtualCamera rig = null;
if (go == null)
{
// Create a new rig - can't do it if prefab instance
if (PrefabUtility.IsPartOfAnyPrefab(vcam.gameObject))
return null;
go = ObjectFactory.CreateGameObject(name);
Undo.RegisterCreatedObjectUndo(go, "created rig");
Undo.SetTransformParent(go.transform, vcam.transform, "parenting pipeline");
}

// Create a new rig with default components
rig = Undo.AddComponent<CinemachineVirtualCamera>(go);
rig.CreatePipeline(copyFrom);
if (copyFrom != null)
ReflectionHelpers.CopyFields(copyFrom, rig);
else
{
// Defaults
go = rig.GetComponentOwner().gameObject;
Undo.AddComponent<CinemachineOrbitalTransposer>(go);
Undo.AddComponent<CinemachineComposer>(go);
rig.InvalidateComponentPipeline();
}
return rig;
};

CinemachineFreeLook.DestroyRigOverride = (GameObject rig) =>
if (child.gameObject.name == name)
{
var vcam = rig.GetComponent<CinemachineVirtualCamera>();
if (vcam != null)
{
vcam.DestroyPipeline();
Undo.DestroyObjectImmediate(vcam);
}
};
go = child.gameObject;
break;
}
}

CinemachineVirtualCamera rig = null;
if (go == null)
{
// Create a new rig - can't do it if prefab instance
if (PrefabUtility.IsPartOfAnyPrefab(vcam.gameObject))
return null;
go = ObjectFactory.CreateGameObject(name);
Undo.RegisterCreatedObjectUndo(go, "created rig");
Undo.SetTransformParent(go.transform, vcam.transform, "parenting pipeline");
}

// Create a new rig with default components
rig = Undo.AddComponent<CinemachineVirtualCamera>(go);
rig.CreatePipeline(copyFrom);
if (copyFrom != null)
ReflectionHelpers.CopyFields(copyFrom, rig);
else
{
// Defaults
go = rig.GetComponentOwner().gameObject;
Undo.AddComponent<CinemachineOrbitalTransposer>(go);
Undo.AddComponent<CinemachineComposer>(go);
rig.InvalidateComponentPipeline();
}
return rig;
}

static void DestroyRigOverride(GameObject rig)
{
var vcam = rig.GetComponent<CinemachineVirtualCamera>();
if (vcam != null)
{
vcam.DestroyPipeline();
Undo.DestroyObjectImmediate(vcam);
}
}

[UnityEditor.InitializeOnLoad]
class EditorInitialize { static EditorInitialize() { ResetStaticsOnLoad(); } }

/// <summary>
/// Register with CinemachineFreeLook to create the pipeline in an undo-friendly manner.
/// </summary>
[RuntimeInitializeOnLoadMethod]
private static void ResetStaticsOnLoad()
{
CinemachineFreeLook.CreateRigOverride = CreateRigOverride;
CinemachineFreeLook.DestroyRigOverride = DestroyRigOverride;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,66 +162,68 @@ void ResetTargetOnUndo()
(targets[i] as CinemachineVirtualCamera).InvalidateComponentPipeline();
}

/// <summary>
/// Register with CinemachineVirtualCamera to create the pipeline in an undo-friendly manner
/// </summary>
[InitializeOnLoad]
class CreatePipelineWithUndo
static Transform CreatePipelineOverride(CinemachineVirtualCamera vcam, string name, CinemachineComponentBase[] copyFrom)
{
static CreatePipelineWithUndo()
// Recycle existing pipeline child (if any)
GameObject go = null;
foreach (Transform child in vcam.transform)
{
CinemachineVirtualCamera.CreatePipelineOverride =
(CinemachineVirtualCamera vcam, string name, CinemachineComponentBase[] copyFrom) =>
if (child.GetComponent<CinemachinePipeline>() != null)
{
// Recycle existing pipeline child (if any)
GameObject go = null;
foreach (Transform child in vcam.transform)
{
if (child.GetComponent<CinemachinePipeline>() != null)
{
go = child.gameObject;
break;
}
}
if (go == null)
{
// Create a new pipeline - can't do it if prefab instance
if (PrefabUtility.IsPartOfAnyPrefab(vcam.gameObject))
return null;
go = ObjectFactory.CreateGameObject(name);
Undo.RegisterCreatedObjectUndo(go, "created pipeline");
Undo.SetTransformParent(go.transform, vcam.transform, "parenting pipeline");
Undo.AddComponent<CinemachinePipeline>(go);
}

var oldStuff = go.GetComponents<CinemachineComponentBase>();
foreach (var c in oldStuff)
Undo.DestroyObjectImmediate(c);
go = child.gameObject;
break;
}
}
if (go == null)
{
// Create a new pipeline - can't do it if prefab instance
if (PrefabUtility.IsPartOfAnyPrefab(vcam.gameObject))
return null;
go = ObjectFactory.CreateGameObject(name);
Undo.RegisterCreatedObjectUndo(go, "created pipeline");
Undo.SetTransformParent(go.transform, vcam.transform, "parenting pipeline");
Undo.AddComponent<CinemachinePipeline>(go);
}

// If copying, transfer the components
if (copyFrom != null)
{
foreach (Component c in copyFrom)
{
Component copy = Undo.AddComponent(go, c.GetType());
Undo.RecordObject(copy, "copying pipeline");
ReflectionHelpers.CopyFields(c, copy);
}
}
return go.transform;
};
var oldStuff = go.GetComponents<CinemachineComponentBase>();
foreach (var c in oldStuff)
Undo.DestroyObjectImmediate(c);

CinemachineVirtualCamera.DestroyPipelineOverride = (GameObject pipeline) =>
// If copying, transfer the components
if (copyFrom != null)
{
foreach (Component c in copyFrom)
{
var oldStuff = pipeline.GetComponents<CinemachineComponentBase>();
foreach (var c in oldStuff)
Undo.DestroyObjectImmediate(c);
// Cannot create or destroy child objects if prefab.
// Just leave it there in that case, it will get discovered and recycled.
if (!PrefabUtility.IsPartOfAnyPrefab(pipeline))
Undo.DestroyObjectImmediate(pipeline);
};
Component copy = Undo.AddComponent(go, c.GetType());
Undo.RecordObject(copy, "copying pipeline");
ReflectionHelpers.CopyFields(c, copy);
}
}
return go.transform;
}

static void DestroyPipelineOverride(GameObject pipeline)
{
var oldStuff = pipeline.GetComponents<CinemachineComponentBase>();
foreach (var c in oldStuff)
Undo.DestroyObjectImmediate(c);
// Cannot create or destroy child objects if prefab.
// Just leave it there in that case, it will get discovered and recycled.
if (!PrefabUtility.IsPartOfAnyPrefab(pipeline))
Undo.DestroyObjectImmediate(pipeline);
}

[UnityEditor.InitializeOnLoad]
class EditorInitialize { static EditorInitialize() { ResetStaticsOnLoad(); } }

/// <summary>
/// Register with CinemachineVirtualCamera to create the pipeline in an undo-friendly manner.
/// </summary>
[RuntimeInitializeOnLoadMethod]
private static void ResetStaticsOnLoad()
{
CinemachineVirtualCamera.CreatePipelineOverride = CreatePipelineOverride;
CinemachineVirtualCamera.DestroyPipelineOverride = DestroyPipelineOverride;
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions com.unity.cinemachine/Editor/Windows/CinemachineCorePrefs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ protected override void WritePrefs(bool value)
CinemachineDebug.GameViewGuidesEnabled = value;
}
}

[UnityEditor.InitializeOnLoad]
class EditorInitialize { static EditorInitialize() { InitializeModule(); } }

[RuntimeInitializeOnLoadMethod]
private static void InitializeModule()
{
CinemachineDebug.GameViewGuidesEnabled = ShowInGameGuides.Value;
CinemachineStoryboard.s_StoryboardGlobalMute = StoryboardGlobalMute.Value;
}

static CinemachineSettings.BoolItem s_SettingsFoldedOut = new("CNMCN_Core_Folded", true);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,13 @@ public struct TerrainSettings
public TerrainSettings TerrainResolution;

const int kColliderBufferSize = 10;

#pragma warning disable UDR0001
// Scratch buffers. These buffers are never reused and don't need to be cleared.
static Collider[] s_ColliderBuffer = new Collider[kColliderBufferSize];
static float[] s_ColliderDistanceBuffer = new float[kColliderBufferSize];
static int[] s_ColliderOrderBuffer = new int[kColliderBufferSize];
#pragma warning restore UDR0001

// Farthest stuff comes first
static readonly IComparer<int> s_ColliderBufferSorter = Comparer<int>.Create((a, b) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -825,8 +825,11 @@ static float ClampRayToBounds(Ray ray, float distance, Bounds bounds)
return distance;
}

#pragma warning disable UDR0001
// Scratch buffer. This buffer is never reused and doesn't need to be cleared.
static Collider[] s_ColliderBuffer = new Collider[5];

#pragma warning restore UDR0001

Vector3 RespectCameraRadius(Vector3 cameraPos, Vector3 lookAtPos)
{
var result = Vector3.zero;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if CINEMACHINE_UGUI
#if CINEMACHINE_UGUI
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Serialization;
Expand All @@ -20,7 +20,10 @@ public class CinemachineStoryboard : CinemachineExtension
/// If checked, all storyboards are globally muted
/// </summary>
[Tooltip("If checked, all storyboards are globally muted")]
#pragma warning disable UDR0001
// Option is set at initialization in the editor. Cannot be reset at runtime.
public static bool s_StoryboardGlobalMute;
#pragma warning restore UDR0001

/// <summary>
/// If checked, the specified image will be displayed as an overlay over the virtual camera's output
Expand Down
2 changes: 1 addition & 1 deletion com.unity.cinemachine/Runtime/Core/CameraState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public struct CameraState
/// <summary>
/// This constant represents "no point in space" or "no direction".
/// </summary>
public static Vector3 kNoPoint = new Vector3(float.NaN, float.NaN, float.NaN);
public static readonly Vector3 kNoPoint = new Vector3(float.NaN, float.NaN, float.NaN);

/// <summary>
/// Raw (un-corrected) world space position of this camera
Expand Down
13 changes: 13 additions & 0 deletions com.unity.cinemachine/Runtime/Core/CameraUpdateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,5 +222,18 @@ public static UpdateTracker.UpdateClock GetVcamUpdateStatus(CinemachineVirtualCa
return UpdateTracker.UpdateClock.Late;
return status.lastUpdateMode;
}

#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod]
private static void ResetStaticsOnLoad()
{
s_RoundRobinIndex = 0;
s_RoundRobinSubIndex = 0;
s_LastFixedUpdateContext = null;
s_LastUpdateTime = 0f;
s_FixedFrameCount = 0;
s_CurrentUpdateFilter = default;
}
#endif
}
}
9 changes: 9 additions & 0 deletions com.unity.cinemachine/Runtime/Core/CinemachineBlend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,15 @@ public CinemachineBlendDefinition(Styles style, float time)
public AnimationCurve CustomCurve;

static AnimationCurve[] s_StandardCurves;

#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod]
private static void ResetStaticsOnLoad()
{
s_StandardCurves = null;
}
#endif

void CreateStandardCurves()
{
s_StandardCurves = new AnimationCurve[(int)Styles.Custom];
Expand Down
Loading