7

我已经在 OpenGL 中实现了一个高度图。目前它只是一个正弦/余弦曲线地形。目前我在白色的“冰”和较暗的“石头”纹理之间进行插值。这样做是这样的:

color = mix(texture2D(ice_layer_tex, texcoord), texture2D(stone_layer_tex, texcoord), (vertex.y + amplitude) / (amplitude * 2))

结果:

从顶部

从底部

它工作正常,但如果我想添加更多纹理,例如草纹理,我该怎么办,以便插值顺序为“冰、石、草”?我想,没有像mix(sampler2D[], percentages[])? 我怎么能按照这个逻辑编写一个 GLSL 方法?

4

3 回答 3

28

mix()实际上只是一个方便的功能,您可以轻松编写自己的东西。定义是:

mix(v1, v2, a) = v1 * (1 - a) + v2 * a

或者换一种说法,它计算 和 的加权平均值v1v2其中有两个权重w1w2是介于 0.0 和 1.0 之间的满足约束的浮点值w1 + w2 = 1.0

v1 * w1 + v2 * w2

您可以直接将其概括为计算超过 2 个输入的加权平均值。例如,对于 3 个输入和v1,您将使用 3 个权重,并且满足约束,并将加权平均值计算为:v2v3w1w2v3w1 + w2 + w3 = 1.0

v1 * w1 + v2 * w2 + v3 * w3

对于您的示例,确定要为 3 个纹理中的每一个使用的权重,然后使用以下内容:

weightIce = ...;
weightStone = ...;
weightGrass = 1.0 - weightIce - weightStone;
color = texture2D(ice_layer_tex, texcoord) * weightIce +
        texture2D(stone_layer_tex, texcoord) * weightStone +
        texture2D(grass_layer_tex, texcoord) * weightGrass;
于 2014-06-23T04:02:26.377 回答
2

不,根据mix()的 GLSL 文档,只有两个参数之间的插值重载。

你可以接受只插入“冰”和“石头”然后将结果与“草”纹理混合吗?

vec4 ice_color   = texture2D(ice_layer_tex,   texcoord);
vec4 stone_color = texture2D(stone_layer_tex, texcoord);
vec4 grass_color = texture2D(grass_layer_tex, texcoord);

vec4 tmp = mix(ice_color, stone_color, pct);
vec4 final_color = mix(tmp, grass_color, pct);
于 2014-06-23T00:31:23.107 回答
2

其他答案已经为mix()您要求的通用功能提供了解决方案。但我建议使用不同的方法,因为您明确写了“插值顺序(冰、石、草)”。在这种情况下,您不需要为每个元素设置任意权重,您只需混合相邻的元素,例如冰+石或石+草,但绝不能混合冰+草或冰+石+草。如果是这种情况,您可以简单地使用 3D 纹理并使用(三)线性过滤。只需将每个 2D 纹理用作 3D 纹理中的切片。前两个 texcoord 可以保持原样,第三个可以直接用于选择两个相邻切片之间的任意混合。由于 texcoords 始终在 [0,1] 范围内,因此您只需将范围映射到该区间即可。中心”i

p=i/num_layers + 1/(2*num_layers)

假设你有冰、石头和草的 3 片。所以你得到

0/3+1/6 = 0.16667       100% ice  
1/3+1/6 = 0.5           100% stone
2/3+1/6 = 0.83333       100% grass

以及介于其间的相邻层之间的任意线性混合,例如

1/3 = 0.3333            50% ice + 50% stone  
      0.6               70% stone  + 30% grass
...
于 2014-06-23T16:42:44.977 回答