GLSL着色器纹理透明度叠色技术

6
我将尝试做一个着色器,用于通过合并四个纹理详细图块来在地形上加载它们,并根据第五张图像来确定每个纹理的混合程度。混合效果很好,但是当我尝试添加我的“mixmap”图像时失败了,我猜测这是由于纹理坐标的问题。
首先,这里是着色器: 顶点着色器。
void main() {
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = ftransform();
}

片段着色器

uniform sampler2D Texture0;
uniform sampler2D Texture1;
uniform sampler2D Texture2;
uniform sampler2D Texture3;
uniform sampler2D Mixmap;

varying vec3 pos;

void main()
{

    vec4 texel0 = texture2D(Texture0, gl_TexCoord[0].st).rgba;
    vec4 texel1 = texture2D(Texture1, gl_TexCoord[0].st).rgba;
    vec4 texel2 = texture2D(Texture2, gl_TexCoord[0].st).rgba;
    vec4 texel3 = texture2D(Texture3, gl_TexCoord[0].st).rgba;
    vec4 mixmapTexel = texture2D(Mixmap, gl_TexCoord[0].st).rgba;

    texel0 *= mixmapTexel.r;
    texel1 = mix(texel0,  texel1, mixmapTexel.g);
    texel2 = mix(texel1, texel2, mixmapTexel.b);
    gl_FragColor = mix(texel2, texel3, mixmapTexel.a);
}

如我所说,混合效果很好。问题在于从我的混合映射中读取的值不正确。
以下是我正在做的更多解释。我正在构建一个分页地形系统,从高度图加载地形。然后,我想使用我的混合映射图像按照rgba组件来表示每种纹理应根据高度混合的比例。
- r代表水 - g代表沙子 - b代表草 - a代表岩石
因此,我需要能够从我的着色器中获取正确的像素值以正确混合我的纹理。
下面是一个混合箱子和文本的示例,以便您可以清楚地看到纹理是如何应用的。
现在,如果我使用简单的混合映射图像(半红半绿),应该会在地形的左侧给我箱子,在右侧给我文本,但我得到了下面的结果。
以下是部分地形生成过程:它遍历顶点数组并创建地形三角形。
void TerrainPage::generateDisplayList()
{
    // create one display list
    mDisplayListIndex = glGenLists(1);

    // compile the display list, store a triangle in it
    glNewList(mDisplayListIndex, GL_COMPILE);
    glFrontFace( GL_CW  ); //   Vertex are added clockwise. Used to calculate normals
    std::vector<Vertex>::iterator it;
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);
    texShader.enable();
    texShader.bindTexture(mTexture0, "Texture0", 0);
    texShader.bindTexture(mTexture1, "Texture1", 1);
    texShader.bindTexture(mTexture2, "Texture2", 2);
    texShader.bindTexture(mTexture3, "Texture3", 3);
    texShader.bindTexture(mMixmapTexture, "Mixmap", 4);
    Vertex v;
    int j=0;
    glEnable(GL_TEXTURE_2D);
    //mTexture.bind();
    glBegin(GL_TRIANGLE_STRIP);
    for(int i = 0; i<mVertices.size(); i++) {
        if(i%(2*mWidth) == 0) glEnd(); glBegin(GL_TRIANGLE_STRIP);
        v = mVertices[i];
        glTexCoord2f(v.texcoords[0], v.texcoords[1]);
        glVertex3f(v.position[0], v.position[1], v.position[2]);
    }
    glEnd();
    glDisable(GL_TEXTURE_2D);
    texShader.disable();
    glEndList();
}

如果需要,我可以提供更多截图和代码。
作为回答的延伸,我尝试通过计算着色器中的UV来实现它。
首先,这是新着色器。
顶点着色器。
varying vec4 VertexPosition;

void main() {

    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = ftransform();
    VertexPosition = gl_ModelViewMatrix * gl_Vertex;;
}

片元着色器

uniform sampler2D Texture0;
uniform sampler2D Texture1;
uniform sampler2D Texture2;
uniform sampler2D Texture3;
uniform sampler2D Mixmap;

varying vec4 VertexPosition;
float side = 500.;

void main()
{

   vec4 texel0 = texture2D(Texture0, gl_TexCoord[0].st).rgba;
   vec4 texel1 = texture2D(Texture1, gl_TexCoord[0].st).rgba;
   vec4 texel2 = texture2D(Texture2, gl_TexCoord[0].st).rgba;
   vec4 texel3 = texture2D(Texture3, gl_TexCoord[0].st).rgba;
   vec4 mixmapTexel = texture2D(Mixmap, VertexPosition.xz/(2.*side)).rgba;

   texel0 *= mixmapTexel.r;
   texel1 = mix(texel0,  texel1, mixmapTexel.g);
   //texel2 = mix(texel1, texel2, mixmapTexel.b);
   //vec4 tx  = mix(texel2, texel3, mixmapTexel.a);
   //vec4 tx = mixmapTexel; //vec4(1, 1, 1, 1.);
    gl_FragColor = texel1;

    //if(test > 250. )
    //    gl_FragColor = vec4(1.,1.,1.,1.);
}

这是结果:

这里是结果

输入图片描述

但如果我移动相机:

输入图片描述

你可以看到,这次箱子和文字并排。但它看起来像是在屏幕坐标系而不是世界坐标系中计算。我可能又对坐标系统感到困惑了。我会努力找到正确的坐标系!我也会寻找多重纹理坐标,一旦弄清楚它的工作原理,可能更方便 ;)

1个回答

8
如果我理解正确的话,您需要为混合贴图使用不同的纹理坐标。当前它正在每个单元格中使用整个混合贴图,这就是为什么每个单元格会得到一半文本、一半纹理箱子的原因。
尝试使用多个纹理坐标。您还可以通过将其除以x方向上地形长度的当前顶点的x位置,以及y方向上的相同操作,在着色器中计算出正确的UV。但如果您缩放了地形,请确保将地形长度乘以该比例尺度。
如果您没有看到我的意思,那么地形的每个单元格都会获得以下UV值: (0,0)、(1,0)、(0,1)或(1,1)。这对于纹理箱子和文本纹理来说是可以的,但混合贴图应该更具分数和多样性。
这里有一个链接到另一个地形教程的链接。它使用DirectX,但顶点/UV生成是可比较的。最大的区别在于,他为整个地形使用一个大的纹理,而您需要为混合贴图做到这一点,但对于其他纹理则不需要。
我想我已经找到了问题所在。请明确存储顶点位置。不要将其乘以模型视图矩阵,例如:
varying vec4 VertexPosition;

void main() {

    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = ftransform();
    //VertexPosition = gl_ModelViewMatrix * gl_Vertex;;
    VertexPosition = gl_Vertex;
}

这将修复它,抱歉我将你的修复后的着色器放入了RenderMonkey中,现在它不再随相机移动了。希望这能帮到你。我之前也遇到了平移问题,但现在看起来像这样:

已修复渲染


1
太棒了,很高兴听到这个消息。我第一次尝试处理地形时也遇到了一点困难。别忘了接受答案。 - zero298

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接