
在本文中,我将解释一种纹理喷涂算法,该算法可让您创建更自然的地形。 该算法可用于3D游戏的着色器以及2D游戏中。
地形纹理的最常见方法之一是混合多个平铺层。 每个图层都有一个不透明度贴图,该贴图定义了地形上纹理存在的程度。 该方法通过将不透明度贴图应用到较高级别而起作用,显示不透明度贴图部分或完全透明的下面的图层。 不透明度图以百分比度量。 当然,在地形的每个点上,由于地形不是透明的,因此所有图层的不透明度之和为百分之一百。 代替贴图纹理,不透明度贴图完全在所有地形上延伸,因此细节水平很低。
现在,我们将转到最有趣的部分-纹理混合算法。 为了简单明了,我们的地形将由沙子和大块鹅卵石组成。

混合的最简单方法是将纹理颜色与不透明度相乘,然后对结果求和。
float3 blend(float4 texture1, float a1, float4 texture2, float a2) { return texture1.rgb * a1 + texture2.rgb * a2; }
在标准地形编辑器的Unity3D中使用了这种技术。 如您所见,过渡是平滑的但不自然。 石头看起来均匀地被沙子弄脏了,但是在现实世界中,事情并非如此。 沙子不会粘在石头上,而是会掉落并填充它们之间的裂缝,从而使石头的顶部保持纯净。
让我们尝试在Excel图形中模拟这种行为。 因为我们希望沙子在鹅卵石之间“掉落”,所以对于每种纹理,我们都需要深度图。 在此示例中,我们认为深度图是从灰度图像生成的,并存储在纹理的Alpha通道中。 在Unity3D中,可以通过设置标志“来自灰度的Alpha”在纹理检查器中完成此操作。
首先,我们将考虑沙子和石头的深度图的简化模型。

地块上的蓝线象征着沙子的深度图,红色是鹅卵石。 请注意,石头的顶部高于沙子的高度。 考虑到这一事实,我们将尝试绘制上面具有该纹理的像素。
float3 blend(float4 texture1, float a1, float4 texture2, float a2) { return texture1.a > texture2.a ? texture1.rgb : texture2.rgb; }

太好了! 鹅卵石的顶部保持纯净,而沙子位于它们之间的裂缝中。 但是我们还没有考虑图层不透明度。 要使用它,我们只对深度深度图和不透明度图求和。
float3 blend(float4 texture1, float a1, float4 texture2, float a2) { return texture1.a + a1 > texture2.a + a2 ? texture1.rgb : texture2.rgb; }
以总和为代价,较少的透明纹理将比平常更高。


因此,我们有一个从沙子到石头的更自然的过渡。 如您所见,沙粒开始填充鹅卵石之间的裂缝,逐渐将它们隐藏起来。 但是,随着计算逐像素进行,伪影开始出现在纹理之间的边界上。 为了获得平滑的结果,我们将深度取为几个像素而不是一个,然后将其混合。
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); }
在上面的代码中,我们首先获得在一定深度处看到的部分地面。

然后我们对其进行归一化以获得新的不透明性。


结果,我们发现了纹理融合算法,该算法使我们能够接近自然地形图像。