【问题标题】:GLSL shader: Interpolate between more than two texturesGLSL 着色器:在两个以上纹理之间进行插值
【发布时间】:2014-08-12 21:53:10
【问题描述】:

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

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

结果:

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

【问题讨论】:

    标签: java opengl lwjgl interpolation heightmap


    【解决方案1】:

    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 个输入 v1v2v3,您将使用满足约束 w1 + w2 + w3 = 1.0 的 3 个权重 w1w2v3,并计算加权平均值为:

    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;
    

    【讨论】:

    • 您好,我知道这是一篇旧帖子,但您能否提一下如何计算 N 值的权重?
    • 您说“满足约束 w1 + w2 = 1.0”,但 GLSL v4.6 spec(第 8.3 节,第 148 页)并未将其作为要求提及。不过,我并不是要迂腐,这是对功能的一个很好的解释。
    【解决方案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);
    

    【讨论】:

    • 我试过这个,但这并不是我想要的。请参阅 Reto 的答案,这很完美:) 无论如何谢谢你^^
    【解决方案3】:

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

    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
    ...
    

    【讨论】:

    • 呵呵,我不知道如何实现或使用 3d 纹理...懒得去googel,你能不能贴一些示例代码? ^^ 它不必包含太多解释,但是.. 是的.. :D
    • @T_01 如果您“懒得去googel”,您将永远无法从 Stack Overflow 社区获得任何形式的答案或帮助。 SO 社区希望您首先搜索 Google,然后搜索 SO 以获得现有答案,最后——在你完成前两个之后——询问 SO。勤奋在这里(以及整个编程中)是一种美德,而懒惰不会让您与 SO 专家或整个编程生涯中的专家走得很远。
    猜你喜欢
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    相关资源
    最近更新 更多