作者:Andrey Mishkinis
在本文中,我将解释如何贴图的抛雪球算法制作出更加自然的地形。这种算法在3D和2D游戏的着色器中都可使用。
上地形贴图的最常用方法之一是混合多个图层。各图层有一个确定地形纹理存在范围的不透明贴图。这种方法就是,把不透明贴图置于更高层级,露出不透明贴图是部分或完全透明的下级图层。不透明贴图是按百分比计算的。当然在地形的各个点上,所有图层的不透明度总和将达到百分百,因为地形不可能透明。不是拼贴材质,这个不透明贴图可能在所有地形上伸展,所以细节程度相当低。
现在,我们再来看看最有趣的部分——混合贴图的算法。为了简化,我们的地形只包含沙子和鹅卵石。
cobble-stones
混合的最简单做法就是,把贴图颜色的不透明度相乘,然后把结果相加。
float3 blend(float4 texture1, float a1, float4 texture2, float a2)
{
return texture1.rgb * a1 + texture2.rgb * a2;
}
这种技术在Unity3D的标准地形编辑器中有使用。正如你所见,过渡很平滑,但不太自然。石头看起来就好像被沙子污染了,但在现实世界中这是不可能发生的情况。沙子不会粘着石头,相反地,沙子会落下来,填补到石头之间的缝隙里,而石头表面仍是干净的。
我们试一下在Excel中模拟这种行为。因为我们希望沙子落在石头之间的缝隙之间,所以每一张贴图都必须有深度贴图。在这个例子中,我们把深度贴图当作由灰度图产生的图像,且被保存在贴图的alpha通道中。在Unity3D中,你可以在贴图检视界面中通过设置“来自灰度图的Alpha”标签来完成。
首先,我们要考虑沙子和石头的深度贴图的简化模型。
depth map
蓝线表示沙子的深度图,红色表示鹅卵石。注意,石头顶部高于沙子层。考虑到这个事实,我们将尝试绘制出超出部分的贴图的像素点。
float3 blend(float4 texture1, float a1, float4 texture2, float a2)
{
return texture1.a > texture2.a ? texture1.rgb : texture2.rgb;
}
texture
很好!石头的顶部是干净的,而沙子就落在石头之间的缝隙里。但我们还没考虑图层的不透明度。我们只要把深度贴图和不透明贴图相加就行了。
float3 blend(float4 texture1, float a1, float4 texture2, float a2)
{
return texture1.a + a1 > texture2.a + a2 ? texture1.rgb : texture2.rgb;
}
较低透明度的总合比通常更高。
depth map 2
sand to stones
所以沙子到石头的过渡更加自然了。如你所见,沙子开始落在石头缝之间,渐渐隐藏起来。但因为计算是一像素一像素发生的,贴图边界的人工迹象就开始明显了。为了改进结果,我们将把若干而不是一个象素点混合起来。
float3 blend(float4 texture1, float a1, float4 texture2, float a2)
{
float depth = 0.2;
float ma = max(texture1.a + a1, texture2.a + a2) – depth;
float b1 = max(texture1.a + a1 – ma, 0);
float b2 = max(texture2.a + a2 – ma, 0);
return (texture1.rgb * b1 + texture2.rgb * b2) / (b1 + b2);
}
在下列代码中,我们首先得到在某种深度下可看到的地面部分。
depth map 3
然后我们把它标准化,以得到新的不透明度。
new opacities
texture blending
以上就是贴图混合算法的结果,相当接近自然地形。
总之,我的目的就是介绍这种算法及其用法。
这个着色器是为回合制策略独立游戏《Steam Squad》开发的。因为我们使用的引擎和开发平台是Unity3D。因为Unity IDE相当灵活,所以我们制作了自己的关卡设计器拓展。一般来说,这个关卡设计器就是是精简版Unity3D地形编辑器加上《Titan Quest》编辑器中的某些功能。
当你给某地形上贴图时,你就需要根据贴图来重新计算不透明贴图。因为所有不透明度总和达到100%,编辑就会自动标准化其他图层的不透明贴图。