Unity SRP 管线【第四讲:URP 阴影】
2023-12-18 18:43:39
URP 全文源码解析参照
引入
在UniversalRenderer.cs/ line 505行处
此处已经准备好了所有渲染数据(所有数据全部存储在了renderingData中)
我们只用renderingData中的数据初设置mainLightShadows
bool mainLightShadows = m_MainLightShadowCasterPass.Setup(ref renderingData);
bool additionalLightShadows = m_AdditionalLightsShadowCasterPass.Setup(ref renderingData);
bool transparentsNeedSettingsPass = m_TransparentSettingsPass.Setup(ref renderingData);
进入函数 m_MainLightShadowCasterPass.Setup(ref renderingData);
MainLightShadowCasterPass.cs
一、MainLightShadowCasterPass 创建
public MainLightShadowCasterPass(RenderPassEvent evt)
在UniversalRenderer管线创建的时候,我们已经做了创建
我们设置MainLightShadow在RenderingShadows(Event = 50)之前
// UniversalRenderer.cs
public UniversalRenderer(UniversalRendererData data) : base(data)
{
...
m_MainLightShadowCasterPass = new MainLightShadowCasterPass(RenderPassEvent.BeforeRenderingShadows);
m_AdditionalLightsShadowCasterPass = new AdditionalLightsShadowCasterPass(RenderPassEvent.BeforeRenderingShadows);
...
}
创建MainLightShadowCasterPass
参数:
基类参数
public RenderPassEvent renderPassEvent { get; set; }
int renderTargetWidth { get; set; }
int renderTargetHeight { get; set; }
自定义参数
const int k_MaxCascades = 4;
const int k_ShadowmapBufferBits = 16;
float m_CascadeBorder; // 边缘模糊度(0~1)
float m_MaxShadowDistanceSq; // 最大阴影距离的平方
int m_ShadowCasterCascadesCount; // 当前设置的Cascades数量
RenderTargetHandle m_MainLightShadowmap; //临时阴影纹理Shader中的索引ID
internal RenderTexture m_MainLightShadowmapTexture;//实际临时阴影纹理,以及设置(深度为16位)
Matrix4x4[] m_MainLightShadowMatrices;// 阴影矩阵
ShadowSliceData[] m_CascadeSlices; // 级联阴影切片数据,包含(
//splitData、 级联阴影数据(由UNITY内置函数提供)
//offsetX/Y、 级联阴影偏移
//resolution 级联阴影分辨率
//shadowTransform 级联阴影矩阵
Vector4[] m_CascadeSplitDistances; // 包围球数据(xyz:位置,w:半径)
GPU ID参数
private static class MainLightShadowConstantBuffer
{
public static int _WorldToShadow;
public static int _ShadowParams;
public static int _CascadeShadowSplitSpheres0;
public static int _CascadeShadowSplitSpheres1;
public static int _CascadeShadowSplitSpheres2;
public static int _CascadeShadowSplitSpheres3;
public static int _CascadeShadowSplitSphereRadii;
public static int _ShadowOffset0;
public static int _ShadowOffset1;
public static int _ShadowOffset2;
public static int _ShadowOffset3;
public static int _ShadowmapSize;
}
MainLightShadowConstantBuffer._WorldToShadow = Shader.PropertyToID("_MainLightWorldToShadow");
MainLightShadowConstantBuffer._ShadowParams = Shader.PropertyToID("_MainLightShadowParams");
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres0 = Shader.PropertyToID("_CascadeShadowSplitSpheres0");
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres1 = Shader.PropertyToID("_CascadeShadowSplitSpheres1");
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres2 = Shader.PropertyToID("_CascadeShadowSplitSpheres2");
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres3 = Shader.PropertyToID("_CascadeShadowSplitSpheres3");
MainLightShadowConstantBuffer._CascadeShadowSplitSphereRadii = Shader.PropertyToID("_CascadeShadowSplitSphereRadii");
MainLightShadowConstantBuffer._ShadowOffset0 = Shader.PropertyToID("_MainLightShadowOffset0");
MainLightShadowConstantBuffer._ShadowOffset1 = Shader.PropertyToID("_MainLightShadowOffset1");
MainLightShadowConstantBuffer._ShadowOffset2 = Shader.PropertyToID("_MainLightShadowOffset2");
MainLightShadowConstantBuffer._ShadowOffset3 = Shader.PropertyToID("_MainLightShadowOffset3");
MainLightShadowConstantBuffer._ShadowmapSize = Shader.PropertyToID("_MainLightShadowmapSize");
m_MainLightShadowmap.Init("_MainLightShadowmapTexture");
二、MainLightShadowCasterPass 初始化
public bool Setup(ref RenderingData renderingData){}
1. 初始化数据(矩阵、cascade分割、切片)
Clear();
2. 一些条件判断,未通过的话将ShadowMap置为默认值
… 这里不作为重点
3. 设置数据
SetUp函数主要是将数据整理保存到类内参数中供类使用
其中设置的数据有:
(1)m_ShadowCasterCascadesCount
光源级联阴影数量
(2)RenderTexture 大小
renderTargetWidth;
renderTargetHeight;
(3)提取级联阴影的光照矩阵以及包围球
Vector4[] m_CascadeSplitDistances[cascadeIndex]
包围球数据(xyz:位置,w:半径)ShadowSliceData[] m_CascadeSlices;
级联阴影切片数据
public struct ShadowSliceData
{
public Matrix4x4 viewMatrix;
public Matrix4x4 projectionMatrix;
public Matrix4x4 shadowTransform;//projectionMatrix * viewMatrix
public int offsetX; //ShadowAtlasMap行偏移
public int offsetY; //ShadowAtlasMap列偏移
public int resolution; //分辨率
public ShadowSplitData splitData;//splitData包含筛选信息
}
提取函数
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
{
bool success = ShadowUtils.ExtractDirectionalLightMatrix(
ref renderingData.cullResults,
ref renderingData.shadowData,
shadowLightIndex,
cascadeIndex,
renderTargetWidth,
renderTargetHeight,
shadowResolution,
light.shadowNearPlane,
out m_CascadeSplitDistances[cascadeIndex],
out m_CascadeSlices[cascadeIndex]);
if (!success)
return SetupForEmptyRendering(ref renderingData);
}
(4)获取新的临时阴影纹理
m_MainLightShadowmapTexture = ShadowUtils.GetTemporaryShadowTexture(renderTargetWidth, renderTargetHeight, k_ShadowmapBufferBits);
(5)存储renderingData中的阴影数据
m_MaxShadowDistanceSq = renderingData.cameraData.maxShadowDistance * renderingData.cameraData.maxShadowDistance;
m_CascadeBorder = renderingData.shadowData.mainLightShadowCascadeBorder;
4. 绑定渲染目标和清除状态
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
ConfigureTarget(new RenderTargetIdentifier(m_MainLightShadowmapTexture), m_MainLightShadowmapTexture.depthStencilFormat, renderTargetWidth, renderTargetHeight, 1, true);
ConfigureClear(ClearFlag.All, Color.black);
}
5. 执行 Execute
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (m_CreateEmptyShadowmap)
{
SetEmptyMainLightCascadeShadowmap(ref context);
return;
}
RenderMainLightCascadeShadowmap(ref context, ref renderingData.cullResults, ref renderingData.lightData, ref renderingData.shadowData);
}
三、Execute 阴影参数设置
RenderMainLightCascadeShadowmap(
ref context,
ref renderingData.cullResults,
ref renderingData.lightData,
ref renderingData.shadowData);
参数设置多引用ShadowsUtils单例中的函数设置
进入函数RenderMainLightCascadeShadowmap
// settings 中为阴影所需要的数据
var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex);
settings.useRenderingLayerMaskTest = UniversalRenderPipeline.asset.supportsLightLayers;
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
{
settings.splitData = m_CascadeSlices[cascadeIndex].splitData;
// 偏移量
Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].resolution);
ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.CastingPunctualLightShadow, false);
ShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex],
ref settings, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].viewMatrix);
}
shadowData.isKeywordSoftShadowsEnabled = shadowLight.light.shadows == LightShadows.Soft && shadowData.supportsSoftShadows;
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, shadowData.mainLightShadowCascadesCount == 1);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, shadowData.mainLightShadowCascadesCount > 1);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, shadowData.isKeywordSoftShadowsEnabled);
SetupMainLightShadowReceiverConstants(cmd, shadowLight, shadowData.supportsSoftShadows);
- SetupShadowCasterConstantBuffer
// 阴影偏移
cmd.SetGlobalVector("_ShadowBias", shadowBias);
// 世界空间光照方向,用于支持阴影法线偏移(normal bias).
Vector3 lightDirection = -shadowLight.localToWorldMatrix.GetColumn(2);
cmd.SetGlobalVector("_LightDirection", new Vector4(lightDirection.x, lightDirection.y, lightDirection.z, 0.0f));
// 世界空间光源位置
Vector3 lightPosition = shadowLight.localToWorldMatrix.GetColumn(3);
cmd.SetGlobalVector("_LightPosition", new Vector4(lightPosition.x, lightPosition.y, lightPosition.z, 1.0f));
- 关闭精确光源阴影 PunctualLightShadow(点光源、方向光、聚光灯)
/* "_CASTING_PUNCTUAL_LIGHT_SHADOW" */
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.CastingPunctualLightShadow, false);
- 渲染cascade阴影
设置默认全局偏移(这应该就是为什么,在unity中,将light的bias都设为0,但还是没有明显的摩尔纹)
cmd.SetGlobalDepthBias(1.0f, 2.5f); // these values match HDRP defaults
设置Viewport、矩阵信息
cmd.SetViewport(new Rect(shadowSliceData.offsetX, shadowSliceData.offsetY, shadowSliceData.resolution, shadowSliceData.resolution));
cmd.SetViewProjectionMatrices(view, proj);
渲染阴影,禁用硬件剪刀矩阵(不知道是什么)
context.DrawShadows(ref settings);
cmd.DisableScissorRect();
- 是否开启主光源阴影、主光源级联阴影、主光源软阴影
/*"_MAIN_LIGHT_SHADOWS"*/
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, shadowData.mainLightShadowCascadesCount == 1);
/*"_MAIN_LIGHT_SHADOWS_CASCADE"*/
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, shadowData.mainLightShadowCascadesCount > 1);
/*"_SHADOWS_SOFT"*/
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, shadowData.isKeywordSoftShadowsEnabled);
-
设置阴影接收常量
- 阴影贴图 “
_MainLightShadowmapTexture
” - 光源矩阵 “
_MainLightWorldToShadow
”(级联矩阵为多个矩阵 Matrix4x4[]) - 阴影参数 “
_MainLightShadowParams
”- x :阴影强度
- y :是否软阴影(1为软,0为硬)
- z :阴影衰减部分的衰减斜率
- w:横坐标0处阴影开始衰减部分的纵坐标
- 级联阴影数据:
四个级联的包围球数据(4 * Vector4)_CascadeShadowSplitSpheres0、1、2、3
四个级联的半径的平方(1 * Vector4)_CascadeShadowSplitSphereRadii
- 软阴影:
阴影像素偏移(左下、右下、左上、右上)_MainLightShadowOffset0/1/2/3
阴影偏移量(偏移x,偏移y,shadowMap宽,shadowMap长_MainLightShadowmapSize
- 阴影贴图 “
-
在渲染结束后释放临时Texture
public override void OnCameraCleanup(CommandBuffer cmd)
{
if (cmd == null)
throw new ArgumentNullException("cmd");
if (m_MainLightShadowmapTexture)
{
RenderTexture.ReleaseTemporary(m_MainLightShadowmapTexture);
m_MainLightShadowmapTexture = null;
}
}
GPU中的阴影数据
Shadows.hlsl
SCREENSPACE_TEXTURE(_ScreenSpaceShadowmapTexture);
SAMPLER(sampler_ScreenSpaceShadowmapTexture);
TEXTURE2D_SHADOW(_MainLightShadowmapTexture);
SAMPLER_CMP(sampler_MainLightShadowmapTexture);
TEXTURE2D_SHADOW(_AdditionalLightsShadowmapTexture);
SAMPLER_CMP(sampler_AdditionalLightsShadowmapTexture);
CBUFFER_START(MainLightShadows)
// Last cascade is initialized with a no-op matrix. It always transforms
// shadow coord to half3(0, 0, NEAR_PLANE). We use this trick to avoid
// branching since ComputeCascadeIndex can return cascade index = MAX_SHADOW_CASCADES
float4x4 _MainLightWorldToShadow[MAX_SHADOW_CASCADES + 1];
float4 _CascadeShadowSplitSpheres0;
float4 _CascadeShadowSplitSpheres1;
float4 _CascadeShadowSplitSpheres2;
float4 _CascadeShadowSplitSpheres3;
float4 _CascadeShadowSplitSphereRadii;
half4 _MainLightShadowOffset0;
half4 _MainLightShadowOffset1;
half4 _MainLightShadowOffset2;
half4 _MainLightShadowOffset3;
half4 _MainLightShadowParams; // (x: shadowStrength, y: 1.0 if soft shadows, 0.0 otherwise, z: main light fade scale, w: main light fade bias)
float4 _MainLightShadowmapSize; // (xy: 1/width and 1/height, zw: width and height)
CBUFFER_END
文章来源:https://blog.csdn.net/weixin_44518102/article/details/134974115
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!