[图形学] Killzone: Shadow Fall 中的体积光效果

reference : 《GPU Pro 5》

简介

        体积光效果是由于光线在潮湿、多尘或烟雾环境中散射产生的(如图3.1所示)。这是一个令人惊叹的自然现象,它可以用于创建壮观的图像,并为环境增添氛围感。

        关于光散射和体积光已经有了许多文章。它们的中的大多数都专注于提高渲染性能和图像质量的技术。但是,它们中的大多数都没有解决在现实中的游戏场景中实现效果所需要克服的挑战。

        在本章中,我们将讨论如何通过在Killzone : Shadow Fall中引入体积光效果以及我们如何处理在开发过程中遇到的问题,将我们的引擎提升到新的水平。

        

        图3.1 体积光效果的例子。

        我们面临的主要的挑战之一是找到一种方法,使得美术能够完全控制在场景中看到多少光量。我们还希望增加动画光强度动画的可能性,以创造更自然的效果。在本章中,我们将描述如何使用粒子效果和特殊的用于查找纹理的3D散射量来实现这一点。

        我们还需要找到一种方法来处理场景中的透明对象。这里的问题是,透明物体要么在体积效果之前,要么在之后渲染。如果先绘制透明对象,那么体积效果会阻挡它们。如果先绘制体积光效果,透明对象将阻挡体积光。我们将展示如何将体积光的强度存储在另一个3D纹理中,以及我们如何使用此数据将透明对象合成到场景中。

        我们的引擎使用延迟渲染。这意味着场景由多个阶段来表达。第一阶段中,场景形状的所有信息被记录在G-Buffer中。G-Buffer包含了照亮场景所需的所有信息,例如表面法线、反照率颜色、粗糙度、反射颜色等。第二阶段中,我们将所有灯光渲染到灯光累积缓冲区中。每个光是一个多边形,它渲染了光照亮的所有像素。这一过程使用了一个shader,它对G-Buffer中所有信息进行采样,并对每个像素执行适当的光照计算。所有灯光形状都附加地渲染到了灯光累积缓冲区中,以形成被点亮场景的图像。本章介绍的技术均适用于任何类型的技术以及渲染方法。但是,描述的一些实现细节仅与延迟渲染引擎相关。

基本算法

         为了渲染体积光效果,我们首先为每个光的体积渲染一个形状。对于点光源,我们将渲染球体,对于聚光灯,我们将渲染圆锥体,对于阳光,我们将渲染全屏四边形,因为阳光的体积覆盖整个场景。我们使用特殊的体积光着色器渲染每个形状。对于每个像素,着色器将计算与光的体积相关的视线的线段。然后我们进入ray-match循环,该循环在该线段上获取多个光贡献样本。美术可以定义我们在每个灯光下的ray-match步数。对于每个ray-match的步骤,我们计算样本的位置,并使用我们用于照亮几何体的那段代码来照亮样本。在进行光照计算时,我们假设我们正在照射一个面向光线方向的、完全漫反射的白色表面,以获得光在样本位置处的最大贡献。因为我们使用用于计算常规曲面的相同代码来计算光照,所以我们会自动支持我们拥有的所有光线特征,例如阴影映射、衰减范围、定义灯光颜色的纹理等。为了提高渲染性能,我们禁用了所有阴影过滤(反走样)的功能。我们发现从每个ray-match步骤的阴影贴图中获取一个简单的点样本足以创建足够好的结果,因此我们通过不进行任何高级阴影过滤来节约大量GPU周期。

        点亮的样本颜色将通过ray-match步长和散射因子进行缩放(衰减),散射因子决定了体积光的强度。在3.2.3节中,我们将描述如何计算散射因子。最后,将所有的ray-match进行样本相加,并将效果添加到场景中。

扫描二维码关注公众号,回复: 5782657 查看本文章

      泛光灯与聚光灯

         在泛光灯和聚光灯的体积光着色器中,我们首先定义从摄像机位置到屏幕像素的世界位置的光线(如图3.2(a))。通过从深度缓冲区获取像素的深度值,并通过使用视图-投影矩阵的逆将其投影回世界空间来计算世界位置。下一步是找到光线进入并在球体或圆锥体的交点。基于这些交点,定义一个线段,表示穿过灯光体积的线段(图3.2(b)),体积光着色器将在此线段上采集多个样本来呈现体积光的效果(如图3.2(c))。我们通过深度测试渲染泛光和聚光灯形状,确保能够丢弃场景几何体遮挡的像素。图3.3显示了放置在带孔的阴影投射球体内的体积点光源的示例场景。此示例场景将始终作为我们的参考。

        

        图3.2 (a) 泛光灯的初始光线 (b) 灯光体积相交测试后的线段 (c) Ray-Match采样

        

        图3.3 示例场景,显示放置在带孔的阴影投射球体内的体积阴影投射点光源。

        太阳光

        对于阳光,我们使用层级阴影映射(cascaded shadow mapping)。因为我们使用延迟渲染,我们可以分别渲染每个阳光的层级。这个方法非常有用,因为我们可以为每个层级重复使用相同的阴影映射,因此可以节省大量的渲染缓冲区内存。

        为了渲染太阳光的体积光效果,我们使用特殊的阳光体积光着色器,在每个阳光层后绘制全屏的四边形。对于每个像素,着色器将从层级的近深度沿着视线进入级联的远深度(图3.4(a)和3.4(b))。当我们的Ray-match样本深度比深度缓冲区中的值更深时,我们将跳出Ray-match循环。

        我们将沿着每个全屏四边形渲染与层级近平面深度相同的深度,并使用深度测试确保我们不渲染场景几何体遮挡的层级像素。

     

        图3.4 (a) 每个阳光层级的初始射线,红色显示由于深度测试失败而未呈现的层级的位置 (b) Ray-match每个阳光层级的样本。红色十字显示我们跳出Ray-match循环的位置。

        散射因子

        散射系数将决定体积光的强度,并由两个因素控制,即散射量和散射相位函数(见方程式(3.2))。散射量,也被称为散射系数,描述了光在各个方向上散射的程度。美术可以根据每束光来确定散射量。对于太阳光,我们还提供了根据高度和视距设置散射量的衰减范围的可能性。

       

        图3.5 Mie-scattering:当光线被较大粒子散射时,向前方向散射的更多。

        在第3.5节中,我们将描述如何通过使用3D查找纹理来更准确、更动态的控制散射量来扩展系统。散射相位函数定义了散射光的角分布。相位函数可用于确定总散射光有多少散射到相机上。对于KillZone:Shadow Fall中的体积光,我们想模拟尘埃、薄雾和烟雾等气体溶胶对光的散射。光被气体溶胶散射的方式可用Mie散射来描述。Mie散射表明,当大气中较大的粒子散射光时,光的正向散射会更大(图3.5)。为了近似Mie散射相位函数,我们使用了Henyey-Greenstein相位函数:

        

        方程式(3.1)中g值控制着正向散射的光线数量(图3.6)。这个值实际上应该基于大气中导致光散射的粒子的类型,但是出于实际原因,我们对它使用一个常量值,美术可以对此进行调整。然后,我们计算特定视角下的散射因子fSF:

        

        

        图3.6 Henyey-Greenstein相位函数在g取不同值下的结果。

低分辨率渲染

        我们使用的ray-match是非常好的,因为它的实现相对简单。然而,缺点是我们需要大量的样本来使它看起来更好。我们采集的样本越多,体积光着色器消耗就越大。为了提高渲染性能,我们决定以较低分辨率进行渲染。我们尝试以四分之一分辨率进行渲染,但发现质量损失太大,所以我们决定使用半分辨率来渲染效果,我们称之为体积光buffer。为了能够以较低分辨率进行渲染,我们还需要相应地缩小深度,以便在渲染体积光时仍然可以使用深度测试。这样的方法另一个优点时,从半分辨率深度进行采样会更快。

        双边上采样

        半分辨率的体积光将使用一个双边上采样着色器进行合成,该着色器将以叠加的方式添加到场景中进行渲染。双边上采样(Bilateral upsampling)将确保我们能够很好地合成分辨率缓冲区,而不会在高分辨率图像边缘形成模糊的伪影(如图3.7(a))。

        图3.7 (a) 使用常规双线性滤波器进行上采样会导致边缘模糊; (b) 使用双边滤波器进行上采样,以保持锐边; (c)经过MSAA抗锯齿滤波器处理后的图像。

         对于每个全分辨率的像素,我们对四个最接近的半分辨率像素的深度和颜色进行采样。然后,对于四个样本里的每一个计算权值,作为常规双线性滤波。然后,根据高分辨率深度和样本的半分辨率深度之间的差异,缩小每个权值。深度差异越大,半分辨率样本的权值越低。所有权值最终都要除以它们的总和以确保归一化。四个样本按照其权值比例进行缩放,并加在一起形成最终的颜色(图3.7(b)和3.7(c))。

Dithered Ray Marching

        为了进一步提高渲染性能,我们决定减少进行Ray-match步骤的数量。降低Ray-match步骤的数量将导致体积光中出现带状伪影(图3.10(a)和(b))。这是因为每个样本对最终图像的影响更大,因而欠采样导致的误差会更大。

        为了减少伪影,我们添加了一个小的灰度抖动的纹理(图3.9(a)),它在屏幕上平铺。对于正在渲染的每个片段,我们使用该纹理进行采样,并根据灰度值在深度上设置Ray-match的采样位置。纹理中的值取值范围在0.0到1.0之间,其中1.0定义的位置与两个Ray-Match样本之间的距离相同(图3.8(b))。

        抖动纹理(图3.9(a))的大小为像素4x4。抖动纹理的Ray-match偏移的分布基于Bayer矩阵。像这样分布的偏移能够确保每个连续的偏移在纹理内具有最大的二维距离。由于4x4边界内的每个体积光像素将获得不同的偏移,因此我们得到一个很好的抖动效果(图3.10(c))。

        

        图3.8 (a) 不使用抖动偏移的Ray-match采样。 (b) 使用抖动偏移的Ray-match采样。

        

        图3.9 (a) 4x4像素灰度抖动纹理 (b) 样本偏移。 纹理中的值为显示值的1/16th。

        双边高斯模糊

        使用双边高斯模糊滤波器,我们可以过滤抖图案,使得图像更加平滑。双边高斯模糊将通过两个pass完成。在第一遍中,过滤器将水平模糊图像,使用一个着色器,将抖动的图像复制到另一个缓冲区,该着色器将对原像素和其两侧的三个像素进行采样。对于每个样本,根据高斯分布函数计算权重。然后,根据样本深度与原像素深度之间的差异缩放每个权重。深度差异越大,权重越小(图3.11)。我们将权重除以总和,得到归一化的结果。最终着色器的输出颜色是通过将所有加权样本加在一起计算出来的(图3.12(b))。

        

       图3.10 (a) 由泛光灯投射的体积光,放置在阴影投射球体中,使用Ray-match(256)渲染。 (b)将步骤次数减少到32个步骤会导致不好看的效果。 (c) 使用32步加抖动图像决定采样位置的方式渲染的Ray-match体积光。 (d) 使用双向高斯模糊滤波器后的最终结果。

        

        图3.11水平高斯模糊pass。当前正在处理的像素标记为红色。左侧显示颜色(顶部)和深度(底部)输入样本,右侧显示了基于高斯分布和深度差的未归一化的样本权重。

        

        图3.12 (a)使用抖动的原图像 (b)应用水平双边高斯模糊后的结果 (c) 应用竖直双边高斯模糊后的结果

        在第二个pass中,我们使用相同的技术复制图像,但是现在我们将对当前像素上方的三个像素和下方的三个像素进行采样,以获得垂直模糊,最后结果是一个平滑的图像,其中锐利的物体边缘仍然保留(图3.12(c))。

控制散射量

        到目前为止,我们的实现已经能够得到一些好看的体积光效果。然而,效果看起来过于均匀、静态,它没有灰尘或者烟雾的感觉。我们也没有足够的控制来确定在场景中的什么区域,什么时候看到以及应该看到多少体积光。我们需要一种更精确、更动态的控制体积光的方法。

        为了克服这些问题,我们提出了一种利用粒子效应来控制散射量的解决方案。使用粒子效果的原因是,它们允许我们以非常灵活的方式定义一个体积,它们集成在我们所有其他游戏系统中,并且是创建动画烟雾和灰尘效果的理想选择。粒子渲染为3D纹理,该纹理将在屏幕上每个像素的深度上有着多个散射量值。3D纹理的宽度和高度是屏幕渲染分辨率的1/8,并且有16个深度切片,buffer保存单精度16位float值来存储数量之,并将用于存储深度达128m的数量。为了提高靠近相机的深度分辨率,我们使用以下公式来分布深度切片:

        

        该方程计算每个切片索引(i)的深度(d),N定义了深度切片的数量,R确定我们要覆盖的深度范围。C定义函数的曲率。C=1.0意味着深度切片在整个深度范围内均匀分布。较高的C值将使得摄像机附近的切片靠得很近,并使远处的切片分散的更远。我们在具体实现中使用c=2.0来获得一个良好的分布。表3.1和图3.13显示了使用16个深度切片和128m深度范围时,深度切片的分布。

         

             表3.1 深度切片的深度

       为了计算给定视图空间深度的三维纹理查找深度坐标,我们可以使用以下公式:

        

        如方程所示,我们将视图空间深度除以深度范围R,然后将计算1/c的幂,这是曲率常数c的幂的倒数。这将给我们提供可用于采样3D纹理的归一化深度坐标。用于计算3D纹理查找坐标的代码如list3.1所示。

        

        图3.13 深度切片分布(N=16,C=2.0,R=128.0)

float GetLookupDepth(float inViewSpaceDepth)
{
    float depth_range = 128.0; // < Depth range R
    float inv_curve_power = 1.0/2.0; // <Inv. power(1.0/C)

    return pow((inViewSpaceDepth / depth_range), inv_curve_power);
}

         列表3.1 计算给定视图空间的深度的三维纹理查找深度坐标。

        我们将粒子渲染为面向相机的公告牌。粒子的alpha通道将用于确定散射量。为了计算一个粒子在每个深度切片上的影响,我们使用list3.2中所示的代码。在函数中,我们首先计算3D纹理查找深度的坐标;然后,我们将该值缩放到0.0到15.0的范围内,以在深度切片索引的范围内对其进行映射。结果particle_slice_pos定义了切片间粒子的位置。粒子对每个深度切片的影响基于particle_slice_pos和每个切片索引的差的绝对值。我们将该值描述为距离,因为它描述了纹理空间中粒子到深度切片的距离。

        如果距离为0.0,则粒子位于与深度切片相同的深度,且粒子的影响为1.0;大于等于1.0的距离意味着颗粒距离超过了一个层,影响为0.0。对于0.0和1.0之间的距离,其影响等于距离的反向值。对于任何切片指数,可以通过将距离值限定在0.0到1.0范围内,并使用f(x) = 1 - x将结果反转为1.0到0.0范围内,来计算影响。

float GetAmountValue(float imParticleDepth, float inScatteringAmount, int inSliceIndex)
{
    int num_depth_slices = 16;//<Number of depth slices
    float particle_slice_pos = GetLookupDepth(inParticleDepth) * (num_depth_slices - 1);
    
    float distance = abs(particle_slice_pos - inSliceIndex);
    float influence = 1.0 - saturate(distance);

    return inScatteringAmount * influence;
}

        列表3.2 对单个深度切片来计算粒子散射数量

        

        图3.14 (a) 使用三维散射量查找的场景 (b) 散射量3D纹理的前视图 (c) 3D纹理中间扫描线的顶视图。图像底部靠近相机。

        每个深度切片的数量值随着getAmountValue函数返回的值而递增。当所有粒子都被渲染后,我们最终得到了一个3D查找纹理,它为屏幕上每个像素的散射量提供了深度上的近似值。在Ray-match循环中,我们使用list3.1中的函数在适当的视图空间深度下对每个Ray-match步骤的3D纹理进行采样,以获得散射量。然后,散射量按每一个Ray-match步骤所经过的世界空间距离进行缩放。虽然散射量的深度的表示不是很精确,但它确实给了我们对场景中不同位置的体积光量的很大控制。强度的微小变化会使效果看起来更自然(图3.14-3.17)。

        

        图3.15 测试场景,显示粒子效果如何在场景中不同位置引起光的散射。在左图中,粒子效果被放置在靠近相机的位置,以使得最靠近聚光灯的光线散射。在右图中,相同的粒子效果被移到离相机更远的地方,使得光线散射到后面的聚光灯上。

        

        图3.16 (a) 由放置在场景中的粒子效果控制的体积光散射。注意太阳光只分布在靠近树的地方 (b) 体积光 (c) 散射量分布中间扫描线的俯视图,显示深度上的散射量,图像底部靠近相机。(d) 散射量的单个深度切片

        

        图3.17 (a) 森林景观,粒子效果仅用于在树木之间产生光散射 (b) 体积光 (c) 数量分布中间扫描线的顶视图,图像底部靠近相机 (d) 散射量的单个切片,显示控制散射量的粒子

        

         图3.18 (a)具有体积光效果和透明物体的场景,请注意,背景中的深色透明对象没有和体积光正确结合在一起 (b) 同一场景使用体积光强度buffer将体积光与透明对象做适当混合 (c) 烟雾效果与体积光的不恰当混合 (d) 使用体积光强度buffer将烟雾与体积光效果适当混合的效果。

透明物体

        当渲染使用alpha混合的透明对象时,我们渲染体积光并将其混合到场景中的方式会导致问题(图3.18(a))尤其是alpha混合粒子效果并没有与体积光效果适当混合(图3.18(c))。根据渲染排序,要么将体积光绘制在所有透明对象的前面,要么将透明对象遮挡住体积光效果。为了解决这一问题,我们必须找到一种方法让透明的着色器知道体积光的存在。如果我们知道透明表面前面有多少体积光,我们就可以将体积光与透明物体适当地混合(图3.18(b)和(d))。

        我们提出的解决方案类似于我们以前用于控制散射量的技术。我们不存储特定深度的散射量,而是将体积光的累积强度存储在另一个3D纹理中,我们称之为体积光强度buffer。

        对于每个Ray-match步骤,我们将计算Ray-match样本颜色的亮度,然后,我们将使用样本的视图空间深度来确定样本在3D纹理的每个深度切片上的影响。然后,每个深度切片的强度值随着影响缩放的样本亮度增加。

        我们使用list3.3中所示的函数来计算3D纹理切片的强度值。计算光线强度对深度切片的影响,使得第一个更近的切片将根据切片指数和样本切片位置的差来得到线性插值的效果。所有更深的切片得到1.0的效果,更近的切片得到0的效果。

float GetSliceIntensity(float in SampleDepth, float inIntensity, float inSliceIndex)
{
    int num_depth_slices = 8; // < Number of depth slices

    float sample_slice_pos = GetLookupDepth(inSampleDepth) * (num_depth_slices - 1);

    float sample_distance = sample_slice_pos - inSliceIndex;
    float sample_influence = 1.0 - saturate(sample_distance);

    return inIntensity * sample_influence;
}

        列表3.3 计算单个深度切片的体积光强度

        由于体积光着色器是以半分辨率而不是1/8分辨率渲染的,因此出于性能原因,我们需要将体积光强度的深度切片减少到8,并将效果距离减少到64m。当所有的灯光都渲染完毕后,体积光强度buffer将近似于所有体积光的强度,在深度上阻挡场景(图3.19(b))。

        

        图3.19 (a) 球体示例场景 (b) 体积强度分布的一条扫描线的俯视图

       合成体积光后渲染的所有透明对象将在适当的视图空间深度对体积光强度进行采样,以确定前面有多少体积光。我们使用List3.1中所示的相同函数来计算3D纹理查找深度坐标,但使用深度范围的调整至来解析减少的深度范围。对于inViewSpaceDepth参数,我们传递透明面片的视图空间深度。三维纹理查找的结果将表示透明表面前面的体积光的强度。

       公式(3.5)显示了我们如何计算透明着色器的新表面颜色:

        

        OrgColor是材质球的原始输出颜色。VLBufferColor是从体积光buffer中采样的颜色,其亮度称为VLBufferIntensity。SampledIntensity变量是指从前面描述的体积光强度buffer中采样的强度。通过将采样强度除以VLBufferIntensity,计算出遮挡表面的体积光比例。VLBufferColor按分数缩放并添加到原始表面颜色中。

局限性

        由于我们的三维查找纹理的深度分辨率低,采样的散射量和光强度值不太准确,虽然我们从当前的实现中得到了一些好看的效果,但仍然有一些限制和不足需要提及。如3.8.1节描述,通过增加3D纹理深度分辨率或使用不同方法存储深度值,可以解决大多数问题。

       散射数量缓冲区

        当光(尤其是在较远的距离上)拾取了错误的散射量值时,可以看到伪影。当摄像机在场景中来回移动时,某些灯光的体积光强度可能因此而淡入淡出。为了将这些伪影降到最低,我们只使用粒子来大致消除较大区域的散射。我们还要确保在深度上渲染足够多的粒子,使得深度上的散射量尽可能平滑,并确保数量之保证自然的外观。

        与透明对象结合

        我们将透明对象结合到场景的解决方案对于靠近相机的透明对象很有效。然而,当体积光效果接近透明物体并在更大距离观察时,强度曲线不够精确,无法正确确定透明表面前面的体积光数量。在这些情况下,透明对象可能看起来比它们应该的更暗或更亮。当来回移动相机时,前面描述的衰减伪影也能在透明物体上看到。但是,在场景中透明对象的结合仍然比之前的完全不考虑体积光的效果要好。更好的算法可以在深度上存储值的和或,来提高3D纹理的深度分辨率以减少这些瑕疵。

        此外,该技术不能区分不同的体积光源,这可能会导致问题。如果我们后面有红色、绿色和蓝色的体积光,那么最终的体积光颜色将是白色。透明物体将于最终的体积光和不同的颜色混合,从而造成与白色混合,而它们实际上应该知道不同深度的不同颜色,这会造成一些伪影。在这些伪影中,放置在体积光中的透明物体会显示出其它体积光在更大距离出产生的奇怪的颜色差,而这根本不会影响透明物体。将红色、蓝色和绿色强度单独存储在强度buffer中可能会解决这一问题,但是,由于我们的性能和内存限制,我们没有进一步研究这一问题。只要一个场景中的灯光颜色变化不大,那么这一问题就很难被注意到。

未来的改进

        曲线压缩法

       通过使用某种形式的曲线压缩算法不同程度的存储深度值,而不是直接存储在3D纹理中,可以提高散射量和体积光强度分布的精度和范围。其它与透明阴影投射对象渲染相关的文章,提出了存储深度值的替代方法。它们描述了如何在深度上存储透光率函数,我们的解决方案可以从这项研究中获益。另外,使用离散余弦变换(DCT)或快速傅里叶变换(FFT)来存储散射量和体积光强度也可能是值得研究的课题。

        不幸的是,由于我们的分布计划很紧,我们没有时间去找到一个更好的解决方案,它既能提高质量,又能保持可接受的性能。

        Epipolar采样

        为了提高渲染性能,我们降低了体积光的分辨率,从而减少了Ray-match采样的数量.Epipolar采样也大大减少了Ray-match采样的数量,然而,它并没有降低屏幕空间的分辨率,而是相对于观察者的位置,降低光源外Ray的分辨率。通过这些Ray降低远处分辨率并不明显。通过使用Epipolar采样,我们应该能够在不损失甚至提高质量的情况下,更大程度地执行减少Ray-match循环的像素数量。

结论

        我们已经展示了体积照明效果在Killzone:Shadow Fall中的实际应用。使用半分辨率Buffer和抖动的Ray-match Buffer设置,我们提升了性能并保持了良好的图形质量。

        我们设法让美术完全控制场景中的体积光强度,通过使用粒子渲染3D纹理来减少光的散射量。

        通过渲染另一个三维查找纹理,定义了体积光深度上的强度。我们解决了大多数与透明对象相关的合成问题。

        虽然我们的方法有局限性,但它确实显示了一种决绝方案,解决了我们在开发Killzone:Shadow Fall体积光效果时发现的一些问题。

参考

[Bayer 73] Bryce Bayer. “An Optimum Method for Two-Level Rendition of Continuous-Tone Pictures.” IEEE International Conference on Communications 1 (1973): 11–15.


[Henyey and Greenstein 41] L. G. Henyey and J. L. Greenstein. “Diffuse Reflection in the Galaxy.” Astrophysical Journal 93 (1941), 70–83.


[Lokovic and Veach 00] Tom Lokovic and Eric Veach. “Deep Shadow Maps.” In Proceedings of ACM SIGGRAPH 2000, Computer Graphics Proceedings, ACS, pp. 385–392. New York: ACM, 2000.

[Pham and van Vliet 05] Tuan Q. Pham and Lucas J. van Vliet. “Separable Bilateral Filtering For Fast Video Preprocessing.” In Proceedings of the IEEE International Conference on Multimedia and Expo, Article no. 1521458.Washington, DC: IEEE Computer Society, 2005.


[Salvi et al. 11] Marco Salvi, Kiril Vidim`ee, Andrew Lauritzen, Aaron Lefohn, and Matt Pharr. “Adaptive Volume Shadow Maps.” In GPU Pro 2, edited by Wolfgang Engel, pp. 225–241. Wellesley, MA: A K Peters, Ltd., 2011.


[Shopf 09] Jeremy Shopf. “Mixed Resolution Rendering.” Presentation, Game Developers Conference 2009, San Francisco, CA, March, 2009. (Available at http://developer.amd.com/wordpress/media/2012/10/ ShopfMixedResolutionRendering.pdf.)


[Sloan et al. 07] Peter-Pike Sloan, Naga K. Govindaraju, Derek Nowrouzezahrai, and John Snyder. “Image-Based Proxy Accumulation for Real-Time Soft Global Illumination.” In Proceedings of the 15th Pacific Conference on Computer Graphics and Applications, pp. 97–105. Washington, DC: IEEE Computer Society, 2007.


[Valient 09] Michal Valient. “The Rendering Technology of Killzone 2.” Presentation, Game Developers Conference 2009, San Francisco, CA, March, 2009. (Available at http://www.guerrilla-games.com/publications.)


[Yusov 14] Egor Yusov. “High Performance Outdoor Light Scattering Using Epipolar Sampling.” In GPU Pro 5, edited by Wolfgang Engel, pp. 101–124. Boca Raton, FL: A K Peters/CRC Press, 2014.

猜你喜欢

转载自blog.csdn.net/ZJU_fish1996/article/details/87352770