zoukankan      html  css  js  c++  java
  • Unity中的shadows(一)

    Unity中的阴影针对不同的光源类型,平行光,点光源,聚光灯有不同的处理方式,casting和receiving的实现都有些区别。我们根据光源类型的不同详细看一下具体的实现。

    平行光阴影

    如图中所示场景,有两个平行光源,我们打开frame debug查看一下:

    可以看到,对于平行光产生的阴影,Unity使用screen space shadow map来保存阴影信息。

    首先,Unity对整个场景跑了一遍深度pass,记录场景的深度信息:

    Unity在这一阶段定义了SHADOWS_DEPTH关键字,并且把ColorMask设置为0,意思是不会输出任何颜色。另外,只有object的shader中包含ShadowCaster标签,才会跑一遍该pass。ShadowCaster的代码可以很简单:

    	float4 MyShadowVertexProgram (VertexData v) : SV_POSITION {
    		return UnityObjectToClipPos(v.position);
    	}
    
    	half4 MyShadowFragmentProgram () : SV_TARGET {
    		return 0;
    	}
    

    我们并不需要返回深度信息,z的值引擎底层会记录下来。

    screen space的深度图有了之后,Unity会基于每个平行光源渲染一张shadow map,简单来说,就是把平行光源当作一个摄像机,做一次正交投影,将场景中物体的深度信息记录在shadow map上。

    之后,Unity会做一次Collect Shadows阴影收集过程,用之前深度图中每个pixel的深度信息,将其重建回世界坐标系下,然后变换到光源空间,对之前光源空间渲染的shadow map进行采样。shadow map采样出的信息就是被光源照射到最近物体的深度,通过比较两个在光源空间下的深度信息,就可以判断出当前pixel是否在阴影内,如果在阴影内则输出0,能被光源照亮则输出1。每个平行光源都对应一张各自的screen space shadow map。

    聚光灯阴影

    如图中所示场景,有两个聚光灯光源,我们打开frame debug查看一下:

    可以看到,与平行光相比,少了深度pass,还有阴影收集的过程,Unity就只是简单地把光源空间内的物体渲染到shadow map上。

    点光源阴影

    这次场景中有两个点光源,打开frame debug:

    可以看到,点光源渲染阴影所用到的pass数量非常多,一个点光源可能需要6次阴影pass,这是因为点光源的shadow map不是一张贴图,而是一个cube map。Unity为点光源阴影定义了SHADOWS_CUBE关键字。

    另外值得注意的是,ShadowCaster的pass需要添加如下定义:

    			#pragma multi_compile_shadowcaster
    
    

    用Visual Studio可以看到具体的keywords:

    // -----------------------------------------
    // Snippet #2 platforms ffffffff:
    Builtin keywords used: SHADOWS_DEPTH SHADOWS_CUBE
    
    2 keyword variants used in scene:
    
    SHADOWS_DEPTH
    SHADOWS_CUBE
    
    

    如果要为主平行光(base pass)添加阴影,需要添加SHADOWS_SCREEN关键字:

    			#pragma multi_compile _ SHADOWS_SCREEN
    
    

    如果要想为第二个平行光,点光源,或者聚光灯(即add pass)添加阴影,则需要如下定义:

    			#pragma multi_compile_fwdadd_fullshadows
    
    

    用Visual Studio可以看到具体的keywords:

    // -----------------------------------------
    // Snippet #1 platforms ffffffff:
    Builtin keywords used: POINT DIRECTIONAL SPOT POINT_COOKIE DIRECTIONAL_COOKIE SHADOWS_SHADOWMASK LIGHTMAP_SHADOW_MIXING SHADOWS_DEPTH SHADOWS_SOFT SHADOWS_SCREEN SHADOWS_CUBE
    
    13 keyword variants used in scene:
    
    POINT
    DIRECTIONAL
    SPOT
    POINT_COOKIE
    DIRECTIONAL_COOKIE
    SHADOWS_DEPTH SPOT
    SHADOWS_DEPTH SHADOWS_SOFT SPOT
    DIRECTIONAL SHADOWS_SCREEN
    DIRECTIONAL_COOKIE SHADOWS_SCREEN
    POINT SHADOWS_CUBE
    POINT SHADOWS_CUBE SHADOWS_SOFT
    POINT_COOKIE SHADOWS_CUBE
    POINT_COOKIE SHADOWS_CUBE SHADOWS_SOFT
    
    阴影设置参数

    在Unity的project settings中的quality项,有如下的若干有关阴影的设置:

    Shadows有3个选项,一是完全关闭阴影,二是只使用hard shadows,三是hard shadows和soft shadows都使用。使用软阴影的好处是阴影的边缘更加光滑,减少锯齿。根据不同的选项,以平行光源为例,unity会在收集阴影阶段使用不同的subshader绘制screen space shadow map:

    Shadow Distance控制阴影显示的距离,太远的物体往往没有显示阴影的必要,通过控制距离可以降低绘制的draw call:

    可以看出,超过阴影显示距离的物体,在光源绘制shadow map时直接就跳过了。

    Shadow Cascade控制是否开启级联阴影,以及级联的数量和区域划分。级联阴影的好处是可以根据物体距离的远近,生成不同分辨率的shadow map,近的物体对高分辨率的shadow map进行采样,得到更多的阴影的细节,远的物体只用对低分辨率的shadow map采样即可,避免不必要的性能浪费。不同分辨率的shadow map在阴影收集阶段同样会被绘制到一张screen space shadow map上,因此只是在光源空间渲染shadow map时,draw call会根据选择级联的数量翻倍:

    Shadow Projection控制级联阴影的区域生成方式。Close Fit利用摄像机的深度信息来计算区域,而Stable Fit利用到摄像机位置的距离信息来计算区域。在scene窗口下,可以选择Miscellaneous / Shadow Cascades来显示级联阴影区域:

    Stable Fit的区域通常更稳定,不会受摄像机自身的位置和旋转影响:

    Shadow Acne

    由于shadow map的精度问题,shadow map上的一个pixel,实际上是对应了场景上的一片区域。而这片区域中的所有点,在shadow caster阶段,都会去取shadow map同一个pixel的深度值,当这个深度值与区域中的所有点的深度值相近的时候,就会出现一部分点比较深度后,在阴影中,而另一部分点却不在阴影中,导致场景中会出现明显的明暗条纹:

    从数学角度上来看,如图所示:

    EF为shadw map采样的深度,那么CF区域中的点由于深度都小于EF,因此不在阴影中;而DF区域中的点深度大于EF,会被判定在阴影中。

    为了解决这一问题,可以在渲染shadow map的时候人为加上偏移,让阴影位于物体之后。这个偏移就被称作shadow bias。

    常用的shadow bias有两种,depth bias和normal bias。depth bias顾名思义,就是在shadow caster阶段,将物体沿着相机空间的z方向往后偏移:

    可以看到,我们将CD区域沿着相机空间的z方向平移到了GI区域。此时shadow map采样到的深度值为EH,它等于BD。这样,CD区域中所有的点深度都不会大于EH(因为最大的深度也就是BD,而BD等于EH),从而保证了CD区域中的所有点都不会判定在阴影中,也就可以消除shadow acne。这里,depth bias的值就是CG的大小。

    normal bias是在shadow caster阶段,将物体沿着自身的法线方向往后偏移:

    原理与depth bias类似,这里normal bias的值就是CG的大小。

    shadow bias的参数可以在光源的属性中进行调整:

    Reference

    [1] Shadows

    [2] 自适应Shadow Bias算法

    本文是Unity中的shadows系列的第一篇文章,如果你觉得我的文章有帮助,欢迎关注我的微信公众号(大龄社畜的游戏开发之路-

  • 相关阅读:
    HTML常用元素标签
    属性列表-边框属性
    (5)opencv的基础操作和矩阵的掩模操作
    (4)关于Alpha通道问题
    (3)关于命名空间的问题
    (2)关于opencv解压
    (1)opencv的安装和遇到的问题
    给adobe acrobat reader 添加图片注释
    安装adobe reader阅读器
    apache安装和mysql php配置问题
  • 原文地址:https://www.cnblogs.com/back-to-the-past/p/15115243.html
Copyright © 2011-2022 走看看