/Library/PackageCache/com.unity.render-pipelines.core@7.5.3/Editor/LookDev/Stage.cs
C# | 368 lines | 238 code | 53 blank | 77 comment | 24 complexity | ef9795462fed29233f6898c0aea3ea78 MD5 | raw file
- using System;
- using System.Collections.Generic;
- using UnityEditor.SceneManagement;
- using UnityEngine;
- using UnityEngine.SceneManagement;
- using UnityEngine.Rendering.LookDev;
- namespace UnityEditor.Rendering.LookDev
- {
- //TODO: add undo support
- /// <summary>
- /// Class handling object of the scene with isolation from other scene based on culling
- /// </summary>
- class Stage : IDisposable
- {
- const int k_PreviewCullingLayerIndex = 31; //Camera.PreviewCullingLayer; //TODO: expose or reflection
- private readonly Scene m_PreviewScene;
- // Everything except camera
- private readonly List<GameObject> m_GameObjects = new List<GameObject>();
- private readonly List<GameObject> m_PersistentGameObjects = new List<GameObject>();
- private readonly Camera m_Camera;
- private readonly Light m_SunLight;
- /// <summary>Get access to the stage's camera</summary>
- public Camera camera => m_Camera;
- /// <summary>Get access to the stage's light</summary>
- public Light sunLight => m_SunLight;
- /// <summary>Get access to the stage's scene</summary>
- public Scene scene => m_PreviewScene;
- private StageRuntimeInterface SRI;
- /// <summary>The runtime interface on stage</summary>
- public StageRuntimeInterface runtimeInterface
- => SRI ?? (SRI = new StageRuntimeInterface(
- CreateGameObjectIntoStage,
- () => camera,
- () => sunLight));
- /// <summary>
- /// Construct a new stage to let your object live.
- /// A stage is a scene with visibility isolation.
- /// </summary>
- /// <param name="sceneName">Name of the scene used.</param>
- public Stage(string sceneName)
- {
- if (string.IsNullOrEmpty(sceneName))
- throw new System.ArgumentNullException("sceneName");
- m_PreviewScene = EditorSceneManager.NewPreviewScene();
- m_PreviewScene.name = sceneName;
- var camGO = EditorUtility.CreateGameObjectWithHideFlags("Look Dev Camera", HideFlags.HideAndDontSave, typeof(Camera));
- MoveIntoStage(camGO, true); //position will be updated right before rendering
- camGO.layer = k_PreviewCullingLayerIndex;
- m_Camera = camGO.GetComponent<Camera>();
- m_Camera.cameraType = CameraType.Game; //cannot be preview in HDRP: too many things skiped
- m_Camera.enabled = false;
- m_Camera.clearFlags = CameraClearFlags.Depth;
- m_Camera.cullingMask = 1 << k_PreviewCullingLayerIndex;
- m_Camera.renderingPath = RenderingPath.DeferredShading;
- m_Camera.useOcclusionCulling = false;
- m_Camera.scene = m_PreviewScene;
- var lightGO = EditorUtility.CreateGameObjectWithHideFlags("Look Dev Sun", HideFlags.HideAndDontSave, typeof(Light));
- MoveIntoStage(lightGO, true); //position will be updated right before rendering
- m_SunLight = lightGO.GetComponent<Light>();
- m_SunLight.type = LightType.Directional;
- m_SunLight.shadows = LightShadows.Soft;
- m_SunLight.intensity = 0f;
- }
- /// <summary>
- /// Move a GameObject into the stage's scene at origin.
- /// </summary>
- /// <param name="gameObject">The gameObject to move.</param>
- /// <param name="persistent">
- /// [OPTIONAL] If true, the object is not recreated with the scene update.
- /// Default value: false.
- /// </param>
- /// <seealso cref="InstantiateIntoStage"/>
- public void MoveIntoStage(GameObject gameObject, bool persistent = false)
- => MoveIntoStage(gameObject, Vector3.zero, gameObject.transform.rotation, persistent);
- /// <summary>
- /// Move a GameObject into the stage's scene at specific position and
- /// rotation.
- /// </summary>
- /// <param name="gameObject">The gameObject to move.</param>
- /// <param name="position">The new world position</param>
- /// <param name="rotation">The new world rotation</param>
- /// <param name="persistent">
- /// [OPTIONAL] If true, the object is not recreated with the scene update.
- /// Default value: false.
- /// </param>
- /// <seealso cref="InstantiateIntoStage"/>
- public void MoveIntoStage(GameObject gameObject, Vector3 position, Quaternion rotation, bool persistent = false)
- {
- if (m_GameObjects.Contains(gameObject))
- return;
- SceneManager.MoveGameObjectToScene(gameObject, m_PreviewScene);
- gameObject.transform.position = position;
- gameObject.transform.rotation = rotation;
- if (persistent)
- m_PersistentGameObjects.Add(gameObject);
- else
- m_GameObjects.Add(gameObject);
- InitAddedObjectsRecursively(gameObject);
- }
- /// <summary>
- /// Instantiate a scene GameObject or a prefab into the stage's scene.
- /// It is instantiated at origin.
- /// </summary>
- /// <param name="prefabOrSceneObject">The element to instantiate</param>
- /// <param name="persistent">
- /// [OPTIONAL] If true, the object is not recreated with the scene update.
- /// Default value: false.
- /// </param>
- /// <returns>The instance</returns>
- /// <seealso cref="MoveIntoStage"/>
- public GameObject InstantiateIntoStage(GameObject prefabOrSceneObject, bool persistent = false)
- => InstantiateIntoStage(prefabOrSceneObject, Vector3.zero, prefabOrSceneObject.transform.rotation, persistent);
- /// <summary>
- /// Instantiate a scene GameObject or a prefab into the stage's scene
- /// at a specific position and rotation.
- /// </summary>
- /// <param name="prefabOrSceneObject">The element to instantiate</param>
- /// <param name="position">The new world position</param>
- /// <param name="rotation">The new world rotation</param>
- /// <param name="persistent">
- /// [OPTIONAL] If true, the object is not recreated with the scene update.
- /// Default value: false.
- /// </param>
- /// <returns>The instance</returns>
- /// <seealso cref="MoveIntoStage"/>
- public GameObject InstantiateIntoStage(GameObject prefabOrSceneObject, Vector3 position, Quaternion rotation, bool persistent = false)
- {
- var handle = GameObject.Instantiate(prefabOrSceneObject);
- MoveIntoStage(handle, position, rotation, persistent);
- return handle;
- }
- /// <summary>Create a GameObject into the stage.</summary>
- /// <param name="persistent">
- /// [OPTIONAL] If true, the object is not recreated with the scene update.
- /// Default value: false.
- /// </param>
- /// <returns>The created GameObject</returns>
- public GameObject CreateGameObjectIntoStage(bool persistent = false)
- {
- var handle = new GameObject();
- MoveIntoStage(handle, persistent);
- return handle;
- }
- /// <summary>Clear all scene object except camera.</summary>
- /// <param name="persistent">
- /// [OPTIONAL] If true, clears also persistent objects.
- /// Default value: false.
- /// </param>
- public void Clear(bool persistent = false)
- {
- foreach (var go in m_GameObjects)
- UnityEngine.Object.DestroyImmediate(go);
- m_GameObjects.Clear();
- if (persistent)
- {
- foreach (var go in m_PersistentGameObjects)
- UnityEngine.Object.DestroyImmediate(go);
- m_PersistentGameObjects.Clear();
- }
- }
- static void InitAddedObjectsRecursively(GameObject go)
- {
- go.hideFlags = HideFlags.HideAndDontSave;
- go.layer = k_PreviewCullingLayerIndex;
- var meshRenderer = go.GetComponent<MeshRenderer>();
- if (meshRenderer != null)
- meshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
- var skinnedMeshRenderer = go.GetComponent<SkinnedMeshRenderer>();
- if (skinnedMeshRenderer != null)
- skinnedMeshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
- var lineRenderer = go.GetComponent<LineRenderer>();
- if (lineRenderer != null)
- lineRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
- var volumes = go.GetComponents<UnityEngine.Rendering.Volume>();
- foreach (var volume in volumes)
- volume.UpdateLayer(); //force update of layer now as the Update can be called after we unregister volume from manager
- foreach (Transform child in go.transform)
- InitAddedObjectsRecursively(child.gameObject);
- }
- /// <summary>Changes stage scene's objects visibility.</summary>
- /// <param name="visible">
- /// True: make them visible.
- /// False: hide them.
- /// </param>
- void SetGameObjectVisible(bool visible)
- {
- foreach (GameObject go in m_GameObjects)
- {
- if (go == null || go.Equals(null))
- continue;
- foreach (UnityEngine.Renderer renderer in go.GetComponentsInChildren<UnityEngine.Renderer>())
- renderer.enabled = visible;
- foreach (Light light in go.GetComponentsInChildren<Light>())
- light.enabled = visible;
- }
- // in case we add camera frontal light and such
- foreach (UnityEngine.Renderer renderer in m_Camera.GetComponentsInChildren<UnityEngine.Renderer>())
- renderer.enabled = visible;
- foreach (Light light in m_Camera.GetComponentsInChildren<Light>())
- light.enabled = visible;
- }
- public void OnBeginRendering(IDataProvider dataProvider)
- {
- SetGameObjectVisible(true);
- dataProvider.OnBeginRendering(runtimeInterface);
- }
- public void OnEndRendering(IDataProvider dataProvider)
- {
- SetGameObjectVisible(false);
- dataProvider.OnEndRendering(runtimeInterface);
- }
- private bool disposedValue = false; // To detect redundant calls
- void CleanUp()
- {
- if (!disposedValue)
- {
- if (SRI != null)
- SRI.SRPData = null;
- SRI = null;
- EditorSceneManager.ClosePreviewScene(m_PreviewScene);
- disposedValue = true;
- }
- }
- ~Stage() => CleanUp();
- /// <summary>Clear and close the stage's scene.</summary>
- public void Dispose()
- {
- CleanUp();
- GC.SuppressFinalize(this);
- }
- }
- class StageCache : IDisposable
- {
- const string firstStageName = "LookDevFirstView";
- const string secondStageName = "LookDevSecondView";
- Stage[] m_Stages;
- Context m_Contexts;
- IDataProvider m_CurrentDataProvider;
- public Stage this[ViewIndex index]
- => m_Stages[(int)index];
- public bool initialized { get; private set; }
- public StageCache(IDataProvider dataProvider, Context contexts)
- {
- m_Contexts = contexts;
- m_Stages = new Stage[2]
- {
- InitStage(ViewIndex.First, dataProvider),
- InitStage(ViewIndex.Second, dataProvider)
- };
- initialized = true;
- }
- Stage InitStage(ViewIndex index, IDataProvider dataProvider)
- {
- Stage stage;
- switch (index)
- {
- case ViewIndex.First:
- stage = new Stage(firstStageName);
- stage.camera.backgroundColor = new Color32(5, 5, 5, 255);
- stage.camera.name += "_1";
- break;
- case ViewIndex.Second:
- stage = new Stage(secondStageName);
- stage.camera.backgroundColor = new Color32(5, 5, 5, 255);
- stage.camera.name += "_2";
- break;
- default:
- throw new ArgumentException("Unknown ViewIndex: " + index);
- }
- dataProvider.FirstInitScene(stage.runtimeInterface);
- m_CurrentDataProvider = dataProvider;
- return stage;
- }
- public void UpdateSceneObjects(ViewIndex index)
- {
- Stage stage = this[index];
- stage.Clear();
- var viewContent = m_Contexts.GetViewContent(index);
- if (viewContent == null)
- {
- viewContent.viewedInstanceInPreview = null;
- return;
- }
- if (viewContent.viewedObjectReference != null && !viewContent.viewedObjectReference.Equals(null))
- viewContent.viewedInstanceInPreview = stage.InstantiateIntoStage(viewContent.viewedObjectReference);
- }
- public void UpdateSceneLighting(ViewIndex index, IDataProvider provider)
- {
- Stage stage = this[index];
- Environment environment = m_Contexts.GetViewContent(index).environment;
- provider.UpdateSky(stage.camera,
- environment == null ? default : environment.sky,
- stage.runtimeInterface);
- }
- private bool disposedValue = false; // To detect redundant calls
- void CleanUp()
- {
- if (!disposedValue)
- {
- foreach (Stage stage in m_Stages)
- {
- m_CurrentDataProvider.Cleanup(stage.runtimeInterface);
- stage.Dispose();
- }
- disposedValue = true;
- }
- }
- ~StageCache() => CleanUp();
- public void Dispose()
- {
- CleanUp();
- GC.SuppressFinalize(this);
- }
- }
- }