UpdateTracker.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. //#define DEBUG_LOG_NAME
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. namespace Cinemachine
  5. {
  6. /// <summary>
  7. /// Attempt to track on what clock transforms get updated
  8. /// </summary>
  9. [DocumentationSorting(DocumentationSortingAttribute.Level.Undoc)]
  10. internal class UpdateTracker
  11. {
  12. public enum UpdateClock { Fixed, Late }
  13. class UpdateStatus
  14. {
  15. const int kWindowSize = 30;
  16. int windowStart;
  17. int numWindowLateUpdateMoves;
  18. int numWindowFixedUpdateMoves;
  19. int numWindows;
  20. int lastFrameUpdated;
  21. Matrix4x4 lastPos;
  22. #if DEBUG_LOG_NAME
  23. string name;
  24. #endif
  25. public UpdateClock PreferredUpdate { get; private set; }
  26. #if DEBUG_LOG_NAME
  27. public UpdateStatus(string targetName, int currentFrame, Matrix4x4 pos)
  28. {
  29. name = targetName;
  30. #else
  31. public UpdateStatus(int currentFrame, Matrix4x4 pos)
  32. {
  33. #endif
  34. windowStart = currentFrame;
  35. lastFrameUpdated = Time.frameCount;
  36. PreferredUpdate = UpdateClock.Late;
  37. lastPos = pos;
  38. }
  39. public void OnUpdate(int currentFrame, UpdateClock currentClock, Matrix4x4 pos)
  40. {
  41. if (lastPos == pos)
  42. return;
  43. if (currentClock == UpdateClock.Late)
  44. ++numWindowLateUpdateMoves;
  45. else if (lastFrameUpdated != currentFrame) // only count 1 per rendered frame
  46. ++numWindowFixedUpdateMoves;
  47. lastPos = pos;
  48. UpdateClock choice;
  49. if (numWindowFixedUpdateMoves > 3 && numWindowLateUpdateMoves < numWindowFixedUpdateMoves / 3)
  50. choice = UpdateClock.Fixed;
  51. else
  52. choice = UpdateClock.Late;
  53. if (numWindows == 0)
  54. PreferredUpdate = choice;
  55. if (windowStart + kWindowSize <= currentFrame)
  56. {
  57. #if DEBUG_LOG_NAME
  58. Debug.Log(name + ": Window " + numWindows + ": Late=" + numWindowLateUpdateMoves + ", Fixed=" + numWindowFixedUpdateMoves);
  59. #endif
  60. PreferredUpdate = choice;
  61. ++numWindows;
  62. windowStart = currentFrame;
  63. numWindowLateUpdateMoves = (PreferredUpdate == UpdateClock.Late) ? 1 : 0;
  64. numWindowFixedUpdateMoves = (PreferredUpdate == UpdateClock.Fixed) ? 1 : 0;
  65. }
  66. }
  67. }
  68. static Dictionary<Transform, UpdateStatus> mUpdateStatus
  69. = new Dictionary<Transform, UpdateStatus>();
  70. [RuntimeInitializeOnLoadMethod]
  71. static void InitializeModule() { mUpdateStatus.Clear(); }
  72. static List<Transform> sToDelete = new List<Transform>();
  73. static void UpdateTargets(UpdateClock currentClock)
  74. {
  75. // Update the registry for all known targets
  76. int now = Time.frameCount;
  77. var iter = mUpdateStatus.GetEnumerator();
  78. while (iter.MoveNext())
  79. {
  80. var current = iter.Current;
  81. if (current.Key == null)
  82. sToDelete.Add(current.Key); // target was deleted
  83. else
  84. current.Value.OnUpdate(now, currentClock, current.Key.localToWorldMatrix);
  85. }
  86. for (int i = sToDelete.Count-1; i >= 0; --i)
  87. mUpdateStatus.Remove(sToDelete[i]);
  88. sToDelete.Clear();
  89. }
  90. public static UpdateClock GetPreferredUpdate(Transform target)
  91. {
  92. if (Application.isPlaying && target != null)
  93. {
  94. UpdateStatus status;
  95. if (mUpdateStatus.TryGetValue(target, out status))
  96. return status.PreferredUpdate;
  97. // Add the target to the registry
  98. #if DEBUG_LOG_NAME
  99. status = new UpdateStatus(target.name, Time.frameCount, target.localToWorldMatrix);
  100. #else
  101. status = new UpdateStatus(Time.frameCount, target.localToWorldMatrix);
  102. #endif
  103. mUpdateStatus.Add(target, status);
  104. }
  105. return UpdateClock.Late;
  106. }
  107. static float mLastUpdateTime;
  108. public static void OnUpdate(UpdateClock currentClock)
  109. {
  110. // Do something only if we are the first controller processing this frame
  111. float now = CinemachineCore.CurrentTime;
  112. if (now != mLastUpdateTime)
  113. {
  114. mLastUpdateTime = now;
  115. UpdateTargets(currentClock);
  116. }
  117. }
  118. }
  119. }