文章来源: 博客园
原文链接: UE4学习笔记:实时渲染原理 | U_N_Owen原文写得很好,但是主题格式我不太喜欢,所以我对文章的格式进行了修整,方便自己日后阅读
光照和阴影(Lighting And Shadows)
和反射一样,光照和阴影在实时渲染中也很难计算,计算光照和阴影需要大量硬件性能,并且计算速度很慢,因此我们会将光照的部分计算量分流到 预计算 或 预渲染 阶段,也就是我们常说的静态光照。静态光照是指所有预先计算而非实时渲染的光照。值得注意的是,虽然在讨论过程中经常讲 静态光照 和 动态光照 放到一起讲,但是从渲染流程上来看静态光照和动态并不是在同一时间进行计算的,而是静态光照会在第 0 步,也就是预计算阶段,甚至是在渲染之前。
静态光照和静态阴影
流程的优缺点
- 静态光照会在编辑器中进行预计算,并将大部分结果存储在光照贴图中,它在性能方面非常快速,但会增加内存占用量。
- 预先计算光照需要花费很长时间,每当模型有变化时,都需要重新渲染光照。
- 模型还必须有光照贴图 UV,关于如何在 UE4 编辑器里生成光照贴图 UV 的知识可以在这里的第三点查询到。
质量的优缺点
- 静态光照可以处理辐射和全局光照。你可以获得真实且高质量的软阴影。
- 可以获得比实时光照更好的质量,拥有更丰富更精确的效果。
- 我们看到的画面质量实际上取决于光照贴图分辨率和 UV 布局,因为光照被烘焙进了纹理,是纹理大小和 UV 布局的质量决定了画面质量实际有多好。
- 由于 UV 布局的关系,光照中还可能出现接缝。
- 光照贴图分辨率会有一个上限(4096,如果你希望的话也可以是 8192),因此巨型模型会缺乏足够的光照贴图 UV 空间,空间不足会导致光照质量变低,只能采用更低分辨率的光照贴图。
- 一旦光照贴图计算完毕,我们就无法改变光照和阴影,除非我们重新计算整个模型。
光照贴图(Lightmaps)
光照贴图本质上就是一张纹理,是一张烘焙有 光照和阴影信息 的图片,然后纹理会和底色相乘,因此它看起来就像是会被照亮一样,但实际上没有。
模型需要有 UV 光照贴图坐标才能使用光照贴图。
在 UE4 中,光照贴图在光照重建过程中由称为Lightmass的系统流程生成。
引擎里实际上是把许多光照贴图打包到一起,并不会单独创建图像。
Lightmass
Lightmass是一个独立的应用,用于处理光源渲染和光照贴图烘焙,是编辑器之外的渲染器。
Lightmass 支持网络分布式渲染。
烘焙质量取决于光源构建质量以及 Lightmass各 个选项级别。
Lightmass 可以有一个或多个 Lightmass 重要体积(Lightmass Importance Volume),任何位于该体积内部的东西都可 以获得更高质量的光照。
放置 Lightmass 重要体积可以让引擎在计算光照的时候着重计算体积内的东西,而不需要着重计算体积外的东西,如果一个场景里面没有放置 Lightmass 重要体积,引擎会在整个场景范围内进行无差别光照计算,这样会提升性能损耗。
间接光照缓存(Indirect Lighting Cache,ILC,官网说这个方法已经被体积光照贴图取代了)
ILC 用来解决动态模型上的预计算光照。
通过启用 显示(Show)->可视化(Visualize)->体积光照贴图(Volumetric Lightmaps) 来显示场景中的光照缓存。
UE4 会在动态对象所在的位置,查找最接近该对象的光照缓存(即体积光照贴图可视化中的球形体),查询它的亮度,然后将其与动态对象 插值 混合,以此实现光照在动态的对象上的间接反射。
(在 UE4.27 中该属性是默认关闭的) 所有可移动对象都有被称为 “间接光照缓存质量(Indirect Lighting Cache Quality)” 的属性,默认 “ILCQ Point” 会选取动态物体最近的一个点查询颜色,“ILCQ Volume”会选取附近 555 个点并从所有这些点中计算出颜色,“ILCQ Off” 可以关闭间接光照缓存以提升性能。
由于 ILC 大部分时候仅能计算平面上的光照缓存,在一间大房子里接近房顶的部分就不会计算缓存,所以可以使用 Lightmass 角色间接细节体积(Lightmass Character Indirect Detail Volume)覆盖需要生成光照缓存的区域,来 迫使 这些区域强制生成间接光照缓存。随笔作者注:该功能应该一并与间接光照缓存被体积光照贴图取代了,因为体积光照贴图现在可以在全部对象周围(而不仅仅是地面位置)生成光照缓存。
可以在 世界设置(World Settings)->Lightmass->Lightmass设置(Lightmass Settings) 里设置这些间接光照缓存的密度,从而获取到更加平滑的动态间接光照效果。体积光照贴图的密度设置也是在这个地方。
- 静态光照总会以完全相同的速度渲染(指烘焙后的),无论你有一个光源,没有光源,还是有五万个灯源,这些都没有区别,你都会获得完全相同的性能。
- 光照贴图分辨率会影响内存和文件大小,而不是帧率,这个和纹理大小是一样的。
- 烘焙时间会随着光照贴图分辨率、模型和光源数量以及质量设置的提升而增加。
- 衰减半径很大或者是源半径很大的光源会降低重新构建的时间。
动态光照和动态阴影
当我们在讨论动态光照和实时光照的时候,它们其实是同一个概念。
流程的优缺点
- 动态光照借助 G 缓冲实现实时渲染。我们使用来自 G 缓冲的图像来计算如何将光照混合上去。
- 因为光照是全动态的,因此不需要像静态光照那样对模型或对象进行限制,只需要添加一个动态光源即可产生效果。
- 然而阴影对于性能的影响非常大。
- 渲染动态阴影有很多种方法,这意味着需要时间和实践才能找到合适的方法和混合方案。
质量的优缺点
- 阴影的性能损耗很大,通常需要降低渲染质量来补偿动态阴影巨大的性能损耗。
- 动态光照不会对大部分内容产生辐射或全局光照,只能得到相当直接的基本光照和阴影。
- 动态光照很难生成软阴影,即使生成了动态软阴影,该阴影也往往不及静态软阴影那样真实。
- 动态光照通常比静态光照看上去更清晰更具“现场感”。感觉被照射物体更像是处在场景中,更加鲜活.
- 动态阴影对模型的尺寸没有要求(静态阴影有要求是因为存在光照贴图大小的限制)。
阴影
阴影极度消耗性能,关闭一些光源的阴影投射会有很大的帮助。
动态阴影主要有四种类型:
常规动态阴影(Regular Dynamic Shadows)
最常用并且最重要的一种动态阴影类型。
常规动态阴影源(Regular Dynamic Shadows Source)是指那些移动性被设置为可移动(Movable)、并且正在投射动态阴影的光源,这些光源投射地阴影被称为 “常规动态阴影”。当这类光源被移动了的时候,由该光源投射的所有阴影都会实时地移动。
逐个对象阴影(Per Object Shadows)或称为固定光源阴影(Stationary Light Shadows)
那些移动性被设置为固定(Stationary)的光源所投射的阴影被称为 “逐个对象阴影” 或 “固定光源阴影”。
固定阴影会混合使用完全依赖光照贴图的静态光源以及完全动态光源,两者兼而有之。
级联阴影贴图(Cascaded Shadow Maps,CSM)
级联阴影贴图会根据距离(指阴影到摄像机的距离)渲染不同的 动态阴影。
因为 CSM 的特性(阴影随着与摄像机的距离增加而逐级质量下降),因此 不适用 于渲染大型室外场景,因为远距离的阴影已经消退到不存在了。
距离场阴影(Distance Field Shadows)
对于级联阴影贴图来说,因为其特性所以会造成不能够渲染远距离模型的阴影,为了 弥补这个不足,我们需要一个新方案来实现能够远距离渲染阴影的同时还不会造成过多性能损耗的方法,这个方法就是距离场阴影。
下面为引擎里存在但是不常使用的阴影类型
插图阴影(Inset Shadow)
和 “逐对象阴影” 类似,但是提供了更高的阴影分辨率,因此对于角色对象来说该阴影是默认启用的。即便附近没有合适的光源,启用了该阴影的对象也可以投射出高分辨率的阴影。
可以通过勾选模型的 细节面板(Details)->光照(Lighting)->动态插图阴影(Dynamic Inset Shadow) 来启用该阴影。
接触阴影(Contact Shadows)
能在细小物体下投射效果不错的接触阴影。例如墙上的盆栽背后细微的阴影。
可以勾选 细节面板(Details)->光照(Lighting)->接触阴影(Contact Shadow) 来启用该阴影。
胶囊阴影(Capsule Shadows)
非常简单且损耗很低,它是用来渲染模型(主要是指骨骼网格体模型)下方阴影的系统。
首先需要对 “骨骼网格体(Skeletal Mesh)” 赋值所需要的碰撞胶囊,可以在骨骼网格体下的 光照(Lighting)->阴影物理资产(Shadow Physics Asset) 设置该骨骼网格体所需要使用的碰撞胶囊(不需要完全准确,甚至只有一个椭圆的碰撞胶囊资产也是允许的,由此也可实现一个风格化的阴影),然后在 骨骼网格体组件(Skeletal Mesh Component)->光照(Lighting) 分类下勾选 “胶囊直接阴影(Capsule Direct Shadow)” 和 “胶囊间接阴影(Capsule Direct Shadow)” 即可启用该类型的阴影。
渲染阴影
我们目前知道了多种渲染阴影的方法,现在需要使用像素着色器来计算和应用阴影。为了简单起见,接下来的动态光源会以点光源为主要关注的对象。
动态光源像球体一样渲染(这也是为什么引擎里面的光源都会有一个淡蓝色球形的范围),原理就像遮罩,球体内的任何像素都会进行经过像素着色器着色运算来混合光照。
正因为动态光源会像球体一样渲染球体内的所有像素,也就是说如果两个动态光源的球体范围互相重叠了,那么重叠部分会经过重复的计算,从而造成性能损失。可以通过开启 光照(Lit)->优化视图模式(Optimization Viewmodes)->光源复杂度(Light Complexity) 来可视化每个光源的渲染范围,单个光源的渲染范围会呈现绿色,如果存在重叠则重叠部分颜色会依次以红色、紫色、白色的颜色过度,复杂度也依次增加,也说明该部分的重叠光源性能损耗越大(因为需要重复计算的次数变多了)。
渲染阴影需要知道四样信息:
- 从摄像机到几何体的距离(从摄像机生成的深度图)、
- 摄像机的位置、
- 光源的位置、
- 几何体到光源的位置(从光源位置生成的 360 度深度图)。
由上述 4 条信息我们可以生成一张 阴影贴图 ,阴影贴图就是在 特定光源的作用下在特定位置能够看到的阴影。
阴影渲染的大致过程是:首先我们知道了某个位置有光源,且知道光源的颜色,光源的范围等信息,然后通过光源生成的 深度图 ,知道我们应该照亮哪些模型不应该照亮哪些模型,然后再混合 世界法线贴图 生成更加细致的阴影,然后再混合之前生成的 阴影贴图 ,为每个被照亮的模型生成了对应的阴影,从而实现了阴影的渲染。
动态光照本身损耗相对较低,特别是在延迟渲染器和如今的正向渲染器中,光源本身 并不是问题和损耗所在,阴影才是。损耗源于像素的着色运算,像素越多,运算速度越慢,这点和反射、材质的性能损耗规律是一样的。我们无法从直接的视觉上观察到一个光源所占用的像素是多是少,光源所占像素的多少是由其属性 “衰减半径(Attenuation Radius)” 显示的淡蓝色线条组成的范围决定的。
因为动态光照中阴影造成的性能损耗很大,因此如果你不是必须使用的话,关闭阴影有助于提升性能。
几何体的面数也会印象阴影的质量及性能损耗,几何体面数越多,计算其阴影就会造成更多的性能损耗,因此降低多边形面数有助于提升性能,如果必须使用高面数的多边形,可以使用距离场阴影来代替常规的动态阴影从而减少性能损耗。
因为阴影是由动态光源生成的,因此可以通过关闭光源来实现减少性能损耗的要求,特别是 光源对象都会在 细节面板(Details)->性能(Performance) 分类里有 “最大绘制距离(Max Draw Distance)” 属性值和 “最大距离衰减范围(Max Distance Fade Range)” 属性值,通过设置这两个属性可以让光源对象在一定距离外就不再产生光源,也不再产生阴影。
根据我自己的测试来看,就算模型因为遮挡而被剔除的时候,其阴影依然会生成。因此对于某个房间里面模型来说,即使玩家站在房间外,而且视角和房间内之间存在一个门模型做遮挡,这样会导致房间内的模型被剔除,但是光照不会。最好的办法就是利用脚本(蓝图或 C++ 都行)控制房间内的动态光源的开关,可以减少不必要的性能损耗。
混合使用静态光照和动态光照
- 静态光照可以用于微弱和远距离的光照。
- 静态光照还可以用于渲染摄像机附近的间接光照。
- 动态光照可以同来突出着色和阴影。并且在前者效果上生成一张具有交互效果的图层。
- 如果需要尽可能高的性能,就只使用静态光照。
- 如果想随时修改光照效果,就只使用动态光照。
雾和半透明
雾(Fog)
UE4 中有大气距离雾(Atmospheric Distance Fog)和指数距离雾(Exponentional Distance Fog)两种距离雾,以及一种局部体积雾(Local Volumetric Fog)。大气距离雾和指数距离雾会随着环境而改变颜色。
距离雾(Distance Fog)意味着雾会随着距离(指距离摄像机的远近)消退,一般来说是随着距离的增长而消退。
距离雾同时也是一种高度雾(Height Fog),和距离雾差不多,高度雾指的是随着高度消退的雾。
所有这些雾效都是基于像素着色器来计算渲染的。
雾效本质上是借助深度图来实现。因为知道深度,就能知道一切对象离摄像机有多远,知道雾的颜色,将该颜色和深度图混合,就能得到实现了雾的深度图,最后再混合之前已经渲染好了的图像,就能获得实现了雾效的图像。
透明度(Transparency)
延迟渲染器在渲染透明度时会遇到严重的困难,因为延迟渲染只有 G 缓冲可以使用,G 缓冲 缺少足够的信息 来正确渲染透明度。
在前向渲染中渲染透明效果会容易得多。
为了获得尽可能高的半透明质量,目前引擎的方法是在前向渲染中完成透明度渲染,然后和延迟渲染结果合并,但是这样会有额外损耗,因为现在需要运行两个流程然后将它们的结果合并到一起,但是好处就是避免了延迟渲染带来的缺少信息的问题。
在材质编辑器界面的 细节面板(Details)->半透明(Translucency)->照明模式(Lighting Mode) 里列举了许多可供半透明材质使用的照明模式解决方案,引擎需要克服系统存在的弱点,因此需要为每种特殊情况制定不同的方案。体积无方向(Volumetric NonDirectional)、体积定向(Volumetric Directional) 的 “体积” 表示它会划分表面和网格体(即在渲染模型时增加额外细分),然后用来和顶层的光照混合;体积逐个顶点无方向(Volumetric PerVertex NonDirectional)、体积逐个顶点定向(Volumetric PerVertext Directional) 也一样,只是基于顶点,“无方向” 总是比 “定向” 损耗更低,“定向” 在半透明效果上更好一些,“无方向”基本上只是在顶层添加环境光照。表面正向着色(Surface ForwardShading)则会在这个材质上面开启表面正向着色。
渲染透明度效果的时候首先会在 G 缓冲中 标识出哪些像素稍后会变成透明。
当以最佳质量渲染透明度时就像素着色器的运算次数而言损耗很大,所以可以使用前向渲染实现。
如果有许多图层覆盖了相同像素,并且有大量像素被覆盖的时候,透明度造成的损耗会特别大。
除了像素着色器本身的损耗以外,渲染排序也会加重损耗,例如透明材质的重叠,会导致被重叠像素反复进行计算,从而加重损耗,重叠的层数越多,损耗就越大。
在实现半透明效果的时候,材质的混合模式(Blend Mode)能使用蒙版(Masked)的话就 尽量使用蒙版,因为该混合模式性能会好很多,如果必须使用半透明的(Translucent)的话,其着色模型(Shading Model)能选无光照(Unlit)就 尽量使用无光照模式 而不是默认光照(Default Lit)模式,因为无光照的性能也比默认光照好一些。我们需要去 “仿造” 半透明的效果,例如将材质颜色替换成对象的背景颜色,从而 “仿造出” 半透明的效果,因为这样即可以实现半透明的效果又不会造成太多的性能损耗。
如果在实现半透明效果时候确定必须使用半透明的混合模式以及默认光照的渲染模型,那么就需要去确定在半透明(Translucency)分类下的属性设置正确,如果需要最佳性能,就在该分类下将光照模式(Lighting Mode)设置成表面正向着色(Surface ForwardShading)。
后期处理(Post Processing)
后期处理就是在渲染流程末端应用的视觉特效,所以被称为 “后期” 处理。
后期处理很大程度上依赖于像素着色器,并且也是通过合成实现,它通过再度使用 G 缓冲来计算各种效果。
常见的后期处理特效有:泛光(Light Bloom)、景深/其他形式的模糊(Depth of Field/Blurring)、镜头眩光(Lensflares)、光束(Light Shafts)、渐晕图(vignette)、色调映射/颜色校正(Tonemapping/Color Correction)、曝光(Exposure)和运动模糊(Motion Blur)。
泛光(Bloom)
引擎会查询当前画面里所有像素的亮度,然后过滤掉所有暗于特定颜色的像素(所谓过滤就是用黑色将其替代),增加剩下像素的亮度或对比度,然后以某种方式模糊这张图像,例如缩小图像再放大到原来尺寸,然后你 可选地 使用一张带有灰尘地遮罩图片或类似镜片灰尘之类的纹理,与模糊后地图像混合,就能得到该灰尘遮罩效果的泛光,最后混合到渲染完成的图像上,就能实现泛光的后期效果。
景深(Depth Of Field)
景深可以通过将深度图和以某种方式模糊后的图像混合的方法来生成,以此生成的图像会在远距离的位置发生模糊,对象离摄像机越远,该对象则越模糊。
颜色校正(Color Correction)
引擎颜色校正是用一种被称为 “查找表(Look Up Table, LUT)” 的方式将数据记录在一条彩色数据查找表(该表可以记录 4096 种不同的颜色偏移)里,然后应用到 UE4 中去查找那些匹配的像素,最后对这些匹配的像素进行对应的处理操作(例如提升亮度、提升红色、减少绿色等操作)。
着色器(Shader)概念
渲染过程中会存在着一系列需要反复计算的过程,如果这些过程在 CPU 中进行处理的话效率会非常低下,“着色器(Shader)” 就是被设计用来进行处理这些过程的软件和硬件,着色器本质上是在 GPU 特定区域进行重复计算,非常的高效,是实时渲染的核心,对于渲染方式和性能损耗有 非常非常 大的影响。
G 缓冲区(GBuffer)概念
- GBuffer 是为每帧准备的一组图像,他们包含了 渲染管线后期所需要用到的所有信息,例如渲染雾效时候GBuffer 用于保存场景的深度。
- 延迟渲染器 需要 使用到 GBuffer。
- 前向渲染器一般来说 不需要 GBuffer,但是也可以使用,只是会让渲染变得复杂。
- 生成 GBuffer 的过程完全是在后台进行的。
- GBuffer 会创建渲染过程后期阶段使用到的所有信息(即上文提到的 “一组图像” )。
混合预计算渲染和实时计算渲染的解决方案。
- 实时计算渲染非常复杂,要求也非常高。
- 因此 UE4 的渲染方案通常是将预计算部分和实时计算部分结合起来。
- 即 UE4 的渲染分为预计算渲染(例如光照贴图等)和实时计算渲染(动态光源实现的动态阴影等)。
- 本随笔作者觉得此概念隐含一个需要掌握的知识,就是当我们谈到 “实时渲染” 的时候,其实谈到的是 “实时渲染” 加上 “预计算渲染”,而不单单只是指代 “实时渲染”。或者可以说,“实时渲染” 包含了 “预计算渲染” 和 “即时渲染”。
- 所谓 “混合”,即指 UE4 引擎本身提供许多问题的解决方案,而我们需要通过选择合适的方案来 “混合” 使用,例如对于阴影,我们可以组合使用级联阴影贴图(近距离对象的阴影)和距离场阴影(远距离及大量对象的阴影)来实现对象阴影的功能。
- 使用混合方案而不是单一方案,是因为混合方案往往能够提供更加高效的解决方案。
渲染质量的可延展性(Scalability)
- 可随时随地地调整渲染质量(画面质量),类似于很多游戏都提供的画质选项。
- 可延展性可让游戏内容移植到不同的设备的。
- 可延展性已经融入到了引擎和渲染工具的每个部分里面了。
- 性能 对于实时渲染来说非常重要,要想维持高性能(并且不过多降低渲染质量),既要掌握可延展性设置,又要正确地去处理应用内容,所以需要知道怎么去用
r.命令;如何去用可延展系统的自动设置;如何合理地去设置游戏内容以保证应用内容已经被充分优化。
渲染相关的命令
r.shoadowquality Value: 控制阴影质量,Value 值为 0 时则关闭阴影。r.Streaming.PoolSize Value: 设置纹理流送池的大小,Value 值的单位为 MB。r.SSR.Quality Value:设置屏幕空间反射质量,默认为 3。
渲染的两种方法:“延迟渲染(Deferred Rendering)” 和 “前向渲染(Forward Rendering)”
- 不仅仅是在 UE4 引擎里面,几乎所有引擎、软件,使用的都是 “延迟渲染” 或 “前向渲染”。
- UE4 引擎默认使用的是延迟渲染,但是也可以手动设置为前向渲染。大多数情况下都会选择延迟渲染。
延迟渲染
- 能够让高要求的设备拥有稳定的性能(适用于当前市面上的许多游戏大作)。
- 支持更多渲染功能。
- 缺点在于抗锯齿,只能使用临时抗锯齿(Temporal Anti-Aliasing, TAA)。
- 着色(Shading)发生在延迟环节中,而且渲染几何体模型的步骤是在渲染光照的步骤之前完成的,这些渲染阶段并不是同时完成,因此该渲染方法被称为 “延迟渲染”。
- 擅长渲染动态光照,擅长提供稳定、可预测的高质量效果,在涉及禁用部分渲染功能的时候会更加灵活。
- 不擅长表面属性相关的功能,不擅长渲染半透明表面。
前向渲染
- “前向渲染” 能够让简单应用或者低端设备带来更流畅的性能(适用于手机游戏、VR游戏、VR应用、VR移动应用等)。
- 仅支持有限的渲染功能。
- 但是能提供更好的抗锯齿,因为可以使用多重采样抗锯齿(Multi Sampling Anti-Aliasing,MSAA)。
- 着色、几何体及材质是在同一环节进行计算的。
- 擅长渲染半透明表面。
- 不擅长混合各种功能。
- 前向渲染器会在基础通道过程执行比延迟渲染器要多得多的步骤,前者会使用更多基于合成的方案。
渲染指标:FPS、Game、Draw 和 GPU
- FPS(Frame Per Second):帧率,即代表着渲染一帧画面所需要的时间,单位通常为 “毫秒(ms)”。
- Game:游戏线程(CPU渲染的进程),通常代表着CPU进行渲染所需的时间。该线程通常用于计算位置(Position)、旋转(Rotation)或变换(Transform)相关的计算,还有动画(Animation)、物理(Physics)、碰撞(Collision)、AI、生成/销毁(Spawning/Destroying)等。
- GPU:渲染线程,通常代表GPU进行渲染所需的时间。该线程通常用于计算具体的渲染,如光照(Lighting)、模型渲染(Rendering of models)、反射(Reflections)、着色器(Shaders)等。
- Draw:绘制线程,该线程大部分时候是由 CPU 负责,GPU 也会处理小部分。
- Game(CPU)渲染和 GPU 渲染是同时发生的。
四种常见的性能问题
- 半透明材质:屏幕当中半透明材质每叠加一层,就要多渲染一次半透明效果,就需要重新计算像素,因为像素是叠加在其他半透明层的上面。半透明像素在屏幕中的占比越多(例如距离半透明材质的物体越近),需要计算的像素越多,性能损耗越大。
- 像素着色器:越是复杂的材质,对性能的损耗越高,判断材质是否复杂可通过判断该材质所包含的指令(Instructions)数量来确定,指令数量越大的材质越复杂。像素在屏幕中的占比也会影响性能(因为占比越大的话,需要计算的像素的数量变多,计算量也会变大)。
- 绘制调用(Draw Call,简称 DC):引擎渲染场景的时候是逐对象渲染,每渲染一个对象就是一次绘制调用,对于模型里拥有多个材质的单例模型来说,每个材质也是一次绘制调用。引擎是以绘制调用为单位进行渲染的。
- 动态阴影:动态阴影会随着场景中多边形的数量增加而产生更多的开销。一般来说,如果你打算在场景中使用大量动态阴影,那么就应该使用低面数的模型,如果要使用高面数的模型,那么就应该使用静态光照或不生成动态阴影。