浏览代码

Merge pull request #1378 from Unity-Technologies/LWRP

Lwrp
/main
GitHub 6 年前
当前提交
c27f37c6
共有 30 个文件被更改,包括 2207 次插入1590 次删除
  1. 42
      ScriptableRenderPipeline/Core/CoreRP/Utilities/CoreUtils.cs
  2. 41
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Data/LightweightPipelineAsset.cs
  3. 55
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/LightweightAssetEditor.cs
  4. 8
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/LightweightCameraEditor.cs
  5. 972
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipeline.cs
  6. 153
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipelineCore.cs
  7. 60
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/DepthCopy.hlsl
  8. 20
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Shadows.hlsl
  9. 7
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightCopyDepth.shader
  10. 4
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightScreenSpaceShadows.shader
  11. 8
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset
  12. 378
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightForwardRenderer.cs
  13. 11
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightForwardRenderer.cs.meta
  14. 179
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightShadowUtils.cs
  15. 11
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightShadowUtils.cs.meta
  16. 8
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes.meta
  17. 57
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DepthOnlyPass.cs
  18. 11
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DepthOnlyPass.cs.meta
  19. 173
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DirectionalShadowsPass.cs
  20. 569
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ForwardLitPass.cs
  21. 11
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ForwardLitPass.cs.meta
  22. 182
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/LocalShadowsPass.cs
  23. 11
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/LocalShadowsPass.cs.meta
  24. 66
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScreenSpaceShadowResolvePass.cs
  25. 11
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScreenSpaceShadowResolvePass.cs.meta
  26. 103
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScriptableRenderPass.cs
  27. 11
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScriptableRenderPass.cs.meta
  28. 635
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightShadowPass.cs
  29. 0
      /ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DirectionalShadowsPass.cs.meta

42
ScriptableRenderPipeline/Core/CoreRP/Utilities/CoreUtils.cs


ClearRenderTarget(cmd, clearFlag, clearColor);
}
// Explicit load and store actions
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier buffer, RenderBufferLoadAction loadAction, RenderBufferStoreAction storeAction, ClearFlag clearFlag, Color clearColor)
{
cmd.SetRenderTarget(buffer, loadAction, storeAction);
ClearRenderTarget(cmd, clearFlag, clearColor);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier buffer, RenderBufferLoadAction loadAction, RenderBufferStoreAction storeAction, ClearFlag clearFlag)
{
SetRenderTarget(cmd, buffer, loadAction, storeAction, clearFlag, clearColorAllBlack);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorBuffer, RenderBufferLoadAction colorLoadAction, RenderBufferStoreAction colorStoreAction,
RenderTargetIdentifier depthBuffer, RenderBufferLoadAction depthLoadAction, RenderBufferStoreAction depthStoreAction,
ClearFlag clearFlag, Color clearColor)
{
cmd.SetRenderTarget(colorBuffer, colorLoadAction, colorStoreAction, depthBuffer, depthLoadAction, depthStoreAction);
ClearRenderTarget(cmd, clearFlag, clearColor);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorBuffer, RenderBufferLoadAction colorLoadAction, RenderBufferStoreAction colorStoreAction,
RenderTargetIdentifier depthBuffer, RenderBufferLoadAction depthLoadAction, RenderBufferStoreAction depthStoreAction,
ClearFlag clearFlag)
{
SetRenderTarget(cmd, colorBuffer, colorLoadAction, colorStoreAction, depthBuffer, depthLoadAction, depthStoreAction, clearFlag, clearColorAllBlack);
}
public static string GetRenderTargetAutoName(int width, int height, int depth, RenderTextureFormat format, string name, bool mips = false, bool enableMSAA = false, MSAASamples msaaSamples = MSAASamples.None)
{
string result = string.Format("{0}_{1}x{2}", name, width, height);

// Unity specifics
public static Material CreateEngineMaterial(string shaderPath)
{
var mat = new Material(Shader.Find(shaderPath))
Shader shader = Shader.Find(shaderPath);
if (shader == null)
{
Debug.LogError("Cannot create required material because shader " + shaderPath + " could not be found");
return null;
}
var mat = new Material(shader)
{
hideFlags = HideFlags.HideAndDontSave
};

public static Material CreateEngineMaterial(Shader shader)
{
if (shader == null)
{
Debug.LogError("Cannot create required material because shader is null");
return null;
}
var mat = new Material(shader)
{
hideFlags = HideFlags.HideAndDontSave

41
ScriptableRenderPipeline/LightweightPipeline/LWRP/Data/LightweightPipelineAsset.cs


[SerializeField] private bool m_SupportsHDR = false;
[SerializeField] private MSAAQuality m_MSAA = MSAAQuality._4x;
[SerializeField] private float m_RenderScale = 1.0f;
[SerializeField] private bool m_SupportsDynamicBatching = true;
[SerializeField] private bool m_DirectionalShadowsSupported = true;
[SerializeField] private ShadowResolution m_ShadowAtlasResolution = ShadowResolution._2048;

[SerializeField] private bool m_LocalShadowsSupported = true;
[SerializeField] private ShadowResolution m_LocalShadowsAtlasResolution = ShadowResolution._512;
[SerializeField] private bool m_SoftShadowsSupported = false;
[SerializeField] private bool m_CustomShaderVariantStrippingSettings = false;
[SerializeField] private bool m_KeepAdditionalLightVariants = true;
[SerializeField] private bool m_KeepVertexLightVariants = true;
[SerializeField] private bool m_KeepDirectionalShadowVariants = true;
[SerializeField] private bool m_KeepLocalShadowVariants = true;
[SerializeField] private bool m_KeepSoftShadowVariants = true;
[SerializeField]
private LightweightPipelineResources m_ResourcesAsset;

get { return m_SupportsHDR; }
}
public int MSAASampleCount
public int MsaaSampleCount
{
get { return (int)m_MSAA; }
set { m_MSAA = (MSAAQuality)value; }

get { return m_RenderScale; }
set { m_RenderScale = value; }
}
public bool SupportsDynamicBatching { get { return m_SupportsDynamicBatching; } }
public bool SupportsDirectionalShadows
{

public bool SupportsSoftShadows
{
get { return m_SoftShadowsSupported; }
}
public bool CustomShaderVariantStripping
{
get { return m_CustomShaderVariantStrippingSettings; }
}
public bool KeepAdditionalLightVariants
{
get { return m_KeepAdditionalLightVariants; }
}
public bool KeepVertexLightVariants
{
get { return m_KeepVertexLightVariants; }
}
public bool KeepDirectionalShadowVariants
{
get { return m_KeepDirectionalShadowVariants; }
}
public bool KeepLocalShadowVariants
{
get { return m_KeepLocalShadowVariants; }
}
public bool KeepSoftShadowVariants
{
get { return m_KeepSoftShadowVariants; }
}
public override Material GetDefaultMaterial()

55
ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/LightweightAssetEditor.cs


public static GUIContent opaqueDownsampling = new GUIContent("Opaque Downsampling", "The downsampling method that is used for the opaque texture");
public static GUIContent hdrContent = new GUIContent("HDR", "Controls the global HDR settings.");
public static GUIContent msaaContent = new GUIContent("Anti Aliasing (MSAA)", "Controls the global anti aliasing settings.");
public static GUIContent dynamicBatching = new GUIContent("Dynamic Batching", "If enabled the pipeline will batch drawcalls with few triangles together by copying their vertex buffers into a shared buffer on a per-frame basis.");
public static GUIContent supportsSoftShadows = new GUIContent("Soft Shadows", "If enabled pipeline will perform shadow filtering. Otherwise all lights that cast shadows will fallback to perform a single shadow sample.");
public static GUIContent supportsDirectionalShadows = new GUIContent("Directional Shadows", "If enabled shadows will be supported for directional lights.");

public static string[] opaqueDownsamplingOptions = {"None", "2x (Bilinear)", "4x (Box)", "4x (Bilinear)"};
}
public static class StrippingStyles
{
public static GUIContent strippingLabel = new GUIContent("Shader Stripping");
public static GUIContent pipelineCapabilitiesLabel = new GUIContent("Pipeline Capabilities", "Select pipeline capabilities variants to be kept in the build.");
public static string[] strippingOptions = {"Automatic", "Custom"};
public static GUIContent localLightsLabel = new GUIContent("Additional Lights", "If enabled additional lights variants won't be stripped from build.");
public static GUIContent vertexLightsLabel = new GUIContent("Vertex Lights", "If enabled vertex lights variants wont' be stripped from build.");
public static GUIContent directionalShadowsLabel = new GUIContent("Directional Shadows", "If enabled directional shadows variants won't be stripped from build.");
public static GUIContent localShadowsLabel = new GUIContent("Local Shadows", "If enabled local shadows variants won't be stripped from build.");
public static GUIContent softShadowsLabel = new GUIContent("Soft Shadows", "If enabled soft shadows variants won't be stripped from build.");
}
AnimBool m_ShowSoftParticles = new AnimBool();
AnimBool m_ShowOpaqueTextureScale = new AnimBool();

private SerializedProperty m_OpaqueDownsamplingProp;
private SerializedProperty m_HDR;
private SerializedProperty m_MSAA;
private SerializedProperty m_SupportsDynamicBatching;
private SerializedProperty m_SoftShadowsSupportedProp;
private SerializedProperty m_DirectionalShadowsSupportedProp;

private SerializedProperty m_LocalShadowSupportedProp;
private SerializedProperty m_LocalShadowsAtlasResolutionProp;
private SerializedProperty m_CustomShaderVariantStripSettingsProp;
private SerializedProperty m_KeepAdditionalLightsProp;
private SerializedProperty m_KeepVertexLightsProp;
private SerializedProperty m_KeepDirectionalShadowsProp;
private SerializedProperty m_KeepLocalShadowsProp;
private SerializedProperty m_KeepSoftShadowsProp;
void OnEnable()
{
m_RenderScale = serializedObject.FindProperty("m_RenderScale");

m_OpaqueDownsamplingProp = serializedObject.FindProperty("m_OpaqueDownsampling");
m_HDR = serializedObject.FindProperty("m_SupportsHDR");
m_MSAA = serializedObject.FindProperty("m_MSAA");
m_SupportsDynamicBatching = serializedObject.FindProperty("m_SupportsDynamicBatching");
m_DirectionalShadowsSupportedProp = serializedObject.FindProperty("m_DirectionalShadowsSupported");
m_ShadowDistanceProp = serializedObject.FindProperty("m_ShadowDistance");

m_LocalShadowsAtlasResolutionProp = serializedObject.FindProperty("m_LocalShadowsAtlasResolution");
m_SoftShadowsSupportedProp = serializedObject.FindProperty("m_SoftShadowsSupported");
m_CustomShaderVariantStripSettingsProp = serializedObject.FindProperty("m_CustomShaderVariantStrippingSettings");
m_KeepAdditionalLightsProp = serializedObject.FindProperty("m_KeepAdditionalLightVariants");
m_KeepVertexLightsProp = serializedObject.FindProperty("m_KeepVertexLightVariants");
m_KeepDirectionalShadowsProp = serializedObject.FindProperty("m_KeepDirectionalShadowVariants");
m_KeepLocalShadowsProp = serializedObject.FindProperty("m_KeepLocalShadowVariants");
m_KeepSoftShadowsProp = serializedObject.FindProperty("m_KeepSoftShadowVariants");
m_ShowSoftParticles.valueChanged.AddListener(Repaint);
m_ShowSoftParticles.value = m_RequireSoftParticlesProp.boolValue;
m_ShowOpaqueTextureScale.valueChanged.AddListener(Repaint);

DrawAnimatedPopup(m_OpaqueDownsamplingProp, Styles.opaqueDownsampling, Styles.opaqueDownsamplingOptions, m_ShowOpaqueTextureScale);
EditorGUILayout.PropertyField(m_HDR, Styles.hdrContent);
EditorGUILayout.PropertyField(m_MSAA, Styles.msaaContent);
EditorGUILayout.PropertyField(m_SupportsDynamicBatching, Styles.dynamicBatching);
EditorGUI.indentLevel--;
EditorGUILayout.Space();

EditorGUILayout.PropertyField(m_SoftShadowsSupportedProp, Styles.supportsSoftShadows);
EditorGUI.indentLevel--;
EditorGUILayout.Space();
EditorGUILayout.Space();
}
void DrawStrippingSettings()
{
EditorGUILayout.LabelField(StrippingStyles.strippingLabel, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
CoreEditorUtils.DrawPopup(StrippingStyles.pipelineCapabilitiesLabel, m_CustomShaderVariantStripSettingsProp, StrippingStyles.strippingOptions);
if (m_CustomShaderVariantStripSettingsProp.boolValue)
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_KeepAdditionalLightsProp, StrippingStyles.localLightsLabel);
EditorGUILayout.PropertyField(m_KeepVertexLightsProp, StrippingStyles.vertexLightsLabel);
EditorGUILayout.PropertyField(m_KeepDirectionalShadowsProp, StrippingStyles.directionalShadowsLabel);
EditorGUILayout.PropertyField(m_KeepLocalShadowsProp, StrippingStyles.localShadowsLabel);
EditorGUILayout.PropertyField(m_KeepSoftShadowsProp, StrippingStyles.softShadowsLabel);
EditorGUI.indentLevel--;
}
EditorGUI.indentLevel--;
EditorGUILayout.Space();
EditorGUILayout.Space();
}
public override void OnInspectorGUI()

UpdateAnimationValues();
DrawRenderingSettings();
DrawShadowSettings();
DrawStrippingSettings();
serializedObject.ApplyModifiedProperties();
}

8
ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/LightweightCameraEditor.cs


if (!settings.targetTexture.hasMultipleDifferentValues)
{
var texture = settings.targetTexture.objectReferenceValue as RenderTexture;
int pipelineSamplesCount = lightweightPipeline.MSAASampleCount;
int pipelineSamplesCount = lightweightPipeline.MsaaSampleCount;
if (texture && texture.antiAliasing > pipelineSamplesCount)
{

MessageType.Warning, true);
if (GUILayout.Button(s_Styles.fixNow))
lightweightPipeline.MSAASampleCount = texture.antiAliasing;
lightweightPipeline.MsaaSampleCount = texture.antiAliasing;
}
}
}

EditorGUILayout.PropertyField(settings.allowMSAA);
if (settings.allowMSAA.boolValue && lightweightPipeline.MSAASampleCount <= 1)
if (settings.allowMSAA.boolValue && lightweightPipeline.MsaaSampleCount <= 1)
lightweightPipeline.MSAASampleCount = 4;
lightweightPipeline.MsaaSampleCount = 4;
}
}

972
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipeline.cs
文件差异内容过多而无法显示
查看文件

153
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipelineCore.cs


using System;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.XR;
public enum FrameRenderingConfiguration
{
None = (0 << 0),
Stereo = (1 << 0),
Msaa = (1 << 1),
BeforeTransparentPostProcess = (1 << 2),
PostProcess = (1 << 3),
DepthPrePass = (1 << 4),
DepthCopy = (1 << 5),
DefaultViewport = (1 << 6),
IntermediateTexture = (1 << 7)
}
[Flags]
public enum PipelineCapabilities
{
AdditionalLights = (1 << 0),

SoftShadows = (1 << 4),
}
public enum MixedLightingSetup
{
None = 0,
ShadowMask,
Subtractive,
};
public struct RenderingData
{
public CameraData cameraData;
public LightData lightData;
public ShadowData shadowData;
public bool supportsDynamicBatching;
}
public struct LightData
{
public int pixelAdditionalLightsCount;
public int totalAdditionalLightsCount;
public int mainLightIndex;
public List<VisibleLight> visibleLights;
public List<int> visibleLocalLightIndices;
}
public struct CameraData
{
public Camera camera;
public float renderScale;
public int msaaSamples;
public bool isSceneViewCamera;
public bool isDefaultViewport;
public bool isOffscreenRender;
public bool isHdrEnabled;
public bool requiresDepthTexture;
public bool requiresSoftParticles;
public bool requiresOpaqueTexture;
public Downsampling opaqueTextureDownsampling;
public bool isStereoEnabled;
public float maxShadowDistance;
public bool postProcessEnabled;
public PostProcessLayer postProcessLayer;
}
public struct ShadowData
{
public bool renderDirectionalShadows;
public bool requiresScreenSpaceShadowResolve;
public int directionalShadowAtlasWidth;
public int directionalShadowAtlasHeight;
public int directionalLightCascadeCount;
public Vector3 directionalLightCascades;
public bool renderLocalShadows;
public int localShadowAtlasWidth;
public int localShadowAtlasHeight;
public bool supportsSoftShadows;
public int bufferBitCount;
public LightShadows renderedDirectionalShadowQuality;
public LightShadows renderedLocalShadowQuality;
}
public class CameraComparer : IComparer<Camera>

public static readonly string LocalShadowsText = "_LOCAL_SHADOWS_ENABLED";
public static readonly string SoftShadowsText = "_SHADOWS_SOFT";
public static readonly string CascadeShadowsText = "_SHADOWS_CASCADE";
public static readonly string DepthNoMsaa = "_DEPTH_NO_MSAA";
public static readonly string DepthMsaa2 = "_DEPTH_MSAA_2";
public static readonly string DepthMsaa4 = "_DEPTH_MSAA_4";
#if UNITY_2018_2_OR_NEWER
public static readonly ShaderKeyword AdditionalLights = new ShaderKeyword(AdditionalLightsText);

{
s_PipelineCapabilities = 0U;
if (pipelineAsset.MaxPixelLights > 1 || pipelineAsset.SupportsVertexLight)
s_PipelineCapabilities |= PipelineCapabilities.AdditionalLights;
// Strip variants based on selected pipeline features
if (!pipelineAsset.CustomShaderVariantStripping)
{
if (pipelineAsset.MaxPixelLights > 1 || pipelineAsset.SupportsVertexLight)
s_PipelineCapabilities |= PipelineCapabilities.AdditionalLights;
if (pipelineAsset.SupportsVertexLight)
s_PipelineCapabilities |= PipelineCapabilities.VertexLights;
if (pipelineAsset.SupportsVertexLight)
s_PipelineCapabilities |= PipelineCapabilities.VertexLights;
if (pipelineAsset.SupportsDirectionalShadows)
s_PipelineCapabilities |= PipelineCapabilities.DirectionalShadows;
if (pipelineAsset.SupportsDirectionalShadows)
s_PipelineCapabilities |= PipelineCapabilities.DirectionalShadows;
if (pipelineAsset.SupportsLocalShadows)
s_PipelineCapabilities |= PipelineCapabilities.LocalShadows;
if (pipelineAsset.SupportsLocalShadows)
s_PipelineCapabilities |= PipelineCapabilities.LocalShadows;
bool anyShadows = pipelineAsset.SupportsDirectionalShadows || pipelineAsset.SupportsLocalShadows;
if (pipelineAsset.SupportsSoftShadows && anyShadows)
s_PipelineCapabilities |= PipelineCapabilities.SoftShadows;
bool anyShadows = pipelineAsset.SupportsDirectionalShadows || pipelineAsset.SupportsLocalShadows;
if (pipelineAsset.SupportsSoftShadows && anyShadows)
s_PipelineCapabilities |= PipelineCapabilities.SoftShadows;
}
else
{
if (pipelineAsset.KeepAdditionalLightVariants)
s_PipelineCapabilities |= PipelineCapabilities.AdditionalLights;
if (pipelineAsset.KeepVertexLightVariants)
s_PipelineCapabilities |= PipelineCapabilities.VertexLights;
if (pipelineAsset.KeepDirectionalShadowVariants)
s_PipelineCapabilities |= PipelineCapabilities.DirectionalShadows;
if (pipelineAsset.KeepLocalShadowVariants)
s_PipelineCapabilities |= PipelineCapabilities.LocalShadows;
if (pipelineAsset.KeepSoftShadowVariants)
s_PipelineCapabilities |= PipelineCapabilities.SoftShadows;
}
}
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,

}
public static void StartStereoRendering(Camera camera, ref ScriptableRenderContext context, FrameRenderingConfiguration renderingConfiguration)
{
if (CoreUtils.HasFlag(renderingConfiguration, FrameRenderingConfiguration.Stereo))
context.StartMultiEye(camera);
}
public static void StopStereoRendering(Camera camera, ref ScriptableRenderContext context, FrameRenderingConfiguration renderingConfiguration)
{
if (CoreUtils.HasFlag(renderingConfiguration, FrameRenderingConfiguration.Stereo))
context.StopMultiEye(camera);
}
public static void GetLightCookieMatrix(VisibleLight light, out Matrix4x4 cookieMatrix)

// Remaining light types don't support cookies
}
public static void CopyTexture(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier dest, Material material)
{
if (SystemInfo.copyTextureSupport != CopyTextureSupport.None)
cmd.CopyTexture(source, dest);
else
cmd.Blit(source, dest, material);
}
public static bool IsSupportedShadowType(LightType lightType)
{
return lightType == LightType.Directional || lightType == LightType.Spot;

{
return lightType == LightType.Directional || lightType == LightType.Spot;
}
public static bool PlatformSupportsMSAABackBuffer()
{
#if UNITY_ANDROID || UNITY_IPHONE || UNITY_TVOS || UNITY_SAMSUNGTV
return true;
#else
return false;
#endif
}
}
}

60
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/DepthCopy.hlsl


}
#if defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
#define DEPTH_TEXTURE_MS Texture2DMSArray
#define DEPTH_TEXTURE_MS(name, samples) Texture2DMSArray<float, samples> name
#define LOAD(uv, sampleIndex) LOAD_TEXTURE2D_ARRAY_MSAA(_CameraDepthTexture, uv, unity_StereoEyeIndex, sampleIndex)
#define SAMPLE(uv) SAMPLE_TEXTURE2D_ARRAY(_CameraDepthTexture, sampler_CameraDepthTexture, uv, unity_StereoEyeIndex).r
#define LOAD(uv, sampleIndex) LOAD_TEXTURE2D_ARRAY_MSAA(_CameraDepthAttachment, uv, unity_StereoEyeIndex, sampleIndex)
#define SAMPLE(uv) SAMPLE_TEXTURE2D_ARRAY(_CameraDepthAttachment, sampler_CameraDepthAttachment, uv, unity_StereoEyeIndex).r
#define DEPTH_TEXTURE_MS Texture2DMS
#define DEPTH_TEXTURE_MS(name, samples) Texture2DMS<float, samples> name
#define LOAD(uv, sampleIndex) LOAD_TEXTURE2D_MSAA(_CameraDepthTexture, uv, sampleIndex)
#define SAMPLE(uv) SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, uv)
#define LOAD(uv, sampleIndex) LOAD_TEXTURE2D_MSAA(_CameraDepthAttachment, uv, sampleIndex)
#define SAMPLE(uv) SAMPLE_DEPTH_TEXTURE(_CameraDepthAttachment, sampler_CameraDepthAttachment, uv)
#ifdef _MSAA_DEPTH
DEPTH_TEXTURE_MS<float> _CameraDepthTexture;
float _SampleCount;
float4 _CameraDepthTexture_TexelSize;
#ifdef _DEPTH_MSAA_2
#define MSAA_SAMPLES 2
#elif _DEPTH_MSAA_4
#define MSAA_SAMPLES 4
#endif
#ifdef _DEPTH_NO_MSAA
DEPTH_TEXTURE(_CameraDepthAttachment);
SAMPLER(sampler_CameraDepthAttachment);
DEPTH_TEXTURE(_CameraDepthTexture);
SAMPLER(sampler_CameraDepthTexture);
DEPTH_TEXTURE_MS(_CameraDepthAttachment, MSAA_SAMPLES);
float4 _CameraDepthAttachment_TexelSize;
#endif
#if UNITY_REVERSED_Z
#define DEPTH_DEFAULT_VALUE 1.0
#define DEPTH_OP min
#else
#define DEPTH_DEFAULT_VALUE 0.0
#define DEPTH_OP max
#ifdef _MSAA_DEPTH
int2 coord = int2(uv * _CameraDepthTexture_TexelSize.zw);
int samples = (int)_SampleCount;
#if UNITY_REVERSED_Z
float outDepth = 1.0;
#define DEPTH_OP min
#else
float outDepth = 0.0;
#define DEPTH_OP max
#endif
#ifdef _DEPTH_NO_MSAA
return SAMPLE(uv);
#else
int2 coord = int2(uv * _CameraDepthAttachment_TexelSize.zw);
float outDepth = DEPTH_DEFAULT_VALUE;
for (int i = 0; i < samples; ++i)
outDepth = DEPTH_OP(LOAD(uv, i), outDepth);
[unroll]
for (int i = 0; i < MSAA_SAMPLES; ++i)
outDepth = DEPTH_OP(LOAD(coord, i), outDepth);
#else
return SAMPLE(uv);
#endif
}

20
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Shadows.hlsl


#define SHADOWS_SCREEN 1
#endif
SCREENSPACE_TEXTURE(_ScreenSpaceShadowMap);
SAMPLER(sampler_ScreenSpaceShadowMap);
SCREENSPACE_TEXTURE(_ScreenSpaceShadowMapTexture);
SAMPLER(sampler_ScreenSpaceShadowMapTexture);
TEXTURE2D_SHADOW(_ShadowMap);
SAMPLER_CMP(sampler_ShadowMap);
TEXTURE2D_SHADOW(_DirectionalShadowmapTexture);
SAMPLER_CMP(sampler_DirectionalShadowmapTexture);
TEXTURE2D_SHADOW(_LocalShadowMapAtlas);
SAMPLER_CMP(sampler_LocalShadowMapAtlas);
TEXTURE2D_SHADOW(_LocalShadowmapTexture);
SAMPLER_CMP(sampler_LocalShadowmapTexture);
CBUFFER_START(_DirectionalShadowBuffer)
// Last cascade is initialized with a no-op matrix. It always transforms

shadowCoord.xy = UnityStereoTransformScreenSpaceTex(shadowCoord.xy);
#if defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
half attenuation = SAMPLE_TEXTURE2D_ARRAY(_ScreenSpaceShadowMap, sampler_ScreenSpaceShadowMap, shadowCoord.xy, unity_StereoEyeIndex).x;
half attenuation = SAMPLE_TEXTURE2D_ARRAY(_ScreenSpaceShadowMapTexture, sampler_ScreenSpaceShadowMapTexture, shadowCoord.xy, unity_StereoEyeIndex).x;
half attenuation = SAMPLE_TEXTURE2D(_ScreenSpaceShadowMap, sampler_ScreenSpaceShadowMap, shadowCoord.xy).x;
half attenuation = SAMPLE_TEXTURE2D(_ScreenSpaceShadowMapTexture, sampler_ScreenSpaceShadowMapTexture, shadowCoord.xy).x;
#endif
return attenuation;

#else
ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
half shadowStrength = GetMainLightShadowStrength();
return SampleShadowmap(shadowCoord, TEXTURE2D_PARAM(_ShadowMap, sampler_ShadowMap), shadowSamplingData, shadowStrength);
return SampleShadowmap(shadowCoord, TEXTURE2D_PARAM(_DirectionalShadowmapTexture, sampler_DirectionalShadowmapTexture), shadowSamplingData, shadowStrength);
#endif
}

float4 shadowCoord = mul(_LocalWorldToShadowAtlas[lightIndex], float4(positionWS, 1.0));
ShadowSamplingData shadowSamplingData = GetLocalLightShadowSamplingData();
half shadowStrength = GetLocalLightShadowStrenth(lightIndex);
return SampleShadowmap(shadowCoord, TEXTURE2D_PARAM(_LocalShadowMapAtlas, sampler_LocalShadowMapAtlas), shadowSamplingData, shadowStrength);
return SampleShadowmap(shadowCoord, TEXTURE2D_PARAM(_LocalShadowmapTexture, sampler_LocalShadowmapTexture), shadowSamplingData, shadowStrength);
#endif
}

7
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightCopyDepth.shader


Shader "Hidden/LightweightPipeline/CopyDepth"
{
Properties
{
[HideInInspector] _SampleCount("MSAA sample count", Float) = 1.0
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "LightweightPipeline"}

#pragma vertex vert
#pragma fragment frag
#pragma multi_compile __ _MSAA_DEPTH
#pragma multi_compile _DEPTH_NO_MSAA _DEPTH_MSAA_2 _DEPTH_MSAA_4
#include "LWRP/ShaderLibrary/DepthCopy.hlsl"

4
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightScreenSpaceShadows.shader


TEXTURE2D_ARRAY(_CameraDepthTexture);
#else
TEXTURE2D(_CameraDepthTexture);
#endif // defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
#endif
SAMPLER(sampler_CameraDepthTexture);

// Screenspace shadowmap is only used for directional lights which use orthogonal projection.
ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
half shadowStrength = GetMainLightShadowStrength();
return SampleShadowmap(coords, TEXTURE2D_PARAM(_ShadowMap, sampler_ShadowMap), shadowSamplingData, shadowStrength);
return SampleShadowmap(coords, TEXTURE2D_PARAM(_DirectionalShadowmapTexture, sampler_DirectionalShadowmapTexture), shadowSamplingData, shadowStrength);
}
ENDHLSL

8
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset


m_Cascade2Split: 0.25
m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467}
m_LocalShadowsSupported: 1
m_LocalShadowsAtlasResolution: 256
m_LocalShadowsAtlasResolution: 512
m_CustomShaderVariantStrippingSettings: 0
m_KeepAdditionalLightVariants: 1
m_KeepVertexLightVariants: 1
m_KeepDirectionalShadowVariants: 1
m_KeepLocalShadowVariants: 1
m_KeepSoftShadowVariants: 1
m_ResourcesAsset: {fileID: 11400000, guid: aac5a08c32552a14c89394b703f1978a, type: 2}
m_ShadowType: 0

378
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightForwardRenderer.cs


using System;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.XR;
namespace UnityEngine.Experimental.Rendering.LightweightPipeline
{
public enum RenderPassHandles
{
DepthPrepass,
DirectionalShadows,
LocalShadows,
ScreenSpaceShadowResolve,
ForwardLit,
Count,
}
public enum MaterialHandles
{
Error,
DepthCopy,
Sampling,
Blit,
ScrenSpaceShadow,
Count,
}
public static class RenderTargetHandles
{
public static int Color;
public static int DepthAttachment;
public static int DepthTexture;
public static int OpaqueColor;
public static int DirectionalShadowmap;
public static int LocalShadowmap;
public static int ScreenSpaceShadowmap;
}
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
public bool useComputeBufferForPerObjectLightIndices
{
get
{
return SystemInfo.supportsComputeShaders &&
!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; }
public FilterRenderersSettings opaqueFilterSettings { get; private set; }
public FilterRenderersSettings transparentFilterSettings { get; private set; }
Dictionary<int, RenderTargetIdentifier> m_ResourceMap = new Dictionary<int, RenderTargetIdentifier>();
List<ScriptableRenderPass> m_ActiveShadowQueue = new List<ScriptableRenderPass>();
List<ScriptableRenderPass> m_ActiveRenderPassQueue = new List<ScriptableRenderPass>();
Material[] m_Materials;
ScriptableRenderPass[] m_RenderPassSet = new ScriptableRenderPass[(int)RenderPassHandles.Count];
public LightweightForwardRenderer(LightweightPipelineAsset pipelineAsset)
{
// RenderTexture format depends on camera and pipeline (HDR, non HDR, etc)
// Samples (MSAA) depend on camera and pipeline
RegisterSurface("_CameraColorTexture", out RenderTargetHandles.Color);
RegisterSurface("_CameraDepthAttachment", out RenderTargetHandles.DepthAttachment);
RegisterSurface("_CameraDepthTexture", out RenderTargetHandles.DepthTexture);
RegisterSurface("_CameraOpaqueTexture", out RenderTargetHandles.OpaqueColor);
RegisterSurface("_DirectionalShadowmapTexture", out RenderTargetHandles.DirectionalShadowmap);
RegisterSurface("_LocalShadowmapTexture", out RenderTargetHandles.LocalShadowmap);
RegisterSurface("_ScreenSpaceShadowMapTexture", out RenderTargetHandles.ScreenSpaceShadowmap);
m_Materials = new Material[(int)MaterialHandles.Count]
{
CoreUtils.CreateEngineMaterial("Hidden/InternalErrorShader"),
CoreUtils.CreateEngineMaterial(pipelineAsset.CopyDepthShader),
CoreUtils.CreateEngineMaterial(pipelineAsset.SamplingShader),
CoreUtils.CreateEngineMaterial(pipelineAsset.BlitShader),
CoreUtils.CreateEngineMaterial(pipelineAsset.ScreenSpaceShadowShader),
};
m_RenderPassSet = new ScriptableRenderPass[(int)RenderPassHandles.Count]
{
new DepthOnlyPass(this),
new DirectionalShadowsPass(this),
new LocalShadowsPass(this),
new ScreenSpaceShadowResolvePass(this),
new ForwardLitPass(this),
};
postProcessRenderContext = new PostProcessRenderContext();
opaqueFilterSettings = new FilterRenderersSettings(true)
{
renderQueueRange = RenderQueueRange.opaque,
};
transparentFilterSettings = new FilterRenderersSettings(true)
{
renderQueueRange = RenderQueueRange.transparent,
};
}
public void Dispose()
{
if (perObjectLightIndices != null)
{
perObjectLightIndices.Release();
perObjectLightIndices = null;
}
for (int i = 0; i < m_Materials.Length; ++i)
CoreUtils.Destroy(m_Materials[i]);
}
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.colorFormat = cameraData.isHdrEnabled ? RenderTextureFormat.DefaultHDR :
RenderTextureFormat.Default;
desc.enableRandomWrite = false;
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 RenderingData renderingData)
{
Clear();
SetupPerObjectLightIndices(ref cullResults, ref renderingData.lightData);
RenderTextureDescriptor baseDescriptor = CreateRTDesc(ref renderingData.cameraData);
bool requiresCameraDepth = renderingData.cameraData.requiresDepthTexture;
bool requiresDepthPrepass = renderingData.shadowData.requiresScreenSpaceShadowResolve ||
renderingData.cameraData.isSceneViewCamera || (requiresCameraDepth && !CanCopyDepth(ref renderingData.cameraData));
// For now VR requires a depth prepass until we figure out how to properly resolve texture2DMS in stereo
requiresDepthPrepass |= renderingData.cameraData.isStereoEnabled;
CommandBuffer cmd = CommandBufferPool.Get("Setup Rendering");
if (requiresDepthPrepass)
EnqueuePass(cmd, RenderPassHandles.DepthPrepass, baseDescriptor, null, RenderTargetHandles.DepthTexture);
if (renderingData.shadowData.renderDirectionalShadows)
{
EnqueuePass(cmd, RenderPassHandles.DirectionalShadows, baseDescriptor);
if (renderingData.shadowData.requiresScreenSpaceShadowResolve)
EnqueuePass(cmd, RenderPassHandles.ScreenSpaceShadowResolve, baseDescriptor, new[] {RenderTargetHandles.ScreenSpaceShadowmap});
}
if (renderingData.shadowData.renderLocalShadows)
EnqueuePass(cmd, RenderPassHandles.LocalShadows, baseDescriptor);
bool requiresDepthAttachment = requiresCameraDepth && !requiresDepthPrepass;
bool requiresColorAttachment = RequiresColorAttachment(ref renderingData.cameraData, baseDescriptor) || requiresDepthAttachment;
int[] colorHandles = (requiresColorAttachment) ? new[] {RenderTargetHandles.Color} : null;
int depthHandle = (requiresColorAttachment) ? RenderTargetHandles.DepthAttachment : -1;
EnqueuePass(cmd, RenderPassHandles.ForwardLit, baseDescriptor, colorHandles, depthHandle, renderingData.cameraData.msaaSamples);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref RenderingData renderingData)
{
// TODO: The reason we have to separate passes into two queues is because shadows require different camera
// context. We need to take a look at approaches to effectively share shadow between cameras, then we
// can move this out
for (int i = 0; i < m_ActiveShadowQueue.Count; ++i)
m_ActiveShadowQueue[i].Execute(ref context, ref cullResults, ref renderingData);
// 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(renderingData.cameraData.camera, renderingData.cameraData.isStereoEnabled);
for (int i = 0; i < m_ActiveRenderPassQueue.Count; ++i)
m_ActiveRenderPassQueue[i].Execute(ref context, ref cullResults, ref renderingData);
#if UNITY_EDITOR
if (renderingData.cameraData.isSceneViewCamera)
{
// Restore Render target for additional editor rendering.
// Note: Scene view camera always perform depth prepass
CommandBuffer cmd = CommandBufferPool.Get("Copy Depth to Camera");
CoreUtils.SetRenderTarget(cmd, BuiltinRenderTextureType.CameraTarget);
cmd.EnableShaderKeyword(LightweightKeywords.DepthNoMsaa);
cmd.DisableShaderKeyword(LightweightKeywords.DepthMsaa2);
cmd.DisableShaderKeyword(LightweightKeywords.DepthMsaa4);
cmd.Blit(GetSurface(RenderTargetHandles.DepthTexture), BuiltinRenderTextureType.CameraTarget, GetMaterial(MaterialHandles.DepthCopy));
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
#endif
DisposePasses(ref context);
}
public RenderTargetIdentifier GetSurface(int handle)
{
RenderTargetIdentifier renderTargetID;
if (handle < 0 || !m_ResourceMap.TryGetValue(handle, out renderTargetID))
{
Debug.LogError(string.Format("Handle {0} has not any surface registered to it.", handle));
return new RenderTargetIdentifier();
}
return renderTargetID;
}
public Material GetMaterial(MaterialHandles handle)
{
int handleID = (int)handle;
if (handleID >= m_Materials.Length)
{
Debug.LogError(string.Format("Material {0} is not registered.",
Enum.GetName(typeof(MaterialHandles), handleID)));
return null;
}
return m_Materials[handleID];
}
ScriptableRenderPass GetPass(RenderPassHandles handle)
{
int handleID = (int)handle;
if (handleID >= m_RenderPassSet.Length)
{
Debug.LogError(string.Format("Render Pass {0} is not registered.",
Enum.GetName(typeof(RenderPassHandles), handleID)));
return null;
}
return m_RenderPassSet[handleID];
}
void Clear()
{
m_ActiveShadowQueue.Clear();
m_ActiveRenderPassQueue.Clear();
}
void RegisterSurface(string shaderProperty, out int handle)
{
handle = Shader.PropertyToID(shaderProperty);
m_ResourceMap.Add(handle, new RenderTargetIdentifier(handle));
}
void EnqueuePass(CommandBuffer cmd, RenderPassHandles passHandle, RenderTextureDescriptor baseDescriptor,
int[] colorAttachmentHandles = null, int depthAttachmentHandle = -1, int samples = 1)
{
ScriptableRenderPass pass = GetPass(passHandle);
pass.Setup(cmd, baseDescriptor, colorAttachmentHandles, depthAttachmentHandle, samples);
if (passHandle == RenderPassHandles.DirectionalShadows || passHandle == RenderPassHandles.LocalShadows)
m_ActiveShadowQueue.Add(pass);
else
m_ActiveRenderPassQueue.Add(pass);
}
bool RequiresColorAttachment(ref CameraData cameraData, RenderTextureDescriptor baseDescriptor)
{
bool isScaledRender = !Mathf.Approximately(cameraData.renderScale, 1.0f);
bool isTargetTexture2DArray = baseDescriptor.dimension == TextureDimension.Tex2DArray;
return cameraData.isSceneViewCamera || isScaledRender || cameraData.isHdrEnabled ||
cameraData.postProcessEnabled || cameraData.requiresOpaqueTexture || isTargetTexture2DArray;
}
bool CanCopyDepth(ref CameraData cameraData)
{
bool msaaEnabledForCamera = cameraData.msaaSamples > 1;
bool supportsTextureCopy = SystemInfo.copyTextureSupport != CopyTextureSupport.None;
bool supportsDepthTarget = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Depth);
bool supportsDepthCopy = !msaaEnabledForCamera && (supportsDepthTarget || supportsTextureCopy);
bool msaaDepthResolve = msaaEnabledForCamera && SystemInfo.supportsMultisampledTextures != 0;
return supportsDepthCopy || msaaDepthResolve;
}
void DisposePasses(ref ScriptableRenderContext context)
{
CommandBuffer cmd = CommandBufferPool.Get("Release Resources");
for (int i = 0; i < m_ActiveShadowQueue.Count; ++i)
m_ActiveShadowQueue[i].Dispose(cmd);
for (int i = 0; i < m_ActiveRenderPassQueue.Count; ++i)
m_ActiveRenderPassQueue[i].Dispose(cmd);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
void SetupPerObjectLightIndices(ref CullResults cullResults, ref LightData lightData)
{
if (lightData.totalAdditionalLightsCount == 0)
return;
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);
}
}
}
}
}

11
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightForwardRenderer.cs.meta


fileFormatVersion: 2
guid: 83797c942458af1439f0f02f681ee8c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

179
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightShadowUtils.cs


using System;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.LightweightPipeline
{
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 LightweightShadowUtils
{
public static bool ExtractDirectionalLightMatrix(ref CullResults cullResults, ref ShadowData shadowData, int shadowLightIndex, int cascadeIndex, int shadowResolution, float shadowNearPlane, out Vector4 cascadeSplitDistance, out ShadowSliceData shadowSliceData, out Matrix4x4 viewMatrix, out Matrix4x4 projMatrix)
{
ShadowSplitData splitData;
bool success = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(shadowLightIndex,
cascadeIndex, shadowData.directionalLightCascadeCount, shadowData.directionalLightCascades, shadowResolution, shadowNearPlane, out viewMatrix, out projMatrix,
out splitData);
float cullingSphereRadius = splitData.cullingSphere.w;
cascadeSplitDistance = splitData.cullingSphere;
cascadeSplitDistance.w = cullingSphereRadius * cullingSphereRadius;
shadowSliceData.offsetX = (cascadeIndex % 2) * shadowResolution;
shadowSliceData.offsetY = (cascadeIndex / 2) * shadowResolution;
shadowSliceData.resolution = shadowResolution;
shadowSliceData.shadowTransform = GetShadowTransform(projMatrix, viewMatrix);
// 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 (shadowData.directionalLightCascadeCount > 1)
ApplySliceTransform(ref shadowSliceData, shadowData.directionalShadowAtlasWidth, shadowData.directionalShadowAtlasHeight);
return success;
}
public static bool ExtractSpotLightMatrix(ref CullResults cullResults, ref ShadowData shadowData, int shadowLightIndex, out Matrix4x4 shadowMatrix, out Matrix4x4 viewMatrix, out Matrix4x4 projMatrix)
{
ShadowSplitData splitData;
bool success = cullResults.ComputeSpotShadowMatricesAndCullingPrimitives(shadowLightIndex, out viewMatrix, out projMatrix, out splitData);
shadowMatrix = GetShadowTransform(projMatrix, viewMatrix);
return success;
}
public static 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();
}
public static 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;
}
public static 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;
}
public static 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));
}
static 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;
}
}
}

11
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightShadowUtils.cs.meta


fileFormatVersion: 2
guid: 6f6f9cae14ad81c44ba88bd7a667b0b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes.meta


fileFormatVersion: 2
guid: c2a16f045b3148e4f9d0d62614a81a61
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

57
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DepthOnlyPass.cs


using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.LightweightPipeline
{
public class DepthOnlyPass : ScriptableRenderPass
{
const string kProfilerTag = "Depth Prepass Setup";
const string kCommandBufferTag = "Depth Prepass";
int kDepthBufferBits = 32;
public DepthOnlyPass(LightweightForwardRenderer renderer) : base(renderer)
{
RegisterShaderPassName("DepthOnly");
}
public override void Setup(CommandBuffer cmd, RenderTextureDescriptor baseDescriptor, int[] colorAttachmentHandles, int depthAttachmentHandle = -1, int samples = 1)
{
base.Setup(cmd, baseDescriptor, colorAttachmentHandles, depthAttachmentHandle, samples);
baseDescriptor.colorFormat = RenderTextureFormat.Depth;
baseDescriptor.depthBufferBits = kDepthBufferBits;
if (samples > 1)
{
baseDescriptor.bindMS = samples > 1;
baseDescriptor.msaaSamples = samples;
}
cmd.GetTemporaryRT(depthAttachmentHandle, baseDescriptor, FilterMode.Point);
}
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get(kCommandBufferTag);
using (new ProfilingSample(cmd, kProfilerTag))
{
SetRenderTarget(cmd, GetSurface(depthAttachmentHandle), RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
ClearFlag.Depth, Color.black);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
var drawSettings = CreateDrawRendererSettings(renderingData.cameraData.camera, SortFlags.CommonOpaque, RendererConfiguration.None, renderingData.supportsDynamicBatching);
if (renderingData.cameraData.isStereoEnabled)
{
Camera camera = renderingData.cameraData.camera;
context.StartMultiEye(camera);
context.DrawRenderers(cullResults.visibleRenderers, ref drawSettings, renderer.opaqueFilterSettings);
context.StopMultiEye(camera);
}
else
context.DrawRenderers(cullResults.visibleRenderers, ref drawSettings, renderer.opaqueFilterSettings);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
}

11
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DepthOnlyPass.cs.meta


fileFormatVersion: 2
guid: 2b327960b30da614ca5f44f2fef0137a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

173
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DirectionalShadowsPass.cs


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;
RenderTextureFormat m_ShadowmapFormat;
RenderTextureDescriptor m_DirectionalShadowmapDescriptor;
Matrix4x4[] m_DirectionalShadowMatrices;
ShadowSliceData[] m_CascadeSlices;
Vector4[] m_CascadeSplitDistances;
public DirectionalShadowsPass(LightweightForwardRenderer renderer) : 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");
m_ShadowmapFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Shadowmap)
? RenderTextureFormat.Shadowmap
: RenderTextureFormat.Depth;
}
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref RenderingData renderingData)
{
if (renderingData.shadowData.renderDirectionalShadows)
{
Clear();
RenderDirectionalCascadeShadowmap(ref context, ref cullResults, ref renderingData.lightData, ref renderingData.shadowData);
}
}
public override void Dispose(CommandBuffer cmd)
{
if (m_DirectionalShadowmapTexture)
{
RenderTexture.ReleaseTemporary(m_DirectionalShadowmapTexture);
m_DirectionalShadowmapTexture = null;
}
}
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);
for (int i = 0; i < m_CascadeSlices.Length; ++i)
m_CascadeSlices[i].Clear();
}
void 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;
VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex];
Light light = shadowLight.light;
Debug.Assert(shadowLight.lightType == LightType.Directional);
if (light.shadows == LightShadows.None)
return;
Bounds bounds;
if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds))
return;
CommandBuffer cmd = CommandBufferPool.Get("Prepare Directional Shadowmap");
m_ShadowCasterCascadesCount = shadowData.directionalLightCascadeCount;
int shadowResolution = LightweightShadowUtils.GetMaxTileResolutionInAtlas(shadowData.directionalShadowAtlasWidth, shadowData.directionalShadowAtlasHeight, m_ShadowCasterCascadesCount);
float shadowNearPlane = light.shadowNearPlane;
Matrix4x4 view, proj;
var settings = new DrawShadowsSettings(cullResults, shadowLightIndex);
m_DirectionalShadowmapTexture = RenderTexture.GetTemporary(shadowData.directionalShadowAtlasWidth,
shadowData.directionalShadowAtlasHeight, k_ShadowmapBufferBits, m_ShadowmapFormat);
m_DirectionalShadowmapTexture.filterMode = FilterMode.Bilinear;
m_DirectionalShadowmapTexture.wrapMode = TextureWrapMode.Clamp;
SetRenderTarget(cmd, m_DirectionalShadowmapTexture, RenderBufferLoadAction.DontCare,
RenderBufferStoreAction.Store, ClearFlag.Depth, Color.black);
bool success = false;
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
{
success = LightweightShadowUtils.ExtractDirectionalLightMatrix(ref cullResults, ref shadowData, shadowLightIndex, cascadeIndex, shadowResolution, shadowNearPlane, out m_CascadeSplitDistances[cascadeIndex], out m_CascadeSlices[cascadeIndex], out view, out proj);
if (success)
{
LightweightShadowUtils.SetupShadowCasterConstants(cmd, ref shadowLight, proj, shadowResolution);
LightweightShadowUtils.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.requiresScreenSpaceShadowResolve)
shadowQuality = LightShadows.Hard;
SetupDirectionalShadowReceiverConstants(ref context, cmd, ref shadowData, shadowLight);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
// TODO: We should have RenderingData as a readonly but currently we need this to pass shadow rendering to litpass
shadowData.renderedDirectionalShadowQuality = shadowQuality;
}
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, new Vector4(m_CascadeSplitDistances[0].w, m_CascadeSplitDistances[1].w, m_CascadeSplitDistances[2].w, m_CascadeSplitDistances[3].w));
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();
}
};
}

569
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ForwardLitPass.cs


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;
// 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];
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);
// Copy Opaque Color Pass
m_SamplingMaterial = renderer.GetMaterial(MaterialHandles.Sampling);
m_SampleOffsetShaderHandle = Shader.PropertyToID("_SampleOffset");
}
public override void Setup(CommandBuffer cmd, RenderTextureDescriptor baseDescriptor, int[] colorAttachmentHandles, int depthAttachmentHandle = -1, int samples = 1)
{
base.Setup(cmd, baseDescriptor, colorAttachmentHandles, depthAttachmentHandle, samples);
m_ColorFormat = baseDescriptor.colorFormat;
if (colorAttachmentHandle != -1)
{
var descriptor = baseDescriptor;
descriptor.depthBufferBits = k_DepthStencilBufferBits; // TODO: does the color RT always need depth?
descriptor.sRGB = true;
descriptor.msaaSamples = samples;
cmd.GetTemporaryRT(colorAttachmentHandle, descriptor, FilterMode.Bilinear);
}
if (depthAttachmentHandle != -1)
{
var descriptor = baseDescriptor;
descriptor.colorFormat = RenderTextureFormat.Depth;
descriptor.depthBufferBits = k_DepthStencilBufferBits;
descriptor.msaaSamples = samples;
descriptor.bindMS = samples > 1;
cmd.GetTemporaryRT(depthAttachmentHandle, descriptor, FilterMode.Point);
}
}
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref RenderingData renderingData)
{
Camera camera = renderingData.cameraData.camera;
bool dynamicBatching = renderingData.supportsDynamicBatching;
SetupShaderConstants(ref context, ref renderingData.cameraData, ref renderingData.lightData, ref renderingData.shadowData);
RendererConfiguration rendererConfiguration = GetRendererConfiguration(renderingData.lightData.totalAdditionalLightsCount);
if (renderingData.cameraData.isStereoEnabled)
context.StartMultiEye(camera);
RenderOpaques(ref context, ref cullResults, ref renderingData.cameraData, rendererConfiguration, dynamicBatching);
if (renderingData.cameraData.postProcessEnabled &&
renderingData.cameraData.postProcessLayer.HasOpaqueOnlyEffects(renderer.postProcessRenderContext))
OpaquePostProcessSubPass(ref context, ref renderingData.cameraData);
if (depthAttachmentHandle != -1)
CopyDepthSubPass(ref context, ref renderingData.cameraData);
if (renderingData.cameraData.requiresOpaqueTexture)
CopyColorSubpass(ref context, ref renderingData.cameraData);
RenderTransparents(ref context, ref cullResults, ref renderingData.cameraData, rendererConfiguration, dynamicBatching);
if (renderingData.cameraData.postProcessEnabled)
PostProcessPass(ref context, ref renderingData.cameraData);
else if (!renderingData.cameraData.isOffscreenRender && colorAttachmentHandle != -1)
FinalBlitPass(ref context, ref renderingData.cameraData);
if (renderingData.cameraData.isStereoEnabled)
{
context.StopMultiEye(camera);
context.StereoEndRender(camera);
}
}
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, ref ShadowData shadowData)
{
CommandBuffer cmd = CommandBufferPool.Get("SetupShaderConstants");
SetupShaderLightConstants(cmd, ref lightData);
SetShaderKeywords(cmd, ref cameraData, ref lightData, ref shadowData);
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, ref ShadowData shadowData)
{
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 = shadowData.renderedDirectionalShadowQuality;
LightShadows localShadowQuality = shadowData.renderedLocalShadowQuality;
// Currently shadow filtering keyword is shared between local and directional shadows.
bool hasSoftShadows = (directionalShadowQuality == LightShadows.Soft || localShadowQuality == LightShadows.Soft) &&
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, RenderBufferLoadAction loadOp, RenderBufferStoreAction storeOp, ClearFlag clearFlag, Color clearColor)
{
if (colorAttachmentHandle != -1)
{
if (depthAttachmentHandle != -1)
SetRenderTarget(cmd, GetSurface(colorAttachmentHandle), loadOp, storeOp, GetSurface(depthAttachmentHandle), loadOp, storeOp, clearFlag, clearColor);
else
SetRenderTarget(cmd, GetSurface(colorAttachmentHandle), loadOp, storeOp, clearFlag, clearColor);
}
else
{
SetRenderTarget(cmd, BuiltinRenderTextureType.CameraTarget, loadOp, storeOp, clearFlag, clearColor);
}
}
void RenderOpaques(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, RendererConfiguration rendererConfiguration, bool dynamicBatching)
{
CommandBuffer cmd = CommandBufferPool.Get("Render Opaques");
Camera camera = cameraData.camera;
ClearFlag clearFlag = GetCameraClearFlag(camera);
// TODO: This was merged from previous LOAD/STORE PR. It seems this should not be DontCare
// and instead we should check clearFlags to wheter set to Clear or DontCare
// Same in screenspace shadow resolve pass. Also we should check for the msaa resolve actions.
SetRenderTarget(cmd, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, clearFlag, CoreUtils.ConvertSRGBToActiveColorSpace(camera.backgroundColor));
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 (colorAttachmentHandle == -1 && cameraData.isDefaultViewport)
cmd.SetViewport(camera.pixelRect);
var drawSettings = CreateDrawRendererSettings(camera, SortFlags.CommonOpaque, rendererConfiguration, dynamicBatching);
context.DrawRenderers(cullResults.visibleRenderers, ref drawSettings, renderer.opaqueFilterSettings);
// Render objects that did not match any shader pass with error shader
RenderObjectsWithError(ref context, ref cullResults, camera, renderer.opaqueFilterSettings, SortFlags.None);
if (camera.clearFlags == CameraClearFlags.Skybox)
context.DrawSkybox(camera);
}
void RenderTransparents(ref ScriptableRenderContext context, ref CullResults cullResults, ref CameraData cameraData, RendererConfiguration rendererConfiguration, bool dynamicBatching)
{
CommandBuffer cmd = CommandBufferPool.Get("Render Transparents");
Camera camera = cameraData.camera;
SetRenderTarget(cmd, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store, ClearFlag.None, Color.black);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
var drawSettings = CreateDrawRendererSettings(camera, SortFlags.CommonTransparent, rendererConfiguration, dynamicBatching);
context.DrawRenderers(cullResults.visibleRenderers, ref drawSettings, renderer.transparentFilterSettings);
// Render objects that did not match any shader pass with error shader
RenderObjectsWithError(ref context, ref cullResults, camera, renderer.transparentFilterSettings, SortFlags.None);
}
void FinalBlitPass(ref ScriptableRenderContext context, ref CameraData cameraData)
{
Material material = cameraData.isStereoEnabled ? null : m_BlitMaterial;
RenderTargetIdentifier sourceRT = GetSurface(colorAttachmentHandle);
CommandBuffer cmd = CommandBufferPool.Get("Final Blit Pass");
cmd.SetGlobalTexture("_BlitTex", sourceRT);
if (!cameraData.isDefaultViewport)
{
SetRenderTarget(cmd, BuiltinRenderTextureType.CameraTarget, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, ClearFlag.All, Color.black);
cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
cmd.SetViewport(cameraData.camera.pixelRect);
LightweightPipeline.DrawFullScreen(cmd, material);
}
else
{
cmd.Blit(GetSurface(colorAttachmentHandle), BuiltinRenderTextureType.CameraTarget, material);
}
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;
}
}
}
// 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(colorAttachmentHandle), 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 OpaquePostProcessSubPass(ref ScriptableRenderContext context, ref CameraData cameraData)
{
CommandBuffer cmd = CommandBufferPool.Get("Render Opaque PostProcess Effects");
RenderTargetIdentifier source = GetSurface(colorAttachmentHandle);
LightweightPipeline.RenderPostProcess(cmd, renderer.postProcessRenderContext, ref cameraData, m_ColorFormat, source, GetSurface(colorAttachmentHandle), true);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
void CopyDepthSubPass(ref ScriptableRenderContext context, ref CameraData cameraData)
{
CommandBuffer cmd = CommandBufferPool.Get("Depth Copy");
RenderTargetIdentifier depthSurface = GetSurface(depthAttachmentHandle);
RenderTargetIdentifier copyDepthSurface = GetSurface(RenderTargetHandles.DepthTexture);
RenderTextureDescriptor descriptor = renderer.CreateRTDesc(ref cameraData);
descriptor.colorFormat = RenderTextureFormat.Depth;
descriptor.depthBufferBits = k_DepthStencilBufferBits;
descriptor.msaaSamples = 1;
descriptor.bindMS = false;
cmd.GetTemporaryRT(RenderTargetHandles.DepthTexture, descriptor, FilterMode.Point);
if (cameraData.msaaSamples > 1)
{
cmd.DisableShaderKeyword(LightweightKeywords.DepthNoMsaa);
if (cameraData.msaaSamples == 4)
{
cmd.DisableShaderKeyword(LightweightKeywords.DepthMsaa2);
cmd.EnableShaderKeyword(LightweightKeywords.DepthMsaa4);
}
else
{
cmd.EnableShaderKeyword(LightweightKeywords.DepthMsaa2);
cmd.DisableShaderKeyword(LightweightKeywords.DepthMsaa4);
}
cmd.Blit(depthSurface, copyDepthSurface, m_DepthCopyMaterial);
}
else
{
cmd.EnableShaderKeyword(LightweightKeywords.DepthNoMsaa);
cmd.DisableShaderKeyword(LightweightKeywords.DepthMsaa2);
cmd.DisableShaderKeyword(LightweightKeywords.DepthMsaa4);
LightweightPipeline.CopyTexture(cmd, depthSurface, copyDepthSurface, m_DepthCopyMaterial);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
void CopyColorSubpass(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(colorAttachmentHandle);
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;
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
}

11
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ForwardLitPass.cs.meta


fileFormatVersion: 2
guid: 6ff0f03778c60ae42890954fcf650d4c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

182
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/LocalShadowsPass.cs


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;
RenderTextureFormat m_LocalShadowmapFormat;
Matrix4x4[] m_LocalShadowMatrices;
ShadowSliceData[] m_LocalLightSlices;
float[] m_LocalShadowStrength;
public LocalShadowsPass(LightweightForwardRenderer renderer) : 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");
m_LocalShadowmapFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Shadowmap)
? RenderTextureFormat.Shadowmap
: RenderTextureFormat.Depth;
}
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref RenderingData renderingData)
{
if (renderingData.shadowData.renderLocalShadows)
{
Clear();
RenderLocalShadowmapAtlas(ref context, ref cullResults, ref renderingData.lightData, ref renderingData.shadowData);
}
}
public override void Dispose(CommandBuffer cmd)
{
if (m_LocalShadowmapTexture)
{
RenderTexture.ReleaseTemporary(m_LocalShadowmapTexture);
m_LocalShadowmapTexture = null;
}
}
void Clear()
{
m_LocalShadowmapTexture = null;
for (int i = 0; i < m_LocalShadowMatrices.Length; ++i)
m_LocalShadowMatrices[i] = Matrix4x4.identity;
for (int i = 0; i < m_LocalLightSlices.Length; ++i)
m_LocalLightSlices[i].Clear();
for (int i = 0; i < m_LocalShadowStrength.Length; ++i)
m_LocalShadowStrength[i] = 0.0f;
}
void RenderLocalShadowmapAtlas(ref ScriptableRenderContext context, ref CullResults cullResults, ref LightData lightData, ref ShadowData shadowData)
{
List<int> localLightIndices = lightData.visibleLocalLightIndices;
List<VisibleLight> visibleLights = lightData.visibleLights;
int shadowCastingLightsCount = 0;
int localLightsCount = localLightIndices.Count;
for (int i = 0; i < localLightsCount; ++i)
{
VisibleLight shadowLight = visibleLights[localLightIndices[i]];
if (shadowLight.lightType == LightType.Spot && shadowLight.light.shadows != LightShadows.None)
shadowCastingLightsCount++;
}
if (shadowCastingLightsCount == 0)
return;
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 = LightweightShadowUtils.GetMaxTileResolutionInAtlas(atlasWidth, atlasHeight, shadowCastingLightsCount);
int shadowSampling = 0;
m_LocalShadowmapTexture = RenderTexture.GetTemporary(shadowData.localShadowAtlasWidth,
shadowData.localShadowAtlasHeight, k_ShadowmapBufferBits, m_LocalShadowmapFormat);
m_LocalShadowmapTexture.filterMode = FilterMode.Bilinear;
m_LocalShadowmapTexture.wrapMode = TextureWrapMode.Clamp;
SetRenderTarget(cmd, m_LocalShadowmapTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
ClearFlag.Depth, Color.black);
for (int i = 0; i < localLightsCount; ++i)
{
int shadowLightIndex = localLightIndices[i];
VisibleLight shadowLight = visibleLights[shadowLightIndex];
Light light = shadowLight.light;
// TODO: Add support to point light shadows
if (shadowLight.lightType != LightType.Spot || shadowLight.light.shadows == LightShadows.None)
continue;
if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds))
continue;
Matrix4x4 shadowTransform;
bool success = LightweightShadowUtils.ExtractSpotLightMatrix(ref cullResults, ref shadowData,
shadowLightIndex, out shadowTransform, out view, out proj);
if (success)
{
// This way of computing the shadow slice only work for spots and with most 4 shadow casting lights per pass
// Change this when point lights are supported.
Debug.Assert(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 = shadowTransform;
m_LocalShadowStrength[i] = light.shadowStrength;
shadowSampling = Math.Max(shadowSampling, (int)light.shadows);
if (shadowCastingLightsCount > 1)
LightweightShadowUtils.ApplySliceTransform(ref m_LocalLightSlices[i], atlasWidth, atlasHeight);
LightweightShadowUtils.SetupShadowCasterConstants(cmd, ref shadowLight, proj, sliceResolution);
var settings = new DrawShadowsSettings(cullResults, shadowLightIndex);
LightweightShadowUtils.RenderShadowSlice(cmd, ref context, ref m_LocalLightSlices[i], proj, view, settings);
}
}
SetupLocalLightsShadowReceiverConstants(ref context, cmd, ref shadowData);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
// TODO: We should have RenderingData as a readonly but currently we need this to pass shadow rendering to litpass
shadowData.renderedLocalShadowQuality = (shadowData.supportsSoftShadows) ? (LightShadows)shadowSampling : LightShadows.Hard;
}
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();
}
}
}

11
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/LocalShadowsPass.cs.meta


fileFormatVersion: 2
guid: f46c1a0c3e3a98848a0efbf4e1fd5675
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

66
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScreenSpaceShadowResolvePass.cs


using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.LightweightPipeline
{
public class ScreenSpaceShadowResolvePass : ScriptableRenderPass
{
public bool softShadows { get; set; }
RenderTextureFormat m_ColorFormat;
Material m_ScreenSpaceShadowsMaterial;
public ScreenSpaceShadowResolvePass(LightweightForwardRenderer renderer) : base(renderer)
{
m_ColorFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8)
? RenderTextureFormat.R8
: RenderTextureFormat.ARGB32;
m_ScreenSpaceShadowsMaterial = renderer.GetMaterial(MaterialHandles.ScrenSpaceShadow);
softShadows = false;
}
public override void Setup(CommandBuffer cmd, RenderTextureDescriptor baseDescriptor, int[] colorAttachmentHandles, int depthAttachmentHandle = -1, int samples = 1)
{
base.Setup(cmd, baseDescriptor, colorAttachmentHandles, depthAttachmentHandle, samples);
baseDescriptor.depthBufferBits = 0;
baseDescriptor.colorFormat = m_ColorFormat;
cmd.GetTemporaryRT(colorAttachmentHandle, baseDescriptor, FilterMode.Bilinear);
}
public override void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref RenderingData renderingData)
{
if (renderingData.shadowData.renderedDirectionalShadowQuality == LightShadows.None)
return;
CommandBuffer cmd = CommandBufferPool.Get("Collect Shadows");
SetShadowCollectPassKeywords(cmd, renderingData.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(colorAttachmentHandle);
SetRenderTarget(cmd, screenSpaceOcclusionTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
ClearFlag.Color | ClearFlag.Depth, Color.white);
cmd.Blit(screenSpaceOcclusionTexture, screenSpaceOcclusionTexture, m_ScreenSpaceShadowsMaterial);
if (renderingData.cameraData.isStereoEnabled)
{
Camera camera = renderingData.cameraData.camera;
context.StartMultiEye(camera);
context.ExecuteCommandBuffer(cmd);
context.StopMultiEye(camera);
}
else
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
void SetShadowCollectPassKeywords(CommandBuffer cmd, int cascadeCount)
{
CoreUtils.SetKeyword(cmd, LightweightKeywords.SoftShadowsText, softShadows);
CoreUtils.SetKeyword(cmd, LightweightKeywords.CascadeShadowsText, cascadeCount > 1);
}
}
}

11
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScreenSpaceShadowResolvePass.cs.meta


fileFormatVersion: 2
guid: 129fea61da31162458736c967c9d98ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

103
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScriptableRenderPass.cs


using System.Collections.Generic;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.LightweightPipeline
{
public abstract class ScriptableRenderPass
{
public LightweightForwardRenderer renderer { get; private set; }
public int[] colorAttachmentHandles { get; private set; }
public int colorAttachmentHandle { get; private set; }
public int depthAttachmentHandle { get; private set; }
public TextureDimension textureDimension { get; private set; }
protected List<ShaderPassName> m_ShaderPassNames = new List<ShaderPassName>();
int samples;
public ScriptableRenderPass(LightweightForwardRenderer renderer)
{
this.renderer = renderer;
}
public virtual void Setup(CommandBuffer cmd, RenderTextureDescriptor baseDescriptor, int[] colorAttachmentHandles = null, int depthAttachmentHandle = -1, int samples = 1)
{
this.colorAttachmentHandles = colorAttachmentHandles;
this.depthAttachmentHandle = depthAttachmentHandle;
this.samples = samples;
colorAttachmentHandle = (colorAttachmentHandles != null && colorAttachmentHandles.Length > 0)
? colorAttachmentHandles[0]
: -1;
textureDimension = baseDescriptor.dimension;
}
public virtual void Dispose(CommandBuffer cmd)
{
if (colorAttachmentHandles != null)
{
for (int i = 0; i < colorAttachmentHandles.Length; ++i)
if (colorAttachmentHandles[i] != -1)
cmd.ReleaseTemporaryRT(colorAttachmentHandles[i]);
}
if (depthAttachmentHandle != -1)
cmd.ReleaseTemporaryRT(depthAttachmentHandle);
}
public abstract void Execute(ref ScriptableRenderContext context, ref CullResults cullResults, ref RenderingData renderingData);
public RenderTargetIdentifier GetSurface(int handle)
{
if (renderer == null)
{
Debug.LogError("Pass has invalid renderer");
return new RenderTargetIdentifier();
}
return renderer.GetSurface(handle);
}
public void RegisterShaderPassName(string passName)
{
m_ShaderPassNames.Add(new ShaderPassName(passName));
}
public DrawRendererSettings CreateDrawRendererSettings(Camera camera, SortFlags sortFlags, RendererConfiguration rendererConfiguration, bool supportsDynamicBatching)
{
DrawRendererSettings settings = new DrawRendererSettings(camera, m_ShaderPassNames[0]);
for (int i = 1; i < m_ShaderPassNames.Count; ++i)
settings.SetShaderPassName(i, m_ShaderPassNames[i]);
settings.sorting.flags = sortFlags;
settings.rendererConfiguration = rendererConfiguration;
settings.flags = DrawRendererFlags.EnableInstancing;
if (supportsDynamicBatching)
settings.flags |= DrawRendererFlags.EnableDynamicBatching;
return settings;
}
public void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorAttachment, RenderBufferLoadAction colorLoadAction,
RenderBufferStoreAction colorStoreAction, ClearFlag clearFlag, Color clearColor)
{
if (textureDimension == TextureDimension.Tex2DArray)
CoreUtils.SetRenderTarget(cmd, colorAttachment, clearFlag, clearColor, 0, CubemapFace.Unknown, -1);
else
CoreUtils.SetRenderTarget(cmd, colorAttachment, colorLoadAction, colorStoreAction, clearFlag, clearColor);
}
public void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorAttachment, RenderBufferLoadAction colorLoadAction,
RenderBufferStoreAction colorStoreAction, RenderTargetIdentifier depthAttachment, RenderBufferLoadAction depthLoadAction,
RenderBufferStoreAction depthStoreAction, ClearFlag clearFlag, Color clearColor)
{
if (textureDimension == TextureDimension.Tex2DArray)
CoreUtils.SetRenderTarget(cmd, colorAttachment, depthAttachment,
clearFlag, clearColor, 0, CubemapFace.Unknown, -1);
else
CoreUtils.SetRenderTarget(cmd, colorAttachment, colorLoadAction, colorStoreAction,
depthAttachment, depthLoadAction, depthStoreAction, clearFlag, clearColor);
}
}
}

11
ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/ScriptableRenderPass.cs.meta


fileFormatVersion: 2
guid: edba24b6007b9dd41824b4656ed8ebcf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

635
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightShadowPass.cs


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 LightweightShadowPass
{
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; } }
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 LightweightShadowPass(LightweightPipelineAsset pipelineAsset, int maxLocalLightsCount)
{
BuildShadowSettings(pipelineAsset);
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 void InitializeResources(CommandBuffer cmd, RenderTextureDescriptor renderTextureDesc)
{
if (RequireScreenSpaceShadowmap)
{
renderTextureDesc.depthBufferBits = 0;
renderTextureDesc.colorFormat = m_ShadowSettings.screenspaceShadowmapTextureFormat;
cmd.GetTemporaryRT(m_ScreenSpaceShadowmapID, renderTextureDesc, FilterMode.Bilinear);
}
}
public 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 bool Execute(ref CullResults cullResults, ref LightData lightData, ref ScriptableRenderContext context)
{
Clear();
bool directionalShadowmapRendered = false;
if (IsDirectionalShadowsEnabled)
directionalShadowmapRendered = RenderDirectionalCascadeShadowmap(ref cullResults, ref lightData, ref context);
if (IsLocalShadowsEnabled)
RenderLocalShadowmapAtlas(ref cullResults, ref lightData, ref context);
return directionalShadowmapRendered && m_ShadowSettings.screenSpace;
}
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;
}
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 CullResults cullResults, ref LightData lightData, ref ScriptableRenderContext context)
{
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 CullResults cullResults, ref LightData lightData, ref ScriptableRenderContext context)
{
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();
}
};
}

/ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightShadowPass.cs.meta → /ScriptableRenderPipeline/LightweightPipeline/LWRP/Passes/DirectionalShadowsPass.cs.meta

正在加载...
取消
保存