LookDev.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. using UnityEngine.Rendering;
  2. using UnityEngine.Rendering.LookDev;
  3. using UnityEditorInternal;
  4. using UnityEngine;
  5. namespace UnityEditor.Rendering.LookDev
  6. {
  7. /// <summary>
  8. /// Main entry point for scripting LookDev
  9. /// </summary>
  10. public static class LookDev
  11. {
  12. const string lastRenderingDataSavePath = "Library/LookDevConfig.asset";
  13. //TODO: ensure only one displayer at time for the moment
  14. static IViewDisplayer s_ViewDisplayer;
  15. static IEnvironmentDisplayer s_EnvironmentDisplayer;
  16. static Compositer s_Compositor;
  17. static StageCache s_Stages;
  18. static Context s_CurrentContext;
  19. internal static IDataProvider dataProvider
  20. => RenderPipelineManager.currentPipeline as IDataProvider;
  21. /// <summary>
  22. /// Get all the data used in LookDev currently (views, layout, debug... )
  23. /// </summary>
  24. internal static Context currentContext
  25. {
  26. //Lazy init: load it when needed instead in static even if you do not support lookdev
  27. get => s_CurrentContext ?? (s_CurrentContext = LoadConfigInternal() ?? defaultContext);
  28. private set => s_CurrentContext = value;
  29. }
  30. static Context defaultContext
  31. {
  32. get
  33. {
  34. var context = UnityEngine.ScriptableObject.CreateInstance<Context>();
  35. context.Init();
  36. return context;
  37. }
  38. }
  39. //[TODO: not compatible with multiple displayer. To rework if needed]
  40. internal static IViewDisplayer currentViewDisplayer => s_ViewDisplayer;
  41. internal static IEnvironmentDisplayer currentEnvironmentDisplayer => s_EnvironmentDisplayer;
  42. /// <summary>State of the LookDev window</summary>
  43. public static bool open { get; private set; }
  44. /// <summary>
  45. /// Does LookDev is supported with the current render pipeline?
  46. /// </summary>
  47. public static bool supported => dataProvider != null;
  48. /// <summary>
  49. /// Reset all LookDevs datas to the default configuration
  50. /// </summary>
  51. public static void ResetConfig()
  52. => currentContext = defaultContext;
  53. static Context LoadConfigInternal(string path = lastRenderingDataSavePath)
  54. {
  55. var objs = InternalEditorUtility.LoadSerializedFileAndForget(path);
  56. Context context = (objs.Length > 0 ? objs[0] : null) as Context;
  57. if (context != null && !context.Equals(null))
  58. context.Init();
  59. return context;
  60. }
  61. /// <summary>
  62. /// Load a different set of datas
  63. /// </summary>
  64. /// <param name="path">Path where to load</param>
  65. internal static void LoadConfig(string path = lastRenderingDataSavePath)
  66. {
  67. var last = LoadConfigInternal(path);
  68. if (last != null)
  69. currentContext = last;
  70. }
  71. /// <summary>
  72. /// Save the current set of datas
  73. /// </summary>
  74. /// <param name="path">[optional] Path to save. By default, saved in Library folder</param>
  75. internal static void SaveConfig(string path = lastRenderingDataSavePath)
  76. {
  77. if (currentContext != null && !currentContext.Equals(null))
  78. InternalEditorUtility.SaveToSerializedFileAndForget(new[] { currentContext }, path, true);
  79. }
  80. /// <summary>open the LookDev window</summary>
  81. public static void Open()
  82. {
  83. s_ViewDisplayer = EditorWindow.GetWindow<DisplayWindow>();
  84. s_EnvironmentDisplayer = EditorWindow.GetWindow<DisplayWindow>();
  85. ConfigureLookDev(reloadWithTemporaryID: false);
  86. }
  87. [Callbacks.DidReloadScripts]
  88. static void OnEditorReload()
  89. {
  90. var windows = Resources.FindObjectsOfTypeAll<DisplayWindow>();
  91. s_ViewDisplayer = windows.Length > 0 ? windows[0] : null;
  92. s_EnvironmentDisplayer = windows.Length > 0 ? windows[0] : null;
  93. open = s_ViewDisplayer != null;
  94. if (open)
  95. ConfigureLookDev(reloadWithTemporaryID: true);
  96. }
  97. static void ConfigureLookDev(bool reloadWithTemporaryID)
  98. {
  99. open = true;
  100. if (s_CurrentContext == null || s_CurrentContext.Equals(null))
  101. LoadConfig();
  102. WaitingSRPReloadForConfiguringRenderer(5, reloadWithTemporaryID: reloadWithTemporaryID);
  103. }
  104. static void WaitingSRPReloadForConfiguringRenderer(int maxAttempt, bool reloadWithTemporaryID, int attemptNumber = 0)
  105. {
  106. if (supported)
  107. {
  108. ConfigureRenderer(reloadWithTemporaryID);
  109. LinkViewDisplayer();
  110. LinkEnvironmentDisplayer();
  111. ReloadStage(reloadWithTemporaryID);
  112. }
  113. else if (attemptNumber < maxAttempt)
  114. EditorApplication.delayCall +=
  115. () => WaitingSRPReloadForConfiguringRenderer(maxAttempt, reloadWithTemporaryID, ++attemptNumber);
  116. else
  117. {
  118. (s_ViewDisplayer as EditorWindow)?.Close();
  119. throw new System.Exception("LookDev is not supported by this Scriptable Render Pipeline: "
  120. + (RenderPipelineManager.currentPipeline == null ? "No SRP in use" : RenderPipelineManager.currentPipeline.ToString()));
  121. }
  122. }
  123. static void ConfigureRenderer(bool reloadWithTemporaryID)
  124. {
  125. s_Stages?.Dispose(); //clean previous occurrence on reloading
  126. s_Stages = new StageCache(dataProvider, currentContext);
  127. s_Compositor?.Dispose(); //clean previous occurrence on reloading
  128. s_Compositor = new Compositer(s_ViewDisplayer, currentContext, dataProvider, s_Stages);
  129. }
  130. static void LinkViewDisplayer()
  131. {
  132. EditorApplication.playModeStateChanged += state =>
  133. (s_ViewDisplayer as EditorWindow)?.Close();
  134. s_ViewDisplayer.OnClosed += () =>
  135. {
  136. s_Compositor?.Dispose();
  137. s_Compositor = null;
  138. s_Stages?.Dispose();
  139. s_Stages = null;
  140. s_ViewDisplayer = null;
  141. //currentContext = null;
  142. //release editorInstanceIDs
  143. currentContext.GetViewContent(ViewIndex.First).CleanTemporaryObjectIndexes();
  144. currentContext.GetViewContent(ViewIndex.Second).CleanTemporaryObjectIndexes();
  145. SaveConfig();
  146. open = false;
  147. };
  148. s_ViewDisplayer.OnLayoutChanged += (layout, envPanelOpen) =>
  149. {
  150. currentContext.layout.viewLayout = layout;
  151. currentContext.layout.showedSidePanel = envPanelOpen;
  152. SaveConfig();
  153. };
  154. s_ViewDisplayer.OnChangingObjectInView += (go, index, localPos) =>
  155. {
  156. switch (index)
  157. {
  158. case ViewCompositionIndex.First:
  159. case ViewCompositionIndex.Second:
  160. currentContext.GetViewContent((ViewIndex)index).UpdateViewedObject(go);
  161. SaveContextChangeAndApply((ViewIndex)index);
  162. break;
  163. case ViewCompositionIndex.Composite:
  164. ViewIndex viewIndex = s_Compositor.GetViewFromComposition(localPos);
  165. currentContext.GetViewContent(viewIndex).UpdateViewedObject(go);
  166. SaveContextChangeAndApply(viewIndex);
  167. break;
  168. }
  169. };
  170. s_ViewDisplayer.OnChangingEnvironmentInView += (obj, index, localPos) =>
  171. {
  172. switch (index)
  173. {
  174. case ViewCompositionIndex.First:
  175. case ViewCompositionIndex.Second:
  176. currentContext.GetViewContent((ViewIndex)index).UpdateEnvironment(obj);
  177. SaveContextChangeAndApply((ViewIndex)index);
  178. break;
  179. case ViewCompositionIndex.Composite:
  180. ViewIndex viewIndex = s_Compositor.GetViewFromComposition(localPos);
  181. currentContext.GetViewContent(viewIndex).UpdateEnvironment(obj);
  182. SaveContextChangeAndApply(viewIndex);
  183. break;
  184. }
  185. };
  186. }
  187. static void LinkEnvironmentDisplayer()
  188. {
  189. s_EnvironmentDisplayer.OnChangingEnvironmentLibrary += currentContext.UpdateEnvironmentLibrary;
  190. }
  191. static void ReloadStage(bool reloadWithTemporaryID)
  192. {
  193. currentContext.GetViewContent(ViewIndex.First).LoadAll(reloadWithTemporaryID);
  194. ApplyContextChange(ViewIndex.First);
  195. currentContext.GetViewContent(ViewIndex.Second).LoadAll(reloadWithTemporaryID);
  196. ApplyContextChange(ViewIndex.Second);
  197. }
  198. static void ApplyContextChange(ViewIndex index)
  199. {
  200. s_Stages.UpdateSceneObjects(index);
  201. s_Stages.UpdateSceneLighting(index, dataProvider);
  202. s_ViewDisplayer.Repaint();
  203. }
  204. /// <summary>Update the rendered element with element in the context</summary>
  205. /// <param name="index">The index of the stage to update</param>
  206. internal static void SaveContextChangeAndApply(ViewIndex index)
  207. {
  208. SaveConfig();
  209. ApplyContextChange(index);
  210. }
  211. }
  212. }