273 lines
12 KiB
C#
273 lines
12 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
using System;
|
|
#if UNITY_2023_3_OR_NEWER
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
#endif
|
|
|
|
namespace VolumetricLights {
|
|
|
|
public class VolumetricLightsTranslucentShadowMapFeature : ScriptableRendererFeature {
|
|
|
|
static class ShaderParams {
|
|
public static int MainTex = Shader.PropertyToID("_MainTex");
|
|
public static int BaseMap = Shader.PropertyToID("_BaseMap");
|
|
public static int BaseColor = Shader.PropertyToID("_BaseColor");
|
|
public static int TranslucencyIntensity = Shader.PropertyToID("_TranslucencyIntensity");
|
|
public static int MainTex_ST = Shader.PropertyToID("_MainTex_ST");
|
|
public static int Color = Shader.PropertyToID("_Color");
|
|
}
|
|
|
|
|
|
public class TranspRenderPass : ScriptableRenderPass {
|
|
|
|
public VolumetricLightsTranslucentShadowMapFeature settings;
|
|
|
|
const string m_strProfilerTag = "TranslucencyPrePass";
|
|
const string m_TranspShader = "Hidden/VolumetricLights/TransparentMultiply";
|
|
const string m_TranspDepthOnlyShader = "Hidden/VolumetricLights/TransparentDepthWrite";
|
|
|
|
class PassData {
|
|
#if UNITY_2022_3_OR_NEWER
|
|
public RTHandle source;
|
|
#else
|
|
public RenderTargetIdentifier source;
|
|
#endif
|
|
#if UNITY_2023_3_OR_NEWER
|
|
public TextureHandle depthTexture;
|
|
#endif
|
|
}
|
|
|
|
static Material transpOverrideMat, transpDepthOnlyMat;
|
|
static Material[] transpOverrideMaterials;
|
|
static VolumetricLight light;
|
|
|
|
ScriptableRenderer renderer;
|
|
#if UNITY_2022_1_OR_NEWER
|
|
RTHandle cameraDepth;
|
|
#else
|
|
RenderTargetIdentifier cameraDepth;
|
|
#endif
|
|
|
|
public TranspRenderPass (VolumetricLightsTranslucentShadowMapFeature settings) {
|
|
this.settings = settings;
|
|
renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
|
|
}
|
|
|
|
public void Setup (ScriptableRenderer renderer, VolumetricLight light) {
|
|
this.renderer = renderer;
|
|
TranspRenderPass.light = light;
|
|
}
|
|
|
|
#if UNITY_2023_3_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
public override void OnCameraSetup (CommandBuffer cmd, ref RenderingData renderingData) {
|
|
base.OnCameraSetup(cmd, ref renderingData);
|
|
#if UNITY_2022_1_OR_NEWER
|
|
cameraDepth = renderer.cameraDepthTargetHandle;
|
|
#else
|
|
cameraDepth = renderer.cameraDepthTarget;
|
|
#endif
|
|
}
|
|
|
|
|
|
#if UNITY_2023_3_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
public override void Configure (CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) {
|
|
|
|
if (light.translucencyMapHandle == null || light.translucencyMapHandle.rt != light.translucentMap) {
|
|
if (light.translucencyMapHandle != null) {
|
|
RTHandles.Release(light.translucencyMapHandle);
|
|
}
|
|
light.translucencyMapHandle = RTHandles.Alloc(light.translucentMap);
|
|
}
|
|
|
|
|
|
ConfigureTarget(light.translucencyMapHandle, cameraDepth);
|
|
ConfigureClear(ClearFlag.Color, Color.white);
|
|
}
|
|
|
|
#if UNITY_2023_3_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData) {
|
|
CommandBuffer cmd = CommandBufferPool.Get(m_strProfilerTag);
|
|
context.ExecuteCommandBuffer(cmd);
|
|
cmd.Clear();
|
|
|
|
ExecutePass(cmd);
|
|
|
|
context.ExecuteCommandBuffer(cmd);
|
|
CommandBufferPool.Release(cmd);
|
|
}
|
|
|
|
#if UNITY_2023_3_OR_NEWER
|
|
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) {
|
|
|
|
using (var builder = renderGraph.AddUnsafePass<PassData>(m_strProfilerTag, out var passData)) {
|
|
|
|
builder.AllowPassCulling(false);
|
|
|
|
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
|
|
|
|
if (light.translucencyMapHandle == null || passData.source == null || passData.source.rt != light.translucentMap) {
|
|
if (light.translucencyMapHandle != null) {
|
|
RTHandles.Release(light.translucencyMapHandle);
|
|
}
|
|
light.translucencyMapHandle = RTHandles.Alloc(light.translucentMap);
|
|
}
|
|
|
|
passData.source = light.translucencyMapHandle;
|
|
// passData.depthTexture = resourceData.activeDepthTexture;
|
|
// builder.UseTexture(resourceData.activeDepthTexture, AccessFlags.Read);
|
|
// ConfigureInput(ScriptableRenderPassInput.Depth);
|
|
|
|
builder.SetRenderFunc((PassData passData, UnsafeGraphContext context) => {
|
|
CommandBuffer cmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);
|
|
cmd.SetRenderTarget(passData.source); //, passData.depthTexture);
|
|
cmd.ClearRenderTarget(false, true, Color.white);
|
|
ExecutePass(cmd);
|
|
});
|
|
}
|
|
}
|
|
#endif
|
|
static void ExecutePass (CommandBuffer cmd) {
|
|
|
|
if (transpOverrideMat == null) {
|
|
Shader transpShader = Shader.Find(m_TranspShader);
|
|
transpOverrideMat = new Material(transpShader);
|
|
}
|
|
|
|
if (transpDepthOnlyMat == null) {
|
|
Shader transpDepthOnlyShader = Shader.Find(m_TranspDepthOnlyShader);
|
|
transpDepthOnlyMat = new Material(transpDepthOnlyShader);
|
|
}
|
|
|
|
int renderersCount = VolumetricLightsTranslucency.objects.Count;
|
|
if (transpOverrideMaterials == null || transpOverrideMaterials.Length < renderersCount) {
|
|
transpOverrideMaterials = new Material[renderersCount];
|
|
}
|
|
|
|
Bounds lightBounds = light.GetBounds();
|
|
float intensity = 10f * light.shadowTranslucencyIntensity / (light.brightness + 0.001f);
|
|
for (int k = 0; k < renderersCount; k++) {
|
|
VolumetricLightsTranslucency transpObject = VolumetricLightsTranslucency.objects[k];
|
|
if (transpObject == null) continue;
|
|
if (transpObject.intensityMultiplier <= 0) continue;
|
|
if (transpObject.theRenderer == null) continue;
|
|
if (!lightBounds.Intersects(transpObject.theRenderer.bounds)) continue;
|
|
|
|
Material mat = transpObject.theRenderer.sharedMaterial;
|
|
if (mat == null) continue;
|
|
|
|
if (transpObject.preserveOriginalShader) {
|
|
cmd.DrawRenderer(transpObject.theRenderer, mat);
|
|
cmd.DrawRenderer(transpObject.theRenderer, transpDepthOnlyMat);
|
|
} else {
|
|
|
|
if (transpObject.intensityMultiplier <= 0) continue;
|
|
|
|
if (transpOverrideMaterials[k] == null) {
|
|
transpOverrideMaterials[k] = Instantiate(transpOverrideMat);
|
|
}
|
|
Material overrideMaterial = transpOverrideMaterials[k];
|
|
Texture texture = Texture2D.whiteTexture;
|
|
Vector2 textureScale = Vector2.one;
|
|
Vector2 textureOffset = Vector2.zero;
|
|
Color color = Color.white;
|
|
if (!string.IsNullOrEmpty(transpObject.baseTexturePropertyName) && mat.HasProperty(transpObject.baseTexturePropertyName)) {
|
|
texture = mat.GetTexture(transpObject.baseTexturePropertyName);
|
|
textureScale = mat.GetTextureScale(transpObject.baseTexturePropertyName);
|
|
textureOffset = mat.GetTextureOffset(transpObject.baseTexturePropertyName);
|
|
} else if (mat.HasProperty(ShaderParams.BaseMap)) {
|
|
texture = mat.GetTexture(ShaderParams.BaseMap);
|
|
textureScale = mat.GetTextureScale(ShaderParams.BaseMap);
|
|
textureOffset = mat.GetTextureOffset(ShaderParams.BaseMap);
|
|
} else if (mat.HasProperty(ShaderParams.MainTex)) {
|
|
texture = mat.GetTexture(ShaderParams.MainTex);
|
|
textureScale = mat.GetTextureScale(ShaderParams.MainTex);
|
|
textureOffset = mat.GetTextureOffset(ShaderParams.MainTex);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(transpObject.baseColorPropertyName) && mat.HasProperty(transpObject.baseColorPropertyName)) {
|
|
color = mat.GetColor(transpObject.baseColorPropertyName);
|
|
} else
|
|
if (mat.HasProperty(ShaderParams.BaseColor)) {
|
|
color = mat.GetColor(ShaderParams.BaseColor);
|
|
} else
|
|
if (mat.HasProperty(ShaderParams.Color)) {
|
|
color = mat.GetColor(ShaderParams.Color);
|
|
}
|
|
overrideMaterial.SetTexture(ShaderParams.MainTex, texture);
|
|
overrideMaterial.SetColor(ShaderParams.Color, color);
|
|
overrideMaterial.SetVector(ShaderParams.MainTex_ST, new Vector4(textureScale.x, textureScale.y, textureOffset.x, textureOffset.y));
|
|
overrideMaterial.SetVector(ShaderParams.TranslucencyIntensity, new Vector4(intensity * transpObject.intensityMultiplier, light.shadowTranslucencyBlend, 0, 0));
|
|
cmd.DrawRenderer(transpObject.theRenderer, overrideMaterial);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public void CleanUp () {
|
|
if (light != null) {
|
|
RTHandles.Release(light.translucencyMapHandle);
|
|
}
|
|
if (transpOverrideMaterials != null) {
|
|
for (int k = 0; k < transpOverrideMaterials.Length; k++) {
|
|
DestroyImmediate(transpOverrideMaterials[k]);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
[Tooltip("If this translucent shadow map render feature can execute on overlay cameras.")]
|
|
public bool ignoreOverlayCamera = true;
|
|
|
|
TranspRenderPass m_ScriptablePass;
|
|
|
|
public override void Create () {
|
|
m_ScriptablePass = new TranspRenderPass(this);
|
|
}
|
|
|
|
private void OnDestroy () {
|
|
if (m_ScriptablePass != null) {
|
|
m_ScriptablePass.CleanUp();
|
|
}
|
|
}
|
|
|
|
bool needsTranslucencyTextureCleanUp;
|
|
|
|
public override void AddRenderPasses (ScriptableRenderer renderer, ref RenderingData renderingData) {
|
|
if (ignoreOverlayCamera && renderingData.cameraData.renderType == CameraRenderType.Overlay) return;
|
|
|
|
int renderersCount = VolumetricLightsTranslucency.objects.Count;
|
|
if (renderersCount == 0) {
|
|
if (!needsTranslucencyTextureCleanUp) return;
|
|
needsTranslucencyTextureCleanUp = false;
|
|
} else {
|
|
needsTranslucencyTextureCleanUp = true;
|
|
}
|
|
|
|
Camera cam = renderingData.cameraData.camera;
|
|
Transform parent = cam.transform.parent;
|
|
if (parent == null) return;
|
|
VolumetricLight light = parent.GetComponent<VolumetricLight>();
|
|
if (light == null || !light.shadowTranslucency || light.translucentMap == null) return;
|
|
if (cam.cameraType == CameraType.Reflection && (cam.cullingMask & (1 << light.gameObject.layer)) == 0) return;
|
|
|
|
m_ScriptablePass.Setup(renderer, light);
|
|
renderer.EnqueuePass(m_ScriptablePass);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|