Shadow Bias Comparison Cover

在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]....

October 5, 2024 · zznewclear13
Screen Space Contact Shadow Cover

使用Compute Shader计算屏幕空间接触阴影

屏幕空间接触阴影 屏幕空间接触阴影是用来解决普通的阴影贴图精度不够的问题而提出来的一种通过深度图在屏幕空间计算阴影的方法。索尼的Bend Studio的Graham Aldridge在Sigraph 2023的索尼创作者大会上,介绍了往日不再(Days Gone)中计算屏幕空间接触阴影的方式,这里可以找到演示文稿和参考代码。 本篇文章相当于是Radial Dispatch系列的第三篇文章了,与上一篇文章一样,这篇文章是基于径向分派Compute Shader中相关算法的实际应用,具体的缓存方式也可以参考上一篇文章使用Group Shared Memory加速径向模糊,这里就不再赘述了。实际上我发现了这样计算接触阴影的一个缺陷,就是不太好计算软阴影了,由于缓存的限制,随机采样只能在一个很小的范围内分布,基本上用不上了。由于使用的是屏幕空间的深度图的信息,加上厚度检测之后很容易出现漏面的问题,封面中的瑕疵也有一部分是来自于我的Relaxed Cone Step Mapping本身深度值的瑕疵,屏幕上半部分的阴影就好很多。这就当作是一个Proof of Concept吧,之后有机会的话再回来优化优化。 本文使用的是Unity 2022.3.21f1,URP版本是14.0.10。 具体的代码 ContactShadowComputeShader.compute 核心的代码来自于前一篇文章径向分派Compute Shader。前一篇文章在循环中是通过统一步长进行采样的,会采样到四个像素中间因此需要双线性插值,这次我们固定水平或者竖直方向的步长为一个像素,这样我们只需要在一个方向上进行线性插值了。由于深度和颜色信息是两种不同的信息,我们仅对距离很近的深度进行线性插值,对于距离较远的两个深度值,我们使用离采样点最近像素的深度值。至于如何判断深度远近,我使用了和屏幕空间反射中相同的_ThicknessParams,默认物体的厚度为linearSampleDepth * _Thickness.y + _Thickness.x。 #pragma kernel ContactShadowPoint #pragma kernel ClearMain // #pragma warning(disable: 3556) #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #define THREAD_COUNT 128 Texture2D<float4> _ColorTex; Texture2D<float> _CameraDepthTexture; RWTexture2D<float4> _RW_TargetTex; float3 _LightPosWS; float4 _LightPosCS; float2 _LightPosSS; float2 _ThicknessParams; float4 _TextureSize; float _LightRange; float _Debug; struct DispatchParams { int2 offset; int count; int stride; int xMajor; }; StructuredBuffer<DispatchParams> _DispatchData; int GetDispatchType(int index, out int dispatchIndex, out DispatchParams dispatchParams) { for (int i=0; i<8; ++i) { dispatchParams = _DispatchData[i]; dispatchIndex = dispatchParams....

April 20, 2024 · zznewclear13
zznewclear13 技术美术 图形学 个人博客 technical art computer graphics