在URP的片元着色器中应用阴影偏移
Shadow Bias 有关Shadow Bias的介绍我只推荐看这篇知乎文章自适应Shadow Bias算法,里面介绍了有关Shadow Bias的几乎所有需要了解的信息。同时这篇文章也指出了Unity目前正在使用的Shadow Caster Vertex Based Bias方法的不足之处。 如果是平时使用URP的话,Unity使用的在绘制Shadow Caster Pass时将ShadowBias添加到顶点的偏移上的方法,虽然称不上尽善尽美,但是也完全够用了。但是在二次元角色渲染的时候,为了营造丝袜勒肉的效果,会在腿部的模型和丝袜的模型交接的区域做一个向内凹陷的效果。这个区域两侧的模型是正常闭合的,其法线是相对的,此时如果使用Unity默认的使用ShadowBias去调整顶点位置的方式,ShadowBias中的NormalBias就会导致这个区域两侧的模型朝着法线的反方向偏移,导致这个区域的阴影在某些角度时会出现漏洞,可以在文章封面图的左边看到明显的瑕疵,右边则是在顶点着色器中使用了ShadowBias,看上去的效果就比较正常了,而且角色的阴影和角色的模型的大小也基本保持一致。当然了,把NormalBias设置成0就不会有这个问题了,但是失去了NormalBias则会带来其他角度的阴影的瑕疵。 本文使用的是Unity2022.3.43f1c1,URP版本是14.0.11。 关于Shadows.hlsl的碎碎念 我讨厌Unity URP Package里的Shadows.hlsl,因为它使用了一个LerpWhiteTo的方法,这个方法定义在CoreRP的CommonMaterial.hlsl里,而不知道为什么Shadows.hlsl并没有包含这个CommonMaterial,这就导致了我只想单独使用Shadows.hlsl时,必须还得手动包含一遍CommonMaterial.hlsl,我觉得这很不合理。 更要命的是,如果在hlsl中想要使用URP的Light结构体,就起码得包含RealtimeLights.hlsl,这个hlsl又包含了Shadows.hlsl。索性我就直接从这些文件中摘取了一套自己的uber_lights.hlsl和uber_shadows.hlsl,这也方便后续做修改。 对于URP的修改 虽然我的想法是尽量做到即插即用,也就是说尽量不去修改URP默认的代码,但是很遗憾为了将ShadowBias移动到片元着色器里,还是得稍作修改。 URP设置ShadowBias是在绘制级联阴影的每一个slice的时候,将其作为参数传给顶点着色器的,也就是说虽然顶点着色器中的参数只有_ShadowBias一个,实际上Unity会使用级联阴影的层级数个ShadowBias,我们需要将其保存起来,在渲染LitForwardPass的时候,根据当前像素的世界坐标找到对应的级联阴影的层级,再查找对应的ShadowBias进行计算。 MainLightShadowCasterPass.cs 主要是在MainLightShadowCasterPass.cs的RenderMainLightCascadeShadowmap方法中,计算得到了当前层级的ShadowBias之后,将其保存在一个数组中留待后续使用。 for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex) { settings.splitData = m_CascadeSlices[cascadeIndex].splitData; Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref renderingData.shadowData, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].resolution); m_MainLightShadowBiases[cascadeIndex] = shadowBias; // Shadow Biases for fragment shader. 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]....