您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
204 行
10 KiB
204 行
10 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace UnityEngine.Experimental.Rendering.LightweightPipeline
|
|
{
|
|
public class LocalShadowsPass : ScriptableRenderPass
|
|
{
|
|
private static class LocalShadowConstantBuffer
|
|
{
|
|
public static int _LocalWorldToShadowAtlas;
|
|
public static int _LocalShadowStrength;
|
|
public static int _LocalShadowOffset0;
|
|
public static int _LocalShadowOffset1;
|
|
public static int _LocalShadowOffset2;
|
|
public static int _LocalShadowOffset3;
|
|
public static int _LocalShadowmapSize;
|
|
}
|
|
|
|
const int k_ShadowmapBufferBits = 16;
|
|
RenderTexture m_LocalShadowmapTexture;
|
|
RenderTextureFormat m_LocalShadowmapFormat;
|
|
|
|
Matrix4x4[] m_LocalShadowMatrices;
|
|
ShadowSliceData[] m_LocalLightSlices;
|
|
float[] m_LocalShadowStrength;
|
|
|
|
const string k_RenderLocalShadows = "Render Local Shadows";
|
|
|
|
|
|
private RenderTargetHandle destination { get; set; }
|
|
|
|
public LocalShadowsPass()
|
|
{
|
|
RegisterShaderPassName("ShadowCaster");
|
|
|
|
m_LocalShadowMatrices = new Matrix4x4[0];
|
|
m_LocalLightSlices = new ShadowSliceData[0];
|
|
m_LocalShadowStrength = new float[0];
|
|
|
|
LocalShadowConstantBuffer._LocalWorldToShadowAtlas = Shader.PropertyToID("_LocalWorldToShadowAtlas");
|
|
LocalShadowConstantBuffer._LocalShadowStrength = Shader.PropertyToID("_LocalShadowStrength");
|
|
LocalShadowConstantBuffer._LocalShadowOffset0 = Shader.PropertyToID("_LocalShadowOffset0");
|
|
LocalShadowConstantBuffer._LocalShadowOffset1 = Shader.PropertyToID("_LocalShadowOffset1");
|
|
LocalShadowConstantBuffer._LocalShadowOffset2 = Shader.PropertyToID("_LocalShadowOffset2");
|
|
LocalShadowConstantBuffer._LocalShadowOffset3 = Shader.PropertyToID("_LocalShadowOffset3");
|
|
LocalShadowConstantBuffer._LocalShadowmapSize = Shader.PropertyToID("_LocalShadowmapSize");
|
|
|
|
m_LocalShadowmapFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Shadowmap)
|
|
? RenderTextureFormat.Shadowmap
|
|
: RenderTextureFormat.Depth;
|
|
}
|
|
|
|
public void Setup(RenderTargetHandle destination, int maxVisibleLocalLights)
|
|
{
|
|
this.destination = destination;
|
|
|
|
if (m_LocalShadowMatrices.Length != maxVisibleLocalLights)
|
|
{
|
|
m_LocalShadowMatrices = new Matrix4x4[maxVisibleLocalLights];
|
|
m_LocalLightSlices = new ShadowSliceData[maxVisibleLocalLights];
|
|
m_LocalShadowStrength = new float[maxVisibleLocalLights];
|
|
}
|
|
}
|
|
|
|
public override void Execute(ScriptableRenderer renderer, ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
if (renderingData.shadowData.renderLocalShadows)
|
|
{
|
|
Clear();
|
|
RenderLocalShadowmapAtlas(ref context, ref renderingData.cullResults, ref renderingData.lightData, ref renderingData.shadowData);
|
|
}
|
|
}
|
|
|
|
public override void FrameCleanup(CommandBuffer cmd)
|
|
{
|
|
if (m_LocalShadowmapTexture)
|
|
{
|
|
RenderTexture.ReleaseTemporary(m_LocalShadowmapTexture);
|
|
m_LocalShadowmapTexture = null;
|
|
}
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
m_LocalShadowmapTexture = null;
|
|
|
|
for (int i = 0; i < m_LocalShadowMatrices.Length; ++i)
|
|
m_LocalShadowMatrices[i] = Matrix4x4.identity;
|
|
|
|
for (int i = 0; i < m_LocalLightSlices.Length; ++i)
|
|
m_LocalLightSlices[i].Clear();
|
|
|
|
for (int i = 0; i < m_LocalShadowStrength.Length; ++i)
|
|
m_LocalShadowStrength[i] = 0.0f;
|
|
}
|
|
|
|
void RenderLocalShadowmapAtlas(ref ScriptableRenderContext context, ref CullResults cullResults, ref LightData lightData, ref ShadowData shadowData)
|
|
{
|
|
List<int> localLightIndices = lightData.visibleLocalLightIndices;
|
|
List<VisibleLight> visibleLights = lightData.visibleLights;
|
|
|
|
int shadowCastingLightsCount = 0;
|
|
int localLightsCount = localLightIndices.Count;
|
|
for (int i = 0; i < localLightsCount; ++i)
|
|
{
|
|
VisibleLight shadowLight = visibleLights[localLightIndices[i]];
|
|
|
|
if (shadowLight.lightType == LightType.Spot && shadowLight.light.shadows != LightShadows.None)
|
|
shadowCastingLightsCount++;
|
|
}
|
|
|
|
if (shadowCastingLightsCount == 0)
|
|
return;
|
|
|
|
Matrix4x4 view, proj;
|
|
Bounds bounds;
|
|
|
|
CommandBuffer cmd = CommandBufferPool.Get(k_RenderLocalShadows);
|
|
using (new ProfilingSample(cmd, k_RenderLocalShadows))
|
|
{
|
|
// TODO: Add support to point light shadows. We make a simplification here that only works
|
|
// for spot lights and with max spot shadows per pass.
|
|
int atlasWidth = shadowData.localShadowAtlasWidth;
|
|
int atlasHeight = shadowData.localShadowAtlasHeight;
|
|
int sliceResolution = LightweightShadowUtils.GetMaxTileResolutionInAtlas(atlasWidth, atlasHeight, shadowCastingLightsCount);
|
|
|
|
m_LocalShadowmapTexture = RenderTexture.GetTemporary(shadowData.localShadowAtlasWidth,
|
|
shadowData.localShadowAtlasHeight, k_ShadowmapBufferBits, m_LocalShadowmapFormat);
|
|
m_LocalShadowmapTexture.filterMode = FilterMode.Bilinear;
|
|
m_LocalShadowmapTexture.wrapMode = TextureWrapMode.Clamp;
|
|
|
|
SetRenderTarget(cmd, m_LocalShadowmapTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
|
|
ClearFlag.Depth, Color.black, TextureDimension.Tex2D);
|
|
|
|
for (int i = 0; i < localLightsCount; ++i)
|
|
{
|
|
int shadowLightIndex = localLightIndices[i];
|
|
VisibleLight shadowLight = visibleLights[shadowLightIndex];
|
|
Light light = shadowLight.light;
|
|
|
|
// TODO: Add support to point light shadows
|
|
if (shadowLight.lightType != LightType.Spot || shadowLight.light.shadows == LightShadows.None)
|
|
continue;
|
|
|
|
if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds))
|
|
continue;
|
|
|
|
Matrix4x4 shadowTransform;
|
|
bool success = LightweightShadowUtils.ExtractSpotLightMatrix(ref cullResults, ref shadowData,
|
|
shadowLightIndex, out shadowTransform, out view, out proj);
|
|
|
|
if (success)
|
|
{
|
|
// This way of computing the shadow slice only work for spots and with most 4 shadow casting lights per pass
|
|
// Change this when point lights are supported.
|
|
Debug.Assert(shadowCastingLightsCount <= 4 && shadowLight.lightType == LightType.Spot);
|
|
|
|
// TODO: We need to pass bias and scale list to shader to be able to support multiple
|
|
// shadow casting local lights.
|
|
m_LocalLightSlices[i].offsetX = (i % 2) * sliceResolution;
|
|
m_LocalLightSlices[i].offsetY = (i / 2) * sliceResolution;
|
|
m_LocalLightSlices[i].resolution = sliceResolution;
|
|
m_LocalLightSlices[i].shadowTransform = shadowTransform;
|
|
|
|
m_LocalShadowStrength[i] = light.shadowStrength;
|
|
|
|
if (shadowCastingLightsCount > 1)
|
|
LightweightShadowUtils.ApplySliceTransform(ref m_LocalLightSlices[i], atlasWidth, atlasHeight);
|
|
|
|
var settings = new DrawShadowsSettings(cullResults, shadowLightIndex);
|
|
LightweightShadowUtils.SetupShadowCasterConstants(cmd, ref shadowLight, proj, sliceResolution);
|
|
LightweightShadowUtils.RenderShadowSlice(cmd, ref context, ref m_LocalLightSlices[i], ref settings, proj, view);
|
|
}
|
|
}
|
|
|
|
SetupLocalLightsShadowReceiverConstants(cmd, ref shadowData);
|
|
}
|
|
context.ExecuteCommandBuffer(cmd);
|
|
CommandBufferPool.Release(cmd);
|
|
}
|
|
|
|
void SetupLocalLightsShadowReceiverConstants(CommandBuffer cmd, ref ShadowData shadowData)
|
|
{
|
|
for (int i = 0; i < m_LocalLightSlices.Length; ++i)
|
|
m_LocalShadowMatrices[i] = m_LocalLightSlices[i].shadowTransform;
|
|
|
|
float invShadowAtlasWidth = 1.0f / shadowData.localShadowAtlasWidth;
|
|
float invShadowAtlasHeight = 1.0f / shadowData.localShadowAtlasHeight;
|
|
float invHalfShadowAtlasWidth = 0.5f * invShadowAtlasWidth;
|
|
float invHalfShadowAtlasHeight = 0.5f * invShadowAtlasHeight;
|
|
|
|
cmd.SetGlobalTexture(destination.id, m_LocalShadowmapTexture);
|
|
cmd.SetGlobalMatrixArray(LocalShadowConstantBuffer._LocalWorldToShadowAtlas, m_LocalShadowMatrices);
|
|
cmd.SetGlobalFloatArray(LocalShadowConstantBuffer._LocalShadowStrength, m_LocalShadowStrength);
|
|
cmd.SetGlobalVector(LocalShadowConstantBuffer._LocalShadowOffset0, new Vector4(-invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f));
|
|
cmd.SetGlobalVector(LocalShadowConstantBuffer._LocalShadowOffset1, new Vector4(invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f));
|
|
cmd.SetGlobalVector(LocalShadowConstantBuffer._LocalShadowOffset2, new Vector4(-invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f));
|
|
cmd.SetGlobalVector(LocalShadowConstantBuffer._LocalShadowOffset3, new Vector4(invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f));
|
|
cmd.SetGlobalVector(LocalShadowConstantBuffer._LocalShadowmapSize, new Vector4(invShadowAtlasWidth, invShadowAtlasHeight,
|
|
shadowData.localShadowAtlasWidth, shadowData.localShadowAtlasHeight));
|
|
}
|
|
}
|
|
}
|