游戏地图技术Terrain Splatting

  spalatting技术指的是在terrain中给指定的tile贴纹理,并且所纹理之间是非线性过渡的.这种技术基本上不耗费CPU,通过显卡多次渲染同一个三角形,在帧缓存中合成纹理.

基础Splatting

    把terrain分成若干个块,对每个块,找出影响它的所有贴图,即块中所有单元(一个或多个tile,取决于你的粒度)所用的贴图和紧邻这个块的单元所使用的贴图.这就是所谓的"splat块"和"splat纹理".为每个块创建顶点缓存,优化.

    对当前块中的每个splat纹理,取所有使用该纹理或与该纹理相邻的单元,创建三角形列表,优化.每个三角形列表就称为一个splat。每个splat块就由若干个相互交叠的splat组成。

    为每个块生成alpha值,让它沿着边界淡出,可以使用顶点的alpha值,但这样要修改顶点缓存,所以我们可以通过生成一张alpha纹理来完成。为每个splat创建一张覆盖整个块的纹理,精度为每个单元2*2像素,对每个像素,找出splat纹理对应的权重.此权重由周围9个单元的纹理影响计算得出,每个texel对权重的影响为从对应单元的中心点按距离递减,到1.75个单元时为0,公式为: Weight(pt1, pt2) = 1 - DistanceSquared(pt1, pt2) / (1.75)^2)(可以设计自己的权重计算公式).计算出所有权重后把它们归一化,使它们相加为1.计算结果为每个splat一张alpha map.

现在从splat纹理中取颜色,alpha map中取alpha值来渲染splat。
可以利用multi-texturing: 背景纹理为Stage 0,alpha map为Stage 1。

D3D设置如下:
// Stage 0 coloring: texture0 * diffuse
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
// Stage 0 alpha: nada
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
device->SetTextureStageState(0, D3DTSS_ALPHAARG1, DECTA_CURRENT);
// Stage 1 coloring: nada
device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
// Stage 1 alpha: texture1
device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
device->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);

 

    注意每个splat的uv不同,在创建顶点缓存时使用标准网格的uv,然后为每个splat使用纹理矩阵把网格映射到对应的tile上,具体说来,Stage 0(splat纹理)的uv每几个单元用一个,Stage 1(alpha map)uv拉伸到整个块。

对不支持multi-texturing的硬件:
    对每个splat,首先用alpha map做为纹理进行渲染,在帧缓存中写入alpha值(32位帧缓存),然后用splat纹理再渲染一遍,取帧缓存中的alpha值(destination alpha)来做混合。

    以上方法有一个细节问题,在两个splat相交处,第一个splat以50%的alpha和帧缓存颜色混合,第二个splat又以50%和当前颜色混合,所以最终结果的25%会来自以前帧缓存中的颜色。最简单的修正办法是先以terrain中最常用的纹理渲染一遍整个terrain,之后的步骤中就不用再构造这个纹理的splat。

    这样所完成的splatting,纹理之间的过渡是线性的(其实是二次的,但非常规则),这种方法得到的纹理有很高的细节。注意要设置splat之间的顺序,比如给每种纹理设置一个优先级,不同顺序渲染出来的效果不一样。

增强Splatting: 1.基础Pass和淡出

可以制作一个"基础纹理(base texture)"来修补splat之间的空洞.通过一个pass来生成这个基础纹理,大小为每个单元4*4 texels.把所有splat纹理用权重(跟上面的alpha map计算方法一样)混合起来得到基础纹理,基础纹理的精度很低,所以使用splat纹理的4*4 mip生成就够了.这样就得到了一张精度很低的terrain贴图.这次就不需要用前面的方法了,在splat过渡的地方会显示基础纹理.

有了这个基础纹理,就产生了另一种可能,在远处只使用基础纹理就足够了,不需要splat.所以我们让splat淡出,到一个指定的距离时关闭.跟制作细节纹理(details texture)的方法相同: 使用顶点alpha,或者把淡出加入到alpha map的mips中.即对alpha map过滤,使产生的mips越来越透明,到4*4 mip(或指定距离对应的mip)时完全透明.这种技巧只有在需要绘制很远的地方时才有优势.

    基础纹理和alpha map都会有通常的块状问题,即在块的边界处由于过滤产生的问题。可以通过沿边界复制像素和把uv起点向纹理内移动半个像素来解决。

增强Splatting: 2.调整alpha值

    有许多方法可以调整alpha map中的alpha值。第一种很简单:把权重的和归一化到比1大的值,然后截断到1。这样就能让基础纹理显示得少点高层纹理显示得多些。

    另一种方法是基于所在的splat层偏移alpha值。增大底层的alpha,减少顶层的alpha。
    方法是对于每个单元,生成alpha map时检查所有相邻的splat,就可以得到当前纹理所在的层。算出下面和上面的层数,然后把alpha值乘以(number_above + 1)/(number_below + number_above + 1)。

最后还可以给alpha增加一点随机值来改进效果。

增加Noise

增加noise可以让splatting纹理的过渡看起来不规则。
这里的noise是splat纹理的alpha通道.在绘制时纹理和alpha通道一起绘制,在noise pass中使用。
生成基础纹理时忽略alpha通道。

noise pass简单地重新渲染一遍splat,把这个alpha混合进去。
D3D设置:

// Stage 0 coloring
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
// Stage 0 alpha
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
// Stage 1 coloring
device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
// Stage 1 alpha
device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
device->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
device->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);

 

    noise alpha通道通常最大值在200左右,不会完全不透明。在splat的中间部分,noise pass不起作用,只是重画一遍像素,在过渡区域,会使得纹理产生不规则的影响.因为不用渲染基础纹理,noise pass增加的三角形数量会少于一倍。
    noise也可以和splat一样淡出,通常会比splat淡出得更快。因为渲染的是同一个顶点缓存所以noise alpha效率很高。

http://www.cbloom.com/3d/techdocs/splatting.txt

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值