《荒野大镖客2》的大气云雾技术
导语:这时候,none-physically-based就还是需要了,这时候建议是,尽可能在高层去做hack和变通,保持底层原子项部分的“physically based“正如phase function这里,底层是HG function,高层是美术来指定的函数。 visibi 这时候,none-physically-based就还是需要了,这时候建议是,尽可能在高层去做hack和变通,保持底层原子项部分的“physically based“正如phase function这里,底层是HG function,高层是美术来指定的函数。 visibility项 ![]() 这一项就是光照信息中间被遮挡的情况,和直接光照有点不一样的是,由于这个是一个scattering的过程,所以完整来讲是光线一路射过来中间每一步的visibility情况的叠加。 ![]() 落实到实际计算中,就是ray marching中间每一步的visibility情况的叠加。 这里visibility主要针对影响大的两个case:terrain、cloud来做计算。 terrain使用ray marching的方式构建一个shadowmap信息; cloud使用exponential shadow map的方式,来encode shadow map信息,来达到非常软阴影的信息,一共存了6mips(esm的使用在刺客信条的文章里也有)。 lighting项 ![]() ambient lighting部分: 远处的ray marching部分,就是sky ambient,把sky scattering存到低精度的paraboloid贴图里面 近处的frustum voxelization部分,sky light+light probe lighting*AO ![]() local light 部分,直接就读light cluster volume。 ![]() froxel froxel也是技术创造的名词:这个的缩写frustum voxel; ![]() 也是用voxel的形式,存储低精度的场景volume信息,然后用于低频信息渲染,比如scattering; 《荒野大镖客2》中的存了三种信息: shadow material lighting (结合前两者来计算) ![]() shadow volume,注意这个不是阴影算法的shadow volume,就是存放shadow的volume信息,包括了普通shadow和cloud shadow; 中间使用了temperal filtering来处理稳定的问题; ![]() material volume,各种材质信息,也带上了wind交互等等(让我想起了战神的风力存在volume中)。 也有temperal filter。 ray marching ![]() 可能有的读者对ray marching还不是特别熟悉,ray marching特别常用于volume类的渲染中,鉴于一些计算硬件和数据的限制,有些情况难以很容易的使用ray trace的方式寻找交点,比如local reflection中要对depth buffer找交点。那么就用步进的方式来找交点,这种方法就是ray marching;这里的步长的选择是应用ray marching的时候需要具体斟酌的地方。 ![]() 回到《荒野大镖客2》,ray marching的步长策略选择也是颇费心思: 考虑到场景深度、ground plane、cloud dome 另外要仔细考虑到云层的厚度信息 即便这样也很容易跳过比较薄的云层。 ray marching优化 先看下最终的性能 ![]() 可以看到ray march是占据着性能的大头,而且这还是经过优化过之后的结果。 这里优化就基于两个大的策略:low resolution + temperal,也就是在低分辨率上做ray march计算,然后通过多帧来重建。 这个部分很精彩,我们多展开。 ![]() 这里ray march的起点是在froxel的末端,带上blue noise(可以理解成一个频率较高的noise了,感兴趣可查下)做偏移。 半分辨率大小,然后分4帧来计算。 ray march reconstruct ![]() 由于是分4帧来构建,所以每帧只能ray march 2x2 像素中的一个,另外三个就要从history buffer中拿。 这里用了temperal相关的很多做法,一些在taa中颇为常见。 1、使用了3x3像素color aabb clamp的方式 2、大的深度断裂的地方,临接像素就不考虑了 3、在深度断裂(depth discrepancies)的地方,放更多的ray 这里能正确的判定出来depth discrepancy还是比较棘手的,要做的事情就是在6x6(2x2 ray, 3x3 neighbouhood, 所以一共6x6)像素中,正确的识别depth的min/max; 尝试1,uniform分布 ![]() 可以看到在frame2里面,min/max就错了,这个会导致误判。 尝试2,checker board方式 能处理的case好很多: ![]() 但是这种情况下还是不行: ![]() 总之局部的分布策略总是有cover不住的情况了,还是要引入整体的信息才行。 尝试3:checker board+depth neighborhood analysis 先是拿到3x3tile(每个tile是2x2像素)的depth min/max,然后每一个tile中和其余的8个点比,如果其余的8个都是min,那么这个就取一个max depth的点。 (编辑:二游网_173173游戏网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |