【问题标题】:GLSL Shaders texture alpha splattingGLSL 着色器纹理 alpha 飞溅
【发布时间】:2012-11-17 19:16:04
【问题描述】:

我正在尝试通过根据第五张图像合并它们来加载地形上的四个纹理细节图块的着色器,其中 r、g、b 和 a 组件用于确定每个纹理的多少应该混合在一起。 混合效果很好,但是当我尝试添加我的“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);
}

正如我所说,混合效果很好。 问题在于从我的 mixmap 读取的值不正确。

这里是关于我在做什么的更多解释。 我正在构建一个分页地形系统,​​从高度图加载地形。 然后我想用我的 mixmap 图像用 rgba 组件表示每个纹理应该根据高度混合多少。

  • r 是水

  • g 是沙子

  • b 是草

  • 摇滚乐

所以我需要能够从我的着色器中获取正确的像素值,以正确混合我的纹理。

这里是一个 crate 和 text 之间的混合示例,以便您可以清楚地看到纹理是如何应用的。

现在,如果我使用简单的混合图图像(半红半绿),它应该给我地形左侧的板条箱和右侧的文本,我得到

这是地形生成过程的一部分:它遍历顶点数组并创建地形三角形

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.);
}

这是结果

但是如果我移动相机:

正如你所见,这次箱子和文字是并排的。但看起来我正在计算屏幕坐标而不是世界坐标。我一定又对坐标系感到困惑了。 我会努力找到合适的!我只是想确保我的方向是正确的。 我也会寻找多纹理坐标,一旦我弄清楚它是如何工作的,它可能会更方便;)

【问题讨论】:

    标签: c++ opengl glsl shader


    【解决方案1】:

    如果我的理解正确,您的混合贴图需要不同的纹理坐标。现在它正在使用每个单元格的整个混合图,这就是为什么每个单元格得到一半文本,一半箱子的原因。

    尝试使用多个 texcoords。您还可以通过将顶点的当前 x 位置除以 x 方向上的地形长度和 y 相同来计算着色器中的正确 UV。但是,如果您缩放的是地形,请务必将地形的长度乘以比例。

    如果你没有明白我在说什么,那么地形的每个单元格都会获得以下任一方面的 UV: (0,0)、(1,0)、(0,1) 或 (1,1)。 这对于 crate 和文本纹理来说很好,但 mixmap 应该更加分散和多样化。

    这里是link 到另一个地形教程。它使用 DirectX,但顶点/UV 生成是可比的。最大的不同是他为整个地形使用了一个大纹理,这是你需要为你的混合贴图做的,而不是你的其他纹理。

    我想我知道出了什么问题。显式存储顶点位置。不要乘以模型视图矩阵即:

    varying vec4 VertexPosition;
    
    void main() {
    
        gl_TexCoord[0] = gl_MultiTexCoord0;
        gl_Position = ftransform();
        //VertexPosition = gl_ModelViewMatrix * gl_Vertex;;
        VertexPosition = gl_Vertex;
    }
    

    这将解决它,抱歉,我将您的固定着色器扔到了 rendermonkey 中,它不再随相机移动。希望这可以帮助。我正在平移,但现在看起来像:

    【讨论】:

    • 太棒了,很高兴听到它。当我第一次尝试地形时,我也遇到了一些麻烦。不要忘记接受答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 2013-06-13
    • 2012-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多