Unity中的shadows(一)

  • 平行光阴影
  • 聚光灯阴影
  • 点光源阴影
  • 阴影设置参数
  • Shadow Acne
  • Reference

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_CUBE2 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_CUBE13 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系列的第一篇文章,如果你觉得我的文章有帮助,欢迎关注我的微信公众号(大龄社畜的游戏开发之路-

Unity中的shadows(一)相关推荐

  1. Unity中的shadows(三)receive shadows

    Unity中的shadows(三)receive shadows SHADOW_COORDS TRANSFER_SHADOW 平行光的SHADOW_ATTENUATION 聚光灯的SHADOW_ATT ...

  2. Unity中的shadows(四)collect shadows

    Unity中的shadows(四)collect shadows 阴影收集 vertex shader frag_hard frag_pcfSoft Reference 本文是Unity中的shado ...

  3. Unity中的shadows(二)cast shadows

    Unity中的shadows(二)cast shadows 投射阴影(平行光,聚光灯) UnityApplyLinearShadowBias UnityClipSpaceShadowCasterPos ...

  4. unity怎么显示骨骼_骨骼动画的原理及在Unity中的使用

    制作骨骼动画 我们看看这几步操作后,我们得到了那些数据: 1.每个皮肤顶点的初始世界坐标. 2.每个骨骼关节顶点的初始世界坐标. 3.每个顶点被骨骼顶点的影响信息. 4.骨骼如何移动. 骨骼动画原理 ...

  5. 【Unity】Planar Shadows平面阴影的实现

    Plannar Shadows,即平面阴影,是一个适用于平坦地形的假阴影技术.要求阴影的Receiver为平面,Occluder不与其他物体穿插. 实现效果 1.定向光源Planar Shadows ...

  6. Unity中的混合光照

    Unity中的混合光照 Baked Indirect Shadowmask Distance Shadowmask Subtractive Reference Unity支持三种混合光照模式,分别是B ...

  7. 详解Unity中的粒子系统Particle System (四)

    前言 上一篇我们主要讲解了Shape形状模块,以及Emission发射模块,这是粒子系统中最为重要的两个模块,学会了它们我们足以做出惊艳的效果,比如霰弹枪的发射,蘑菇蛋的冲击波等等.本篇讲的内容依旧重 ...

  8. 在Unity中使用ComputeShader

    目前Unity中有两种并行运算的方式 1)C# Job System,在CPU上以多线程的方式并行运算,通常用来处理逻辑相关内容 2)Compute Shader,从DirectX11.OpenGL4 ...

  9. 【Unity Shader】Unity中阴影映射标准制作流程

    前半部分的基于图片的实时阴影技术是百人计划的前半部分总结,后面的Unity中的实现过程是<入门精要>中的实现. 1 基于图片的实时阴影技术 这里的"基于图片"指阴影生成 ...

最新文章

  1. WCF 4.0 REST Service JSON跨域调用
  2. LDD3源码分析之访问控制
  3. EasyUI DateTimeBox设置默认时间的注意点
  4. activiti 工作流_springboot+activiti+angular 集成activiti工作流实现,源码分享
  5. spark-submit
  6. mysql数据库char类型长度_mysql数据库设计字符类型及长度
  7. 7 centos 时钟跟物理机同步_centos7上使用chrony自动同步时间
  8. golang 指针总结(与C/C++区别不大,就是不可以p+1偏移)
  9. iPhone 14或让果粉再度“梦碎”:屏幕指纹和120Hz高刷屏都没了
  10. 逻辑表达式是否合法_Linux shell 逻辑运算符、逻辑表达式详解
  11. CnCiswumWN
  12. linux执行hadoop程序,gcc编译和运行hadoop c api程序
  13. SI24R1兼容NRF24L01P DEMO板使用说明书
  14. Android Studio控件属性大全
  15. 花卉拍摄技巧 8 — 荷莲
  16. 并行计算与集群技术(2)
  17. 程序员是什么又代表这多少角色?你想过吗?
  18. 简述什么是T-SQL
  19. 关于Openlayers Overlay事件监听的一个坑
  20. python 快乐数判断_Python小课堂 习题答案和讲解

热门文章

  1. 安卓逆向分析中常用动态调试方法总结
  2. Bugku-杂项-合集
  3. Chapter 09:人脸识别与车牌检测
  4. 基于AIOT技术的智慧教室智能物联管控系统设计与实现(提纲)
  5. 食品包装到底应该怎么应用二维码?
  6. 白话Layer2.Finance:DeFi这座城的公共地铁
  7. 【一天一门编程语言】Haskell 语言程序设计极简教程
  8. 今天,我决定第18次卸载今日头条...
  9. SQL Sever数据库损坏修复
  10. windows中的guest与everyone用户的作用