GLSL着色器:var A中的半个颜色值,var B中的另一半,没有条件语句

时间:2016-11-21 08:52:54

标签: glsl shader fragment-shader

我正在研究一种纹理/地形喷涂GLSL着色器,它将支持8种纹理。

我制作的第一个版本使用RGBA作为输入 - 每个通道是每个纹理的强度。

第二个版本我试图通过将它们分成两半来加倍“通道”。例如;

  • R0 = Texture1上没有任何内容
  • R64 =纹理1的一半
  • R127 =全纹理1
  • R128 =没有纹理5
  • R196 =半纹理5
  • R254 =全纹理5

andsoforth。

我已经知道如果 - 着色器中的陈述是非常糟糕的做法 - 它也感觉做错了。

问题是,我不知道将每个通道的一半用作完整变量的数学函数。

这是片段着色器代码;

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform sampler2D texture; //Texture

uniform float surfWidth;
uniform float surfHeight;

uniform float xpos;
uniform float ypos;

void main()
{
    //Setting the main texture position
    vec2 texpos = (v_vTexcoord*vec2(surfWidth, surfHeight)) +     vec2(xpos, ypos);

    //Modulo 1 for repeat, devide by 4 because its a 4x4 texture sheet
    float tpx = mod(texpos.x,1.0)/4.0;
    float tpy = mod(texpos.y,1.0)/4.0;

    //Setup terrain "intensities"
    float t1 = 0.0;
    float t2 = 0.0;
    float t3 = 0.0;
    float t4 = 0.0;
    float t5 = 0.0;
    float t6 = 0.0;
    float t7 = 0.0;
    float t8 = 0.0;

    //Load from the surface (splatmap)
    float btr = (v_vColour * texture2D(gm_BaseTexture,     v_vTexcoord)).r;
    float btg = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).g;
    float btb = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).b;
    float bta = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).a;

    //Calculating what texture to use (also deviding each channel into     2)
    if (btr <= 0.5) {
        t1 = btr*2.0;
    } else {
        t5 = (btr-0.5)*2.0;
    }

    if (btg <= 0.5) {
        t2 = btg*2.0;
    } else {
        t6 = (btg-0.5)*2.0;
    }

    if (btb <= 0.5) {
        t3 = btb*2.0;
    } else {
        t7 = (btb-0.5)*2.0;
    }

    if (bta <= 0.5) {
        t4 = bta*2.0;
    } else {
        t8 = (bta-0.5)*2.0;
    }

    //Get terrain pixels at proper positions
    vec4 ter1 = texture2D(texture, vec2(tpx, tpy));
    ter1.a = t1;
    vec4 ter2 = texture2D(texture, vec2(tpx+0.25, tpy));
    ter2.a = t2;
    vec4 ter3 = texture2D(texture, vec2(tpx+0.50, tpy));
    ter3.a = t3;
    vec4 ter4 = texture2D(texture, vec2(tpx+0.75, tpy));
    ter4.a = t4;

    vec4 ter5 = texture2D(texture, vec2(tpx, tpy+0.25));
    ter5.a = t5;
    vec4 ter6 = texture2D(texture, vec2(tpx+0.25, tpy+0.25));
    ter6.a = t6;
    vec4 ter7 = texture2D(texture, vec2(tpx+0.50, tpy+0.25));
    ter7.a = t7;
    vec4 ter8 = texture2D(texture, vec2(tpx+0.75, tpy+0.25));
    ter8.a = t8;

    //Output to screen
    gl_FragColor =
    ter1*vec4(t1) +
    ter2*vec4(t2) +
    ter3*vec4(t3) +
    ter4*vec4(t4) +
    ter5*vec4(t5) +
    ter6*vec4(t6) +
    ter7*vec4(t7) +
    ter8*vec4(t8);
}

我很确定我需要clamp()lerp()这样的东西,但我无法绕过它......

此外,当纹理重叠时,它们变得“更亮”(因为两个纹理都只是在最后一个语句中添加...我不知道如何防止这种情况发生并且总是输出纹理本身的“最大值” (这样它就不会“点亮”)。打扰一下,如果我听起来很笨,这是我的第一个真正的着色器:)

1 个答案:

答案 0 :(得分:1)

分支在现代硬件上并没有那么糟糕,假设它们跨越多个片段并且可能节省大量工作。用分支编写逻辑看起来像这样:

btr *= 2.;
t1   = fract(min(btr,1.));
t5   = max(btr-1.,0.);

请注意,根据您的方法,您无法混合两个&#34; splatting渠道&#34;它们被包装在相同的颜色通道中(即混合t1和t5)。只是采样另一个splatmap会更简单(也可能更有效)。

关于混合最终输出,假设您想要线性混合,则将各个权重除以所有权重的总和。

float sum = t1+t2+t3+t4+t5+t6+t7+t8;
gl_FragColor = ter1*(t1/sum) + ter2*(t2/sum) + ter3*(t3/sum) + ...