浏览代码
Moved most content to LightweightForwardRenderer. Created passes to encapsulate logic. Currently passes are selected based on primitive feature/capabilities/frame settings.
/main
Moved most content to LightweightForwardRenderer. Created passes to encapsulate logic. Currently passes are selected based on primitive feature/capabilities/frame settings.
/main
Felipe Lira
7 年前
当前提交
17a99791
共有 20 个文件被更改,包括 1995 次插入 和 1603 次删除
-
2ScriptableRenderPipeline/LightweightPipeline/LWRP/Data/LightweightPipelineAsset.cs
-
8ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/LightweightCameraEditor.cs
-
964ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipeline.cs
-
102ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipelineCore.cs
-
34ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DepthOnlyPass.cs
-
35ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScriptableRenderPass.cs
-
20ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Shadows.hlsl
-
4ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightScreenSpaceShadows.shader
-
326ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightForwardRenderer.cs
-
326ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DirectionalShadowsPass.cs
-
652ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ForwardLitPass.cs
-
11ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ForwardLitPass.cs.meta
-
313ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/LocalShadowsPass.cs
-
11ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/LocalShadowsPass.cs.meta
-
75ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScreenSpaceShadowOcclusionPass.cs
-
11ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScreenSpaceShadowOcclusionPass.cs.meta
-
643ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ShadowPass.cs
-
61ScriptableRenderPipeline/LightweightPipeline/LWRP/ForwardRenderer.cs
-
0/ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DirectionalShadowsPass.cs.meta
-
0/ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightForwardRenderer.cs.meta
964
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipeline.cs
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
using System.Collections.Generic; |
|||
using UnityEngine.Rendering; |
|||
using UnityEngine.Rendering.PostProcessing; |
|||
using UnityEngine.XR; |
|||
|
|||
namespace UnityEngine.Experimental.Rendering.LightweightPipeline |
|||
{ |
|||
public enum MaterialHandles |
|||
{ |
|||
Error, |
|||
DepthCopy, |
|||
Sampling, |
|||
Blit, |
|||
ScrenSpaceShadow, |
|||
Count, |
|||
} |
|||
|
|||
public static class RenderTargetHandles |
|||
{ |
|||
public static int Color; |
|||
public static int Depth; |
|||
public static int DepthMS; |
|||
public static int OpaqueColor; |
|||
public static int DirectionalShadowmap; |
|||
public static int LocalShadowmap; |
|||
public static int ScreenSpaceOcclusion; |
|||
} |
|||
|
|||
public class LightweightForwardRenderer |
|||
{ |
|||
// Lights are culled per-object. In platforms that don't use StructuredBuffer
|
|||
// the engine will set 4 light indices in the following constant unity_4LightIndices0
|
|||
// Additionally the engine set unity_4LightIndices1 but LWRP doesn't use that.
|
|||
const int k_MaxConstantLocalLights = 4; |
|||
|
|||
// LWRP uses a fixed constant buffer to hold light data. This must match the value of
|
|||
// MAX_VISIBLE_LIGHTS 16 in Input.hlsl
|
|||
const int k_MaxVisibleLocalLights = 16; |
|||
|
|||
const int k_MaxVertexLights = 4; |
|||
public int maxSupportedLocalLightsPerPass |
|||
{ |
|||
get |
|||
{ |
|||
return useComputeBufferForPerObjectLightIndices ? k_MaxVisibleLocalLights : k_MaxConstantLocalLights; |
|||
} |
|||
} |
|||
|
|||
// TODO: Profile performance of using ComputeBuffer on mobiles that support it vs
|
|||
public bool useComputeBufferForPerObjectLightIndices |
|||
{ |
|||
get { return !Application.isMobilePlatform && Application.platform != RuntimePlatform.WebGLPlayer; } |
|||
} |
|||
|
|||
public int maxVisibleLocalLights { get { return k_MaxVisibleLocalLights; } } |
|||
|
|||
public int maxSupportedVertexLights { get { return k_MaxVertexLights; } } |
|||
|
|||
public PostProcessRenderContext postProcessRenderContext { get; private set; } |
|||
|
|||
public ComputeBuffer perObjectLightIndices { get; private set; } |
|||
|
|||
//RenderGraphNode m_RenderGraph;
|
|||
List<ScriptableRenderPass> m_ShadowPassList = new List<ScriptableRenderPass>(); |
|||
List<ScriptableRenderPass> m_RenderPassList = new List<ScriptableRenderPass>(); |
|||
Dictionary<int, RenderTargetIdentifier> m_ResourceMap = new Dictionary<int, RenderTargetIdentifier>(); |
|||
|
|||
DepthOnlyPass depthOnlyPass; |
|||
DirectionalShadowsPass directionalShadowPass; |
|||
LocalShadowsPass localShadowsPass; |
|||
ScreenSpaceShadowOcclusionPass screenSpaceShadowOcclusionPass; |
|||
ForwardLitPass forwardLitPass; |
|||
|
|||
Dictionary<int, Material> m_Materials; |
|||
List<RenderPassAttachment> m_AttachmentList; |
|||
|
|||
RenderPass m_RenderPass; |
|||
|
|||
public LightweightForwardRenderer(LightweightPipelineAsset pipelineAsset) |
|||
{ |
|||
// RenderTexture format depends on camera and pipeline (HDR, non HDR, etc)
|
|||
// Samples (MSAA) depend on camera and pipeline
|
|||
AddSurface("_CameraColorTexture", out RenderTargetHandles.Color); |
|||
AddSurface("_CameraDepthTexture", out RenderTargetHandles.Depth); |
|||
AddSurface("_CameraDepthMSTexture", out RenderTargetHandles.DepthMS); |
|||
AddSurface("_CameraOpaqueTexture", out RenderTargetHandles.OpaqueColor); |
|||
AddSurface("_DirectionalShadowmapTexture", out RenderTargetHandles.DirectionalShadowmap); |
|||
AddSurface("_LocalShadowmapTexture", out RenderTargetHandles.LocalShadowmap); |
|||
AddSurface("_ScreenSpaceShadowMapTexture", out RenderTargetHandles.ScreenSpaceOcclusion); |
|||
|
|||
m_Materials = new Dictionary<int, Material>((int)MaterialHandles.Count); |
|||
m_Materials.Add((int)MaterialHandles.Error, CoreUtils.CreateEngineMaterial("Hidden/InternalErrorShader")); |
|||
m_Materials.Add((int)MaterialHandles.DepthCopy, CoreUtils.CreateEngineMaterial(pipelineAsset.CopyDepthShader)); |
|||
m_Materials.Add((int)MaterialHandles.Sampling, CoreUtils.CreateEngineMaterial(pipelineAsset.SamplingShader)); |
|||
m_Materials.Add((int)MaterialHandles.Blit, CoreUtils.CreateEngineMaterial(pipelineAsset.BlitShader)); |
|||
m_Materials.Add((int)MaterialHandles.ScrenSpaceShadow, CoreUtils.CreateEngineMaterial(pipelineAsset.ScreenSpaceShadowShader)); |
|||
Debug.Assert(m_Materials.Count == (int)MaterialHandles.Count, "All materials in MaterialHandles should be created."); |
|||
|
|||
depthOnlyPass = new DepthOnlyPass(this); |
|||
directionalShadowPass = new DirectionalShadowsPass(this, pipelineAsset.DirectionalShadowAtlasResolution); |
|||
localShadowsPass = new LocalShadowsPass(this, pipelineAsset.LocalShadowAtlasResolution); |
|||
screenSpaceShadowOcclusionPass = new ScreenSpaceShadowOcclusionPass(this); |
|||
forwardLitPass = new ForwardLitPass(this); |
|||
|
|||
postProcessRenderContext = new PostProcessRenderContext(); |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
if (perObjectLightIndices != null) |
|||
{ |
|||
perObjectLightIndices.Release(); |
|||
perObjectLightIndices = null; |
|||
} |
|||
|
|||
for (int i = 0; i < m_Materials.Count; ++i) |
|||
CoreUtils.Destroy(m_Materials[i]); |
|||
m_Materials.Clear(); |
|||
} |
|||
|
|||
public Material GetMaterial(MaterialHandles resourceHandle) |
|||
{ |
|||
int resourceHandleID = (int)resourceHandle; |
|||
if (resourceHandleID < 0 || resourceHandleID >= m_Materials.Count) |
|||
return null; |
|||
|
|||
return m_Materials[resourceHandleID]; |
|||
} |
|||
|
|||
void AddSurface(string shaderProperty, out int handle) |
|||
{ |
|||
handle = Shader.PropertyToID(shaderProperty); |
|||
m_ResourceMap.Add(handle, new RenderTargetIdentifier(handle)); |
|||
} |
|||
|
|||
public RenderTextureDescriptor CreateRTDesc(ref CameraData cameraData, float scaler = 1.0f) |
|||
{ |
|||
Camera camera = cameraData.camera; |
|||
RenderTextureDescriptor desc; |
|||
if (cameraData.isStereoEnabled) |
|||
desc = XRSettings.eyeTextureDesc; |
|||
else |
|||
desc = new RenderTextureDescriptor(camera.pixelWidth, camera.pixelHeight); |
|||
|
|||
float renderScale = cameraData.renderScale; |
|||
desc.width = (int)((float)desc.width * renderScale * scaler); |
|||
desc.height = (int)((float)desc.height * renderScale * scaler); |
|||
return desc; |
|||
} |
|||
|
|||
public void Setup(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, ref LightData lightData) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("Setup Rendering"); |
|||
m_ShadowPassList.Clear(); |
|||
m_RenderPassList.Clear(); |
|||
SetupPerObjectLightIndices(ref cullResults, ref lightData); |
|||
RenderTextureDescriptor baseDescriptor = CreateRTDesc(ref cameraData); |
|||
|
|||
bool shadowsEnabledForCamera = cameraData.maxShadowDistance > 0.0f; |
|||
bool msaaEnabledForCamera = cameraData.msaaSamples > 1; |
|||
bool supportsTexture2DMS = SystemInfo.supportsMultisampledTextures != 0; |
|||
bool supportsTextureCopy = SystemInfo.copyTextureSupport != CopyTextureSupport.None; |
|||
bool copyShaderSupported = GetMaterial(MaterialHandles.DepthCopy).shader.isSupported && (msaaEnabledForCamera == supportsTexture2DMS); |
|||
bool supportsDepthCopy = copyShaderSupported || supportsTextureCopy; |
|||
bool requiresCameraDepth = cameraData.requiresDepthTexture || cameraData.postProcessEnabled; |
|||
bool requiresDepthPrepassToResolveMsaa = msaaEnabledForCamera && !supportsTexture2DMS; |
|||
bool renderDirectionalShadows = shadowsEnabledForCamera && lightData.shadowData.supportsDirectionalShadows; |
|||
bool requiresScreenSpaceOcclusion = renderDirectionalShadows && lightData.shadowData.requiresScreenSpaceOcclusion; |
|||
bool requiresDepthPrepass = requiresCameraDepth && !supportsDepthCopy || requiresScreenSpaceOcclusion || requiresDepthPrepassToResolveMsaa; |
|||
|
|||
bool intermediateRenderTexture = cameraData.isSceneViewCamera || |
|||
!Mathf.Approximately(cameraData.renderScale, 1.0f) || |
|||
cameraData.isHdrEnabled || |
|||
baseDescriptor.dimension == TextureDimension.Tex2DArray || |
|||
cameraData.postProcessEnabled || |
|||
(msaaEnabledForCamera && |
|||
!LightweightPipeline.PlatformSupportsMSAABackBuffer()); |
|||
|
|||
|
|||
if (requiresDepthPrepass) |
|||
{ |
|||
depthOnlyPass.Setup(cmd, baseDescriptor, 1); |
|||
m_RenderPassList.Add(depthOnlyPass); |
|||
} |
|||
|
|||
if (renderDirectionalShadows) |
|||
{ |
|||
directionalShadowPass.Setup(cmd, baseDescriptor, 1); |
|||
m_ShadowPassList.Add(directionalShadowPass); |
|||
if (requiresScreenSpaceOcclusion) |
|||
{ |
|||
screenSpaceShadowOcclusionPass.Setup(cmd, baseDescriptor, 1); |
|||
m_RenderPassList.Add(screenSpaceShadowOcclusionPass); |
|||
} |
|||
} |
|||
|
|||
if (shadowsEnabledForCamera && lightData.shadowData.supportsLocalShadows) |
|||
{ |
|||
localShadowsPass.Setup(cmd, baseDescriptor, 1); |
|||
m_ShadowPassList.Add(localShadowsPass); |
|||
} |
|||
|
|||
int colorHandle = (intermediateRenderTexture) ? RenderTargetHandles.Color : -1; |
|||
|
|||
int depthHandle = (requiresCameraDepth && !requiresDepthPrepass) |
|||
? ((msaaEnabledForCamera) ? RenderTargetHandles.DepthMS : RenderTargetHandles.Depth) |
|||
: -1; |
|||
|
|||
forwardLitPass.colorHandles = new[] { colorHandle }; |
|||
forwardLitPass.depthHandle = depthHandle; |
|||
forwardLitPass.Setup(cmd, baseDescriptor, cameraData.msaaSamples); |
|||
|
|||
m_RenderPassList.Add(forwardLitPass); |
|||
|
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
public void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, |
|||
ref LightData lightData) |
|||
{ |
|||
for (int i = 0; i < m_ShadowPassList.Count; ++i) |
|||
m_ShadowPassList[i].Execute(ref context, ref cullResults, ref cameraData, ref lightData); |
|||
|
|||
// SetupCameraProperties does the following:
|
|||
// Setup Camera RenderTarget and Viewport
|
|||
// VR Camera Setup and SINGLE_PASS_STEREO props
|
|||
// Setup camera view, proj and their inv matrices.
|
|||
// Setup properties: _WorldSpaceCameraPos, _ProjectionParams, _ScreenParams, _ZBufferParams, unity_OrthoParams
|
|||
// Setup camera world clip planes props
|
|||
// setup HDR keyword
|
|||
// Setup global time properties (_Time, _SinTime, _CosTime)
|
|||
context.SetupCameraProperties(cameraData.camera, cameraData.isStereoEnabled); |
|||
|
|||
for (int i = 0; i < m_RenderPassList.Count; ++i) |
|||
m_RenderPassList[i].Execute(ref context, ref cullResults, ref cameraData, ref lightData); |
|||
|
|||
#if UNITY_EDITOR
|
|||
if (cameraData.isSceneViewCamera) |
|||
CopyDepth(ref context); |
|||
#endif
|
|||
|
|||
DisposePasses(ref context); |
|||
} |
|||
|
|||
void CopyDepth(ref ScriptableRenderContext context) |
|||
{ |
|||
// Restore Render target for additional editor rendering.
|
|||
CommandBuffer cmd = CommandBufferPool.Get("Copy Depth to Camera"); |
|||
CoreUtils.SetRenderTarget(cmd, BuiltinRenderTextureType.CameraTarget); |
|||
cmd.Blit(GetSurface(RenderTargetHandles.Depth), BuiltinRenderTextureType.CameraTarget, GetMaterial(MaterialHandles.DepthCopy)); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
void DisposePasses(ref ScriptableRenderContext context) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("Release Resources"); |
|||
for (int i = 0; i < m_ShadowPassList.Count; ++i) |
|||
m_ShadowPassList[i].Dispose(cmd); |
|||
|
|||
for (int i = 0; i < m_RenderPassList.Count; ++i) |
|||
m_RenderPassList[i].Dispose(cmd); |
|||
|
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
void SetupPerObjectLightIndices(ref CullResults cullResults, ref LightData lightData) |
|||
{ |
|||
if (lightData.totalAdditionalLightsCount > 0) |
|||
{ |
|||
List<VisibleLight> visibleLights = lightData.visibleLights; |
|||
int[] perObjectLightIndexMap = cullResults.GetLightIndexMap(); |
|||
int directionalLightCount = 0; |
|||
|
|||
// Disable all directional lights from the perobject light indices
|
|||
// Pipeline handles them globally
|
|||
for (int i = 0; i < visibleLights.Count; ++i) |
|||
{ |
|||
VisibleLight light = visibleLights[i]; |
|||
if (light.lightType == LightType.Directional) |
|||
{ |
|||
perObjectLightIndexMap[i] = -1; |
|||
++directionalLightCount; |
|||
} |
|||
else |
|||
perObjectLightIndexMap[i] -= directionalLightCount; |
|||
} |
|||
cullResults.SetLightIndexMap(perObjectLightIndexMap); |
|||
|
|||
// if not using a compute buffer, engine will set indices in 2 vec4 constants
|
|||
// unity_4LightIndices0 and unity_4LightIndices1
|
|||
if (useComputeBufferForPerObjectLightIndices) |
|||
{ |
|||
int lightIndicesCount = cullResults.GetLightIndicesCount(); |
|||
if (lightIndicesCount > 0) |
|||
{ |
|||
if (perObjectLightIndices == null) |
|||
{ |
|||
perObjectLightIndices = new ComputeBuffer(lightIndicesCount, sizeof(int)); |
|||
} |
|||
else if (perObjectLightIndices.count < lightIndicesCount) |
|||
{ |
|||
perObjectLightIndices.Release(); |
|||
perObjectLightIndices = new ComputeBuffer(lightIndicesCount, sizeof(int)); |
|||
} |
|||
|
|||
cullResults.FillLightIndices(perObjectLightIndices); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public RenderTargetIdentifier GetSurface(int handle) |
|||
{ |
|||
if (handle < 0) |
|||
{ |
|||
Debug.LogError(string.Format("Handle {0} has not any surface registered to it.", handle)); |
|||
return new RenderTargetIdentifier(); |
|||
} |
|||
|
|||
return m_ResourceMap[handle]; |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Experimental.Rendering.LightweightPipeline |
|||
{ |
|||
public class DirectionalShadowsPass : ScriptableRenderPass |
|||
{ |
|||
const int k_MaxCascades = 4; |
|||
const int k_ShadowmapBufferBits = 16; |
|||
int m_ShadowCasterCascadesCount; |
|||
|
|||
RenderTexture m_DirectionalShadowmapTexture; |
|||
RenderTextureDescriptor m_DirectionalShadowmapDescriptor; |
|||
|
|||
Matrix4x4[] m_DirectionalShadowMatrices; |
|||
ShadowSliceData[] m_CascadeSlices; |
|||
Vector4[] m_CascadeSplitDistances; |
|||
Vector4 m_CascadeSplitRadii; |
|||
|
|||
public DirectionalShadowsPass(LightweightForwardRenderer renderer, int atlasResolution) : base(renderer) |
|||
{ |
|||
RegisterShaderPassName("ShadowCaster"); |
|||
|
|||
m_DirectionalShadowMatrices = new Matrix4x4[k_MaxCascades + 1]; |
|||
m_CascadeSlices = new ShadowSliceData[k_MaxCascades]; |
|||
m_CascadeSplitDistances = new Vector4[k_MaxCascades]; |
|||
|
|||
DirectionalShadowConstantBuffer._WorldToShadow = Shader.PropertyToID("_WorldToShadow"); |
|||
DirectionalShadowConstantBuffer._ShadowData = Shader.PropertyToID("_ShadowData"); |
|||
DirectionalShadowConstantBuffer._DirShadowSplitSpheres = Shader.PropertyToID("_DirShadowSplitSpheres"); |
|||
DirectionalShadowConstantBuffer._DirShadowSplitSphereRadii = Shader.PropertyToID("_DirShadowSplitSphereRadii"); |
|||
DirectionalShadowConstantBuffer._ShadowOffset0 = Shader.PropertyToID("_ShadowOffset0"); |
|||
DirectionalShadowConstantBuffer._ShadowOffset1 = Shader.PropertyToID("_ShadowOffset1"); |
|||
DirectionalShadowConstantBuffer._ShadowOffset2 = Shader.PropertyToID("_ShadowOffset2"); |
|||
DirectionalShadowConstantBuffer._ShadowOffset3 = Shader.PropertyToID("_ShadowOffset3"); |
|||
DirectionalShadowConstantBuffer._ShadowmapSize = Shader.PropertyToID("_ShadowmapSize"); |
|||
|
|||
RenderTextureFormat shadowmapFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Shadowmap) |
|||
? RenderTextureFormat.Shadowmap |
|||
: RenderTextureFormat.Depth; |
|||
|
|||
m_DirectionalShadowmapDescriptor = new RenderTextureDescriptor(atlasResolution, |
|||
atlasResolution, shadowmapFormat, k_ShadowmapBufferBits); |
|||
|
|||
Clear(); |
|||
} |
|||
|
|||
public override void Setup(CommandBuffer cmd, RenderTextureDescriptor baseDescriptor, int samples) |
|||
{ |
|||
//m_DirectionalShadowmapTexture = RenderTexture.GetTemporary(m_DirectionalShadowmapDescriptor);
|
|||
//m_DirectionalShadowmapTexture.filterMode = FilterMode.Bilinear;
|
|||
//m_DirectionalShadowmapTexture.wrapMode = TextureWrapMode.Clamp;
|
|||
} |
|||
|
|||
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, ref LightData lightData) |
|||
{ |
|||
Clear(); |
|||
|
|||
ShadowData shadowData = lightData.shadowData; |
|||
if (shadowData.supportsDirectionalShadows) |
|||
lightData.shadowData.renderedDirectionalShadowQuality = RenderDirectionalCascadeShadowmap(ref context, ref cullResults, ref lightData, ref shadowData); |
|||
} |
|||
|
|||
public override void Dispose(CommandBuffer cmd) |
|||
{ |
|||
if (m_DirectionalShadowmapTexture) |
|||
{ |
|||
RenderTexture.ReleaseTemporary(m_DirectionalShadowmapTexture); |
|||
m_DirectionalShadowmapTexture = null; |
|||
} |
|||
m_Disposed = true; |
|||
} |
|||
|
|||
void Clear() |
|||
{ |
|||
m_DirectionalShadowmapTexture = null; |
|||
|
|||
for (int i = 0; i < m_DirectionalShadowMatrices.Length; ++i) |
|||
m_DirectionalShadowMatrices[i] = Matrix4x4.identity; |
|||
|
|||
for (int i = 0; i < m_CascadeSplitDistances.Length; ++i) |
|||
m_CascadeSplitDistances[i] = new Vector4(0.0f, 0.0f, 0.0f, 0.0f); |
|||
|
|||
m_CascadeSplitRadii = new Vector4(0.0f, 0.0f, 0.0f, 0.0f); |
|||
|
|||
for (int i = 0; i < m_CascadeSlices.Length; ++i) |
|||
m_CascadeSlices[i].Clear(); |
|||
} |
|||
|
|||
LightShadows RenderDirectionalCascadeShadowmap(ref ScriptableRenderContext context, ref CullResults cullResults, ref LightData lightData, ref ShadowData shadowData) |
|||
{ |
|||
LightShadows shadowQuality = LightShadows.None; |
|||
int shadowLightIndex = lightData.mainLightIndex; |
|||
if (shadowLightIndex == -1) |
|||
return shadowQuality; |
|||
|
|||
VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex]; |
|||
Light light = shadowLight.light; |
|||
Debug.Assert(shadowLight.lightType == LightType.Directional); |
|||
|
|||
if (light.shadows == LightShadows.None) |
|||
return shadowQuality; |
|||
|
|||
Bounds bounds; |
|||
if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds)) |
|||
return shadowQuality; |
|||
|
|||
CommandBuffer cmd = CommandBufferPool.Get("Prepare Directional Shadowmap"); |
|||
m_ShadowCasterCascadesCount = shadowData.directionalLightCascadeCount; |
|||
|
|||
int shadowResolution = GetMaxTileResolutionInAtlas(shadowData.directionalShadowAtlasWidth, shadowData.directionalShadowAtlasHeight, m_ShadowCasterCascadesCount); |
|||
float shadowNearPlane = light.shadowNearPlane; |
|||
|
|||
Matrix4x4 view, proj; |
|||
var settings = new DrawShadowsSettings(cullResults, shadowLightIndex); |
|||
|
|||
m_DirectionalShadowmapTexture = RenderTexture.GetTemporary(m_DirectionalShadowmapDescriptor); |
|||
m_DirectionalShadowmapTexture.filterMode = FilterMode.Bilinear; |
|||
m_DirectionalShadowmapTexture.wrapMode = TextureWrapMode.Clamp; |
|||
CoreUtils.SetRenderTarget(cmd, m_DirectionalShadowmapTexture, ClearFlag.Depth); |
|||
m_Disposed = false; |
|||
|
|||
bool success = false; |
|||
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex) |
|||
{ |
|||
success = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(shadowLightIndex, |
|||
cascadeIndex, m_ShadowCasterCascadesCount, shadowData.directionalLightCascades, shadowResolution, shadowNearPlane, out view, out proj, |
|||
out settings.splitData); |
|||
|
|||
float cullingSphereRadius = settings.splitData.cullingSphere.w; |
|||
m_CascadeSplitDistances[cascadeIndex] = settings.splitData.cullingSphere; |
|||
m_CascadeSplitRadii[cascadeIndex] = cullingSphereRadius * cullingSphereRadius; |
|||
|
|||
if (!success) |
|||
break; |
|||
|
|||
m_CascadeSlices[cascadeIndex].offsetX = (cascadeIndex % 2) * shadowResolution; |
|||
m_CascadeSlices[cascadeIndex].offsetY = (cascadeIndex / 2) * shadowResolution; |
|||
m_CascadeSlices[cascadeIndex].resolution = shadowResolution; |
|||
m_CascadeSlices[cascadeIndex].shadowTransform = GetShadowTransform(proj, view); |
|||
|
|||
// If we have shadow cascades baked into the atlas we bake cascade transform
|
|||
// in each shadow matrix to save shader ALU and L/S
|
|||
if (m_ShadowCasterCascadesCount > 1) |
|||
ApplySliceTransform(ref m_CascadeSlices[cascadeIndex], shadowData.directionalShadowAtlasWidth, shadowData.directionalShadowAtlasHeight); |
|||
|
|||
SetupShadowCasterConstants(cmd, ref shadowLight, proj, shadowResolution); |
|||
RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex], proj, view, settings); |
|||
} |
|||
|
|||
if (success) |
|||
{ |
|||
shadowQuality = (shadowData.supportsSoftShadows) ? light.shadows : LightShadows.Hard; |
|||
|
|||
// In order to avoid shader variants explosion we only do hard shadows when sampling shadowmap in the lit pass.
|
|||
// GLES2 platform is forced to hard single cascade shadows.
|
|||
if (!shadowData.requiresScreenSpaceOcclusion) |
|||
shadowQuality = LightShadows.Hard; |
|||
|
|||
SetupDirectionalShadowReceiverConstants(ref context, cmd, ref shadowData, shadowLight); |
|||
} |
|||
|
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
return shadowQuality; |
|||
} |
|||
|
|||
Matrix4x4 GetShadowTransform(Matrix4x4 proj, Matrix4x4 view) |
|||
{ |
|||
// Currently CullResults ComputeDirectionalShadowMatricesAndCullingPrimitives doesn't
|
|||
// apply z reversal to projection matrix. We need to do it manually here.
|
|||
if (SystemInfo.usesReversedZBuffer) |
|||
{ |
|||
proj.m20 = -proj.m20; |
|||
proj.m21 = -proj.m21; |
|||
proj.m22 = -proj.m22; |
|||
proj.m23 = -proj.m23; |
|||
} |
|||
|
|||
Matrix4x4 worldToShadow = proj * view; |
|||
|
|||
var textureScaleAndBias = Matrix4x4.identity; |
|||
textureScaleAndBias.m00 = 0.5f; |
|||
textureScaleAndBias.m11 = 0.5f; |
|||
textureScaleAndBias.m22 = 0.5f; |
|||
textureScaleAndBias.m03 = 0.5f; |
|||
textureScaleAndBias.m23 = 0.5f; |
|||
textureScaleAndBias.m13 = 0.5f; |
|||
|
|||
// Apply texture scale and offset to save a MAD in shader.
|
|||
return textureScaleAndBias * worldToShadow; |
|||
} |
|||
|
|||
void ApplySliceTransform(ref ShadowSliceData shadowSliceData, int atlasWidth, int atlasHeight) |
|||
{ |
|||
Matrix4x4 sliceTransform = Matrix4x4.identity; |
|||
float oneOverAtlasWidth = 1.0f / atlasWidth; |
|||
float oneOverAtlasHeight = 1.0f / atlasHeight; |
|||
sliceTransform.m00 = shadowSliceData.resolution * oneOverAtlasWidth; |
|||
sliceTransform.m11 = shadowSliceData.resolution * oneOverAtlasHeight; |
|||
sliceTransform.m03 = shadowSliceData.offsetX * oneOverAtlasWidth; |
|||
sliceTransform.m13 = shadowSliceData.offsetY * oneOverAtlasHeight; |
|||
|
|||
// Apply shadow slice scale and offset
|
|||
shadowSliceData.shadowTransform = sliceTransform * shadowSliceData.shadowTransform; |
|||
} |
|||
|
|||
void RenderShadowSlice(CommandBuffer cmd, ref ScriptableRenderContext context, ref ShadowSliceData shadowSliceData, |
|||
Matrix4x4 proj, Matrix4x4 view, DrawShadowsSettings settings) |
|||
{ |
|||
cmd.SetViewport(new Rect(shadowSliceData.offsetX, shadowSliceData.offsetY, shadowSliceData.resolution, shadowSliceData.resolution)); |
|||
cmd.EnableScissorRect(new Rect(shadowSliceData.offsetX + 4, shadowSliceData.offsetY + 4, shadowSliceData.resolution - 8, shadowSliceData.resolution - 8)); |
|||
|
|||
cmd.SetViewProjectionMatrices(view, proj); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
context.DrawShadows(ref settings); |
|||
cmd.DisableScissorRect(); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
} |
|||
|
|||
int GetMaxTileResolutionInAtlas(int atlasWidth, int atlasHeight, int tileCount) |
|||
{ |
|||
int resolution = Mathf.Min(atlasWidth, atlasHeight); |
|||
if (tileCount > Mathf.Log(resolution)) |
|||
{ |
|||
Debug.LogError( |
|||
String.Format( |
|||
"Cannot fit {0} tiles into current shadowmap atlas of size ({1}, {2}). ShadowMap Resolution set to zero.", |
|||
tileCount, atlasWidth, atlasHeight)); |
|||
return 0; |
|||
} |
|||
|
|||
int currentTileCount = atlasWidth / resolution * atlasHeight / resolution; |
|||
while (currentTileCount < tileCount) |
|||
{ |
|||
resolution = resolution >> 1; |
|||
currentTileCount = atlasWidth / resolution * atlasHeight / resolution; |
|||
} |
|||
return resolution; |
|||
} |
|||
|
|||
void SetupShadowCasterConstants(CommandBuffer cmd, ref VisibleLight visibleLight, Matrix4x4 proj, float cascadeResolution) |
|||
{ |
|||
Light light = visibleLight.light; |
|||
float bias = 0.0f; |
|||
float normalBias = 0.0f; |
|||
|
|||
// Use same kernel radius as built-in pipeline so we can achieve same bias results
|
|||
// with the default light bias parameters.
|
|||
const float kernelRadius = 3.65f; |
|||
|
|||
if (visibleLight.lightType == LightType.Directional) |
|||
{ |
|||
// Scale bias by cascade's world space depth range.
|
|||
// Directional shadow lights have orthogonal projection.
|
|||
// proj.m22 = -2 / (far - near) since the projection's depth range is [-1.0, 1.0]
|
|||
// In order to be correct we should multiply bias by 0.5 but this introducing aliasing along cascades more visible.
|
|||
float sign = (SystemInfo.usesReversedZBuffer) ? 1.0f : -1.0f; |
|||
bias = light.shadowBias * proj.m22 * sign; |
|||
|
|||
// Currently only square POT cascades resolutions are used.
|
|||
// We scale normalBias
|
|||
double frustumWidth = 2.0 / (double)proj.m00; |
|||
double frustumHeight = 2.0 / (double)proj.m11; |
|||
float texelSizeX = (float)(frustumWidth / (double)cascadeResolution); |
|||
float texelSizeY = (float)(frustumHeight / (double)cascadeResolution); |
|||
float texelSize = Mathf.Max(texelSizeX, texelSizeY); |
|||
|
|||
// Since we are applying normal bias on caster side we want an inset normal offset
|
|||
// thus we use a negative normal bias.
|
|||
normalBias = -light.shadowNormalBias * texelSize * kernelRadius; |
|||
} |
|||
else if (visibleLight.lightType == LightType.Spot) |
|||
{ |
|||
float sign = (SystemInfo.usesReversedZBuffer) ? -1.0f : 1.0f; |
|||
bias = light.shadowBias * sign; |
|||
normalBias = 0.0f; |
|||
} |
|||
else |
|||
{ |
|||
Debug.LogWarning("Only spot and directional shadow casters are supported in lightweight pipeline"); |
|||
} |
|||
|
|||
Vector3 lightDirection = -visibleLight.localToWorld.GetColumn(2); |
|||
cmd.SetGlobalVector("_ShadowBias", new Vector4(bias, normalBias, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector("_LightDirection", new Vector4(lightDirection.x, lightDirection.y, lightDirection.z, 0.0f)); |
|||
} |
|||
|
|||
void SetupDirectionalShadowReceiverConstants(ref ScriptableRenderContext context, CommandBuffer cmd, ref ShadowData shadowData, VisibleLight shadowLight) |
|||
{ |
|||
Light light = shadowLight.light; |
|||
|
|||
int cascadeCount = m_ShadowCasterCascadesCount; |
|||
for (int i = 0; i < k_MaxCascades; ++i) |
|||
m_DirectionalShadowMatrices[i] = (cascadeCount >= i) ? m_CascadeSlices[i].shadowTransform : Matrix4x4.identity; |
|||
|
|||
// We setup and additional a no-op WorldToShadow matrix in the last index
|
|||
// because the ComputeCascadeIndex function in Shadows.hlsl can return an index
|
|||
// out of bounds. (position not inside any cascade) and we want to avoid branching
|
|||
Matrix4x4 noOpShadowMatrix = Matrix4x4.zero; |
|||
noOpShadowMatrix.m33 = (SystemInfo.usesReversedZBuffer) ? 1.0f : 0.0f; |
|||
m_DirectionalShadowMatrices[k_MaxCascades] = noOpShadowMatrix; |
|||
|
|||
float invShadowAtlasWidth = 1.0f / shadowData.directionalShadowAtlasWidth; |
|||
float invShadowAtlasHeight = 1.0f / shadowData.directionalShadowAtlasHeight; |
|||
float invHalfShadowAtlasWidth = 0.5f * invShadowAtlasWidth; |
|||
float invHalfShadowAtlasHeight = 0.5f * invShadowAtlasHeight; |
|||
cmd.SetGlobalTexture(RenderTargetHandles.DirectionalShadowmap, m_DirectionalShadowmapTexture); |
|||
cmd.SetGlobalMatrixArray(DirectionalShadowConstantBuffer._WorldToShadow, m_DirectionalShadowMatrices); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowData, new Vector4(light.shadowStrength, 0.0f, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVectorArray(DirectionalShadowConstantBuffer._DirShadowSplitSpheres, m_CascadeSplitDistances); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._DirShadowSplitSphereRadii, m_CascadeSplitRadii); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowOffset0, new Vector4(-invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowOffset1, new Vector4(invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowOffset2, new Vector4(-invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowOffset3, new Vector4(invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowmapSize, new Vector4(invShadowAtlasWidth, invShadowAtlasHeight, |
|||
shadowData.directionalShadowAtlasWidth, shadowData.directionalShadowAtlasHeight)); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
} |
|||
}; |
|||
} |
|
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using UnityEngine.Experimental.GlobalIllumination; |
|||
using UnityEngine.Rendering; |
|||
using UnityEngine.Rendering.PostProcessing; |
|||
using UnityEngine.XR; |
|||
|
|||
namespace UnityEngine.Experimental.Rendering.LightweightPipeline |
|||
{ |
|||
public class ForwardLitPass : ScriptableRenderPass |
|||
{ |
|||
const int k_DepthStencilBufferBits = 32; |
|||
Vector4 k_DefaultLightPosition = new Vector4(0.0f, 0.0f, 1.0f, 0.0f); |
|||
Vector4 k_DefaultLightColor = Color.black; |
|||
Vector4 k_DefaultLightAttenuation = new Vector4(0.0f, 1.0f, 0.0f, 1.0f); |
|||
Vector4 k_DefaultLightSpotDirection = new Vector4(0.0f, 0.0f, 1.0f, 0.0f); |
|||
Vector4 k_DefaultLightSpotAttenuation = new Vector4(0.0f, 1.0f, 0.0f, 0.0f); |
|||
|
|||
Vector4[] m_LightPositions; |
|||
Vector4[] m_LightColors; |
|||
Vector4[] m_LightDistanceAttenuations; |
|||
Vector4[] m_LightSpotDirections; |
|||
Vector4[] m_LightSpotAttenuations; |
|||
|
|||
RenderTextureFormat m_ColorFormat; |
|||
MixedLightingSetup m_MixedLightingSetup; |
|||
Material m_BlitMaterial; |
|||
Material m_ErrorMaterial; |
|||
|
|||
// Depth Copy Pass
|
|||
Material m_DepthCopyMaterial; |
|||
const string k_MSAADepthKeyword = "_MSAA_DEPTH"; |
|||
int m_SampleCountShaderHandle; |
|||
|
|||
// Opaque Copy Pass
|
|||
Material m_SamplingMaterial; |
|||
float[] m_OpaqueScalerValues = {1.0f, 0.5f, 0.25f, 0.25f}; |
|||
int m_SampleOffsetShaderHandle; |
|||
|
|||
List<ShaderPassName> m_LegacyShaderPassNames; |
|||
|
|||
public ForwardLitPass(LightweightForwardRenderer renderer) : base(renderer) |
|||
{ |
|||
RegisterShaderPassName("LightweightForward"); |
|||
RegisterShaderPassName("SRPDefaultUnlit"); |
|||
|
|||
m_LegacyShaderPassNames = new List<ShaderPassName>(); |
|||
m_LegacyShaderPassNames.Add(new ShaderPassName("Always")); |
|||
m_LegacyShaderPassNames.Add(new ShaderPassName("ForwardBase")); |
|||
m_LegacyShaderPassNames.Add(new ShaderPassName("PrepassBase")); |
|||
m_LegacyShaderPassNames.Add(new ShaderPassName("Vertex")); |
|||
m_LegacyShaderPassNames.Add(new ShaderPassName("VertexLMRGBM")); |
|||
m_LegacyShaderPassNames.Add(new ShaderPassName("VertexLM")); |
|||
|
|||
PerCameraBuffer._MainLightPosition = Shader.PropertyToID("_MainLightPosition"); |
|||
PerCameraBuffer._MainLightColor = Shader.PropertyToID("_MainLightColor"); |
|||
PerCameraBuffer._MainLightCookie = Shader.PropertyToID("_MainLightCookie"); |
|||
PerCameraBuffer._WorldToLight = Shader.PropertyToID("_WorldToLight"); |
|||
PerCameraBuffer._AdditionalLightCount = Shader.PropertyToID("_AdditionalLightCount"); |
|||
PerCameraBuffer._AdditionalLightPosition = Shader.PropertyToID("_AdditionalLightPosition"); |
|||
PerCameraBuffer._AdditionalLightColor = Shader.PropertyToID("_AdditionalLightColor"); |
|||
PerCameraBuffer._AdditionalLightDistanceAttenuation = Shader.PropertyToID("_AdditionalLightDistanceAttenuation"); |
|||
PerCameraBuffer._AdditionalLightSpotDir = Shader.PropertyToID("_AdditionalLightSpotDir"); |
|||
PerCameraBuffer._AdditionalLightSpotAttenuation = Shader.PropertyToID("_AdditionalLightSpotAttenuation"); |
|||
PerCameraBuffer._LightIndexBuffer = Shader.PropertyToID("_LightIndexBuffer"); |
|||
|
|||
int maxVisibleLocalLights = renderer.maxVisibleLocalLights; |
|||
m_LightPositions = new Vector4[maxVisibleLocalLights]; |
|||
m_LightColors = new Vector4[maxVisibleLocalLights]; |
|||
m_LightDistanceAttenuations = new Vector4[maxVisibleLocalLights]; |
|||
m_LightSpotDirections = new Vector4[maxVisibleLocalLights]; |
|||
m_LightSpotAttenuations = new Vector4[maxVisibleLocalLights]; |
|||
|
|||
// TODO: HDR
|
|||
m_ColorFormat = RenderTextureFormat.Default; |
|||
m_BlitMaterial = renderer.GetMaterial(MaterialHandles.Blit); |
|||
m_ErrorMaterial = renderer.GetMaterial(MaterialHandles.Error); |
|||
|
|||
// Copy Depth Pass
|
|||
m_DepthCopyMaterial = renderer.GetMaterial(MaterialHandles.DepthCopy); |
|||
m_SampleCountShaderHandle = Shader.PropertyToID("_SampleCount"); |
|||
|
|||
// Copy Opaque Color Pass
|
|||
m_SamplingMaterial = renderer.GetMaterial(MaterialHandles.Sampling); |
|||
m_SampleOffsetShaderHandle = Shader.PropertyToID("_SampleOffset"); |
|||
} |
|||
|
|||
public override void Setup(CommandBuffer cmd, RenderTextureDescriptor baseDescriptor, int samples) |
|||
{ |
|||
if (colorHandles[0] != -1) |
|||
{ |
|||
var descriptor = baseDescriptor; |
|||
descriptor.colorFormat = m_ColorFormat; |
|||
descriptor.depthBufferBits = k_DepthStencilBufferBits; // TODO: does the color RT always need depth?
|
|||
descriptor.sRGB = true; |
|||
descriptor.msaaSamples = samples; |
|||
descriptor.enableRandomWrite = false; |
|||
cmd.GetTemporaryRT(colorHandles[0], descriptor, FilterMode.Bilinear); |
|||
} |
|||
|
|||
if (depthHandle != -1) |
|||
{ |
|||
var descriptor = baseDescriptor; |
|||
descriptor.colorFormat = RenderTextureFormat.Depth; |
|||
descriptor.depthBufferBits = k_DepthStencilBufferBits; |
|||
descriptor.msaaSamples = samples; |
|||
descriptor.bindMS = samples > 1; |
|||
cmd.GetTemporaryRT(colorHandles[1], descriptor, FilterMode.Point); |
|||
} |
|||
m_Disposed = false; |
|||
} |
|||
|
|||
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, ref LightData lightData) |
|||
{ |
|||
Camera camera = cameraData.camera; |
|||
SetupShaderConstants(ref context, ref cameraData, ref lightData); |
|||
RendererConfiguration rendererConfiguration = GetRendererConfiguration(lightData.totalAdditionalLightsCount); |
|||
|
|||
if (cameraData.isStereoEnabled) |
|||
context.StartMultiEye(camera); |
|||
|
|||
RenderOpaques(ref context, ref cullResults, ref cameraData, rendererConfiguration); |
|||
|
|||
if (cameraData.postProcessEnabled && |
|||
cameraData.postProcessLayer.HasOpaqueOnlyEffects(renderer.postProcessRenderContext)) |
|||
OpaquePostProcessPass(ref context, ref cameraData); |
|||
|
|||
if (cameraData.requiresDepthTexture) |
|||
CopyDepthPass(ref context, ref cameraData); |
|||
|
|||
if (cameraData.requiresOpaqueTexture) |
|||
OpaqueTexturePass(ref context, ref cameraData); |
|||
|
|||
RenderTransparents(ref context, ref cullResults, ref cameraData, rendererConfiguration); |
|||
|
|||
if (cameraData.postProcessEnabled) |
|||
PostProcessPass(ref context, ref cameraData); |
|||
|
|||
// No blit to backbuffer if camera is offscreen render.
|
|||
if (!cameraData.isOffscreenRender && !cameraData.postProcessEnabled && colorHandles[0] != -1) |
|||
FinalBlitPass(ref context, ref cameraData); |
|||
|
|||
if (cameraData.isStereoEnabled) |
|||
{ |
|||
context.StopMultiEye(cameraData.camera); |
|||
context.StereoEndRender(cameraData.camera); |
|||
} |
|||
} |
|||
|
|||
public override void Dispose(CommandBuffer cmd) |
|||
{ |
|||
if (!m_Disposed) |
|||
{ |
|||
for (int i = 0; i < colorHandles.Length; ++i) |
|||
{ |
|||
if (colorHandles[i] != -1) |
|||
cmd.ReleaseTemporaryRT(colorHandles[i]); |
|||
} |
|||
|
|||
if (depthHandle != -1) |
|||
cmd.ReleaseTemporaryRT(depthHandle); |
|||
m_Disposed = true; |
|||
} |
|||
} |
|||
|
|||
RendererConfiguration GetRendererConfiguration(int localLightsCount) |
|||
{ |
|||
RendererConfiguration configuration = RendererConfiguration.PerObjectReflectionProbes | RendererConfiguration.PerObjectLightmaps | RendererConfiguration.PerObjectLightProbe; |
|||
if (localLightsCount > 0) |
|||
{ |
|||
if (renderer.useComputeBufferForPerObjectLightIndices) |
|||
configuration |= RendererConfiguration.ProvideLightIndices; |
|||
else |
|||
configuration |= RendererConfiguration.PerObjectLightIndices8; |
|||
} |
|||
|
|||
return configuration; |
|||
} |
|||
|
|||
void SetupShaderConstants(ref ScriptableRenderContext context, ref CameraData cameraData, ref LightData lightData) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("SetupShaderConstants"); |
|||
SetupShaderLightConstants(cmd, ref lightData); |
|||
SetShaderKeywords(cmd, ref cameraData, ref lightData); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
void SetupShaderLightConstants(CommandBuffer cmd, ref LightData lightData) |
|||
{ |
|||
// Clear to default all light constant data
|
|||
for (int i = 0; i < renderer.maxVisibleLocalLights; ++i) |
|||
InitializeLightConstants(lightData.visibleLights, -1, out m_LightPositions[i], |
|||
out m_LightColors[i], |
|||
out m_LightDistanceAttenuations[i], |
|||
out m_LightSpotDirections[i], |
|||
out m_LightSpotAttenuations[i]); |
|||
|
|||
m_MixedLightingSetup = MixedLightingSetup.None; |
|||
|
|||
// Main light has an optimized shader path for main light. This will benefit games that only care about a single light.
|
|||
// Lightweight pipeline also supports only a single shadow light, if available it will be the main light.
|
|||
SetupMainLightConstants(cmd, ref lightData); |
|||
SetupAdditionalLightConstants(cmd, ref lightData); |
|||
} |
|||
|
|||
void SetupMainLightConstants(CommandBuffer cmd, ref LightData lightData) |
|||
{ |
|||
Vector4 lightPos, lightColor, lightDistanceAttenuation, lightSpotDir, lightSpotAttenuation; |
|||
List<VisibleLight> lights = lightData.visibleLights; |
|||
InitializeLightConstants(lightData.visibleLights, lightData.mainLightIndex, out lightPos, out lightColor, out lightDistanceAttenuation, out lightSpotDir, out lightSpotAttenuation); |
|||
|
|||
if (lightData.mainLightIndex >= 0) |
|||
{ |
|||
VisibleLight mainLight = lights[lightData.mainLightIndex]; |
|||
Light mainLightRef = mainLight.light; |
|||
|
|||
if (LightweightPipeline.IsSupportedCookieType(mainLight.lightType) && mainLightRef.cookie != null) |
|||
{ |
|||
Matrix4x4 lightCookieMatrix; |
|||
LightweightPipeline.GetLightCookieMatrix(mainLight, out lightCookieMatrix); |
|||
cmd.SetGlobalTexture(PerCameraBuffer._MainLightCookie, mainLightRef.cookie); |
|||
cmd.SetGlobalMatrix(PerCameraBuffer._WorldToLight, lightCookieMatrix); |
|||
} |
|||
} |
|||
|
|||
cmd.SetGlobalVector(PerCameraBuffer._MainLightPosition, new Vector4(lightPos.x, lightPos.y, lightPos.z, lightDistanceAttenuation.w)); |
|||
cmd.SetGlobalVector(PerCameraBuffer._MainLightColor, lightColor); |
|||
} |
|||
|
|||
void SetupAdditionalLightConstants(CommandBuffer cmd, ref LightData lightData) |
|||
{ |
|||
int maxVisibleLocalLights = renderer.maxVisibleLocalLights; |
|||
List<VisibleLight> lights = lightData.visibleLights; |
|||
if (lightData.totalAdditionalLightsCount > 0) |
|||
{ |
|||
int localLightsCount = 0; |
|||
for (int i = 0; i < lights.Count && localLightsCount < maxVisibleLocalLights; ++i) |
|||
{ |
|||
VisibleLight light = lights[i]; |
|||
if (light.lightType != LightType.Directional) |
|||
{ |
|||
InitializeLightConstants(lights, i, out m_LightPositions[localLightsCount], |
|||
out m_LightColors[localLightsCount], |
|||
out m_LightDistanceAttenuations[localLightsCount], |
|||
out m_LightSpotDirections[localLightsCount], |
|||
out m_LightSpotAttenuations[localLightsCount]); |
|||
localLightsCount++; |
|||
} |
|||
} |
|||
|
|||
cmd.SetGlobalVector(PerCameraBuffer._AdditionalLightCount, new Vector4(lightData.pixelAdditionalLightsCount, |
|||
lightData.totalAdditionalLightsCount, 0.0f, 0.0f)); |
|||
|
|||
// if not using a compute buffer, engine will set indices in 2 vec4 constants
|
|||
// unity_4LightIndices0 and unity_4LightIndices1
|
|||
if (renderer.perObjectLightIndices != null) |
|||
cmd.SetGlobalBuffer("_LightIndexBuffer", renderer.perObjectLightIndices); |
|||
} |
|||
else |
|||
{ |
|||
cmd.SetGlobalVector(PerCameraBuffer._AdditionalLightCount, Vector4.zero); |
|||
} |
|||
|
|||
cmd.SetGlobalVectorArray(PerCameraBuffer._AdditionalLightPosition, m_LightPositions); |
|||
cmd.SetGlobalVectorArray(PerCameraBuffer._AdditionalLightColor, m_LightColors); |
|||
cmd.SetGlobalVectorArray(PerCameraBuffer._AdditionalLightDistanceAttenuation, m_LightDistanceAttenuations); |
|||
cmd.SetGlobalVectorArray(PerCameraBuffer._AdditionalLightSpotDir, m_LightSpotDirections); |
|||
cmd.SetGlobalVectorArray(PerCameraBuffer._AdditionalLightSpotAttenuation, m_LightSpotAttenuations); |
|||
} |
|||
|
|||
ClearFlag GetCameraClearFlag(Camera camera) |
|||
{ |
|||
ClearFlag clearFlag = ClearFlag.None; |
|||
CameraClearFlags cameraClearFlags = camera.clearFlags; |
|||
if (cameraClearFlags != CameraClearFlags.Nothing) |
|||
{ |
|||
clearFlag |= ClearFlag.Depth; |
|||
if (cameraClearFlags == CameraClearFlags.Color || cameraClearFlags == CameraClearFlags.Skybox) |
|||
clearFlag |= ClearFlag.Color; |
|||
} |
|||
|
|||
return clearFlag; |
|||
} |
|||
|
|||
void SetShaderKeywords(CommandBuffer cmd, ref CameraData cameraData, ref LightData lightData) |
|||
{ |
|||
int vertexLightsCount = lightData.totalAdditionalLightsCount - lightData.pixelAdditionalLightsCount; |
|||
|
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.AdditionalLightsText, lightData.totalAdditionalLightsCount > 0); |
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.MixedLightingSubtractiveText, m_MixedLightingSetup == MixedLightingSetup.Subtractive); |
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.VertexLightsText, vertexLightsCount > 0); |
|||
|
|||
// TODO: We have to discuss cookie approach on LWRP.
|
|||
// CoreUtils.SetKeyword(cmd, LightweightKeywords.MainLightCookieText, mainLightIndex != -1 && LightweightUtils.IsSupportedCookieType(visibleLights[mainLightIndex].lightType) && visibleLights[mainLightIndex].light.cookie != null);
|
|||
|
|||
LightShadows directionalShadowQuality = lightData.shadowData.renderedDirectionalShadowQuality; |
|||
LightShadows localShadowQuality = lightData.shadowData.renderedLocalShadowQuality; |
|||
|
|||
// Currently shadow filtering keyword is shared between local and directional shadows.
|
|||
bool hasSoftShadows = (directionalShadowQuality == LightShadows.Soft || localShadowQuality == LightShadows.Soft) && |
|||
lightData.shadowData.supportsSoftShadows; |
|||
|
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.DirectionalShadowsText, directionalShadowQuality != LightShadows.None); |
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.LocalShadowsText, localShadowQuality != LightShadows.None); |
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.SoftShadowsText, hasSoftShadows); |
|||
|
|||
// TODO: Remove this. legacy particles support will be removed from Unity in 2018.3. This should be a shader_feature instead with prop exposed in the Standard particles shader.
|
|||
CoreUtils.SetKeyword(cmd, "SOFTPARTICLES_ON", cameraData.requiresSoftParticles); |
|||
} |
|||
|
|||
void SetRenderTarget(CommandBuffer cmd, ClearFlag clearFlag) |
|||
{ |
|||
if (colorHandles[0] != -1) |
|||
{ |
|||
if (depthHandle != -1) |
|||
CoreUtils.SetRenderTarget(cmd, GetSurface(colorHandles[0]), GetSurface(depthHandle), clearFlag); |
|||
else |
|||
CoreUtils.SetRenderTarget(cmd, GetSurface(colorHandles[0]), clearFlag); |
|||
} |
|||
else |
|||
{ |
|||
CoreUtils.SetRenderTarget(cmd, BuiltinRenderTextureType.CameraTarget, clearFlag); |
|||
} |
|||
} |
|||
|
|||
void RenderOpaques(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, RendererConfiguration settings) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("Render Opaques"); |
|||
Camera camera = cameraData.camera; |
|||
|
|||
ClearFlag clearFlag = GetCameraClearFlag(camera); |
|||
SetRenderTarget(cmd, clearFlag); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
|
|||
// If rendering to an intermediate RT we resolve viewport on blit due to offset not being supported
|
|||
// while rendering to a RT.
|
|||
if (colorHandles[0] == -1 && cameraData.isDefaultViewport) |
|||
cmd.SetViewport(camera.pixelRect); |
|||
|
|||
var opaqueDrawSettings = new DrawRendererSettings(camera, m_ShaderPassNames[0]); |
|||
for (int i = 1; i < m_ShaderPassNames.Count; ++i) |
|||
opaqueDrawSettings.SetShaderPassName(1, m_ShaderPassNames[1]); |
|||
opaqueDrawSettings.sorting.flags = SortFlags.CommonOpaque; |
|||
opaqueDrawSettings.rendererConfiguration = settings; |
|||
|
|||
var opaqueFilterSettings = new FilterRenderersSettings(true) |
|||
{ |
|||
renderQueueRange = RenderQueueRange.opaque |
|||
}; |
|||
|
|||
context.DrawRenderers(cullResults.visibleRenderers, ref opaqueDrawSettings, opaqueFilterSettings); |
|||
|
|||
// Render objects that did not match any shader pass with error shader
|
|||
RenderObjectsWithError(ref context, ref cullResults, camera, opaqueFilterSettings, SortFlags.None); |
|||
|
|||
if (camera.clearFlags == CameraClearFlags.Skybox) |
|||
context.DrawSkybox(camera); |
|||
} |
|||
|
|||
void RenderTransparents(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, RendererConfiguration config) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("Render Opaques"); |
|||
Camera camera = cameraData.camera; |
|||
SetRenderTarget(cmd, ClearFlag.None); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
|
|||
var transparentSettings = new DrawRendererSettings(camera, m_ShaderPassNames[0]); |
|||
for (int i = 1; i < m_ShaderPassNames.Count; ++i) |
|||
transparentSettings.SetShaderPassName(1, m_ShaderPassNames[1]); |
|||
transparentSettings.sorting.flags = SortFlags.CommonTransparent; |
|||
transparentSettings.rendererConfiguration = config; |
|||
|
|||
var transparentFilterSettings = new FilterRenderersSettings(true) |
|||
{ |
|||
renderQueueRange = RenderQueueRange.transparent |
|||
}; |
|||
|
|||
context.DrawRenderers(cullResults.visibleRenderers, ref transparentSettings, transparentFilterSettings); |
|||
|
|||
// Render objects that did not match any shader pass with error shader
|
|||
RenderObjectsWithError(ref context, ref cullResults, camera, transparentFilterSettings, SortFlags.None); |
|||
} |
|||
|
|||
void FinalBlitPass(ref ScriptableRenderContext context, ref CameraData cameraData) |
|||
{ |
|||
var cmd = CommandBufferPool.Get("Final Blit Pass"); |
|||
if (cameraData.isStereoEnabled && XRSettings.eyeTextureDesc.dimension == TextureDimension.Tex2DArray) |
|||
cmd.Blit(GetSurface(colorHandles[0]), BuiltinRenderTextureType.CameraTarget); |
|||
else |
|||
LightweightPipeline.Blit(cmd, ref cameraData, GetSurface(colorHandles[0]), BuiltinRenderTextureType.CameraTarget, cameraData.isStereoEnabled ? null : m_BlitMaterial); |
|||
|
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
void InitializeLightConstants(List<VisibleLight> lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightDistanceAttenuation, out Vector4 lightSpotDir, |
|||
out Vector4 lightSpotAttenuation) |
|||
{ |
|||
lightPos = k_DefaultLightPosition; |
|||
lightColor = k_DefaultLightColor; |
|||
lightDistanceAttenuation = k_DefaultLightSpotAttenuation; |
|||
lightSpotDir = k_DefaultLightSpotDirection; |
|||
lightSpotAttenuation = k_DefaultLightAttenuation; |
|||
|
|||
// When no lights are visible, main light will be set to -1.
|
|||
// In this case we initialize it to default values and return
|
|||
if (lightIndex < 0) |
|||
return; |
|||
|
|||
VisibleLight lightData = lights[lightIndex]; |
|||
if (lightData.lightType == LightType.Directional) |
|||
{ |
|||
Vector4 dir = -lightData.localToWorld.GetColumn(2); |
|||
lightPos = new Vector4(dir.x, dir.y, dir.z, 0.0f); |
|||
} |
|||
else |
|||
{ |
|||
Vector4 pos = lightData.localToWorld.GetColumn(3); |
|||
lightPos = new Vector4(pos.x, pos.y, pos.z, 1.0f); |
|||
} |
|||
|
|||
// VisibleLight.finalColor already returns color in active color space
|
|||
lightColor = lightData.finalColor; |
|||
|
|||
// Directional Light attenuation is initialize so distance attenuation always be 1.0
|
|||
if (lightData.lightType != LightType.Directional) |
|||
{ |
|||
// Light attenuation in lightweight matches the unity vanilla one.
|
|||
// attenuation = 1.0 / 1.0 + distanceToLightSqr * quadraticAttenuation
|
|||
// then a smooth factor is applied to linearly fade attenuation to light range
|
|||
// the attenuation smooth factor starts having effect at 80% of light range
|
|||
// smoothFactor = (lightRangeSqr - distanceToLightSqr) / (lightRangeSqr - fadeStartDistanceSqr)
|
|||
// We rewrite smoothFactor to be able to pre compute the constant terms below and apply the smooth factor
|
|||
// with one MAD instruction
|
|||
// smoothFactor = distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr)
|
|||
// distanceSqr * oneOverFadeRangeSqr + lightRangeSqrOverFadeRangeSqr
|
|||
float lightRangeSqr = lightData.range * lightData.range; |
|||
float fadeStartDistanceSqr = 0.8f * 0.8f * lightRangeSqr; |
|||
float fadeRangeSqr = (fadeStartDistanceSqr - lightRangeSqr); |
|||
float oneOverFadeRangeSqr = 1.0f / fadeRangeSqr; |
|||
float lightRangeSqrOverFadeRangeSqr = -lightRangeSqr / fadeRangeSqr; |
|||
float quadAtten = 25.0f / lightRangeSqr; |
|||
lightDistanceAttenuation = new Vector4(quadAtten, oneOverFadeRangeSqr, lightRangeSqrOverFadeRangeSqr, 1.0f); |
|||
} |
|||
|
|||
if (lightData.lightType == LightType.Spot) |
|||
{ |
|||
Vector4 dir = lightData.localToWorld.GetColumn(2); |
|||
lightSpotDir = new Vector4(-dir.x, -dir.y, -dir.z, 0.0f); |
|||
|
|||
// Spot Attenuation with a linear falloff can be defined as
|
|||
// (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle)
|
|||
// This can be rewritten as
|
|||
// invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle)
|
|||
// SdotL * invAngleRange + (-cosOuterAngle * invAngleRange)
|
|||
// If we precompute the terms in a MAD instruction
|
|||
float cosOuterAngle = Mathf.Cos(Mathf.Deg2Rad * lightData.spotAngle * 0.5f); |
|||
// We neeed to do a null check for particle lights
|
|||
// This should be changed in the future
|
|||
// Particle lights will use an inline function
|
|||
float cosInnerAngle; |
|||
if (lightData.light != null) |
|||
cosInnerAngle = Mathf.Cos(LightmapperUtils.ExtractInnerCone(lightData.light) * 0.5f); |
|||
else |
|||
cosInnerAngle = Mathf.Cos((2.0f * Mathf.Atan(Mathf.Tan(lightData.spotAngle * 0.5f * Mathf.Deg2Rad) * (64.0f - 18.0f) / 64.0f)) * 0.5f); |
|||
float smoothAngleRange = Mathf.Max(0.001f, cosInnerAngle - cosOuterAngle); |
|||
float invAngleRange = 1.0f / smoothAngleRange; |
|||
float add = -cosOuterAngle * invAngleRange; |
|||
lightSpotAttenuation = new Vector4(invAngleRange, add, 0.0f); |
|||
} |
|||
|
|||
Light light = lightData.light; |
|||
|
|||
// TODO: Add support to shadow mask
|
|||
if (light != null && light.bakingOutput.mixedLightingMode == MixedLightingMode.Subtractive && light.bakingOutput.lightmapBakeType == LightmapBakeType.Mixed) |
|||
{ |
|||
if (m_MixedLightingSetup == MixedLightingSetup.None && lightData.light.shadows != LightShadows.None) |
|||
{ |
|||
m_MixedLightingSetup = MixedLightingSetup.Subtractive; |
|||
lightDistanceAttenuation.w = 0.0f; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void AfterOpaque(ref ScriptableRenderContext context, ref CameraData cameraData) |
|||
{ |
|||
//if (m_RequireDepthTexture)
|
|||
//{
|
|||
// CommandBuffer cmd = CommandBufferPool.Get("After Opaque");
|
|||
|
|||
// bool setRenderTarget = false;
|
|||
// RenderTargetIdentifier depthRT = m_DepthRT;
|
|||
|
|||
// // TODO: There's currently an issue in the PostFX stack that has a one frame delay when an effect is enabled/disabled
|
|||
// // when an effect is disabled, HasOpaqueOnlyEffects returns true in the first frame, however inside render the effect
|
|||
// // state is update, causing RenderPostProcess here to not blit to FinalColorRT. Until the next frame the RT will have garbage.
|
|||
// if (CoreUtils.HasFlag(config, FrameRenderingConfiguration.BeforeTransparentPostProcess))
|
|||
// {
|
|||
// // When only have one effect in the stack we blit to a work RT then blit it back to active color RT.
|
|||
// // This seems like an extra blit but it saves us a depth copy/blit which has some corner cases like msaa depth resolve.
|
|||
// if (m_RequireCopyColor)
|
|||
// {
|
|||
// RenderPostProcess(cmd, m_CurrCameraColorRT, m_CopyColorRT, true);
|
|||
// cmd.Blit(m_CopyColorRT, m_CurrCameraColorRT);
|
|||
// }
|
|||
// else
|
|||
// RenderPostProcess(cmd, m_CurrCameraColorRT, m_CurrCameraColorRT, true);
|
|||
|
|||
// setRenderTarget = true;
|
|||
// SetRenderTarget(cmd, m_CurrCameraColorRT, m_DepthRT);
|
|||
// }
|
|||
|
|||
// if (CoreUtils.HasFlag(config, FrameRenderingConfiguration.DepthCopy))
|
|||
// {
|
|||
// bool forceBlit = false;
|
|||
// if (m_MSAASamples > 1)
|
|||
// {
|
|||
// cmd.SetGlobalFloat(m_SampleCount, (float)m_MSAASamples);
|
|||
// cmd.EnableShaderKeyword(kMSAADepthKeyword);
|
|||
// forceBlit = true;
|
|||
// }
|
|||
// else
|
|||
// cmd.DisableShaderKeyword(kMSAADepthKeyword);
|
|||
|
|||
// CopyTexture(cmd, m_DepthRT, m_CopyDepth, m_CopyDepthMaterial, forceBlit);
|
|||
// depthRT = m_CopyDepth;
|
|||
// setRenderTarget = true;
|
|||
// cmd.SetGlobalTexture(RenderTargetHandle.Depth, m_CopyDepth);
|
|||
// }
|
|||
|
|||
// if (setRenderTarget)
|
|||
// SetRenderTarget(cmd, m_CurrCameraColorRT, depthRT);
|
|||
// context.ExecuteCommandBuffer(cmd);
|
|||
// CommandBufferPool.Release(cmd);
|
|||
//}
|
|||
} |
|||
|
|||
// TODO: move to postfx pass
|
|||
void PostProcessPass(ref ScriptableRenderContext context, ref CameraData cameraData) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("Render PostProcess Effects"); |
|||
LightweightPipeline.RenderPostProcess(cmd, renderer.postProcessRenderContext, ref cameraData, m_ColorFormat, GetSurface(colorHandles[0]), BuiltinRenderTextureType.CameraTarget, false); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] |
|||
void RenderObjectsWithError(ref ScriptableRenderContext context, ref CullResults cullResults, Camera camera, FilterRenderersSettings filterSettings, SortFlags sortFlags) |
|||
{ |
|||
if (m_ErrorMaterial != null) |
|||
{ |
|||
DrawRendererSettings errorSettings = new DrawRendererSettings(camera, m_LegacyShaderPassNames[0]); |
|||
for (int i = 1; i < m_LegacyShaderPassNames.Count; ++i) |
|||
errorSettings.SetShaderPassName(i, m_LegacyShaderPassNames[i]); |
|||
|
|||
errorSettings.sorting.flags = sortFlags; |
|||
errorSettings.rendererConfiguration = RendererConfiguration.None; |
|||
errorSettings.SetOverrideMaterial(m_ErrorMaterial, 0); |
|||
context.DrawRenderers(cullResults.visibleRenderers, ref errorSettings, filterSettings); |
|||
} |
|||
} |
|||
|
|||
void OpaquePostProcessPass(ref ScriptableRenderContext context, ref CameraData cameraData) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("Render Opaque PostProcess Effects"); |
|||
|
|||
RenderTargetIdentifier source; |
|||
// If have a single opaque postfx we need to create a temp texture as otherwise source and target
|
|||
// would be the same
|
|||
if (cameraData.postProcessLayer.sortedBundles[PostProcessEvent.BeforeTransparent].Count == 1) |
|||
{ |
|||
// TODO:
|
|||
// cmd.GetTemporaryRT();
|
|||
source = GetSurface(colorHandles[0]); |
|||
} |
|||
else |
|||
source = GetSurface(colorHandles[0]); |
|||
|
|||
LightweightPipeline.RenderPostProcess(cmd, renderer.postProcessRenderContext, ref cameraData, m_ColorFormat, source, GetSurface(colorHandles[0]), true); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
void CopyDepthPass(ref ScriptableRenderContext context, ref CameraData cameraData) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("Depth Copy"); |
|||
if (depthHandle == RenderTargetHandles.DepthMS) |
|||
{ |
|||
cmd.SetGlobalFloat(m_SampleCountShaderHandle, cameraData.msaaSamples); |
|||
cmd.EnableShaderKeyword(k_MSAADepthKeyword); |
|||
cmd.Blit(GetSurface(RenderTargetHandles.DepthMS), GetSurface(RenderTargetHandles.Depth), m_DepthCopyMaterial); |
|||
} |
|||
else |
|||
{ |
|||
// TODO:
|
|||
//cmd.Blit(GetSurface(RenderTargetHandle.Depth), depthCopy, m_DepthCopyMaterial);
|
|||
} |
|||
cmd.DisableShaderKeyword(k_MSAADepthKeyword); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
// bool forceBlit = false;
|
|||
// if (m_MSAASamples > 1)
|
|||
// {
|
|||
// cmd.SetGlobalFloat(m_SampleCount, (float)m_MSAASamples);
|
|||
// cmd.EnableShaderKeyword(kMSAADepthKeyword);
|
|||
// forceBlit = true;
|
|||
// }
|
|||
// else
|
|||
// cmd.DisableShaderKeyword(kMSAADepthKeyword);
|
|||
|
|||
// CopyTexture(cmd, m_DepthRT, m_CopyDepth, m_CopyDepthMaterial, forceBlit);
|
|||
// depthRT = m_CopyDepth;
|
|||
// setRenderTarget = true;
|
|||
// cmd.SetGlobalTexture(RenderTargetHandle.Depth, m_CopyDepth);
|
|||
} |
|||
|
|||
void OpaqueTexturePass(ref ScriptableRenderContext context, ref CameraData cameraData) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("Copy Opaque Color"); |
|||
Downsampling downsampling = cameraData.opaqueTextureDownsampling; |
|||
float opaqueScaler = m_OpaqueScalerValues[(int)downsampling]; |
|||
|
|||
RenderTextureDescriptor opaqueDesc = renderer.CreateRTDesc(ref cameraData, opaqueScaler); |
|||
RenderTargetIdentifier colorRT = GetSurface(colorHandles[0]); |
|||
RenderTargetIdentifier opaqueColorRT = GetSurface(RenderTargetHandles.OpaqueColor); |
|||
|
|||
cmd.GetTemporaryRT(RenderTargetHandles.OpaqueColor, opaqueDesc, cameraData.opaqueTextureDownsampling == Downsampling.None ? FilterMode.Point : FilterMode.Bilinear); |
|||
switch (downsampling) |
|||
{ |
|||
case Downsampling.None: |
|||
cmd.Blit(colorRT, opaqueColorRT); |
|||
break; |
|||
case Downsampling._2xBilinear: |
|||
cmd.Blit(colorRT, opaqueColorRT); |
|||
break; |
|||
case Downsampling._4xBox: |
|||
m_SamplingMaterial.SetFloat(m_SampleOffsetShaderHandle, 2); |
|||
cmd.Blit(colorRT, opaqueColorRT, m_SamplingMaterial, 0); |
|||
break; |
|||
case Downsampling._4xBilinear: |
|||
cmd.Blit(colorRT, opaqueColorRT); |
|||
break; |
|||
} |
|||
//SetRenderTarget(cmd, m_CurrCameraColorRT, m_DepthRT);
|
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 6ff0f03778c60ae42890954fcf650d4c |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Experimental.Rendering.LightweightPipeline |
|||
{ |
|||
public class LocalShadowsPass : ScriptableRenderPass |
|||
{ |
|||
const int k_ShadowmapBufferBits = 16; |
|||
RenderTexture m_LocalShadowmapTexture; |
|||
RenderTextureDescriptor m_LocalShadowmapDescriptor; |
|||
|
|||
Matrix4x4[] m_LocalShadowMatrices; |
|||
ShadowSliceData[] m_LocalLightSlices; |
|||
float[] m_LocalShadowStrength; |
|||
|
|||
public LocalShadowsPass(LightweightForwardRenderer renderer, int atlasResolution) : base(renderer) |
|||
{ |
|||
RegisterShaderPassName("ShadowCaster"); |
|||
|
|||
int maxVisibleLocalLights = renderer.maxVisibleLocalLights; |
|||
m_LocalShadowMatrices = new Matrix4x4[maxVisibleLocalLights]; |
|||
m_LocalLightSlices = new ShadowSliceData[maxVisibleLocalLights]; |
|||
m_LocalShadowStrength = new float[maxVisibleLocalLights]; |
|||
|
|||
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"); |
|||
|
|||
RenderTextureFormat shadowmapFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Shadowmap) |
|||
? RenderTextureFormat.Shadowmap |
|||
: RenderTextureFormat.Depth; |
|||
|
|||
m_LocalShadowmapDescriptor = new RenderTextureDescriptor(atlasResolution, atlasResolution, shadowmapFormat, k_ShadowmapBufferBits); |
|||
|
|||
Clear(); |
|||
} |
|||
|
|||
public override void Setup(CommandBuffer cmd, RenderTextureDescriptor baseDescriptor, int samples) |
|||
{ |
|||
//m_LocalShadowmapTexture = RenderTexture.GetTemporary(m_LocalShadowmapDescriptor);
|
|||
//m_LocalShadowmapTexture.filterMode = FilterMode.Bilinear;
|
|||
//m_LocalShadowmapTexture.wrapMode = TextureWrapMode.Clamp;
|
|||
|
|||
m_Disposed = false; |
|||
} |
|||
|
|||
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, ref LightData lightData) |
|||
{ |
|||
Clear(); |
|||
ShadowData shadowData = lightData.shadowData; |
|||
if (shadowData.supportsLocalShadows) |
|||
lightData.shadowData.renderedLocalShadowQuality = RenderLocalShadowmapAtlas(ref context, ref cullResults, ref lightData, ref shadowData); |
|||
} |
|||
|
|||
public override void Dispose(CommandBuffer cmd) |
|||
{ |
|||
if (m_LocalShadowmapTexture) |
|||
{ |
|||
RenderTexture.ReleaseTemporary(m_LocalShadowmapTexture); |
|||
m_LocalShadowmapTexture = null; |
|||
} |
|||
|
|||
m_Disposed = true; |
|||
} |
|||
|
|||
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; |
|||
} |
|||
|
|||
LightShadows RenderLocalShadowmapAtlas(ref ScriptableRenderContext context, ref CullResults cullResults, ref LightData lightData, ref ShadowData shadowData) |
|||
{ |
|||
LightShadows shadowQuality = LightShadows.None; |
|||
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 shadowQuality; |
|||
|
|||
CommandBuffer cmd = CommandBufferPool.Get("Prepare Local Lights Shadowmap"); |
|||
Matrix4x4 view, proj; |
|||
Bounds bounds; |
|||
|
|||
// 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 = GetMaxTileResolutionInAtlas(atlasWidth, atlasHeight, shadowCastingLightsCount); |
|||
int shadowSampling = 0; |
|||
|
|||
m_LocalShadowmapTexture = RenderTexture.GetTemporary(m_LocalShadowmapDescriptor); |
|||
m_LocalShadowmapTexture.filterMode = FilterMode.Bilinear; |
|||
m_LocalShadowmapTexture.wrapMode = TextureWrapMode.Clamp; |
|||
m_Disposed = false; |
|||
|
|||
CoreUtils.SetRenderTarget(cmd, m_LocalShadowmapTexture, ClearFlag.Depth); |
|||
|
|||
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; |
|||
|
|||
var settings = new DrawShadowsSettings(cullResults, shadowLightIndex); |
|||
|
|||
if (cullResults.ComputeSpotShadowMatricesAndCullingPrimitives(shadowLightIndex, out view, out proj, out settings.splitData)) |
|||
{ |
|||
// 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(localLightsCount <= 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 = GetShadowTransform(proj, view); |
|||
|
|||
if (shadowCastingLightsCount > 1) |
|||
ApplySliceTransform(ref m_LocalLightSlices[i], atlasWidth, atlasHeight); |
|||
|
|||
SetupShadowCasterConstants(cmd, ref shadowLight, proj, sliceResolution); |
|||
RenderShadowSlice(cmd, ref context, ref m_LocalLightSlices[i], proj, view, settings); |
|||
m_LocalShadowStrength[i] = light.shadowStrength; |
|||
shadowSampling = Math.Max(shadowSampling, (int)light.shadows); |
|||
} |
|||
} |
|||
|
|||
SetupLocalLightsShadowReceiverConstants(ref context, cmd, ref shadowData); |
|||
shadowQuality = (shadowData.supportsSoftShadows) ? (LightShadows)shadowSampling : LightShadows.Hard; |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
return shadowQuality; |
|||
} |
|||
|
|||
Matrix4x4 GetShadowTransform(Matrix4x4 proj, Matrix4x4 view) |
|||
{ |
|||
// Currently CullResults ComputeDirectionalShadowMatricesAndCullingPrimitives doesn't
|
|||
// apply z reversal to projection matrix. We need to do it manually here.
|
|||
if (SystemInfo.usesReversedZBuffer) |
|||
{ |
|||
proj.m20 = -proj.m20; |
|||
proj.m21 = -proj.m21; |
|||
proj.m22 = -proj.m22; |
|||
proj.m23 = -proj.m23; |
|||
} |
|||
|
|||
Matrix4x4 worldToShadow = proj * view; |
|||
|
|||
var textureScaleAndBias = Matrix4x4.identity; |
|||
textureScaleAndBias.m00 = 0.5f; |
|||
textureScaleAndBias.m11 = 0.5f; |
|||
textureScaleAndBias.m22 = 0.5f; |
|||
textureScaleAndBias.m03 = 0.5f; |
|||
textureScaleAndBias.m23 = 0.5f; |
|||
textureScaleAndBias.m13 = 0.5f; |
|||
|
|||
// Apply texture scale and offset to save a MAD in shader.
|
|||
return textureScaleAndBias * worldToShadow; |
|||
} |
|||
|
|||
void ApplySliceTransform(ref ShadowSliceData shadowSliceData, int atlasWidth, int atlasHeight) |
|||
{ |
|||
Matrix4x4 sliceTransform = Matrix4x4.identity; |
|||
float oneOverAtlasWidth = 1.0f / atlasWidth; |
|||
float oneOverAtlasHeight = 1.0f / atlasHeight; |
|||
sliceTransform.m00 = shadowSliceData.resolution * oneOverAtlasWidth; |
|||
sliceTransform.m11 = shadowSliceData.resolution * oneOverAtlasHeight; |
|||
sliceTransform.m03 = shadowSliceData.offsetX * oneOverAtlasWidth; |
|||
sliceTransform.m13 = shadowSliceData.offsetY * oneOverAtlasHeight; |
|||
|
|||
// Apply shadow slice scale and offset
|
|||
shadowSliceData.shadowTransform = sliceTransform * shadowSliceData.shadowTransform; |
|||
} |
|||
|
|||
void RenderShadowSlice(CommandBuffer cmd, ref ScriptableRenderContext context, ref ShadowSliceData shadowSliceData, |
|||
Matrix4x4 proj, Matrix4x4 view, DrawShadowsSettings settings) |
|||
{ |
|||
cmd.SetViewport(new Rect(shadowSliceData.offsetX, shadowSliceData.offsetY, shadowSliceData.resolution, shadowSliceData.resolution)); |
|||
cmd.EnableScissorRect(new Rect(shadowSliceData.offsetX + 4, shadowSliceData.offsetY + 4, shadowSliceData.resolution - 8, shadowSliceData.resolution - 8)); |
|||
|
|||
cmd.SetViewProjectionMatrices(view, proj); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
context.DrawShadows(ref settings); |
|||
cmd.DisableScissorRect(); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
} |
|||
|
|||
int GetMaxTileResolutionInAtlas(int atlasWidth, int atlasHeight, int tileCount) |
|||
{ |
|||
int resolution = Mathf.Min(atlasWidth, atlasHeight); |
|||
if (tileCount > Mathf.Log(resolution)) |
|||
{ |
|||
Debug.LogError( |
|||
String.Format( |
|||
"Cannot fit {0} tiles into current shadowmap atlas of size ({1}, {2}). ShadowMap Resolution set to zero.", |
|||
tileCount, atlasWidth, atlasHeight)); |
|||
return 0; |
|||
} |
|||
|
|||
int currentTileCount = atlasWidth / resolution * atlasHeight / resolution; |
|||
while (currentTileCount < tileCount) |
|||
{ |
|||
resolution = resolution >> 1; |
|||
currentTileCount = atlasWidth / resolution * atlasHeight / resolution; |
|||
} |
|||
return resolution; |
|||
} |
|||
|
|||
void SetupShadowCasterConstants(CommandBuffer cmd, ref VisibleLight visibleLight, Matrix4x4 proj, float cascadeResolution) |
|||
{ |
|||
Light light = visibleLight.light; |
|||
float bias = 0.0f; |
|||
float normalBias = 0.0f; |
|||
|
|||
// Use same kernel radius as built-in pipeline so we can achieve same bias results
|
|||
// with the default light bias parameters.
|
|||
const float kernelRadius = 3.65f; |
|||
|
|||
if (visibleLight.lightType == LightType.Directional) |
|||
{ |
|||
// Scale bias by cascade's world space depth range.
|
|||
// Directional shadow lights have orthogonal projection.
|
|||
// proj.m22 = -2 / (far - near) since the projection's depth range is [-1.0, 1.0]
|
|||
// In order to be correct we should multiply bias by 0.5 but this introducing aliasing along cascades more visible.
|
|||
float sign = (SystemInfo.usesReversedZBuffer) ? 1.0f : -1.0f; |
|||
bias = light.shadowBias * proj.m22 * sign; |
|||
|
|||
// Currently only square POT cascades resolutions are used.
|
|||
// We scale normalBias
|
|||
double frustumWidth = 2.0 / (double)proj.m00; |
|||
double frustumHeight = 2.0 / (double)proj.m11; |
|||
float texelSizeX = (float)(frustumWidth / (double)cascadeResolution); |
|||
float texelSizeY = (float)(frustumHeight / (double)cascadeResolution); |
|||
float texelSize = Mathf.Max(texelSizeX, texelSizeY); |
|||
|
|||
// Since we are applying normal bias on caster side we want an inset normal offset
|
|||
// thus we use a negative normal bias.
|
|||
normalBias = -light.shadowNormalBias * texelSize * kernelRadius; |
|||
} |
|||
else if (visibleLight.lightType == LightType.Spot) |
|||
{ |
|||
float sign = (SystemInfo.usesReversedZBuffer) ? -1.0f : 1.0f; |
|||
bias = light.shadowBias * sign; |
|||
normalBias = 0.0f; |
|||
} |
|||
else |
|||
{ |
|||
Debug.LogWarning("Only spot and directional shadow casters are supported in lightweight pipeline"); |
|||
} |
|||
|
|||
Vector3 lightDirection = -visibleLight.localToWorld.GetColumn(2); |
|||
cmd.SetGlobalVector("_ShadowBias", new Vector4(bias, normalBias, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector("_LightDirection", new Vector4(lightDirection.x, lightDirection.y, lightDirection.z, 0.0f)); |
|||
} |
|||
|
|||
void SetupLocalLightsShadowReceiverConstants(ref ScriptableRenderContext context, 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(RenderTargetHandles.LocalShadowmap, 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)); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f46c1a0c3e3a98848a0efbf4e1fd5675 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Experimental.Rendering.LightweightPipeline |
|||
{ |
|||
public class ScreenSpaceShadowOcclusionPass : ScriptableRenderPass |
|||
{ |
|||
public bool softShadows { get; set; } |
|||
|
|||
RenderTextureFormat m_ColorFormat; |
|||
Material m_ScreenSpaceShadowsMaterial; |
|||
|
|||
public ScreenSpaceShadowOcclusionPass(LightweightForwardRenderer renderer) : base(renderer) |
|||
{ |
|||
m_ColorFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8) |
|||
? RenderTextureFormat.R8 |
|||
: RenderTextureFormat.ARGB32; |
|||
|
|||
m_ScreenSpaceShadowsMaterial = renderer.GetMaterial(MaterialHandles.ScrenSpaceShadow); |
|||
softShadows = false; |
|||
m_Disposed = true; |
|||
} |
|||
|
|||
public override void Setup(CommandBuffer cmd, RenderTextureDescriptor baseDescriptor, int samples) |
|||
{ |
|||
baseDescriptor.depthBufferBits = 0; |
|||
baseDescriptor.colorFormat = m_ColorFormat; |
|||
cmd.GetTemporaryRT(RenderTargetHandles.ScreenSpaceOcclusion, baseDescriptor, FilterMode.Bilinear); |
|||
m_Disposed = false; |
|||
} |
|||
|
|||
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, ref LightData lightData) |
|||
{ |
|||
if (lightData.shadowData.renderedDirectionalShadowQuality == LightShadows.None) |
|||
return; |
|||
|
|||
CommandBuffer cmd = CommandBufferPool.Get("Collect Shadows"); |
|||
SetShadowCollectPassKeywords(cmd, lightData.shadowData.directionalLightCascadeCount); |
|||
|
|||
// Note: The source isn't actually 'used', but there's an engine peculiarity (bug) that
|
|||
// doesn't like null sources when trying to determine a stereo-ized blit. So for proper
|
|||
// stereo functionality, we use the screen-space shadow map as the source (until we have
|
|||
// a better solution).
|
|||
// An alternative would be DrawProcedural, but that would require further changes in the shader.
|
|||
RenderTargetIdentifier screenSpaceOcclusionTexture = GetSurface(RenderTargetHandles.ScreenSpaceOcclusion); |
|||
cmd.SetRenderTarget(screenSpaceOcclusionTexture); |
|||
cmd.ClearRenderTarget(true, true, Color.white); |
|||
cmd.Blit(screenSpaceOcclusionTexture, screenSpaceOcclusionTexture, m_ScreenSpaceShadowsMaterial); |
|||
|
|||
if (cameraData.isStereoEnabled) |
|||
{ |
|||
context.StartMultiEye(cameraData.camera); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
context.StopMultiEye(cameraData.camera); |
|||
} |
|||
else |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
public override void Dispose(CommandBuffer cmd) |
|||
{ |
|||
if (!m_Disposed) |
|||
{ |
|||
cmd.ReleaseTemporaryRT(RenderTargetHandles.ScreenSpaceOcclusion); |
|||
m_Disposed = true; |
|||
} |
|||
} |
|||
|
|||
void SetShadowCollectPassKeywords(CommandBuffer cmd, int cascadeCount) |
|||
{ |
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.SoftShadowsText, softShadows); |
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.CascadeShadowsText, cascadeCount > 1); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 129fea61da31162458736c967c9d98ae |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Experimental.Rendering.LightweightPipeline |
|||
{ |
|||
[Serializable] |
|||
public class ShadowSettings |
|||
{ |
|||
public bool supportsDirectionalShadows; |
|||
public bool screenSpace; |
|||
public int directionalShadowAtlasWidth; |
|||
public int directionalShadowAtlasHeight; |
|||
public float maxShadowDistance; |
|||
public int directionalLightCascadeCount; |
|||
public Vector3 directionalLightCascades; |
|||
public bool supportsLocalShadows; |
|||
public int localShadowAtlasWidth; |
|||
public int localShadowAtlasHeight; |
|||
public bool supportsSoftShadows; |
|||
public int bufferBitCount; |
|||
|
|||
public RenderTextureFormat shadowmapTextureFormat; |
|||
public RenderTextureFormat screenspaceShadowmapTextureFormat; |
|||
|
|||
static ShadowSettings defaultShadowSettings = null; |
|||
|
|||
public static ShadowSettings Default |
|||
{ |
|||
get |
|||
{ |
|||
if (defaultShadowSettings == null) |
|||
{ |
|||
defaultShadowSettings = new ShadowSettings(); |
|||
defaultShadowSettings.supportsDirectionalShadows = true; |
|||
defaultShadowSettings.screenSpace = true; |
|||
defaultShadowSettings.directionalShadowAtlasHeight = defaultShadowSettings.directionalShadowAtlasWidth = 2048; |
|||
defaultShadowSettings.directionalLightCascadeCount = 1; |
|||
defaultShadowSettings.directionalLightCascades = new Vector3(0.067f, 0.2f, 0.467f); |
|||
defaultShadowSettings.supportsLocalShadows = true; |
|||
defaultShadowSettings.localShadowAtlasWidth = 512; |
|||
defaultShadowSettings.localShadowAtlasHeight = 512; |
|||
defaultShadowSettings.bufferBitCount = 16; |
|||
defaultShadowSettings.shadowmapTextureFormat = RenderTextureFormat.Shadowmap; |
|||
defaultShadowSettings.screenspaceShadowmapTextureFormat = RenderTextureFormat.R8; |
|||
defaultShadowSettings.supportsSoftShadows = false; |
|||
} |
|||
return defaultShadowSettings; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public struct ShadowSliceData |
|||
{ |
|||
public Matrix4x4 shadowTransform; |
|||
public int offsetX; |
|||
public int offsetY; |
|||
public int resolution; |
|||
|
|||
public void Clear() |
|||
{ |
|||
shadowTransform = Matrix4x4.identity; |
|||
offsetX = offsetY = 0; |
|||
resolution = 1024; |
|||
} |
|||
} |
|||
|
|||
public class ShadowPass : ScriptableRenderPass |
|||
{ |
|||
public bool isDirectionalShadowsEnabled { get { return m_ShadowSettings.supportsDirectionalShadows; } } |
|||
public bool isLocalShadowsEnabled { get { return m_ShadowSettings.supportsLocalShadows; } } |
|||
public bool requireScreenSpaceShadowmap { get { return isDirectionalShadowsEnabled && m_ShadowSettings.screenSpace; } } |
|||
public bool directionalShadowsRendered { get { return m_DirectionalShadowmapQuality != LightShadows.None; } } |
|||
public bool localShadowsRendered { get { return m_LocalShadowmapQuality != LightShadows.None; } } |
|||
public bool isSoftShadowsEnabled { get { return m_ShadowSettings.supportsSoftShadows; } } |
|||
|
|||
// TODO: Remove this after we handle the passes dependencies
|
|||
public bool requireScreenSpaceResolve { get; private set; } |
|||
|
|||
public float renderingDistance { get { return m_ShadowSettings.maxShadowDistance; } } |
|||
|
|||
private const int kMaxCascades = 4; |
|||
|
|||
private int m_ShadowCasterCascadesCount; |
|||
private int m_DirectionalShadowmapID; |
|||
private int m_LocalShadowmapID; |
|||
private int m_ScreenSpaceShadowmapID; |
|||
|
|||
private ShadowSettings m_ShadowSettings = ShadowSettings.Default; |
|||
|
|||
private Material m_ScreenSpaceShadowsMaterial; |
|||
|
|||
private RenderTexture m_DirectionalShadowmapTexture; |
|||
private RenderTexture m_LocalShadowmapTexture; |
|||
private RenderTargetIdentifier m_ScreenSpaceShadowmapTexture; |
|||
|
|||
private RenderTextureDescriptor m_DirectionalShadowmapDescriptor; |
|||
private RenderTextureDescriptor m_LocalShadowmapDescriptor; |
|||
|
|||
private LightShadows m_DirectionalShadowmapQuality; |
|||
private LightShadows m_LocalShadowmapQuality; |
|||
|
|||
private Matrix4x4[] m_DirectionalShadowMatrices; |
|||
private ShadowSliceData[] m_CascadeSlices; |
|||
private Vector4[] m_CascadeSplitDistances; |
|||
private Vector4 m_CascadeSplitRadii; |
|||
|
|||
private Matrix4x4[] m_LocalShadowMatrices; |
|||
private ShadowSliceData[] m_LocalLightSlices; |
|||
private float[] m_LocalShadowStrength; |
|||
|
|||
public ShadowPass(ForwardRenderer renderer, int[] inputs, int[] targets, |
|||
LightweightPipelineAsset pipelineAsset, int maxLocalLightsCount) : |
|||
base(renderer, inputs, targets) |
|||
{ |
|||
BuildShadowSettings(pipelineAsset); |
|||
RegisterShaderPassName("ShadowCaster"); |
|||
|
|||
m_DirectionalShadowMatrices = new Matrix4x4[kMaxCascades + 1]; |
|||
m_CascadeSlices = new ShadowSliceData[kMaxCascades]; |
|||
m_CascadeSplitDistances = new Vector4[kMaxCascades]; |
|||
|
|||
m_LocalShadowMatrices = new Matrix4x4[maxLocalLightsCount]; |
|||
m_LocalLightSlices = new ShadowSliceData[maxLocalLightsCount]; |
|||
m_LocalShadowStrength = new float[maxLocalLightsCount]; |
|||
|
|||
DirectionalShadowConstantBuffer._WorldToShadow = Shader.PropertyToID("_WorldToShadow"); |
|||
DirectionalShadowConstantBuffer._ShadowData = Shader.PropertyToID("_ShadowData"); |
|||
DirectionalShadowConstantBuffer._DirShadowSplitSpheres = Shader.PropertyToID("_DirShadowSplitSpheres"); |
|||
DirectionalShadowConstantBuffer._DirShadowSplitSphereRadii = Shader.PropertyToID("_DirShadowSplitSphereRadii"); |
|||
DirectionalShadowConstantBuffer._ShadowOffset0 = Shader.PropertyToID("_ShadowOffset0"); |
|||
DirectionalShadowConstantBuffer._ShadowOffset1 = Shader.PropertyToID("_ShadowOffset1"); |
|||
DirectionalShadowConstantBuffer._ShadowOffset2 = Shader.PropertyToID("_ShadowOffset2"); |
|||
DirectionalShadowConstantBuffer._ShadowOffset3 = Shader.PropertyToID("_ShadowOffset3"); |
|||
DirectionalShadowConstantBuffer._ShadowmapSize = Shader.PropertyToID("_ShadowmapSize"); |
|||
|
|||
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_DirectionalShadowmapID = Shader.PropertyToID("_ShadowMap"); |
|||
m_LocalShadowmapID = Shader.PropertyToID("_LocalShadowMapAtlas"); |
|||
m_ScreenSpaceShadowmapID = Shader.PropertyToID("_ScreenSpaceShadowMap"); |
|||
m_ScreenSpaceShadowmapTexture = new RenderTargetIdentifier(m_ScreenSpaceShadowmapID); |
|||
|
|||
m_DirectionalShadowmapDescriptor = new RenderTextureDescriptor(m_ShadowSettings.directionalShadowAtlasWidth, |
|||
m_ShadowSettings.directionalShadowAtlasHeight, m_ShadowSettings.shadowmapTextureFormat, m_ShadowSettings.bufferBitCount); |
|||
|
|||
m_LocalShadowmapDescriptor = new RenderTextureDescriptor(m_ShadowSettings.localShadowAtlasWidth, |
|||
m_ShadowSettings.localShadowAtlasHeight, m_ShadowSettings.shadowmapTextureFormat, m_ShadowSettings.bufferBitCount); |
|||
|
|||
m_ScreenSpaceShadowsMaterial = CoreUtils.CreateEngineMaterial(pipelineAsset.ScreenSpaceShadowShader); |
|||
|
|||
Clear(); |
|||
} |
|||
|
|||
public override void BindSurface(CommandBuffer cmd, RenderTextureDescriptor attachmentDescriptor, int samples) |
|||
{ |
|||
if (requireScreenSpaceShadowmap) |
|||
{ |
|||
attachmentDescriptor.depthBufferBits = 0; |
|||
attachmentDescriptor.colorFormat = m_ShadowSettings.screenspaceShadowmapTextureFormat; |
|||
cmd.GetTemporaryRT(m_ScreenSpaceShadowmapID, attachmentDescriptor, FilterMode.Bilinear); |
|||
} |
|||
} |
|||
|
|||
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref PassData passData) |
|||
{ |
|||
Clear(); |
|||
|
|||
bool directionalShadowmapRendered = false; |
|||
if (isDirectionalShadowsEnabled) |
|||
directionalShadowmapRendered = RenderDirectionalCascadeShadowmap(ref context, ref cullResults, ref passData.lightData); |
|||
|
|||
if (isLocalShadowsEnabled) |
|||
RenderLocalShadowmapAtlas(ref context, ref cullResults, ref passData.lightData); |
|||
|
|||
requireScreenSpaceResolve = directionalShadowmapRendered && m_ShadowSettings.screenSpace; |
|||
} |
|||
|
|||
public override void Dispose(CommandBuffer cmd) |
|||
{ |
|||
cmd.ReleaseTemporaryRT(m_ScreenSpaceShadowmapID); |
|||
|
|||
if (m_DirectionalShadowmapTexture) |
|||
{ |
|||
RenderTexture.ReleaseTemporary(m_DirectionalShadowmapTexture); |
|||
m_DirectionalShadowmapTexture = null; |
|||
} |
|||
|
|||
if (m_LocalShadowmapTexture) |
|||
{ |
|||
RenderTexture.ReleaseTemporary(m_LocalShadowmapTexture); |
|||
m_LocalShadowmapTexture = null; |
|||
} |
|||
} |
|||
|
|||
public void CollectShadows(Camera camera, FrameRenderingConfiguration frameRenderingConfiguration, ref ScriptableRenderContext context) |
|||
{ |
|||
CommandBuffer cmd = CommandBufferPool.Get("Collect Shadows"); |
|||
|
|||
SetShadowCollectPassKeywords(cmd); |
|||
|
|||
// Note: The source isn't actually 'used', but there's an engine peculiarity (bug) that
|
|||
// doesn't like null sources when trying to determine a stereo-ized blit. So for proper
|
|||
// stereo functionality, we use the screen-space shadow map as the source (until we have
|
|||
// a better solution).
|
|||
// An alternative would be DrawProcedural, but that would require further changes in the shader.
|
|||
cmd.SetRenderTarget(m_ScreenSpaceShadowmapTexture); |
|||
cmd.ClearRenderTarget(true, true, Color.white); |
|||
cmd.Blit(m_ScreenSpaceShadowmapTexture, m_ScreenSpaceShadowmapTexture, m_ScreenSpaceShadowsMaterial); |
|||
|
|||
LightweightPipeline.StartStereoRendering(camera, ref context, frameRenderingConfiguration); |
|||
|
|||
context.ExecuteCommandBuffer(cmd); |
|||
|
|||
LightweightPipeline.StopStereoRendering(camera, ref context, frameRenderingConfiguration); |
|||
|
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
private void BuildShadowSettings(LightweightPipelineAsset pipelineAsset) |
|||
{ |
|||
// Until we can have keyword stripping forcing single cascade hard shadows on gles2
|
|||
bool supportsScreenSpaceShadows = SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES2; |
|||
|
|||
m_ShadowSettings = ShadowSettings.Default; |
|||
m_ShadowSettings.supportsDirectionalShadows = pipelineAsset.SupportsDirectionalShadows; |
|||
m_ShadowSettings.screenSpace = m_ShadowSettings.supportsDirectionalShadows && supportsScreenSpaceShadows; |
|||
m_ShadowSettings.directionalLightCascadeCount = (m_ShadowSettings.screenSpace) ? pipelineAsset.CascadeCount : 1; |
|||
|
|||
m_ShadowSettings.directionalShadowAtlasWidth = pipelineAsset.DirectionalShadowAtlasResolution; |
|||
m_ShadowSettings.directionalShadowAtlasHeight = pipelineAsset.DirectionalShadowAtlasResolution; |
|||
m_ShadowSettings.maxShadowDistance = pipelineAsset.ShadowDistance; |
|||
|
|||
switch (m_ShadowSettings.directionalLightCascadeCount) |
|||
{ |
|||
case 1: |
|||
m_ShadowSettings.directionalLightCascades = new Vector3(1.0f, 0.0f, 0.0f); |
|||
break; |
|||
|
|||
case 2: |
|||
m_ShadowSettings.directionalLightCascades = new Vector3(pipelineAsset.Cascade2Split, 1.0f, 0.0f); |
|||
break; |
|||
|
|||
default: |
|||
m_ShadowSettings.directionalLightCascades = pipelineAsset.Cascade4Split; |
|||
break; |
|||
} |
|||
|
|||
m_ShadowSettings.supportsLocalShadows = pipelineAsset.SupportsLocalShadows; |
|||
m_ShadowSettings.localShadowAtlasWidth = m_ShadowSettings.localShadowAtlasHeight = pipelineAsset.LocalShadowAtlasResolution; |
|||
m_ShadowSettings.supportsSoftShadows = pipelineAsset.SupportsSoftShadows; |
|||
|
|||
m_ShadowSettings.bufferBitCount = 16; |
|||
|
|||
m_ShadowSettings.shadowmapTextureFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Shadowmap) |
|||
? RenderTextureFormat.Shadowmap |
|||
: RenderTextureFormat.Depth; |
|||
|
|||
m_ShadowSettings.screenspaceShadowmapTextureFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8) |
|||
? RenderTextureFormat.R8 |
|||
: RenderTextureFormat.ARGB32; |
|||
} |
|||
|
|||
private void Clear() |
|||
{ |
|||
m_DirectionalShadowmapTexture = null; |
|||
m_LocalShadowmapTexture = null; |
|||
m_DirectionalShadowmapQuality = LightShadows.None; |
|||
m_LocalShadowmapQuality = LightShadows.None; |
|||
|
|||
for (int i = 0; i < m_DirectionalShadowMatrices.Length; ++i) |
|||
m_DirectionalShadowMatrices[i] = Matrix4x4.identity; |
|||
|
|||
for (int i = 0; i < m_LocalShadowMatrices.Length; ++i) |
|||
m_LocalShadowMatrices[i] = Matrix4x4.identity; |
|||
|
|||
for (int i = 0; i < m_CascadeSplitDistances.Length; ++i) |
|||
m_CascadeSplitDistances[i] = new Vector4(0.0f, 0.0f, 0.0f, 0.0f); |
|||
|
|||
m_CascadeSplitRadii = new Vector4(0.0f, 0.0f, 0.0f, 0.0f); |
|||
|
|||
for (int i = 0; i < m_CascadeSlices.Length; ++i) |
|||
m_CascadeSlices[i].Clear(); |
|||
|
|||
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; |
|||
|
|||
requireScreenSpaceResolve = false; |
|||
} |
|||
|
|||
private void SetShadowCollectPassKeywords(CommandBuffer cmd) |
|||
{ |
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.SoftShadowsText, m_DirectionalShadowmapQuality == LightShadows.Soft); |
|||
CoreUtils.SetKeyword(cmd, LightweightKeywords.CascadeShadowsText, m_ShadowSettings.directionalLightCascadeCount > 1); |
|||
} |
|||
|
|||
private bool RenderDirectionalCascadeShadowmap(ref ScriptableRenderContext context, ref CullResults cullResults, ref LightData lightData) |
|||
{ |
|||
int shadowLightIndex = lightData.mainLightIndex; |
|||
if (shadowLightIndex == -1) |
|||
return false; |
|||
|
|||
VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex]; |
|||
Light light = shadowLight.light; |
|||
Debug.Assert(shadowLight.lightType == LightType.Directional); |
|||
|
|||
if (light.shadows == LightShadows.None) |
|||
return false; |
|||
|
|||
CommandBuffer cmd = CommandBufferPool.Get("Prepare Directional Shadowmap"); |
|||
m_ShadowCasterCascadesCount = m_ShadowSettings.directionalLightCascadeCount; |
|||
|
|||
int shadowResolution = GetMaxTileResolutionInAtlas(m_ShadowSettings.directionalShadowAtlasWidth, m_ShadowSettings.directionalShadowAtlasHeight, m_ShadowCasterCascadesCount); |
|||
float shadowNearPlane = light.shadowNearPlane; |
|||
|
|||
Bounds bounds; |
|||
if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds)) |
|||
return false; |
|||
|
|||
Matrix4x4 view, proj; |
|||
var settings = new DrawShadowsSettings(cullResults, shadowLightIndex); |
|||
|
|||
m_DirectionalShadowmapTexture = RenderTexture.GetTemporary(m_DirectionalShadowmapDescriptor); |
|||
m_DirectionalShadowmapTexture.filterMode = FilterMode.Bilinear; |
|||
m_DirectionalShadowmapTexture.wrapMode = TextureWrapMode.Clamp; |
|||
|
|||
CoreUtils.SetRenderTarget(cmd, m_DirectionalShadowmapTexture, ClearFlag.Depth); |
|||
|
|||
bool success = false; |
|||
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex) |
|||
{ |
|||
success = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(shadowLightIndex, |
|||
cascadeIndex, m_ShadowCasterCascadesCount, m_ShadowSettings.directionalLightCascades, shadowResolution, shadowNearPlane, out view, out proj, |
|||
out settings.splitData); |
|||
|
|||
float cullingSphereRadius = settings.splitData.cullingSphere.w; |
|||
m_CascadeSplitDistances[cascadeIndex] = settings.splitData.cullingSphere; |
|||
m_CascadeSplitRadii[cascadeIndex] = cullingSphereRadius * cullingSphereRadius; |
|||
|
|||
if (!success) |
|||
break; |
|||
|
|||
m_CascadeSlices[cascadeIndex].offsetX = (cascadeIndex % 2) * shadowResolution; |
|||
m_CascadeSlices[cascadeIndex].offsetY = (cascadeIndex / 2) * shadowResolution; |
|||
m_CascadeSlices[cascadeIndex].resolution = shadowResolution; |
|||
m_CascadeSlices[cascadeIndex].shadowTransform = GetShadowTransform(proj, view); |
|||
|
|||
// If we have shadow cascades baked into the atlas we bake cascade transform
|
|||
// in each shadow matrix to save shader ALU and L/S
|
|||
if (m_ShadowCasterCascadesCount > 1) |
|||
ApplySliceTransform(ref m_CascadeSlices[cascadeIndex], m_ShadowSettings.directionalShadowAtlasWidth, m_ShadowSettings.directionalShadowAtlasHeight); |
|||
|
|||
SetupShadowCasterConstants(cmd, ref shadowLight, proj, shadowResolution); |
|||
RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex], proj, view, settings); |
|||
} |
|||
|
|||
if (success) |
|||
{ |
|||
m_DirectionalShadowmapQuality = (isSoftShadowsEnabled) ? light.shadows : LightShadows.Hard; |
|||
|
|||
// In order to avoid shader variants explosion we only do hard shadows when sampling shadowmap in the lit pass.
|
|||
// GLES2 platform is forced to hard single cascade shadows.
|
|||
if (!m_ShadowSettings.screenSpace) |
|||
m_DirectionalShadowmapQuality = LightShadows.Hard; |
|||
|
|||
SetupDirectionalShadowReceiverConstants(cmd, shadowLight, ref context); |
|||
} |
|||
|
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
return success; |
|||
} |
|||
|
|||
private void RenderLocalShadowmapAtlas(ref ScriptableRenderContext context, ref CullResults cullResults, ref LightData lightData) |
|||
{ |
|||
List<int> localLightIndices = lightData.localLightIndices; |
|||
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; |
|||
|
|||
CommandBuffer cmd = CommandBufferPool.Get("Prepare Local Lights Shadowmap"); |
|||
Matrix4x4 view, proj; |
|||
Bounds bounds; |
|||
|
|||
// 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 = m_ShadowSettings.localShadowAtlasWidth; |
|||
int atlasHeight = m_ShadowSettings.localShadowAtlasHeight; |
|||
int sliceResolution = GetMaxTileResolutionInAtlas(atlasWidth, atlasHeight, shadowCastingLightsCount); |
|||
int shadowSampling = 0; |
|||
|
|||
m_LocalShadowmapTexture = RenderTexture.GetTemporary(m_LocalShadowmapDescriptor); |
|||
m_LocalShadowmapTexture.filterMode = FilterMode.Bilinear; |
|||
m_LocalShadowmapTexture.wrapMode = TextureWrapMode.Clamp; |
|||
|
|||
CoreUtils.SetRenderTarget(cmd, m_LocalShadowmapTexture, ClearFlag.Depth); |
|||
|
|||
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; |
|||
|
|||
var settings = new DrawShadowsSettings(cullResults, shadowLightIndex); |
|||
|
|||
if (cullResults.ComputeSpotShadowMatricesAndCullingPrimitives(shadowLightIndex, out view, out proj, out settings.splitData)) |
|||
{ |
|||
// 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(localLightsCount <= 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 = GetShadowTransform(proj, view); |
|||
|
|||
if (shadowCastingLightsCount > 1) |
|||
ApplySliceTransform(ref m_LocalLightSlices[i], atlasWidth, atlasHeight); |
|||
|
|||
SetupShadowCasterConstants(cmd, ref shadowLight, proj, sliceResolution); |
|||
RenderShadowSlice(cmd, ref context, ref m_LocalLightSlices[i], proj, view, settings); |
|||
m_LocalShadowStrength[i] = light.shadowStrength; |
|||
shadowSampling = Math.Max(shadowSampling, (int)light.shadows); |
|||
} |
|||
} |
|||
|
|||
SetupLocalLightsShadowReceiverConstants(cmd, ref context); |
|||
|
|||
m_LocalShadowmapQuality = (isSoftShadowsEnabled) ? (LightShadows)shadowSampling : LightShadows.Hard; |
|||
context.ExecuteCommandBuffer(cmd); |
|||
CommandBufferPool.Release(cmd); |
|||
} |
|||
|
|||
private Matrix4x4 GetShadowTransform(Matrix4x4 proj, Matrix4x4 view) |
|||
{ |
|||
// Currently CullResults ComputeDirectionalShadowMatricesAndCullingPrimitives doesn't
|
|||
// apply z reversal to projection matrix. We need to do it manually here.
|
|||
if (SystemInfo.usesReversedZBuffer) |
|||
{ |
|||
proj.m20 = -proj.m20; |
|||
proj.m21 = -proj.m21; |
|||
proj.m22 = -proj.m22; |
|||
proj.m23 = -proj.m23; |
|||
} |
|||
|
|||
Matrix4x4 worldToShadow = proj * view; |
|||
|
|||
var textureScaleAndBias = Matrix4x4.identity; |
|||
textureScaleAndBias.m00 = 0.5f; |
|||
textureScaleAndBias.m11 = 0.5f; |
|||
textureScaleAndBias.m22 = 0.5f; |
|||
textureScaleAndBias.m03 = 0.5f; |
|||
textureScaleAndBias.m23 = 0.5f; |
|||
textureScaleAndBias.m13 = 0.5f; |
|||
|
|||
// Apply texture scale and offset to save a MAD in shader.
|
|||
return textureScaleAndBias * worldToShadow; |
|||
} |
|||
|
|||
private void ApplySliceTransform(ref ShadowSliceData shadowSliceData, int atlasWidth, int atlasHeight) |
|||
{ |
|||
Matrix4x4 sliceTransform = Matrix4x4.identity; |
|||
float oneOverAtlasWidth = 1.0f / atlasWidth; |
|||
float oneOverAtlasHeight = 1.0f / atlasHeight; |
|||
sliceTransform.m00 = shadowSliceData.resolution * oneOverAtlasWidth; |
|||
sliceTransform.m11 = shadowSliceData.resolution * oneOverAtlasHeight; |
|||
sliceTransform.m03 = shadowSliceData.offsetX * oneOverAtlasWidth; |
|||
sliceTransform.m13 = shadowSliceData.offsetY * oneOverAtlasHeight; |
|||
|
|||
// Apply shadow slice scale and offset
|
|||
shadowSliceData.shadowTransform = sliceTransform * shadowSliceData.shadowTransform; |
|||
} |
|||
|
|||
private void RenderShadowSlice(CommandBuffer cmd, ref ScriptableRenderContext context, ref ShadowSliceData shadowSliceData, |
|||
Matrix4x4 proj, Matrix4x4 view, DrawShadowsSettings settings) |
|||
{ |
|||
cmd.SetViewport(new Rect(shadowSliceData.offsetX, shadowSliceData.offsetY, shadowSliceData.resolution, shadowSliceData.resolution)); |
|||
cmd.EnableScissorRect(new Rect(shadowSliceData.offsetX + 4, shadowSliceData.offsetY + 4, shadowSliceData.resolution - 8, shadowSliceData.resolution - 8)); |
|||
|
|||
cmd.SetViewProjectionMatrices(view, proj); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
context.DrawShadows(ref settings); |
|||
cmd.DisableScissorRect(); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
} |
|||
|
|||
private int GetMaxTileResolutionInAtlas(int atlasWidth, int atlasHeight, int tileCount) |
|||
{ |
|||
int resolution = Mathf.Min(atlasWidth, atlasHeight); |
|||
if (tileCount > Mathf.Log(resolution)) |
|||
{ |
|||
Debug.LogError( |
|||
String.Format( |
|||
"Cannot fit {0} tiles into current shadowmap atlas of size ({1}, {2}). ShadowMap Resolution set to zero.", |
|||
tileCount, atlasWidth, atlasHeight)); |
|||
return 0; |
|||
} |
|||
|
|||
int currentTileCount = atlasWidth / resolution * atlasHeight / resolution; |
|||
while (currentTileCount < tileCount) |
|||
{ |
|||
resolution = resolution >> 1; |
|||
currentTileCount = atlasWidth / resolution * atlasHeight / resolution; |
|||
} |
|||
return resolution; |
|||
} |
|||
|
|||
private void SetupShadowCasterConstants(CommandBuffer cmd, ref VisibleLight visibleLight, Matrix4x4 proj, float cascadeResolution) |
|||
{ |
|||
Light light = visibleLight.light; |
|||
float bias = 0.0f; |
|||
float normalBias = 0.0f; |
|||
|
|||
// Use same kernel radius as built-in pipeline so we can achieve same bias results
|
|||
// with the default light bias parameters.
|
|||
const float kernelRadius = 3.65f; |
|||
|
|||
if (visibleLight.lightType == LightType.Directional) |
|||
{ |
|||
// Scale bias by cascade's world space depth range.
|
|||
// Directional shadow lights have orthogonal projection.
|
|||
// proj.m22 = -2 / (far - near) since the projection's depth range is [-1.0, 1.0]
|
|||
// In order to be correct we should multiply bias by 0.5 but this introducing aliasing along cascades more visible.
|
|||
float sign = (SystemInfo.usesReversedZBuffer) ? 1.0f : -1.0f; |
|||
bias = light.shadowBias * proj.m22 * sign; |
|||
|
|||
// Currently only square POT cascades resolutions are used.
|
|||
// We scale normalBias
|
|||
double frustumWidth = 2.0 / (double)proj.m00; |
|||
double frustumHeight = 2.0 / (double)proj.m11; |
|||
float texelSizeX = (float)(frustumWidth / (double)cascadeResolution); |
|||
float texelSizeY = (float)(frustumHeight / (double)cascadeResolution); |
|||
float texelSize = Mathf.Max(texelSizeX, texelSizeY); |
|||
|
|||
// Since we are applying normal bias on caster side we want an inset normal offset
|
|||
// thus we use a negative normal bias.
|
|||
normalBias = -light.shadowNormalBias * texelSize * kernelRadius; |
|||
} |
|||
else if (visibleLight.lightType == LightType.Spot) |
|||
{ |
|||
float sign = (SystemInfo.usesReversedZBuffer) ? -1.0f : 1.0f; |
|||
bias = light.shadowBias * sign; |
|||
normalBias = 0.0f; |
|||
} |
|||
else |
|||
{ |
|||
Debug.LogWarning("Only spot and directional shadow casters are supported in lightweight pipeline"); |
|||
} |
|||
|
|||
Vector3 lightDirection = -visibleLight.localToWorld.GetColumn(2); |
|||
cmd.SetGlobalVector("_ShadowBias", new Vector4(bias, normalBias, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector("_LightDirection", new Vector4(lightDirection.x, lightDirection.y, lightDirection.z, 0.0f)); |
|||
} |
|||
|
|||
private void SetupDirectionalShadowReceiverConstants(CommandBuffer cmd, VisibleLight shadowLight, ref ScriptableRenderContext context) |
|||
{ |
|||
Light light = shadowLight.light; |
|||
|
|||
int cascadeCount = m_ShadowCasterCascadesCount; |
|||
for (int i = 0; i < kMaxCascades; ++i) |
|||
m_DirectionalShadowMatrices[i] = (cascadeCount >= i) ? m_CascadeSlices[i].shadowTransform : Matrix4x4.identity; |
|||
|
|||
// We setup and additional a no-op WorldToShadow matrix in the last index
|
|||
// because the ComputeCascadeIndex function in Shadows.hlsl can return an index
|
|||
// out of bounds. (position not inside any cascade) and we want to avoid branching
|
|||
Matrix4x4 noOpShadowMatrix = Matrix4x4.zero; |
|||
noOpShadowMatrix.m33 = (SystemInfo.usesReversedZBuffer) ? 1.0f : 0.0f; |
|||
m_DirectionalShadowMatrices[kMaxCascades] = noOpShadowMatrix; |
|||
|
|||
float invShadowAtlasWidth = 1.0f / m_ShadowSettings.directionalShadowAtlasWidth; |
|||
float invShadowAtlasHeight = 1.0f / m_ShadowSettings.directionalShadowAtlasHeight; |
|||
float invHalfShadowAtlasWidth = 0.5f * invShadowAtlasWidth; |
|||
float invHalfShadowAtlasHeight = 0.5f * invShadowAtlasHeight; |
|||
cmd.SetGlobalTexture(m_DirectionalShadowmapID, m_DirectionalShadowmapTexture); |
|||
cmd.SetGlobalMatrixArray(DirectionalShadowConstantBuffer._WorldToShadow, m_DirectionalShadowMatrices); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowData, new Vector4(light.shadowStrength, 0.0f, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVectorArray(DirectionalShadowConstantBuffer._DirShadowSplitSpheres, m_CascadeSplitDistances); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._DirShadowSplitSphereRadii, m_CascadeSplitRadii); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowOffset0, new Vector4(-invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowOffset1, new Vector4(invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowOffset2, new Vector4(-invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowOffset3, new Vector4(invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f)); |
|||
cmd.SetGlobalVector(DirectionalShadowConstantBuffer._ShadowmapSize, new Vector4(invShadowAtlasWidth, invShadowAtlasHeight, |
|||
m_ShadowSettings.directionalShadowAtlasWidth, m_ShadowSettings.directionalShadowAtlasHeight)); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
} |
|||
|
|||
private void SetupLocalLightsShadowReceiverConstants(CommandBuffer cmd, ref ScriptableRenderContext context) |
|||
{ |
|||
for (int i = 0; i < m_LocalLightSlices.Length; ++i) |
|||
m_LocalShadowMatrices[i] = m_LocalLightSlices[i].shadowTransform; |
|||
|
|||
float invShadowAtlasWidth = 1.0f / m_ShadowSettings.localShadowAtlasWidth; |
|||
float invShadowAtlasHeight = 1.0f / m_ShadowSettings.localShadowAtlasHeight; |
|||
float invHalfShadowAtlasWidth = 0.5f * invShadowAtlasWidth; |
|||
float invHalfShadowAtlasHeight = 0.5f * invShadowAtlasHeight; |
|||
|
|||
cmd.SetGlobalTexture(m_LocalShadowmapID, 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, |
|||
m_ShadowSettings.localShadowAtlasWidth, m_ShadowSettings.localShadowAtlasHeight)); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
} |
|||
}; |
|||
} |
|
|||
using System.Collections.Generic; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Experimental.Rendering.LightweightPipeline |
|||
{ |
|||
public static class RenderTargetHandle |
|||
{ |
|||
public static int Color; |
|||
public static int Depth; |
|||
public static int DepthMS; |
|||
public static int OpaqueColor; |
|||
public static int DirectionalShadowmap; |
|||
public static int LocalShadowmap; |
|||
public static int ScreenSpaceOcclusion; |
|||
} |
|||
|
|||
|
|||
public class ForwardRenderer |
|||
{ |
|||
private Dictionary<int, RenderTargetIdentifier> m_ResourceMap = new Dictionary<int, RenderTargetIdentifier>(); |
|||
private List<ScriptableRenderPass> m_Passes = new List<ScriptableRenderPass>(); |
|||
private List<ScriptableRenderPass> m_Graph = new List<ScriptableRenderPass>(); |
|||
|
|||
public ForwardRenderer() |
|||
{ |
|||
// RenderTexture format depends on camera and pipeline (HDR, non HDR, etc)
|
|||
// Samples (MSAA) depend on camera and pipeline
|
|||
RenderTargetHandle.Color = Shader.PropertyToID("_CameraColorTexture"); |
|||
RenderTargetHandle.Depth = Shader.PropertyToID("_CameraDepthTexture"); |
|||
RenderTargetHandle.DepthMS = Shader.PropertyToID("_CameraDepthMSTexture"); |
|||
RenderTargetHandle.OpaqueColor = Shader.PropertyToID("_CameraOpaqueTexture"); |
|||
RenderTargetHandle.DirectionalShadowmap = Shader.PropertyToID("_DirectionalShadowmapTexture"); |
|||
RenderTargetHandle.LocalShadowmap = Shader.PropertyToID("_LocalShadowmapTexture"); |
|||
RenderTargetHandle.ScreenSpaceOcclusion = Shader.PropertyToID("_ScreenSpaceShadowMapTexture"); |
|||
|
|||
m_ResourceMap.Add(RenderTargetHandle.Color, new RenderTargetIdentifier(RenderTargetHandle.Color)); |
|||
m_ResourceMap.Add(RenderTargetHandle.Depth, new RenderTargetIdentifier(RenderTargetHandle.Depth)); |
|||
m_ResourceMap.Add(RenderTargetHandle.DepthMS, new RenderTargetIdentifier(RenderTargetHandle.DepthMS)); |
|||
m_ResourceMap.Add(RenderTargetHandle.OpaqueColor, new RenderTargetIdentifier(RenderTargetHandle.OpaqueColor)); |
|||
m_ResourceMap.Add(RenderTargetHandle.DirectionalShadowmap, new RenderTargetIdentifier(RenderTargetHandle.DirectionalShadowmap)); |
|||
m_ResourceMap.Add(RenderTargetHandle.LocalShadowmap, new RenderTargetIdentifier(RenderTargetHandle.LocalShadowmap)); |
|||
m_ResourceMap.Add(RenderTargetHandle.ScreenSpaceOcclusion, new RenderTargetIdentifier(RenderTargetHandle.ScreenSpaceOcclusion)); |
|||
} |
|||
|
|||
public void AddPass(ScriptableRenderPass pass) |
|||
{ |
|||
m_Passes.Add(pass); |
|||
} |
|||
|
|||
public List<ScriptableRenderPass> BuildRenderGraph() |
|||
{ |
|||
m_Graph.Clear(); |
|||
return m_Graph; |
|||
} |
|||
|
|||
public RenderTargetIdentifier GetSurface(int handle) |
|||
{ |
|||
return m_ResourceMap[handle]; |
|||
} |
|||
} |
|||
} |
撰写
预览
正在加载...
取消
保存
Reference in new issue