Files
Shopping_UnityVR/Assets/UmbraSoftShadows/Runtime/Scripts/UmbraRenderFeature.RG.cs
2026-04-16 04:58:10 +09:00

484 lines
26 KiB
C#

#if UNITY_2023_3_OR_NEWER
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;
using System.Collections.Generic;
namespace Umbra {
internal partial class UmbraRenderFeature : ScreenSpaceShadows {
private partial class UmbraScreenSpaceShadowsPass : ScriptableRenderPass {
class PassData {
public UmbraScreenSpaceShadowsPass pass;
public UniversalShadowData shadowData;
public UniversalLightData lightData;
public UniversalCameraData cameraData;
public UniversalRenderingData renderingData;
public TextureHandle rtCameraDepthTexture;
public TextureHandle rtCameraNormalsTexture;
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
if (mat == null) {
Debug.LogError("Umbra material not initialized");
return;
}
using (var builder = renderGraph.AddUnsafePass<PassData>("Umbra Soft Shadows", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
desc = cameraData.cameraTargetDescriptor;
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
desc.graphicsFormat = screenShadowTextureFormat;
UmbraProfile profile = settings.profile;
if (profile.downsample && !profile.preserveEdges) {
desc.width /= 2;
desc.height /= 2;
}
Camera cam = cameraData.camera;
#if UNITY_EDITOR
if (profile.frameSkipOptimization && Application.isPlaying) {
#else
if (profile.frameSkipOptimization) {
#endif
newShadowmap = !shadowTextures.TryGetValue(cam, out m_RenderTarget);
}
if (RenderingUtils.ReAllocateHandleIfNeeded(ref m_RenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp, name: "_ScreenSpaceShadowmapTexture")) {
newShadowmap = true;
}
if (newShadowmap) {
shadowTextures[cam] = m_RenderTarget;
}
builder.AllowGlobalStateModification(true);
#if UNITY_6000_0_OR_NEWER
TextureHandle shadowmap = renderGraph.ImportTexture(m_RenderTarget, new RenderTargetInfo {
width = desc.width,
height = desc.height,
volumeDepth = 1,
msaaSamples = 1,
format = desc.graphicsFormat
});
#else
TextureHandle shadowmap = renderGraph.ImportTexture(m_RenderTarget);
#endif
builder.UseTexture(shadowmap, AccessFlags.ReadWrite);
if (UmbraSoftShadows.isDeferred && resourceData.gBuffer[2].IsValid()) {
passData.rtCameraNormalsTexture = resourceData.gBuffer[2];
builder.UseTexture(passData.rtCameraNormalsTexture, AccessFlags.Read);
}
passData.rtCameraDepthTexture = resourceData.cameraDepthTexture;
builder.UseTexture(resourceData.cameraDepthTexture, AccessFlags.Read);
if ((input & ScriptableRenderPassInput.Normal) != 0) {
builder.UseTexture(resourceData.cameraNormalsTexture, AccessFlags.Read);
}
passData.pass = this;
passData.cameraData = cameraData;
passData.lightData = frameData.Get<UniversalLightData>();
passData.shadowData = frameData.Get<UniversalShadowData>();
passData.renderingData = frameData.Get<UniversalRenderingData>();
builder.SetRenderFunc(static (PassData data, UnsafeGraphContext rgContext) => {
if (data.rtCameraDepthTexture.IsValid()) {
mat.SetTexture(ShaderParams.CameraDepthTexture, data.rtCameraDepthTexture);
}
if (data.rtCameraNormalsTexture.IsValid()) {
mat.SetTexture(ShaderParams.CameraNormalsTexture, data.rtCameraNormalsTexture);
}
CommandBuffer cmd = CommandBufferHelpers.GetNativeCommandBuffer(rgContext.cmd);
cmd.SetGlobalTexture(m_RenderTarget.name, m_RenderTarget.nameID);
ExecutePass(cmd, data);
});
}
}
static void ExecutePass (CommandBuffer cmd, PassData passData) {
UmbraProfile profile = settings.profile;
int frameCount = Time.frameCount;
#if UNITY_EDITOR
bool useFrame = !Application.isPlaying || !profile.frameSkipOptimization || newShadowmap || !usesCachedShadowmap;
#else
bool useFrame = !profile.frameSkipOptimization || newShadowmap || !usesCachedShadowmap;
#endif
if (useFrame) {
cachedShadowmapTimestap = frameCount;
newShadowmap = false;
RTHandle shadowsHandle;
if (profile.downsample && profile.preserveEdges) {
desc.width /= 2;
desc.height /= 2;
#if UNITY_6000_0_OR_NEWER
RenderingUtils.ReAllocateHandleIfNeeded(ref m_DownscaledRenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp);
#else
RenderingUtils.ReAllocateIfNeeded(ref m_DownscaledRenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp);
#endif
shadowsHandle = m_DownscaledRenderTarget;
}
else {
shadowsHandle = m_RenderTarget;
}
float farClipPlane = passData.cameraData.camera.farClipPlane;
int cascadeCount = passData.shadowData.mainLightShadowCascadesCount;
UniversalRenderPipelineAsset urpAsset = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
float shadowMaxDistance = urpAsset.shadowDistance;
Pass castShadowsPass;
if (profile.shadowSource == ShadowSource.UnityShadows) {
castShadowsPass = Pass.UnityShadows;
}
else {
castShadowsPass = Pass.UmbraCastShadows;
if (profile.transparentReceiverPlane) {
mat.EnableKeyword(ShaderParams.SKW_RECEIVER_PLANE);
cmd.SetGlobalFloat(ShaderParams.ReceiverPlaneAltitude, profile.receiverPlaneAltitude);
}
else {
mat.DisableKeyword(ShaderParams.SKW_RECEIVER_PLANE);
}
cmd.SetGlobalVector(ShaderParams.ShadowData, new Vector4(profile.sampleCount, 1024 / Mathf.Pow(2, profile.posterization), profile.blurEdgeTolerance * 1000f, (profile.blurDepthAttenStart + profile.blurDepthAttenLength) / farClipPlane));
float shadowMaxDepth = profile.transparentReceiverPlane ? 2 : shadowMaxDistance / farClipPlane;
cmd.SetGlobalVector(ShaderParams.ShadowData2, new Vector4(1f - profile.contactStrength, profile.distantSpread, shadowMaxDepth, profile.lightSize * 0.02f));
cmd.SetGlobalVector(ShaderParams.ShadowData3, new Vector4(profile.blurDepthAttenStart / farClipPlane, profile.blurDepthAttenLength / farClipPlane, profile.blurGrazingAttenuation, profile.blurEdgeSharpness));
cmd.SetGlobalVector(ShaderParams.ShadowData4, new Vector4(profile.occludersCount, profile.occludersSearchRadius * 0.02f, profile.contactStrength > 0 ? profile.contactStrengthKnee * 0.1f : 0.00001f, profile.maskScale));
cmd.SetGlobalVector(ShaderParams.SourceSize, new Vector4(desc.width, desc.height, 0, 0));
cmd.SetGlobalInt(ShaderParams.EarlyOutSamples, profile.earlyOutSamples);
if (cascadeCount > 1) {
VisibleLight shadowLight = passData.lightData.visibleLights[shadowLightIndex];
float shadowNearPlane = shadowLight.light.shadowNearPlane;
for (int k = 0; k < cascadeCount; k++) {
passData.renderingData.cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(shadowLightIndex,
k, cascadeCount, passData.shadowData.mainLightShadowCascadesSplit, urpAsset.mainLightShadowmapResolution, shadowNearPlane, out _, out Matrix4x4 proj,
out _);
Matrix4x4 invProj = proj.inverse;
autoCascadeScales[k] = Mathf.Abs(invProj.MultiplyPoint(ShaderParams.Vector3Back).z - invProj.MultiplyPoint(ShaderParams.Vector3Forward).z) / 100f;
}
Vector4[] cascadeRectsTemp = cascadeRectsWithPadding[cascadeCount - 1];
float texel = 1f / urpAsset.mainLightShadowmapResolution;
float padding = texel;
for (int c = 0; c < 4; c++) {
Vector4 defaultRect = cascadeRects[cascadeCount - 1][c];
Vector4 rect = cascadeRectsTemp[c];
rect.x = defaultRect.x + padding;
rect.y = defaultRect.y + padding;
rect.z = defaultRect.z - padding;
rect.w = defaultRect.w - padding;
cascadeRectsTemp[c] = rect;
}
cmd.SetGlobalVectorArray(ShaderParams.UmbraCascadeRects, cascadeRectsTemp);
cascadeScales[0] = profile.cascade1Scale * autoCascadeScales[0];
cascadeScales[1] = profile.cascade2Scale * autoCascadeScales[1];
cascadeScales[2] = profile.cascade3Scale * autoCascadeScales[2];
cascadeScales[3] = profile.cascade4Scale * autoCascadeScales[3];
cmd.SetGlobalFloatArray(ShaderParams.UmbraCascadeScales, cascadeScales);
}
if ((UmbraSoftShadows.isDeferred && profile.normalsSource == NormalSource.GBufferNormals) || profile.effectiveNormalsSource == NormalSource.NormalsPass || profile.downsample) {
mat.EnableKeyword(ShaderParams.SKW_NORMALS_TEXTURE);
}
else {
mat.DisableKeyword(ShaderParams.SKW_NORMALS_TEXTURE);
}
#if !UNITY_WEBGL
if (profile.enableContactHardening) {
mat.EnableKeyword(ShaderParams.SKW_CONTACT_HARDENING);
}
else
#endif
{
mat.DisableKeyword(ShaderParams.SKW_CONTACT_HARDENING);
}
mat.DisableKeyword(ShaderParams.SKW_LOOP_STEP_X3);
mat.DisableKeyword(ShaderParams.SKW_LOOP_STEP_X2);
if (profile.loopStepOptimization == LoopStep.x3) {
mat.EnableKeyword(ShaderParams.SKW_LOOP_STEP_X3);
}
else if (profile.loopStepOptimization == LoopStep.x2) {
mat.EnableKeyword(ShaderParams.SKW_LOOP_STEP_X2);
}
if (profile.style == Style.Textured && profile.maskTexture != null) {
mat.EnableKeyword(ShaderParams.SKW_MASK_TEXTURE);
mat.SetTexture(ShaderParams.MaskTexture, profile.maskTexture);
}
else {
mat.DisableKeyword(ShaderParams.SKW_MASK_TEXTURE);
}
}
// Resolve screen space shadows
Blitter.BlitCameraTexture(cmd, m_RenderTarget, shadowsHandle, mat, (int)castShadowsPass);
// Blend cascades 0 & 1
if (profile.shadowSource == ShadowSource.UmbraShadows) {
if (profile.blendCascades && cascadeCount > 1) {
cmd.SetGlobalVector(ShaderParams.BlendCascadeData, new Vector4(profile.cascade1BlendingStrength * 100f, profile.cascade2BlendingStrength * 100f, profile.cascade3BlendingStrength * 100f, 1f));
Blitter.BlitCameraTexture(cmd, shadowsHandle, shadowsHandle, mat, (int)Pass.CascadeBlending);
}
}
// Add contact shadows
if (profile.contactShadows && SetupContactShadowsMaterial(passData.cameraData.camera, profile, mat)) {
if (!settings.debugShadows && profile.actualContactShadowsInjectionPoint == ContactShadowsInjectionPoint.ShadowTexture) {
Blitter.BlitCameraTexture(cmd, shadowsHandle, shadowsHandle, mat, (int)Pass.ContactShadows);
}
}
// Downscale depth for upscaler
if (profile.downsample && profile.preserveEdges) {
RenderTextureDescriptor downscampledDepthDesc = desc;
downscampledDepthDesc.colorFormat = RenderTextureFormat.RFloat;
cmd.GetTemporaryRT(ShaderParams.DownsampledDepth, downscampledDepthDesc);
FullScreenBlit(cmd, ShaderParams.DownsampledDepth, mat, (int)Pass.DownsampledDepth);
mat.EnableKeyword(ShaderParams.SKW_PRESERVE_EDGES);
}
else {
mat.DisableKeyword(ShaderParams.SKW_PRESERVE_EDGES);
}
if (profile.shadowSource == ShadowSource.UnityShadows) {
if (profile.downsample && profile.preserveEdges) {
// upscale
FullScreenBlit(cmd, m_DownscaledRenderTarget, m_RenderTarget, mat, (int)Pass.ComposeUnity);
}
}
else {
if (profile.style == Style.Default && profile.blurIterations > 0) {
cmd.SetGlobalFloat(ShaderParams.BlurSpread, profile.blurSpread);
// perform blur
cmd.GetTemporaryRT(ShaderParams.BlurTemp, desc);
cmd.GetTemporaryRT(ShaderParams.BlurTemp2, desc);
cmd.SetGlobalFloat(ShaderParams.BlurScale, 1f);
RenderTargetIdentifier shadowsRT = shadowsHandle;
RenderTargetIdentifier blurredRT = ShaderParams.BlurTemp2;
if (profile.blurType == BlurType.Box) {
for (int k = 0; k < profile.blurIterations; k++) {
blurredRT = (k % 2) == 0 ? ShaderParams.BlurTemp2 : ShaderParams.BlurTemp;
FullScreenBlit(cmd, shadowsRT, blurredRT, mat, (int)Pass.BoxBlur);
shadowsRT = blurredRT;
cmd.SetGlobalFloat(ShaderParams.BlurScale, k + 1f);
}
}
else {
if (profile.blurType == BlurType.Gaussian15) {
mat.EnableKeyword(ShaderParams.SKW_BLUR_HQ);
}
else {
mat.DisableKeyword(ShaderParams.SKW_BLUR_HQ);
}
FullScreenBlit(cmd, shadowsRT, ShaderParams.BlurTemp, mat, (int)Pass.BlurHoriz);
cmd.SetGlobalFloat(ShaderParams.BlurScale, 1f);
for (int k = 0; k < profile.blurIterations - 1; k++) {
FullScreenBlit(cmd, ShaderParams.BlurTemp, ShaderParams.BlurTemp2, mat, (int)Pass.BlurVert);
cmd.SetGlobalFloat(ShaderParams.BlurScale, k + 2f);
FullScreenBlit(cmd, ShaderParams.BlurTemp2, ShaderParams.BlurTemp, mat, (int)Pass.BlurHoriz);
}
FullScreenBlit(cmd, ShaderParams.BlurTemp, ShaderParams.BlurTemp2, mat, (int)Pass.BlurVert);
}
// blit blurred shadows
FullScreenBlit(cmd, blurredRT, m_RenderTarget, mat, (int)Pass.ComposeWithBlending);
}
else if (profile.downsample && profile.preserveEdges) {
// upscale
FullScreenBlit(cmd, m_DownscaledRenderTarget, m_RenderTarget, mat, (int)Pass.Compose);
}
}
}
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowScreen, true);
}
}
private partial class UmbraScreenSpaceShadowsPostPass : ScriptableRenderPass {
internal class PassData {
internal UniversalShadowData shadowData;
}
private static void ExecutePass (RasterCommandBuffer cmd, UniversalShadowData shadowData) {
int cascadesCount = shadowData.mainLightShadowCascadesCount;
bool mainLightShadows = shadowData.supportsMainLightShadows;
bool receiveShadowsNoCascade = mainLightShadows && cascadesCount == 1;
bool receiveShadowsCascades = mainLightShadows && cascadesCount > 1;
// Before transparent object pass, force to disable screen space shadow of main light
cmd.SetKeyword(ShaderGlobalKeywords.MainLightShadowScreen, false);
// then enable main light shadows with or without cascades
cmd.SetKeyword(ShaderGlobalKeywords.MainLightShadows, receiveShadowsNoCascade);
cmd.SetKeyword(ShaderGlobalKeywords.MainLightShadowCascades, receiveShadowsCascades);
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Umbra Screen Space Shadow Post Pass", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
TextureHandle color = resourceData.activeColorTexture;
builder.SetRenderAttachment(color, 0, AccessFlags.Write);
passData.shadowData = frameData.Get<UniversalShadowData>();
builder.AllowGlobalStateModification(true);
builder.SetRenderFunc(static (PassData data, RasterGraphContext rgContext) => {
ExecutePass(rgContext.cmd, data.shadowData);
});
}
}
}
private partial class UmbraDebugPass : ScriptableRenderPass {
internal class PassData {
internal Camera cam;
}
private static void ExecutePass (RasterCommandBuffer cmd, Camera cam) {
Material mat = UmbraScreenSpaceShadowsPass.mat;
if (mat == null) return;
RTHandle shadows = null;
Dictionary<Camera, RTHandle> shadowTextures = shadowPass.shadowTextures;
if (shadowTextures != null) {
shadows = shadowTextures[cam];
}
if (shadows == null) return;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
Blitter.BlitTexture(cmd, shadows, new Vector4(1, 1, 0, 0), mat, (int)Pass.DebugShadows);
if (settings.debugShadows && settings.profile != null && settings.profile.contactShadows) {
Blitter.BlitTexture(cmd, shadows, new Vector4(1, 1, 0, 0), mat, (int)Pass.ContactShadowsAfterOpaque);
}
}
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Umbra Debug Pass", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
TextureHandle color = resourceData.activeColorTexture;
builder.SetRenderAttachment(color, 0, AccessFlags.Write);
passData.cam = frameData.Get<UniversalCameraData>().camera;
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => {
ExecutePass(rgContext.cmd, data.cam);
});
}
}
}
private partial class UmbraContactShadowsAfterOpaquePass : ScriptableRenderPass {
internal class PassData {
internal TextureHandle colorTexture;
internal TextureHandle depthTexture;
}
private static void ExecutePass (RasterCommandBuffer cmd, RTHandle source, RTHandle depth) {
Material mat = UmbraScreenSpaceShadowsPass.mat;
if (mat == null) return;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
mat.SetTexture(ShaderParams.CameraDepthTexture, depth);
UmbraProfile profile = settings.profile;
if (profile.transparentReceiverPlane) {
cmd.SetGlobalFloat(ShaderParams.ReceiverPlaneAltitude, profile.receiverPlaneAltitude);
}
cmd.SetGlobalVector(ShaderParams.SourceSize, new Vector4(source.rt.width, source.rt.height, 0, 0));
Blitter.BlitTexture(cmd, source, new Vector4(1, 1, 0, 0), mat, (int)Pass.ContactShadowsAfterOpaque);
}
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Umbra Contact Shadows After Opaque Pass", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
TextureHandle color = resourceData.activeColorTexture;
if (UmbraSoftShadows.isDeferred && resourceData.gBuffer[4].IsValid()) {
passData.depthTexture = resourceData.gBuffer[4];
builder.UseTexture(passData.depthTexture, AccessFlags.Read);
}
else {
passData.depthTexture = resourceData.cameraDepthTexture;
builder.UseTexture(resourceData.cameraDepthTexture, AccessFlags.Read);
}
builder.AllowGlobalStateModification(true);
builder.SetRenderAttachment(color, 0, AccessFlags.Write);
passData.colorTexture = color;
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => {
ExecutePass(rgContext.cmd, data.colorTexture, data.depthTexture);
});
}
}
}
private partial class UmbraOverlayShadows : ScriptableRenderPass {
internal class PassData {
internal TextureHandle colorTexture;
}
private static void ExecutePass (RasterCommandBuffer cmd, RTHandle source) {
Material mat = UmbraScreenSpaceShadowsPass.mat;
if (mat == null) return;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
Color shadowColor = settings.profile.overlayShadowsColor;
shadowColor.a = settings.profile.overlayShadowsIntensity;
mat.SetColor(ShaderParams.OverlayShadowColor, shadowColor);
Blitter.BlitTexture(cmd, source, new Vector4(1, 1, 0, 0), mat, (int)Pass.OverlayShadows);
}
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Umbra Overlay Shadows", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
TextureHandle color = resourceData.activeColorTexture;
builder.SetRenderAttachment(color, 0, AccessFlags.Write);
passData.colorTexture = color;
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => {
ExecutePass(rgContext.cmd, data.colorTexture);
});
}
}
}
}
}
#endif