using UnityEngine; using System.Collections; namespace VLB { [ExecuteInEditMode] [HelpURL(Consts.Help.SD.UrlDynamicOcclusionDepthBuffer)] public class DynamicOcclusionDepthBuffer : DynamicOcclusionAbstractBase { public new const string ClassName = "DynamicOcclusionDepthBuffer"; /// /// The beam can only be occluded by objects located on the layers matching this mask. /// It's very important to set it as restrictive as possible (checking only the layers which are necessary) /// to perform a more efficient process in order to increase the performance. /// It should NOT include the layer on which the beams are generated. /// public LayerMask layerMask = Consts.DynOcclusion.LayerMaskDefault; /// /// Whether or not the virtual camera will use occlusion culling during rendering from the beam's POV. /// public bool useOcclusionCulling = Consts.DynOcclusion.DepthBufferOcclusionCullingDefault; /// /// Controls how large the depth texture captured by the virtual camera is. /// The lower the resolution, the better the performance, but the less accurate the rendering. /// public int depthMapResolution = Consts.DynOcclusion.DepthBufferDepthMapResolutionDefault; /// /// Fade out the beam before the occlusion surface in order to soften the transition. /// public float fadeDistanceToSurface = Consts.DynOcclusion.DepthBufferFadeDistanceToSurfaceDefault; protected override string GetShaderKeyword() { return ShaderKeywords.SD.OcclusionDepthTexture; } protected override MaterialManager.SD.DynamicOcclusion GetDynamicOcclusionMode() { return MaterialManager.SD.DynamicOcclusion.DepthTexture; } Camera m_DepthCamera = null; bool m_NeedToUpdateOcclusionNextFrame = false; void ProcessOcclusionInternal() { UpdateDepthCameraPropertiesAccordingToBeam(); m_DepthCamera.Render(); } protected override bool OnProcessOcclusion(ProcessOcclusionSource source) { Debug.Assert(m_Master && m_DepthCamera); if (SRPHelper.IsUsingCustomRenderPipeline()) // Recursive rendering is not supported on SRP m_NeedToUpdateOcclusionNextFrame = true; else ProcessOcclusionInternal(); return true; } void Update() { if (m_NeedToUpdateOcclusionNextFrame && m_Master && m_DepthCamera && Time.frameCount > 1) // fix NullReferenceException in UnityEngine.Rendering.Universal.Internal.CopyDepthPass.Execute when using SRP { ProcessOcclusionInternal(); m_NeedToUpdateOcclusionNextFrame = false; } } void UpdateDepthCameraPropertiesAccordingToBeam() { Debug.Assert(m_Master); Utils.SetupDepthCamera(m_DepthCamera , m_Master.coneApexOffsetZ, m_Master.maxGeometryDistance, m_Master.coneRadiusStart, m_Master.coneRadiusEnd , m_Master.beamLocalForward, m_Master.GetLossyScale(), m_Master.IsScalable(), m_Master.beamInternalLocalRotation , true); } public bool HasLayerMaskIssues() { if(Config.Instance.geometryOverrideLayer) { int layerBit = 1 << Config.Instance.geometryLayerID; return ((layerMask.value & layerBit) == layerBit); } return false; } protected override void OnValidateProperties() { base.OnValidateProperties(); depthMapResolution = Mathf.Clamp(Mathf.NextPowerOfTwo(depthMapResolution), 8, 2048); fadeDistanceToSurface = Mathf.Max(fadeDistanceToSurface, 0f); } void InstantiateOrActivateDepthCamera() { if (m_DepthCamera != null) { m_DepthCamera.gameObject.SetActive(true); // active it in case it has been disabled by OnDisable() } else { // delete old depth cameras when duplicating the GAO gameObject.ForeachComponentsInDirectChildrenOnly(cam => DestroyImmediate(cam.gameObject), true); m_DepthCamera = Utils.NewWithComponent("Depth Camera"); if (m_DepthCamera && m_Master) { m_DepthCamera.enabled = false; m_DepthCamera.cullingMask = layerMask; m_DepthCamera.clearFlags = CameraClearFlags.Depth; m_DepthCamera.depthTextureMode = DepthTextureMode.Depth; m_DepthCamera.renderingPath = RenderingPath.VertexLit; // faster m_DepthCamera.useOcclusionCulling = useOcclusionCulling; m_DepthCamera.gameObject.hideFlags = Consts.Internal.ProceduralObjectsHideFlags; m_DepthCamera.transform.SetParent(transform, false); Config.Instance.SetURPScriptableRendererIndexToDepthCamera(m_DepthCamera); var rt = new RenderTexture(depthMapResolution, depthMapResolution, 16, RenderTextureFormat.Depth); m_DepthCamera.targetTexture = rt; UpdateDepthCameraPropertiesAccordingToBeam(); #if UNITY_EDITOR UnityEditor.GameObjectUtility.SetStaticEditorFlags(m_DepthCamera.gameObject, m_Master.GetStaticEditorFlagsForSubObjects()); m_DepthCamera.gameObject.SetSameSceneVisibilityStatesThan(m_Master.gameObject); #endif } } } protected override void OnEnablePostValidate() { InstantiateOrActivateDepthCamera(); } protected override void OnDisable() { base.OnDisable(); if (m_DepthCamera) m_DepthCamera.gameObject.SetActive(false); } protected override void Awake() { base.Awake(); #if UNITY_EDITOR MarkMaterialAsDirty(); #endif } protected override void OnDestroy() { base.OnDestroy(); DestroyDepthCamera(); #if UNITY_EDITOR MarkMaterialAsDirty(); #endif } void DestroyDepthCamera() { if (m_DepthCamera) { if (m_DepthCamera.targetTexture) { m_DepthCamera.targetTexture.Release(); DestroyImmediate(m_DepthCamera.targetTexture); m_DepthCamera.targetTexture = null; } DestroyImmediate(m_DepthCamera.gameObject); // Make sure to delete the GAO m_DepthCamera = null; } } protected override void OnModifyMaterialCallback(MaterialModifier.Interface owner) { Debug.Assert(owner != null); owner.SetMaterialProp(ShaderProperties.SD.DynamicOcclusionDepthTexture, m_DepthCamera.targetTexture); var scale = m_Master.GetLossyScale(); owner.SetMaterialProp(ShaderProperties.SD.DynamicOcclusionDepthProps, new Vector4(Mathf.Sign(scale.x) * Mathf.Sign(scale.z), Mathf.Sign(scale.y), fadeDistanceToSurface, m_DepthCamera.orthographic ? 0f : 1f)); } #if UNITY_EDITOR bool m_NeedToReinstantiateDepthCamera = false; void MarkMaterialAsDirty() { // when adding/removing this component in editor, we might need to switch from a GPU Instanced material to a custom one, // since this feature doesn't support GPU Instancing if (!Application.isPlaying) m_Master._EditorSetBeamGeomDirty(); } protected override void OnValidate() { base.OnValidate(); m_NeedToReinstantiateDepthCamera = true; } void LateUpdate() { if (!Application.isPlaying) { if (m_NeedToReinstantiateDepthCamera) { DestroyDepthCamera(); InstantiateOrActivateDepthCamera(); m_NeedToReinstantiateDepthCamera = false; } if(m_Master && m_Master.enabled) ProcessOcclusion(ProcessOcclusionSource.EditorUpdate); } } #endif // UNITY_EDITOR } }