Car/Assets/VolumetricLightBeam/Scripts/SD/DynamicOcclusionDepthBuffer.cs

226 lines
8.4 KiB
C#
Raw Permalink Normal View History

using UnityEngine;
using System.Collections;
namespace VLB
{
[ExecuteInEditMode]
[HelpURL(Consts.Help.SD.UrlDynamicOcclusionDepthBuffer)]
public class DynamicOcclusionDepthBuffer : DynamicOcclusionAbstractBase
{
public new const string ClassName = "DynamicOcclusionDepthBuffer";
/// <summary>
/// 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.
/// </summary>
public LayerMask layerMask = Consts.DynOcclusion.LayerMaskDefault;
/// <summary>
/// Whether or not the virtual camera will use occlusion culling during rendering from the beam's POV.
/// </summary>
public bool useOcclusionCulling = Consts.DynOcclusion.DepthBufferOcclusionCullingDefault;
/// <summary>
/// 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.
/// </summary>
public int depthMapResolution = Consts.DynOcclusion.DepthBufferDepthMapResolutionDefault;
/// <summary>
/// Fade out the beam before the occlusion surface in order to soften the transition.
/// </summary>
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<Camera>(cam => DestroyImmediate(cam.gameObject), true);
m_DepthCamera = Utils.NewWithComponent<Camera>("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
}
}