Shadow

屏幕空间的阴影实现步骤:

1、首先得到从当前摄像机处观察到的深度纹理。在延迟渲染里这张深度图本来就有,如果是前向渲染的话就需要把场景整个渲染一遍,把深度渲染到深度图中。

2、然后再从光源出发得到从该光源处观察到的深度纹理,也被称为这个光源的ShadowMap。

3、然后在屏幕空间做一次阴影收集计算(Shadows Collector),这次计算会得到一张屏幕空间阴影纹理,也就是说这张图里面需要有阴影的部分已经显示在图上了。这个过程概括来说就是把每一个像素根据它在摄像机深度纹理中的深度值得到世界空间坐标,再把它的坐标从世界空间转换到光源空间中,和光源的ShadowMap里面的深度值对比,如果大于ShadowMap中的深度距离,那么就说明光源无法照到,在阴影内。

4、最后,在正常渲染物体为它计算阴影的时候,只需要按照当前处理的fragment在屏幕空间中的位置对步骤3得到的屏幕空间阴影图采样就可以了。

 

在渲染阴影的时候,会渲染一张相机空间的深度图,然后每个光源会在该光源空间视图渲染4张深度图,纹理贴图被分成四个象限,每个象限从不同的角度进行渲染。这是因为我们选择使用四个级联阴影。 如果你要切换到两个级联阴影,场景将对每个光源渲染整个场景两次。如果没有级联阴影的话,它只是对每个光源渲染整个场景一次。

 

级联阴影可以在Project Setting下的Quality(质量)里面设置Shadow Cascades

 

Unity使用Hidden /Internal-ScreenSpaceShadows这个着色器进行这个pass的渲染。从场景相机和光源的深度纹理贴图中进行每个片段的采样、进行比较、并将最终的阴影值渲染为屏幕空间的阴影贴图。被照亮的纹理像素设置为1,阴影贴图的纹理像素设置为0。此时,Unity还可以执行过滤,来创建那些柔和的阴影。

完成阴影的渲染。然后渲染场景,光源的颜色会乘以存储在阴影贴图中的值,当这个光源应该被遮挡的时候,这会消除这个光源的影响。

每个被渲染的片段都会对阴影贴图进行采样。

 

 

阴影瑕疵

使用低质量的硬阴影的时候,会看到一些阴影出现在它们不应该出现的地方,不管质量设置如何,这种情况都可能发生。

shadowMap中的每个纹理像素表示的是光线射到表面的点。然而,纹理像素不是单一的点。阴影贴图中的纹理像素最终会覆盖更大的区域。它们与光的方向对齐,而不是与表面对齐,这样可能光会在物体边缘透过,在阴影里看到亮光的瑕疵。

 

 

 

添加光照模型为"ShaowCaster"的Pass可以投射阴影。在顶点着色器中把顶点转换到裁剪空间即可。

 

 

阴影偏移

 

阴影偏移分两种

1:Bias偏移

2:法线偏移

两种方式Unity的实现都是往摄像机方向靠近一点点

 

unity_LightShadowBias.xyz

x分量代表了Bias偏移相关的值。

y分量代表了进行Bias偏移时,差值用的t值,一般为1。

z分量(slope depth bias scale)代表了法线缩放的值,并且判断z为0的话不进行法线偏移。

 

阴影坐标法线偏移

 

阴影坐标Bias偏移

 

 

质量设置中启用了抗锯齿,会发现它们不能与标准的抗锯齿技术混合在一起使用。

多重采样抗锯齿技术通过沿着三角形边缘执行一些超采样来去除三角形边缘的混叠。 细节纹理贴图对多重采样抗锯齿技术没有什么影响。重要的是,当Unity渲染屏幕空间的阴影贴图时候,它会使用覆盖整个视图的单个四边形。 因此,在屏幕空间的阴影贴图中根本就没有三角形边缘,因此多重采样抗锯齿技术不会影响屏幕空间阴影贴图。多重采样抗锯齿技术只对最终图像起作用,但是阴影值是从屏幕空间的阴影贴图中直接获取的。当靠近较暗表面的一个比较亮的表面被遮蔽的时候,这就会变得非常明显。明暗几何之间的边缘是反锯齿的,但是阴影边缘不是。

 

 

半透明阴影

Pass{

Name "ShadowCaster"

Tags{ "LightMode" = "ShadowCaster" }

ZWrite On

ZTest LEqual

CGPROGRAM

#pragma target 3.0

#pragma vertex vert

#pragma fragment frag

#pragma multi_compile_shadowcaster

#define UNITY_STANDARD_USE_SHADOW_OUTPUT_STRUCT

#define UNITY_STANDARD_USE_DITHER_MASK

#define UNITY_STANDARD_USE_SHADOW_UVS

#include "UnityStandardShadow.cginc"

fixed _AlphaScale;

struct VertexOutput

{

V2F_SHADOW_CASTER_NOPOS

float2 tex : TEXCOORD1;

};

void vert(VertexInput v, out VertexOutput o, out float4 opos : SV_POSITION)

{

TRANSFER_SHADOW_CASTER_NOPOS(o,opos)

o.tex = v.uv0;

}

half4 frag(VertexOutput i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target

{

half alpha = tex2D(_MainTex, i.tex).a * _AlphaScale;

half alphaRef = tex3D(_DitherMaskLOD, float3(vpos.xy*0.25,alpha*0.9375)).a;

clip(alphaRef - 0.01);

SHADOW_CASTER_FRAGMENT(i)

}

ENDCG

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值