【译】《GPU GEMS 3》----Next-Generation SpeedTree Rendering 翻译[1] 收藏
最近在研究树木的渲染,看了一些相关的技术说明,几乎都是老外写的,再次为中国游戏产业的前景感到担忧。看了几天的英文,索性也把其中的重要部分翻译了出来,在这里与大家共享,先贴出《GPU GEMS 3》第4章的翻译,第一次写翻译,不免有错漏的地方,欢迎大家指出。如需转载,请先与本人联系。name:LeYond ,qq:413952706
第四章 下一代SpeedTree渲染
4.1. 导言
SpeedTree是IDV开发的中间层程序包,用以渲染实时树木。游戏使用SpeedTree在选择如何渲染SpeedTrees有很大的自由度。我们讨论几种高质量的GeForce880的特性,对下一代SpeedTree进行扩展。首先边缘裁剪为树枝和树干的轮廓增加细节。其次,阴影贴图在树叶个体级别上增加真实的自阴影。除此之外,我们进一步简化叶子双面的光照模型和HDR的渲染。最后,伴随Alpha通道的多重采样抗锯齿产生非常高的视觉效果,避免了走样的现象。
4.2. 轮廓裁剪
树枝和树干都是有机、不规则且复杂的。图4-1就是一个典型的例子:虽然树枝都接近圆柱体,但轮廓的细节部分显得粗糙且不规则。一个中等精度或低精度的树干模型包含1000个面,是不能表现这些细节的。由此产生的笔直的多边形边缘是很难发现的,但它所生成的计算机图像中却又显得重要。
许多算法都可以帮助在树枝上长生大量的细节,就如图4-1所看到的。最原始且最广泛的便是用凹凸贴图技术。凹凸贴图技术在树干的内部(即非边缘)可生成不错的效果,就像图4-1中绿色方框里显示的那样。但是,他完全不可能在边缘生成如蓝色方框里显示的高度细节。同时它也不能生成因观察者的变化而产生的深度视差效果。有两种比凹凸贴图更好的技术:雕刻纹理relief mapping(Oliveira and Policarpo 2005),视差纹理parallax occlusion mapping (POM)(Tatarchuk 2006)。这两种技术都是在物体的表面进行光线跟踪,他们能增加视差和自身遮蔽的效果。(我们使用雕刻纹理来包含这两种效果。)在视察贴图中,该效果再次别限制于物体的内部,物体的轮廓毅然没有改变。题刻纹理提供了几种扩展,其中之一支持轮廓部分,但它需要而外的预处理来实现它。最终,模型的花纹和位移纹理都能同时被应用,但如果要渲染一个充满树木的森林的话,它的巨大开销在几何处理中是不值得的。
我们的方法,将在树干部分使用雕刻纹理,使得在树干内部产生细节,并增加技术来产生轮廓细节。这些都不被SpeedTree的着色器支持,但他们能够简单地加入,因为可以使用工具、文件还有在API中增加自己的函数,包括附加的纹理。
在轮廓部分,我们使用自己开发的轮廓裁剪的技术。虽然这个技术不像Sander et al. 2000中描述的那样,但效果非常相似。我们的技术是在物体的轮廓上垂直挤出薄片。这些轮廓进行像雕刻纹理中光线在高度图中的相似的计算。有了雕刻纹理在树枝多边形上的使用,这个技术不需要而外的预计算。
4.2.1 轮廓薄片的挤压
轮廓渲染的第一个不走是挤压薄片。我们通过平滑每个顶点的法线来使轮廓的边缘包含在三角形中。如果顶点法线和观察向量的点乘在三角形边缘改变符号,我们则在计算已经变换的观察向量和已经变换的法线的点积,在这个三角形边缘上,且点积等于0的位置新建一个顶点。图4.2是此步骤的示意图。
图4-2. 在一个观察方向,单个三角形上边缘的挤压
(a)顶点已经平滑的三角形 (b)观察向量的计算 (c)轮廓断点的计算 (d)薄片挤压
图4-2. 在一个观察方向,单个三角形上边缘的挤压
最近在研究树木的渲染,看了一些相关的技术说明,几乎都是老外写的,再次为中国游戏产业的前景感到担忧。看了几天的英文,索性也把其中的重要部分翻译了出来,在这里与大家共享,先贴出《GPU GEMS 3》第4章的翻译,第一次写翻译,不免有错漏的地方,欢迎大家指出。如需转载,请先与本人联系。name:LeYond ,qq:413952706
4.3 阴影
有了轮廓的效果提升,我们还要继续为提高阴影的质量而前进。因为对每个游戏引擎来说,一般情况下阴影技术都会有所不同,out-of-the-box SpeedTree的阴影是在程序未运行时便预计算好的,并且是固定不变的,所以SpeedTree能够工作在许多不同的引擎上。但这种方法有这些缺点:
· 当树木的模型随风运动时,阴影的动画只能运用纹理坐标的变化,如:拉伸,旋转等。
· 预计算阴影不能像动态一样的真实,特别是阴影投射到树干上时。
· 树叶没有自身阴影
4.3.1 树叶的自阴影
我们的第二个目标是让树叶面板上的树叶看起来有独立的阴影。(SpeedTree同时使用树叶面板和3D树叶模型;本节详细介绍树叶面板的自阴影。)树叶的自阴影并不简单,因为树叶公面板很单一,它用2D来表现复杂的3d物体。这些面板总是面朝摄像机,因此,他们总是平行于观察平面。图4-9显示了一棵使用面板的树。在这种方法上,我们使用阴影贴图(参阅King 2004关于阴影贴图技术的介绍.)让阴影有真实的表现,我们必须改变阴影贴图的生成过程和阴影贴图的投影方式。
图4-9 阴影贴图在树叶面板上的垂直投影
· 我们树叶的阴影贴图的生成大部分根据如下的标准进行渲染。树叶面板旋转至面朝观察者的位置。当渲染至贴图纹理时,他们旋转至面向光源使其能生成好的阴影投影。但是,如图4-10中的例子,它们绕自己的中心旋转时会有问题出现。在图中,浅颜色的树叶面板被旋转向观察者;绿色的树叶面板在相同位置,但现在旋转至面朝光源。在图4-10a中,绿色的树叶面板只会被蓝色树叶面板的下半部分所投影。为了解决这个问题,我们像图4-10b一样简单地旋转。我们故意地适当进行进行(向上)平移,这个量是树叶面板高度的一半。
· 树叶面板的几何平面在生成阴影贴图时有更重要的问题。像一个树叶面板平面应用了阴影贴图会导致在投影时出现细长的条纹(如图4-12)。只有在光源在眼睛附近才会运行良好。
· 在阴影实现阶段,为了让阴影生成更真实且没有条纹,我们通过改变它的方向改变阴影的位置。(请注意,我们不会改变几何体和光栅位置----树叶面板仍然是一个2d矩形。我们只通过计算来改变位置。)偏移系数被存储在一张纹理,面片中的每片树叶都被统一地交叉。图4-11显示了最终的纹理。通过这个新的树叶位置,我们将它投射到灯光空间并对阴影贴图进行采样。因为独立地修改了面板中的每片树叶,所以它必须在像素着色器中运行。所用的函数已经在清单4-1中详细地给出。
清单4-1 运行阴影贴图偏移像素着色器代码
float PSShadowMapFetch(Input In)
{
// Let In.VP and In.VV be float3;
// 让In.VP和In.VV转换为float3格式
// In.VP - interpolated Vertex Position output by VS
// In.VP – 从顶点着色器传入的已变换的顶点坐标
// In.VV - View Vector output by VS
// In.VV – 从顶点着色器传入的观察向量
// OCT - Offset Coefficient Texture
// OCT – 偏移系数纹理
// SMPP - Shadow Map Pixel Position
// SMPP – 阴影贴图像素坐标
// SMMatrix - transform to Shadow Map space
// SMMatrix – 转换到阴影贴图空间
float3 SMPP = In.VP + In.VV * tex2D(OCT, In.TexCoord).x;
float3 SMCoord = mul(SMMatrix, float4(SMPP, 1));
float SM = tex2D(SMTexture, SMCoord);
return SM;
}
图4-12显示了两种偏移的形式。(除了阴影效果外,为了突出阴影其他灯光和颜色已经被移除。)两种不真实的现象都可以再图4-12a中看到:由于2D的树叶面板垂直投影,会有纵向条纹的出现。当渲染阴影贴图时,在树叶面板上也会出现斜的条纹。在图4-12b,这些不真实的现象被去除了。结果非常细腻且自然。在我们的实时演示中,独立叶片的阴影会随风运动。
最近在研究树木的渲染,看了一些相关的技术说明,几乎都是老外写的,再次为中国游戏产业的前景感到担忧。看了几天的英文,索性也把其中的重要部分翻译了出来,在这里与大家共享,先贴出《GPU GEMS 3》第4章的翻译,第一次写翻译,不免有错漏的地方,欢迎大家指出。如需转载,请先与本人联系。name:LeYond ,qq:413952706
4.3.2 叠加阴影贴图
图4-15 照明比较
(a)预计算漫反射贴图 (b)逐像素阴影照明 (c)普通光照 (d)双面光照
4.4.2 镜面光照明
除了调节双面的照明,我们修改镜面光照,以提高其真实性。首先,在普通的镜面光照射下,远处的数目偏向微弱的闪光,所以我们随着距离的拉远而降低镜面光。下一步,我们我们注意到现实中的树叶有获取其他的光线。图4-16展示了一些经典的带有光泽的树叶,从这里我们总结出3点。镜面光反射是受控于树叶坐标轴的平面,它清晰地把镜面光划分开来.相对这些平面的效果,好的纹理细节和其他效果是微不足道的:镜面光不会有锋利边缘,因为他们有玻璃一样的材质。由于我们是对整棵树的构造感兴趣,而不是叶子的纹理,我们使用这些观察效果来简化我们的叶子镜面光照模型。要模仿轴的分离,我们使用一张更加粗糙的V形发现贴图,将叶子分开成两半。最后,因为太多的细节因为镜面光的加入而被闪光覆盖,我们偏移纹理在发现贴图中提取更低的Mipmap等级。结果将会更加平滑,也有更加温和的镜面光,而不会产生生硬的光照假象。
图4-16 此叶子照片展示了镜面光的现象
不幸的是,虽然提升了树叶的阴影质量,但没有从阴影贴图中去除其他场景。 在广阔的户外场景中,一张阴影贴图经常是不足够的。叠加阴影贴图(CSM)是解决这一问题的一种常见的技术,它通过把平截头体分解成若干个空间,并把每个区域渲染进不同的纹理当中。(关于CSM的描述可以查看Zhang et al. 2006。也可以查阅本书的第10章“在可编程GPUs上实现平行分割阴影贴图”获得更多相关技术。)
为了减少CPU的开销,不同级别的栅格有不同的绘制频率:
· 最靠近的栅格在每一帧都更新。所有属于它的物体都被渲染出来。
· 第二个级别的栅格是每两帧更新一次。大型植物没有渲染入阴影贴图。
· 第三个级别的栅格是每四帧更新一次。只有叶子才渲染进阴影贴图。
阴影贴图渲染之后,我们有许多方法在我们的3D世界种产生阴影:
1. 使用适当级别,在阴影贴图渲染物体时使用相同的命令。
2. 在每个层级中取出像素并混合它们。
3. 使用纹理数组并在像素着色器中选择适当的层级
4. 使用视口,将渲染目标分割为若干个阴影贴图。
每一种方法都有它自己的优点和缺点。在SpeedTree中,我们选择第二种设置。
4.4 叶子的光照
光照在观察者的感知中扮演着很重要的角色。SpeedTree的最新版本为树叶面板的逐像素动态光照提供了必要的数据,如切线和法线贴图。同时,SpeedTree的树叶面板能只使用预计算漫反射纹理。精细的光照和阴影能事先烘焙到漫反射纹理中。我们选择第一种解决方案,因为它支持全动态关照。
4.4.1. 双面光照
除了镜面光照,我们注意到,叶子的漫反射颜色取决于观察者跟太阳的位置关系。图4-13展现了两张叶子在不同的瞬间,在相同光照、相同曝光的设置条件下拍摄。(细心观察枯萎的褐色部分,你可以比较两张照片中的同一片树叶。一片用红色点标记。)当树叶背光时,大部分表现出是没有反射光;取而代之的是透过来的光。当光线穿过树叶,树叶的颜色会轻微第转向黄色或红色。
图4-13 试验观察方向的真实树叶光照
(a)树叶面光 (b)树叶背光
基于这种观察,我们已实施如下计划来模拟双面的自然照面。
· 黄色树叶颜色是在片段着色器中产生,float3向量各分量为(Diffuse.g * 0.9, Diffuse.g * 1.0, Diffuse.g * 0.2).
· 根据不同的μ—角度,如图4-14所示。是灯光方向向量和观察方向向量的夹角。
图4-14 背光中的叶子
取决于µ,镜面光成分会被削弱,因为背面没有光线会发生反射。这种做法可能看起来幼稚,但他让图片更加真实可信。如图4-15.