欢迎光临散文网 会员登陆 & 注册

浅谈游戏中3种常用阴影渲染技术

2021-04-30 12:20 作者:独立游戏人-老雷  | 我要投稿

版权声明

  • 本文为“优梦创客”原创文章,您可以自由转载,但必须加入完整的版权声明

  • 更多学习资源请加QQ:1517069595,获取(企业级性能优化/热更新/Shader特效/服务器/商业项目实战/每周直播/一对一指导)

前言

众所周知,在游戏当中,阴影是无处不在的,如果一款游戏没有阴影,那么不光画质会大大折扣,游戏性也会大大降低,因此,我将通过这篇文章给大家谈一谈关于三种阴影渲染方式相关的知识,由于篇幅所限,我将着重讲解一种基础的渲染方式即平面阴影的实现。

一、平面阴影

  • 平面阴影虽然是一种相对简单的渲染方式,但是在我们的平面游戏中是一种非常普遍的阴影渲染方式,比如王者荣耀中就采用了这种阴影渲染方式,如下图,右侧代码实际上就是王者荣耀平面阴影的一个代码实现

1.1 实现步骤

  • 对一个角色模型进行了两次绘制(两个Pass):

    • 一次是利用模型数据绘制了游戏物体本身

    • 第二次是利用模型数据绘制角色阴影,我称这种绘制方法为两遍绘制。

  • 第一个Pass在我之前的视频中有介绍过,今天就不着重讲解了,这篇文章主要讲解第二个Pass的绘制

  • 首先要给大家介绍一下图形着色器,图形着色器由两个部分组成:

    • 我们可以将一个基础模型看做是一个三角形,这个三角形由三个点构成,如何去控制这个三角形在场景中的位置呢?这时,就需要用到我们的顶点渲染程序来确定三角形的绘制位置。下面是一段顶点渲染程序。

    • 第一部分为顶点渲染,确定顶点位置

第二部分为像素着色:

  • 当我们确定了三角形在场景中的位置之后,他的内部需要填充一个什么样的颜色呢?像素着色程序就是对三角形内部填充颜色的一个设置。下面是一段像素着色程序。

回到我们的游戏阴影绘制来说,我们究竟要在顶点程序和像素程序里面做什么呢?

  1. 首先,我们在顶点程序里面需要干两件事情,第一件事情,就是把所有的顶点变换到世界空间,同时在地面上产生一个垂直的投影,第二件事,我要计算我的光线,根据光线的投射方将对地面的投影做一个平移。

  2. 其次,当我们的模型投影好之后,就要对阴影进行一个着色,通过rgb和透明度的设置,也就是半透明混合,来达到本身的颜色和阴影的颜色进行混合,最后得到一个“五彩斑斓的黑“的阴影效果。

  3. 当你掌握了第二个pass的绘制,基本就达到了shader绘制入门的水平,但是在一个商业项目中,这样的一个阴影效果是不够完善的,如果单纯的利用这种方法渲染阴影,会产生很多问题。我会例举其中的几个问题,并提供我的解决方案。

1.2 平面阴影渲染所存在的问题

  1. 阴影重叠

    • 阴影是半透明的,在渲染前,我们会开启阴影渲染的透明混合状态,模型的正面和背面的三角形可能重复渲染,造成不透明度的叠加,这种的叠加是非常杂乱无章的。如图所示,阴影非常地杂乱。

    • 什么是阴影重叠?:

  • 造成阴影重叠的原因:

    • 其实主要原因是我们Unity中默认的叠加方法是加法叠加,使得一个阴影被渲染了多次

  • 解决方法:

    • 我们为了解决阴影重叠的问题,应当保证每个阴影区域只被渲染一次,如何做到每个阴影只渲染一次呢?这里我要为大家介绍一种名为模板缓冲区的东西,什么是模板缓冲区呢?模板缓冲区实质上就是一个和我们屏幕大小一样的二维数组,他的原理如图所示。


    • 模板缓冲区对阴影进行渲染时,我们会在每一帧渲染时,将像素点的值设置为零,我们用零与特定的参考数值进行比较,当他满足比较条件即通过我们的模板测试时,对于通过测试的像素点,我们将他的模板值替换为参考值,当下一次在相同的位置进行渲染时,就无法通过模板测试,我们就舍弃了该片元,从而保证一个像素点只被渲染一次。

2.其他问题

  • 除了阴影重叠的问题之外,还存在着两个问题:

    1. 由于平面阴影所在的高度与地面相同,由于浮点精度问题,会造成“深度抖动问题”

        2.由于阴影是物体本体压扁形成的,所以,在地面边界处,物体的阴影可能超出边界


  • 优势:

    • 不需要打灯

    • 渲染速度快

  • 劣势

    • 只适用于平面表面

    • 高低起伏的地面上会出现阴影穿插,当出现地面起伏时,阴影会被凸起的地面遮挡


二、阴影锥

  • 原理:

    • 阴影锥采用了一种叫做模板缓冲区的方式,如下图,存在一个三角形,当光源照射三角形,它会产生阴影,我们对这个三角形进行一个拉伸,正面会拉长出来一个紫色区域和一个蓝色区域,这两个区域称之为正面区域,背面会产生一个褐色区域,当这三个区域拉长出来之后,就会形成一个三棱锥,也就是阴影锥。


  • 实现方法:

    • 阴影锥的实现公式其实就是(1)+(2)-(3)

三、阴影贴图

3.1阴影贴图的特点

    • 阴影贴图是Unity官方所采纳的一种阴影渲染方式,官方为了集成阴影贴图的方式,已经做了很多的工作,我们作为开发者只需要在场景中设置好灯光,并且设置游戏中的gameobject是否能够产生阴影就能够完成

    • 需要一个额外的ShadowCaster通道

    • 便于实现软阴影

3.2阴影贴图的实现

  1. 第一步:在灯光的位置生成一张深度图,将场景中的深度值渲染到深度图里面,如下图,地面的部分和方块被光线照到的地方需要被渲染,那么我们就把他们的深度值渲染到我们的深度图里面。这些场景的信息会被存储到一个额外的pass即ShadowCaster。

ShadowCaster是专门用来取得场景的深度信息的pass,这个Pass的深度信息是从灯光的位置取得的

  1. 第二步:

    • 假如我们要渲染地平面,而地平面是由一个个点组成的,假如我们要渲染点P,如果用我们的肉眼去看,那么很容易就可以看出点P是在阴影中,但是计算机如何知道点P是否应该被渲染呢?

    • 将渲染的深度图,与点P在灯光空间中的深度值做比较,这里涉及到将点P的摄像机空间的深度值转换到灯光空间中。将点P转到灯光空间后,可以理解为点P距离灯光0.9,距离摄像机0.4,因为0.9>0.4,所以点P位于阴影之中,不用渲染。

3.3软阴影

  • ShadowMap也能实现软阴影的效果,软阴影是游戏中重要的阴影效果,一个阴影是由本影和半影组成的,软阴影就是所谓的半影,如右下角的图,阴影的周围伴随着虚化的阴影。

  • 进一步学习的内容:

    • 如果场景中有多个光源,会对同一个物体造成多个阴影,如何实现多光源的实时阴影以及他的性能优化,可以继续关注我们的课程。

    • 如图左边一个飞机停在飞机跑道上,因为跑道贴图和飞机阴影的深度值相同,因此会出现抖动。

    • 深度抖动问题的解决。

    • 多光源实时阴影及其性能优化 。

  • 这篇文章我主要讲解了两个方面的知识,平面阴影的实现和模板缓冲区的使用,另外介绍了阴影锥和阴影贴图的实现原理,并且也介绍了一些商业项目中阴影效果实现可能产生的问题。

点赞、分享加关注可获得教程配套视频 更多学习资源请加QQ:1517069595获取(企业级性能优化/热更新/Shader特效/服务器/商业项目实战/每周直播/一对一指导

作者:优梦创客

出处: bilibili


浅谈游戏中3种常用阴影渲染技术的评论 (共 条)

分享到微博请遵守国家法律