命子迁
[西汉][司马谈]
太史公执迁手而泣曰:“余先周室之太史也。自上世尝显功名于虞夏,典天官事。
后世中衰,绝于予乎?汝复为太史,则续吾祖矣。
今天子接千岁之统,封泰山,而余不得从行,是命也夫,命也夫!
余死,汝必为太史;为太史,无忘吾所欲论著矣。
且夫孝始于事亲,中于事君,终于立身。扬名于后世,以显父母,此孝之大者。
夫天下称诵周公,言其能论歌文武之德,宣周邵之风,达太王王季之思虑,爰及公刘,以尊后稷也。
幽厉之后,王道缺,礼乐衰,孔子脩旧起废,论诗书,作春秋,则学者至今则之。
自获麟以来四百有余岁,而诸侯相兼,史记放绝。
今汉兴,海内一统,明主贤君忠臣死义之士,余为太史而弗论载,废天下之史文,余甚惧焉,汝其念哉!”
迁俯首流涕曰:“小子不敏,请悉论先人所次旧闻,弗敢阙。”
今天给各位分享的是索尼旗下工作室Guerrilla Games(主打产品《KillZone》FPS系列)在Siggraph2015上分享的《地平线-零之曙光》中Volumetric Cloud的实现技术,这里是原文链接,PPT中有一些视频,这里就不搬运了,有兴趣的同学自行翻阅吧。
演讲者Andrew Schneider原来是做voxel动画出身,《地平线》的体积云效果是Andrew跟另一个程序Nathan Vos一起完成的,整个体积云的消耗大概是2ms+20MB,在这种资源占用的情况下,基本上可以放弃此前游戏中使用高清贴图来模拟云层的做法了。
先来介绍一下背景,Guerrilla此前主要产品类型为FPS,FPS中玩家的视角与移动轨迹基本上都可以预先设定好,因此可以通过手动将一些高清天空盒与公告板摆放在合适的位置来伪造一种真实效果。这些高清的资源可以通过PS手动绘制,也可以通过烘焙方式生成。之后在shader中加上动画效果,可以得到非常好的天空效果。
不过《地平线》是一种完全不同的游戏类型,其主要特点在于:
- 开放世界,玩家可以出现在任何一个位置
- 为了模拟自然规律,需要为之实现一个24小时光照变化的Day-Night Cycle
- 场景中的天气也需要随着场景跟时间的变化而变化
- 天空跟场景也需要达到史诗级的效果
光照与天气变化除了能够提供一种真实氛围之外,还有助于提供位置与时间信息。
为了能够给玩家一种良好的体验,Guerrilla为云层效果设定了一些目标:
- 云层的效果允许美术同学自行调整
- 能够实现多种真实云彩类型的模拟
- 能够实现与天气的适配
- 需要能够随着时间而变化
- 效果要非常的好看
下面先来看一下Cloud此前的技术方案。
Guerrila此前的云层实现是通过流体力学方程生成出来的(能够模拟云层从无到有从小到大的变化过程),这种方式得到的云层效果非常好,不过缺点在于美术同学控制起来比较困难,毕竟方程式不是那么直观。
作为改良,Guerrilla决定将云层分割成不同的小单元,每个小单元用一个简单的形状来模拟:
- 对每个单元进行voxelizing处理
- 在每个单元内部调用流体力学方程进行Cloud Generation
- 直到整个效果接近美术同学想要的表现为止(这里应该是有一个迭代,不过不清楚的是,迭代针对的是Cloud Generation还是前面的两个步骤)
之后在生成的Cloud模型上对主散射跟次散射(Primary & Secondary Scattering)进行光照预计算,这里给出的效果图是在Houndini上使用CPU计算得到,整个过程需要10s
生成的Cloud Assets可以用三种方式整合到游戏中:
- 第一种,可以将流体力学方程生成好的Cloud用模型数据保存下来,其烘焙好的光照数据也可以用球谐方程预先存储下来,之后在游戏中直接取用即可。这种方式比较适合那些密度比较高的浓厚云层,对于那些轻薄的云层就不太适合了(是性价比不高,还是表现不好?)
- 第二种方式比较常用,用公告板来模拟立体云层表现,不过如果想要实现云层随着时间而变化的话,就需要支持多朝向以及多时间段的云层变化,Guerrilla虽然解决了这些难题,但是在处理云层之间的阴影遮挡的时候卡住了
- 第三种方式,用skydome(天穹,环绕地球的一圈立体球环)来实现体积云的渲染,这种方式还可以跟大气渲染相结合,这种方法能够满足Guerrilla的大部分需求
- 综合考虑这三种方式发现,这几种方式都不能实现云层随着时间而变化的需求,且内存占用与GPU Overdraw也比较严重
- 因此这几种传统的将云层看成Asset来绘制的方式都不是Guerrilla所需要的
Guerrilla甚至尝试体积云的实现方式,众所周知体积云的消耗是当前游戏所不能负担的:
- 渲染时间消耗高
- 需要较多的texture read instructions
- 通过Ray March实现
不过,目前已经有很多快速可靠的volumetric lighting实现方法,且“2012 Production Volume Rendering Course”中有通过噪声来生成Cloud的方法,从理论上来说,体积云的方法是值得尝试的。
Guerrilla首先尝试的是在相机前渲染多个叠加起来的几何体,并在surface上采样Perlin噪声,虽然结果证明此实现确实缓慢,但是却证明是有效的,不过前面云层渲染的目标中想要实现的是多种不同类型的云层而非仅仅上图所示的bandy clouds。
之后Guerrilla通过Houndini为给定的几何形状生成一系列3D贴图,而通过Houndini的GL插件,Guerrilla还建立了一套用于实现Cloud System跟Lighting Model的GL Shader原型。
通过很多trick手段,Guerrilla成功的通过程序实现了Houndini云层效果的模拟,缺点在于想要实现可动的云层,成本就比较高(差不多需要1s来渲染一帧),虽然结果很让人赞叹,但还是不能满足需求。
为了进一步优化,Guerrilla尝试放弃预先通过简单形状来定义云层形状的方法,转而通过低分辨率的噪声基于一定规则进行叠加来模拟Cloud,这里的噪声需要选取比较接近真实云层表现的。
下面就是Guerrilla Cloud System的核心了,主要分成四块,首先来介绍一下Cloud Modeling实现方法
下面先来列举一下Cloud的种类,云层可以分成三大类:
- 低层的Strato Clouds,包含三种小类
- 中层的Alto Clouds,有带状跟棉花状两种
- 高层的Cirro Clouds,通常为大尺寸的带状云,且蓬松程度不高
此外,还有一种横跨三种高度的云层-Comulonimbus Clouds,为了方便参照,珠峰的高度为8848m。
这里需要提及一本1961年由两个气象学家撰写的一本名字叫做“The Clouds”的书籍,其中详细介绍了云层生成的方式,且提供了很多经验式的结果与概念,对于Cloud Modeling起到了很大的作用。
上面列举的是云层产生的一些基本规则:
- 云层密度随着海拔的增加而增加
- 海拔越高,气温越低
- 云层密度过高,会凝结成雨雪
- 风力方向是三维的,随着海拔的增加会发生变化
- 云层通常是地表的热气在上升的过程中压缩而产生
- 热气在上升的过程中,随着密度的增加,形状会逐渐趋近圆形
- 热气稀薄的地方,其显示效果接近雾气Fog
- 大气涡流会对云层的形状施加影响
Guerrilla的云层实现依然是借助Ray Marching来实现的,沿着从相机出发的射线对Cloud噪声进行采样,从而以sampler的形式来完成对云层形状的Modeling。
在Ray Marching的过程中,需要对Ray Marching的每一个点进行光照计算,并构建一个Alpha通道(干啥用的,存储云层的光照?)
网络上有许多体积云实时渲染的实现方法,其中最常见的是一种叫做Fractal Brownian Motion(简称FBM)的方法,这种方法的基本思路是将不同频率的Perlin噪声叠加到一起,直到获得令人满意的Cloud细节为止。
FBM算法的基本思路是,通过将不同频率不同振幅的噪声叠加到一起,来获得更为随机的噪声数据,其基本实现思路可以用一个循环来给出:
int nLoops = 8;
float fAmplitudeScale = 0.8f;
float fFrequencyScale = 2.0f;
float fAmplitude = 1.0f;
float fFrequency = 1.0f;
float fOutputNoise = 0.0f;
for(int i = 0; i < nLoops; i++)
{
fOutputNoise += fAmplitude * noise(fFrequency);
fAmplitude *= fAmplitudeScale;
fFrequency *= fFrequencyScale;
}
之后,这些Perlin噪声会用一种梯度(gradient)的方式组合在一起,梯度定义了云层密度随着高度而变化的规律。
这种方式得到的Cloud比较逼真,但是效果又比较违和,因为云层没有一块大型的起主导作用的云朵,因而观察者很难从云的形状看出来这个云层的变化规律,比较难受。
作为对比,上面给出的这张图就要舒服多了,其中的云层很容易让人联想到工厂排放的水蒸气在上方凝结而成云,底部的云层比较稀薄,而上方的云层则凝结力度更高。
再来看一下FBM生成的Cloud,可以看到充满屏幕的多是一些稀薄的云层,而缺少上图中那种翻涌而起的鼓胀感,因此也就缺少了云层来龙去脉的暗示信息。
由于Perlin噪声得到的云层无法实现这种菜花似的效果,因此Guerrilla尝试寻找其他的替代噪声。
Worley噪声是Worley在1996年提出的,主要用在水面效果上,比如光穿过水面在水底的焦散现象等。如果将其效果翻转(黑白对调),得到的结果如上图所示,可以看到,已经比较接近所需要的菜花云的效果了。
将之按照FBM的方式进行不同频率的叠加,并将叠加的效果来对Perlin噪声进行调制(主要是进行膨胀),之所以要这样做,是为了保留Perlin噪声整体形状的连接感,这种拼接的噪声被称作“Perlin-Worley”噪声。
为了提升性能,通常会将所需要的参数制作成3D贴图,而为了尽可能少的Texture Reads以及使用尽可能低的贴图分辨率,Guerrilla将PW噪声压缩到三张贴图上,其中两张3D贴图,一张2D贴图。
第一张3D贴图有四个通道,其分辨率为128^3,第一个通道存储的就是PW噪声,而剩下的三个通道则用于存储不同频率的Worley噪声,跟标准FBM方法一样,这张贴图通常用来设定云层的大致形状。
第二张3D贴图有三个通道,其分辨率为32^3,这三个通道存储的也是不同频率的Worley噪声,用于为云层添加细节(云朵轮廓处的细小锯齿状边缘)。
第三张贴图为2D贴图,分辨率为128^2,由三个通道组成,这张贴图中存储的是不会发散(non divergent)的curl噪声,用于实现大气涡流的模拟,在实现中,会调用这个噪声对云层的形状进行扭曲以得到一种涡流扰动的效果。
在标准的FBM中,会需要一张高度梯度图(height gradient)用于对不同高度的噪声生成参数进行修正,Guerrilla这边有一点不同的,因为所有云层类型中最重要的就是距离玩家最近的Strato Clouds,而前面说过,Strato Clouds又包含三种不同的Cloud,为了更逼真的模拟Strato Clouds,Guerrilla使用三张高度梯度图用于对这三种不同的Cloud噪声进行调制,除此之外,在实现过程中还需要一张一维的coverage贴图用于指出某一点对应的云层浓度,浓度可以用一个[0,1]范围内的值表示。
这张图右侧的天空是与水平线呈30度夹角的效果,下面按照标准流程来进行云层的渲染:
- 首先对第一张3D贴图进行采样,并将结果乘上高度梯度图,输出云层的大致形状
- 之后,将上一步的结果跟coverage贴图相乘,用于降低云层底部的浓度。
第二步的作用是为了保证Cloud在底部比较稀疏,随着海拔的上升,其浓度逐渐增加。得到基本Cloud形状之后,下一步就是为之添加细节。
- 在云层的边缘位置,将前面得到的云层形状跟第二张细节贴图数据相减。这里有一个小窍门,如果想要在边缘得到稀薄云层的效果,可以将第二张细节贴图中的Worley噪声沿着云层底部(at the base of clouds)进行翻转。
- 同时,为了模拟大气涡流的效果,在这一步中还会读取curl噪声贴图的数据对第二张细节贴图的结果进行调制。
这里放了一个游戏中的效果视频,通过调整coverage贴图,云层从薄变厚,并随之触发从cumulus到stratus的过渡。
上面介绍的是静态Cloud的实现,下面介绍一下动态Cloud的相关细节。
在Guerrilla的实现中,Coverage贴图以及Cloud type是一个随着天气而变化的函数:
- 在天气变化的过程中,会控制上述两个参数的变化,并在一定条件触发之后,实现雨雪效果。
这张图左下角的小图代表了用于驱动云层变化的输入参数贴图,其中粉色部分表示的是天气系统的输出,红色表示的是coverage贴图,绿色表示的是precipitation(雨雪),而蓝色的表示的云层类型。天气系统会以一种渐变的方式调制输出这张贴图,用于实现云层的动态变化,调制过程提供了一些参数给美术同学进行控制,上图中近处的是cumulus雨云,而远处则是普通的cumulus云层。
通常情况下,云层既包含cumulus云也包含stratus云,上图中红色部分表示蓝色通道数值较低,说明云层类型主要是stratus,对应的是屏幕中间的远景云。
上图中绿色部分的precipitation信号,将会将任意类型的云层转变为覆盖率为70%的cumulonimbus云。
precipitation不但会改变云层的类型,同时还会生成雨效。
如果增加风速,并提高降雨的概率,就会触发雷云的切入,并开始刷出雨效。
Guerrilla希望绘制出来的云层在地平线上有一个较好的表现,比如不会被远处的山脉所遮挡:
- 云层绘制的区域以玩家所在位置为中心,35000m为半径
- 以距离玩家15000m为起始位置
- 在50% coverage的时开始stratus到cumulus的切换
通过上述设计原则,可以保证在地平线位置云层总是会存在一些变化,从而很好的营造一种史诗般的效果,从上图可以看到,按照这些原则生成的调制贴图具有较好的coverage&cloud type表现。
为了得到较好的效果,E3预告片中的调制贴图是人工绘制的,在渲染的时候,会使用人工贴图覆盖天气系统自动生成的调制贴图。
对Modeling步骤做一个总结:
- 按照标准的ray marching流程框架进行
- 以两种LOD来构建clouds
- 一种低频的LOD用于控制云层的形状
- 一种高频的LOD用于控制云层边缘的细节与涡流扭曲
- 所使用的的噪声是Perlin,Worley以及Curl三种混合而成
- 对于每种云层类型,都会制定一套预设数据,用于控制云层密度随高度而变化的规律,以及coverage
- 这些预设数据会随着场景切换,被天气系统用来生成对应的调制贴图
- 云层的动态表现会受到风力的影响
下面来介绍一下Cloud的光照计算,当下存在着众多的lighting方法,不过它们的通用问题在于需要较多的采样计算,然而留给Cloud的预算往往无法支撑这么高的消耗,因此这些方法都无法达到Guerrilla的要求,不过它山之石可以攻玉,下面对现存的方法中能够实现Guerrilla所需要的三种最重要的光照特征的进行简单介绍。
Guerrilla想要实现的光照特征有三种:
- 太阳光散射
- 观察者面向太阳时的云层银边
- 观察者背向太阳时的暗边
前面两种光照特征都有现成的方法可供借鉴,最后一种特征需要Guerrilla自行完成。
进入云层的光线,会在云层中发生折射(其实是多次散射)
部分光线会在散射的过程中偏离原有的方向,射向其他地方(out-scattering)
部分光线会在散射的过程中被其中的介质所吸收
此外,射入人眼的光线还包含一部分太阳光的in-scattering部分。
在电影行业,这三种光线分布通常会需要使用大量的时间来进行运算,不过在游戏中,就没有这么高的预算预留了,因此通常会用概率论的方式近似求得这三种光线分布。
比尔定律是光线在介质中传播时能量变化的基本规律,基本含义是光线的能量随着传播介质的厚度(光学厚度)的增加而呈指数形式衰减,这是云层光照模型的基础。
不过,还有一个参数会影响光线在云层中的散射情况,这个参数叫做相函数,用于指示光线发生散射时,各个方向散射能量的分布情况,这个参数对于实现Guerrilla前面所需要的银边效果有着非常重要的作用。
云层中散射光线中继续向前的部分通常要高于被反弹回去的部分,这种特性叫做各向异性散射。1941年提出的HG模型是模拟云层各向异性散射的重要依据。
在Ray Marching的过程中,每次计算一个采样点的光照结果的时候,都需要将比尔定律跟HG函数相乘,来得到对应的光照输出。
这里给出单纯比尔定律的云层渲染效果(左侧)以及考虑了HG分布的效果(右侧)的对比,显然HG效果有助于提升云层的真实感。
下面介绍在Guerrilla之前,没有前人研究过的暗边的实现技术
再来回顾一下前面的云层光线传播示意图
如果对比云层中的两个点,一个位于云层边缘(上侧蓝点),另一个位于云层中心(下侧蓝点),从直观上来看,处于云层边缘的点应该能够得到更多的光照,而处于云层中心的点由于遮挡的存在所接触的光线较少。不过实际上是,如果将云层看成是光线收集器的话,那么云层中心的点能够汇聚更多的in-scattering光线,而云层由于后向的反射光线分布较少,在边缘处所能够反射的光线是非常有限的。
在电影业想要实现暗边效果,可能需要大量的采样来获得真实感,不过在游戏中就没有这么高的预算,只能采用近似的方法来逼近这个效果。
云层的这种背光效果其实跟很多粉末状物体光照效果非常近似。
暗边效果其实在云层的很多地方都可以观察到,即使是那种比较稀薄的云也不例外,只不过这种云上面的暗边效果更为宽而泛而已。
之所以使用比尔定律+HG相函数渲染得到的光照效果看不到这个表现,是因为比尔定律定义的Transmittance Function实际上是一种近似,忽略了这种效果的一些计算。根据能量守恒定律,云层散射出去的光线跟其吸收的光线的能量是保持一致的,而云层个点出射光线的强度实际上可以看成是基于云层深度的统计概率函数。
云层内部的in-scattering能量会随着云层的深度而增加,这个规律可以使用Powder定律来描述
将比尔定律跟粉末定律相乘,可以得到如上图所示的紫色曲线,Guerrilla尝试在ACM论文中找到Beer-Powder定律的相关描述,不过没有得到任何结果,看起来这应该是他们首创。
对比不同的Transmittance Function的实施效果,可以看到,添加了Powder定律之后,云层的表现得到了Guerrilla所追求的暗边效果,更加具有真实感。
这里给出比尔定律跟Beer-Powder定律的大图对比。
这里给出了游戏中的真实效果展示对比,浓密云层上的效果较为显著。
不过这里需要注意的是,由于暗边效应是在观察者背对太阳的时候才能看到的效果,因此在使用的时候注意条件,当条件不满足的时候应该退化成比尔定律。
这里给了一个视频,展示了观察方向的变化对于暗边效应的控制效果。
最后,Guerrilla这边会在需要渲染雨效的时候,增加云层的吸收强度,从而得到对乌云的模拟。
总结一下,云层光照实现的四个主要部分。
前面介绍了云层的模型生成与光照计算,下面来介绍一下Guerrilla的渲染算法以及如何将云层整合到大气效果中还有Day-Night Cycle的实现。
这里展示了地球与大气层的宏观模型,云层则分布在大气层中的不同高度。
在一个平整的地面上(比如海洋)可以很容易的看到云层沿着地平线而弯曲的效果。
Guerrilla将球环状大气层分成两个部分:
- 低海拔区域(1500m~4000m),这部分大气层中的Cloud以Strato为主
- 高海拔区域(>4000m),这部分大气层中的Cloud以alto以及cirro为主,由于这部分区域距离观察者较远,且通常比较稀薄,因此出于对性能的考虑,将放弃使用ray marching进行渲染,而使用成本更低的2D面片加上动画模拟的效果来实现。
通过ray marching来渲染云层,可以很容易的实现水平线的弯曲效果
同时也可以通过收缩大气层的半径的方式来强制调小场景的scale。
由于ray marching的成本较高,为了避免无谓的浪费,在ray marching过程中,会使用两层LOD来设置step size,从而跳过那些云层之外计算
前面在介绍云层建模的时候说过,云层的模型有两种噪声,一种低频的用于生成基本的云层形状,另一种高频的用于丰富云层边缘的细节,因此高频噪声总是在底层噪声应用之后,对于云层边缘进行处理的。
这也就是说,只有在低频噪声采样过程中返回非零结果(云层)时,才需要进行高频噪声腐蚀所需要的相关计算,这种实现方式一方面可以节省成本,另一方面也有助于实现云层周边的isosurface效果(没找到这个单词的意思,推测应该是各项同性,即云层周边各个方向的细节比较接近)
因此,在渲染的时候,最开始的时候,是以一种较大step size的方式来进行简单采样,直到检测到与云层的碰撞,这个时候会回退一步(避免缺漏),并开始进行细密step size的采样计算,在细密采样的时候,同时进行高频噪声的采样计算。
另外,一旦ray marching的结果alpha值不小于1,就说明到此为止后面的光线都无法传过来,因此后续的ray marching就没有意义了,根据这一点可以实现一些优化。
而在ray marching过程中alpha如果一直没有达到1的话,就继续采样,直到采到的像素的密度为0,说明此时已经穿出云层了,继续恢复开始时的那种稀疏采样方式。
由于大气层的深度跟观察方向有关,因此Guerrilla在垂直方向上使用的采样点最多为64,而在水平方向上使用的采样点最多为128。不过这些采样点只是用于构建贴图的alpha通道的,如果需要计算光强的话,还需要更多的采样点。
这里展示的是实际渲染中的光强计算方式。在实际计算中,会对ray marching的每个采样点计算其输出的光强,这个光强需要考虑输入光强(主要来自于太阳光,包括直射光强跟次一级散射光强)以及沿着ray marching路径反向传输时的损耗,损耗在这里是由前面构建的alpha通道数据来表述(其实可以看成是衰减),因此实际的输出光强等于输入光强乘上对应的alpha衰减,就是此点贡献的光强。
在输入光强的计算中,Guerrilla需要进行六次采样,这六次采样都分布在朝向太阳的光锥之中,这种采样点分布方式有助于消除其他使用相邻采样点密度函数作为权重得到的banding瑕疵,此外,最后一点会需要放置在距离其他五点较远的地方,以便于捕捉到其他云层对挡墙云层的投影效果。
这里给出的是只使用alpha采样点进行光强计算的结果,其实已经很有云层的感觉了,如果每一点都按照前面所述进行六个采样点计算的话,消耗会非常高,为了平衡性能跟质量,Guerrilla选择对alpha数值高于0.3的ray marching采样点使用六点采样,低于0.3的则只使用一点采样,通过这种方式可以提升一倍的性能。
这里展示的是优化采样方法的结果,并没有看出来有什么异常。
这里给出的是每个光强采样点输出的能量值,每个点对应的d值是不同的(这里的r是什么东西?),之后将多个点的能量值加权求和之后,再根据ray marching采样点位置处的衰减系数进行传输衰减计算。
此外,前面说过,高层的alto以及cirro云是用2D贴图实现的,因此这里还需要对贴图进行采样计算
这里是Guerrilla搜集的不同种类的alto以及cirro云的素材,这些贴图会随着时间进行uv动画。
现实生活中的云彩由于各种不同频率的光线的作用,会呈现非常漂亮的颜色,这里由于是近似渲染,因此也需要为云层的颜色进行特殊处理,这里给出一些关于云层颜色的逻辑假设:
- 天光对云层颜色的影响随着海拔的增加而增加
- 方向光所导致的云层颜色应该以太阳光为主
- 云层距离相机越远,由于大气散射作用的存在,云层可见度也越低
因此,基于以上三点,云层的颜色应该等于天光与太阳光的加权乘上大气散射导致的衰减系数。
根据前面介绍的相关方法,就可以实现实时的动态的云层渲染了,且其消耗的内存也非常的低。
总结一下渲染的实现方法:
- 只在有必要的时候才进行高消耗的采样计算
- alpha ray marching采样点为64~128,每个ray marching点最多使用6个分布在椎体中的光强采样点
- 在alpha值小于某个阈值的时候,光强采样点数目从六个减低到1个
如果不进行性能优化的话,实现前面所说的云层渲染效果大概需要20ms,这显然还不能满足实时渲染的需求。
Guerrilla通过使用分帧渲染的方式来进一步提升性能表现。
将整个屏幕分割成4x4的block,每一帧只对每个block中的一个像素进行更新,其他像素则直接使用上一帧的渲染结果(这里有一个reprojection计算,即并不是按照uv直接取用,而是需要进行一次反向投影,找到上一帧中的结果)。此外,由于每帧渲染的像素数目较少,因此也不需要进行全分辨率渲染,输出的云层贴图的分辨率可以使用全分辨率的1/4 x 1/4。
对于那些无法通过reprojection获得结果的像素,将会直接从输出的低分辨率云层贴图中通过线性采样获取。
此外,如果将最终输出的云层显示结果贴图以1/2 x 1/2分辨率进行渲染,并通过上采样再输出的话,整个云层渲染的性能将达到未优化之前的十倍,即只需要2ms即可完成(不知道会不会有点糊)
这里给出的是PS4上采样的结果,前景的效果确实有点糊,不过2ms的预算能达到这样的表现已经非常令人震惊了。