代码编织梦想

本期为GAMES104《现代游戏引擎:从入门到实践》视频公开课文字实录第15期。本课程由GAMES(图形学与混合现实研讨会)发起,游戏引擎技术专家王希携手游戏引擎一线开发者共同研发。

课程共计22个课时,将介绍现代游戏引擎所涉及的系统架构,技术点,引擎系统相关的知识。为配合学习实践,课程组在 GitHub 上开源了小引擎Piccolo,上线1个月即获得了2900+star, 累计下载量已超过20000+。

以下内容为公开课视频转文字版本,为阅读通顺,有删减

01「基础光照解决方案」

让我们从简单的渲染流程开始入手,暂时不考虑一些抽象的概念,比如辐射度、微面元、BRDF、球谐函数、积分、信号处理等。因为光场非常复杂,所以我们先对世界进行简化。

首先,定义一个主光源(Dominant Light),主光源可以是方向光、点光源、聚光灯。在一个物体的表面上,会存在很多光场,我们无法详细得知这些光场的信息。然而,我们可以定义一个环境光(Ambient Light)。即移除主光源之后,环境施加在物体上的光。我们可以使用一个平均值来代替环境光,然后我们就得到了环境光的简化表示。对于四面八方的环境光,我们使用一个数值就可以代替。

其次,我们需要实现一些特殊的效果。想象一下,环境中有些物体的表面会非常光滑,因此会反射环境中的其他物体,其实这个时候它不是主光,而是环境的一条光正好跟你的那个入射光的方向和法线和那个反射光的方向正好和法线的重合了。

人们研发了一种技术来表示这类效果,这就是环境贴图。环境贴图由六张图片拼接而成,类似于将一个立方体的六个面展开之后所形成的图像。根据观察者所在的位置,以及表面的法线方向,进行反射,找到立方体所在位置的图像。这样就可以表达光场在物体表面所形成的强烈反射效果。通过这样简单的组合,我们就基本上实现了渲染方程。我们将半球形的光场分布,模拟成一个均匀的环境光,来表示Irradiance的低频信息,再加上一个突出的主光源,然后通过环境贴图来表达Irradiance中的一些高频信息,这样就可以表示BRDF中的Specular项。回忆一下,在学习微积分时,如果给定一个通用函数,通过积分对其求解,这时,是很难得到这个函数的解析解的。然而,如果我们对方程的参数进行特例化,就很容易得到方程的解析解。这里的思路也类似。

受限于算法和硬件的限制,图形工程师们在早期无法直接求解渲染方程。因此,他们另辟蹊径,使用了上述方法来解决光照问题。

接下来,就是对材质的处理。整个材质模型的发展一直伴随着BRDF模型的发展,各种理论层出不穷,最前沿的理论已经开始研究利用光的波动理论来处理材质,包括光的干涉、衍射等。在材质模型的各种理论流派中,有一派被称为“经验派”。即不研究物理世界的本质,而是根据自己的观察对材质进行处理,拟合出一个经验模型,然后将经验模型和真实模型的效果进行对比,并对参数进行调整。

经验派的具体做法如下:首先,为材质设定一个漫反射项,以模拟四面八方入射的光线所产生的效果,这一项从每个角度观察的数值都一样。然后,为材质设定一个高光项,对应于光滑物体表面的反射效果。大家通过观察可以发现,对于光滑表面来说,反射的波瓣(Lobe)会很尖锐,而有些表面的反射波瓣的变化会相对缓慢。在数学上,幂函数可以用来模拟这种尖锐的变化,函数的幂次越高,函数的变化就越陡峭。

这里我们介绍著名的“Blinn-Phong模型”。Blinn-Phong模型非常简单,分为三项,分别是环境光项(Ambient)、漫反射项(Diffuse)和高光项(Specular)如下图所示:

漫反射(Diffuse)项的计算是使用入射角的余弦项乘以入射光,再乘以一个反弹率,因为有些能量会在这个过程中被吸收。高光(Specular)项则用来模拟一些特别亮的效果,即看上去很像金属,很像光滑表面感觉的效果。将漫反射项和高光项相加(还有Ambient项,不过一般只是Diffuse项的一个百分比乘积),就得到了Blinn-Phong材质模型。

Blinn-Phong材质模型虽然简单,也很粗暴,但是直到今天我仍然觉得非常亲切。希望同学们有机会可以实现一下Blinn-Phong模型。在Blinn-Phong模型中,体现了一个朴素的光学原理,即光线是可以叠加的。在渲染方程中,也应用了这个原理,这就是为什么可以将方程中的所有出射光积分(相加)起来的原因。这是光学的一个基本假设,不管这些光线来自于何方,来自于哪个光源,它们都可以被线性叠加到一起。

Blinn-Phong模型虽然简单易用,但存在两个比较大的问题。第一个问题是能量不保守的问题。对于游戏渲染来说,这个问题影响不是很大。然而,如果我们使用Blinn-Phong模型进行离线渲染,就会出现问题。即在设置好Specular、Diffuse和Power等参数之后,最终计算出来的出射能量会大于入射能量。想象一下,我们我们真正实现了一个光线追踪算法,当进行多次反弹追踪时,这个震荡会被放大,如下图所示:

图中的球体内部本来存在一个黑腔。然而,当我们使用Blinn-Phong模型进行光线追踪时,如果有光漏到黑腔中,在经过多次反弹之后,就会出现图中左图的效果,黑腔会变亮。这个效果是错误的。因此,我们有一个说法叫做“Energy Conservation”。大家通常翻译成“能量守恒”,我个人认为这一翻译并不十分准确,称为“能量保守”会更合适(编者注:即反射光的能量只会小于或等于入射光的能量,而不会变大——引用自《Physically Based Rendering(3rd)》第350页关于“Energy Conservation”的解释)

因为这一过程中的能量并不会一直保持不变,在光射到物体的表面时,一定会有部分能量被表面吸收,因此能量会发生损失,在不断弹射的过程中,光线的能量会不断损失。因此,我们需要确保出射能量小于等于入射能量。当不存在能量保守的限制时,在光线追踪环境下就会出现问题。

第二个问题对于艺术家们十分不友好。虽然Blinn-Phong模型非常简单,但这个模型和真实世界中的物体的关联并不大。当艺术家们想要表达复杂材质时,就会发现,Blinn-Phong模型无法表达一些细节效果。比如上图中的左图,看起来就很有塑料质感。这就是Blinn-Phong模型的特点——无论怎么调整参数,物体看起来都会具有塑料感。木头、石头的效果像塑料,金属效果也像塑料。但是现代材质(比如我们后面会提到的PBR材质)就能够将金属效果表达的非常到位。在现代游戏中,我们基本上已经看不到使用Blinn-Phong模型的材质。但这并不影响Blinn-Phong模型在渲染领域所产生的重大影响和地位。

最后,就是对光源的可见性问题。阴影问题实际上很简单,所需要解决的问题就是从人眼所看到的场景中的每个点,对于光源是不是可见的。当然,这是在光源要么是方向光、要么是点光源或者聚光灯的情况下才成立的。如果光源更复杂,则需要进行一个百分比的计算。大约在二三十年前,大家就提出了很多的阴影算法。我印象特别深的方法叫做“Shadow Volume”方法。大家如果去回顾一些早期的游戏,比如《毁灭战士3》,那个时代用的阴影方法就是“Shadow Volume”,因为那时候硬件不支持阴影贴图(Shadow Map)。包括“Perspective Shadow”等方法。如果大家去搜索图形学行业内的相关论文,就会发现,大约15年前到20年前的那些论文,人们提出了很多种方法来处理阴影。然而,对于游戏引擎行业来说,阴影贴图是一切阴影算法的基础。

阴影贴图方法的思想非常简单。因为我们需要知道的是某个点到光源的可见性。首先,我们从光源的视角渲染一次场景,渲染过程中并不需要进行着色,只需要计算出每个点的深度信息即可。这个深度就表示了每个点到光源的距离。然后从真正的相机位置渲染场景,并将每个点反向投影到光源视角的场景中,以得到该点在阴影贴图中的深度。将该点的深度与从阴影贴图中对应位置采样得到的深度值相比较,如果该点的深度更大,则说明该点位于阴影中。否则,该点就不在阴影中。该方法十分简单,具体的算法细节,大家可以参考GAMES101和GAMES202课程。我们只介绍阴影贴图的基本思想。

阴影贴图也有一些问题需要解决。第一个问题就是从光源处渲染场景和从相机处渲染场景的采样率不同。大家如果学习过信号和系统就会知道,当两者的采样率不一致时,阴影就会产生各种各样的失真(Artifact)这就是阴影贴图中的自遮挡问题,特别是对于很精细的结构来说,如果阴影贴图的精度不够,或者采样率不够,亦或深度的精度不够,就会产生很多失真。对于游戏行业来说,简单的办法是添加一个偏移(Bias),将容差变得更大。这样可以解决大部分问题,然而,这有时候又会产生人脚浮空的问题(编者注:即所谓的“Pater-Panning”效应)。大家如果体验一些早期的做的不是特别好的游戏,就会发现,人的阴影与脚总会相隔一定距离,比如5公分或10公分,这是很常见的一种情况。

直到今天,当我们使用阴影贴图技术时,如果光源特别靠近地平线,这种情况下的阴影仍然很难处理,因为阴影会拉得非常长。然而在实际游戏设计中,艺术家们很多时候都更喜欢这种“落日余晖”的效果。血红的夕阳下,天空中出现了五彩的云,建筑拖下了长长的影子,主角的剪影出现在场景中。而对于图形学工程师来说,这种效果实现却起来十分麻烦。最近有一款游戏,为了实现类似的效果,使用了两套阴影算法。当太阳比较接近天顶的时候,使用了一套算法;当太阳开始逐渐接近地平线,比如清晨和傍晚时,就逐渐过渡到另外一套算法。这样才能解决这个问题。因此,阴影是让图形工程师最头痛的一个问题。

通过上文中介绍的简单的方案,我们使用一个简单的光源,加上环境光,再使用环境贴图实现反射。就解决了渲染方程中关于光的部分。然后使用Blinn-Phong模型处理材质,将渲染方程中的积分部分变成了一个多项式时间就可以计算出来的问题。

这样就能够计算出完整的光照。最后,使用阴影贴图来处理阴影。这样,我们就基本解决了前文中提出的三个挑战。这一系列简单的方案,配合上优秀的艺术家所输出的美术作品,就能够实现很不错的画面效果。直到今天,在有些特殊场合,仍然会使用上述方案。比如当游戏运行时的硬件配置特别低的时候,就可以全部切换到这一方案。移动端也可以使用这种方案。虽然上述方案稍显过时,但仍然建议大家掌握上述方案,然后再学习最新的高端技术。

本文编辑:Piccolo 社区编委会 彭渊

如对本节课有任何问题,欢迎加入我们的社群或给我们发送邮件:

piccolo-gameengine@boomingtech.com

关于我们

Piccolo游戏引擎社区

Piccolo社区是中国开源游戏引擎社区,由游戏引擎行业大佬、共创官、学习者共同建立。你可以在我们的社区里交流技术、互助问答、参加活动,你也可以参与Piccolo 的共建,如撰写贡献代码、撰写技术文章、参与技术挑战等。

Piccolo游戏引擎

由中国游戏引擎社区Piccolo开源的一款Mini游戏引擎。采用世界-关卡-游戏对象-组件的简洁架构,便于理解游戏引擎架构思想,它不仅能有效的帮助开发者学习游戏引擎架构知识,也能帮助一线开发者实验引擎算法与第三方库、辅助个人项目快速启动。截止目前,Github点赞已突破3600+,累计下载量已超过20000+

Piccolo GitHub地址:https://github.com/BoomingTech/Piccolo/discussions

关注公众号GAMES104,回复【入群】,加入Piccolo社群

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_74737520/article/details/129836352

GAMES101-现代计算机图形学入门-闫令琪 - lecture15 光线追踪3 - 辐射度量学、渲染方程(Ray Tracing 3) - 课后笔记-爱代码爱编程

光线追踪3 - 辐射度量学、渲染方程和全局光照 内容: 辐射度量学光线传输(Light transport) 反射方程(The reflection equation)渲染方程(The rendering equation)全局光照(Global illumination)辐射度量学 Radiant energy:辐射能量,单位位焦耳J,在图形

Failed to install app-debug.apk: Failure [INSTALL_FAILED_TEST_ONLY: installPackageLI]-爱代码爱编程

使用adb 安装android studio生成的app-debug.apk包时抱以下错误 adb install D:\app\android\project\DVR\app\build\outputs\apk\debug\app-debug.apk Failed to install D:\app\android\project\DVR\app\bu

视频+课件|3D视觉从入门到精通系统学习教程-爱代码爱编程

前言 很多粉丝在公众号后台留言,不知如何入门3D视觉、3D领域的主线是什么,一些难点该如何解决,有哪些方法,导师新开的3D视觉方向无人指导等等。这些痛点,工坊的许多童鞋都踩过坑,也为大家提出了许多非常有价值的问题和解决思路,涵盖了计算机视觉与深度学习、点云处理、SLAM、三维重建、结构光、双目视觉、深度估计、3D检测、自动驾驶、多传感器融合等多个方

启蒙之路 | 跨平台渲染引擎之路:拨云见日-爱代码爱编程

本文已获得作者授权,原文作者:格子林ll 原文链接:https://zhuanlan.zhihu.com/p/58817407 前言 最近在工作中越来越多地接触到一些3D以及相比常见特性更酷炫的效果,因此萌发了想要自己从0开始打造一个渲染引擎的念头,一方面是为了更好地实现公司业务的需求,另一方面则是可以学到整个渲染流水线上的方方

games104-渲染中光和材质的数学魔法-爱代码爱编程

绘制的核心是什么? 光:光子、反射反弹 材质:光和物质怎么反应 渲染:Shader 如何去做一些复杂的计算 渲染宗师,James Kajiya 1986年,提出了渲染方程 BRDF 双向反射方程 观察角度:模拟人眼 观察点

《games104-爱代码爱编程

目录 渲染计算的三大组成部分 渲染方程及挑战 渲染方程式 挑战一 挑战二 挑战三 总结一下三个挑战 简易光照解决方案 光源的简化 材质的简化 阴影的简化 基于预计算的全局光照 如何表现全局光照 卷积定理(Convolution Theorem) 球谐函数(Spherical Harmonics) Lightmap Ligh

【games104】 渲染中光和材质的数学魔法_ggx现象-爱代码爱编程

一、渲染方程 在games101课程中我们了解到,所有的渲染都可以根据一个渲染方程来得到。在某一点x,他在方向的出射值(output radiance)等于他本身在这一点这一方向的辐射值(emitted radiance)加上在这一点的入射值(incoming radiance)反射出的能量的总和。为散射函数,表示在表示在方向入射方向出射能量的反射比例。