【博物纳新】专栏是 UWA 旨在为开发者 举荐新鲜、易用、乏味的开源我的项目 ,帮忙大家在我的项目研发之余发现世界上的热门我的项目、前沿技术或者令人惊叹的视觉效果,并摸索将其利用到本人我的项目的可行性。 很多时候,咱们并不知道本人想要什么,直到某一天咱们遇到了它。
明天举荐的我的项目来自 UWA 开源库:https://lab.uwa4d.com/lab/5b5…
一、概览
AO(Ambient Occlusion)是一种基于全局照明中的环境光(Ambient Light)参数和环境几何信息来计算场景中任何一点的光照强度系数的算法。AO 形容了外表上的任何一点所承受到的环境光被四周几何体所遮蔽的百分比,因而使得渲染的后果更加富裕层次感,对比度更高。
该我的项目介绍了一种疾速的基于顶点的 AO 算法,将 AO 看做模型顶点的一个属性,通过深度相机对模型多地位的采样,联合模型顶点的深度校验来计算对应的 AO 值。该办法相比拟于 SSAO,是一种比拟玲珑快捷的繁难办法。通过对该项目标学习,读者能够初步理解 AO 算法的思维,也能够学到该算法的具体简化策略。
二、原理概述
总体来说,该算法能够分为两个步骤:
1. 采样:通过扭转深度相机的地位并对指标物体渲染,把各个地位获取到的深度图保留下来作为采样数据。
2. 计算 AO:将采样数据通过深度校验来辨认出须要遮蔽的模型顶点并依照肯定权重累加遮蔽值,以达到暗影成果。
该办法并不是一个实时计算的办法,而是一个一步到位的办法,实质上是在运行刚开始时就计算好了一个带有 AO 的材质并替换掉模型原有的材质。所以它并不会随着光照的扭转而扭转,艰深来讲就是“把容易变暗的中央的色彩画得暗一点”。
三、具体实现
从 geoAO.cs 来看,所有的工作都是在 Start()中实现的,如下图,而采样和计算 AO 的次要逻辑大都在 DoAO()中。
1. 采样
该步骤须要一个深度摄像机来采样深度图,摄像机的创立在 CreateAOCam()中实现:
该摄像机从创立开始就是暗藏状态(148 行),因为咱们并不需要 OnRenderImage()每帧都执行,咱们想要它“按需执行”,确切来说是为了让 Blit 函数“按需执行”(如下图),那么咱们能够通过把相机暗藏,用 Camera.Render()来手动调用 OnRenderImage()。
除此之外,咱们也留神到为了模仿平行光成果而把摄像机模式改成了正交(150 行),且开启了深度模式(158 行),这时一个深度相机就曾经筹备实现了。
采样环节最外围的环节如下图,该局部在 DoAO()函数中:
首先,该 for 循环的循环次数对应着采样次数,也就是最终渲染进去的深度图样本数量,而样本个数决定了 AO 的精度高下:
在每一轮采样过程中,AO 摄像机(AOCam)作为一个独自的深度摄像机,会达到一个新的曾经计算好的地位(256 行),而后看向模型(257 行),接着把筹备好 VP 矩阵传给 Shader,最初渲染。
这里能够留神到 276 行就是在手动调用 OnRenderImage()函数,但其实计算 AO 这一步就是在 276 行在 Shader(VertexAOCompute.shader)中进行的,相当于每一轮循环都会做一次 AO 运算,而后每轮得出的 AO 值最终会累加在一起附给一个新的材质。
2. 计算 AO
AO 的计算在 VertexAOCompute.shader 中。下图是片元着色器局部:
判断到底哪些点须要有“遮蔽”的局部就是 120-121 行。从 118 行的正文咱们也能够晓得,变量 o“决定了遮蔽会有多暗”,而 120 行通知咱们,对于 vertex.z 和 z 相差过大的点,也就是被遮蔽的点,o 不会参加累加(121 行),因为 o 越大模型就会越亮。最初的累加会带上权重,只不过每次采样的权重都一样而已(124 行)。
而上一步计算出的 AO(65 行)作为上图中的_AOTex 参加了最终图像插值时的权重值(67 行)。最终渲染出的图像会附着在一个新材质球上,而该材质球会替换掉模型原有材质(如下图),至此 AO 成果就增加到了模型上。
3. Tips
该工程计算 AO 的过程很间接地体现出了 AO 算法的思维。
概括来讲,环境遮挡被定义为从外表上某一点可能逃离场景的射线的比例。上文提到的每一轮 AO 采样计算相当于图中每条绿色的射线,而判断深度是在看该射线是否会被遮挡,最初的累加就是在计算比例,而这里通过样本均值来估算积分的过程也是蒙特卡洛积分思维的体现。
四、性能剖析
本次测试用的是低端机型 OPPO A32(4G RAM),测试分为开启和不开启 GeoAO 这两种状况。首先,下图显示的是开启状况下的 FPS 均值和 GPU 耗时状况:
下图是不开启该插件的状况:
能够看出即便在低端机型上,该工具的开启也没有为 GPU 和 FPS 造成压力,相同的是,GPU 耗时反而比不开启的状况下要低,这是因为该插件只是在 Start()函数中置换了一下物体材质,而新材质比不开启时的材质(Standard)更轻量化的缘故。
提醒:并不倡议在游戏中途加上该成果,因为它会因为 Shader.CreateGPUProgram 和 AO 计算而引起卡顿。其中,Shader.CreateGPUProgram 的耗时能够进一步通过收集变体并预热的形式排除,能够参阅《一种 Shader 变体收集和打包编译优化的思路》;而剩下的 AO 计算局部放在场景加载阶段实现则是能够承受的开销。
综上所述,该插件是一个比拟轻量级且成果尚可的计划。
作者公布我的项目时的介绍应用的是英文编写,为了不便大家浏览,UWA 开源库已将其翻译成中文版本,欢送大家独特学习。
明天的举荐就到这儿啦,或者它可间接应用,或者它须要您的润色,或者它启发了您的思路 ……