【Unity——阴影实现基本原理】

前言

本文是对Unity中阴影实现原理的简单介绍,不涉及Shader实现细节。

文章目录

一.阴影的实现原理
1.1 简单的解释
1.2 实现原理
二.Unity中的阴影
2.1 阴影映射纹理,深度纹理,阴影纹理简介
2.2 阴影的投射与接收

一.实现原理

1.1简单的解释

假设下面这一张图是当前摄像机中呈现出的内容,不包含任何阴影。
图1

阴影映射的原理是:采样上图中像素,获取像素在世界空间中的位置(对应了世界空间中的一个点),判断这个点是否能被光源“看见”。

如果这个点与光源连线中间没有被其它物体遮挡,则这个点在光中。
如果被遮挡,则这个点在阴影中。需要为这个点(像素)打上阴影。
对上图中像素遍历后打上阴影后的结果如下图。
在这里插入图片描述

1.2实现原理

关于“点与光源连线之间是否有物体遮挡”,我们通过类似深度缓冲的技术来实现。
我们在灯光位置设置一个假想的摄像机,并渲染从光线中看到的场景深度,
并将这些结果保存下来,得到阴影映射纹理(shadowmap)
光源的位置,通过假想摄像机得到的阴影映射纹理(shadowmap)见下图
在这里插入图片描述
阴影映射纹理(shadowmap)的每个像素都可以在世界空间中重新映射,并会告诉你光看到的像素以及该点与光源本身的距离。在上图中,如果我们采样阴影映射纹理(shadowmap)中P3/P2这一像素,我们实际可以获得的是世界空间中点P3到光源的距离。

让我们梳理一下整个过程:
对于上图中P1这个摄像机视角中的一个像素,我们采样这个像素获取其在世界空间中的位置(可以视为一个点),然后将这个点映射到阴影映射纹理(shadowmap)中,得到其在阴影映射纹理(shadowmap)中应对应的像素P1,然后采样阴影映射纹理(shadowmap)中P1这个点,获取光看到的像素以及该点与光源本身的距离。两者相等,点P1不在阴影中。
对于摄像机视角里的像素P2,,在映射到阴影映射纹理(shadowmap)后得到像素P3/P2,然后采样阴影映射纹理(shadowmap)中P3/P2这个像素获取到的值是世界坐标下P3到光源的距离,与世界坐标系下P2到光源的距离不相等。P2在阴影中。

二.Unity中的阴影

2.1阴影映射纹理,深度纹理,阴影纹理简介

在《Unity Shader入门精要》第九章有关阴影的内容中,作者提到了以下三个纹理
1.光源的阴影映射纹理
2.屏幕空间的深度纹理
3.屏幕空间的阴影纹理
用图片直观的认识这三张纹理有利于后续的理解
首先,以下是书中实验场景与最终渲染效果
在这里插入图片描述

1.光源的阴影映射纹理,也就是刚才说的shadowmap
在这里插入图片描述
2.屏幕空间的深度纹理
在延迟渲染里这张深度图(纹理)本来就有,如果是前向渲染的话就需要把场景整个渲染一遍,把深度渲染到深度图(纹理)中。
在这里插入图片描述
3.屏幕空间的阴影纹理
左图为阴影纹理,右图为最终渲染效果
作者在github对这张纹理做出了解释:获取这张纹理的主要思路就是从摄像机的深度纹理里采样得到该fragment的深度值,然后利用矩阵变换计算得到该点对应的世界空间的世界坐标(利用CameraToWorld矩阵),然后再变换到光源空间下的坐标(利用WorldToShadow矩阵),最后拿这个坐标对光源的ShadowMap采样计算阴影。最终将所有结果存储到一张阴影纹理中。
计算获取阴影纹理的总体思路和第一节中所述是一致的,不同之处在于,在进行比较时不是使用世界空间下点到光源的距离,而是使用了光源空间下点到光源的距离

在这里插入图片描述

2.2阴影的投射与接收

显而易见,阴影的产生需要光源,阴影投射体,与接收阴影的物体。
在本节例子中,立方体既向地面投射了阴影,又接收了来自立面的阴影。
在Unity中我们可以通过相关选项来控制物体的投射/接收阴影。如下图在这里插入图片描述
作者在书中P198对投射阴影/接收阴影做出的解释大意为:如果物体开启了投射阴影属性,Unity就会把物体加入到光源的阴影映射纹理的计算中。其它物体在对阴影映射纹理进行采样时就会收到该物体的影响。
以第一节的图片举例:如果P3所在球体未开启投射阴影属性,那么右侧的阴影映射纹理中红框所示阴影圆块将不存在,阴影映射纹理中P3/P2存储的信息将是P2到光源的距离。P2在渲染时被映射到阴影映射纹理后采样阴影映射纹理得到的不再是P3到光源的距离,而是P2到光源的距离。二者相等,P2将被判断为不在阴影中。屏幕空间的阴影纹理中点P2处将不再有阴影。在这里插入图片描述
下图演示了在帧调试器中,打开/关闭立方体的投射阴影选项对屏幕空间的阴影纹理的影响。
开启:在这里插入图片描述
关闭:
在这里插入图片描述
关闭立方体的阴影投射最终渲染结果:
在这里插入图片描述
对于阴影的接收,无论物体是否开启,都不会影响屏幕空间阴影纹理的计算结果。在此不再举例。

参考文章1:Unity阴影和深度纹理的补充说明(重要)
参考文章2:延迟渲染阴影映射

猜你喜欢

转载自blog.csdn.net/m0_62316271/article/details/128515034