【问题标题】:Multiple textures in GLSL - only one worksGLSL 中的多个纹理 - 只有一个有效
【发布时间】:2011-04-03 21:53:59
【问题描述】:

我的问题是在 GLSL 着色器中可以访问多个纹理。 这就是我正在做的事情:

着色器:

uniform sampler2D sampler0;
uniform sampler2D sampler1;
uniform float blend;
void main( void )
{
    vec2 coords = gl_TexCoord[0];
    vec4 col = texture2D(sampler0, coords);
    vec4 col2 = texture2D(sampler1, coords);
    if (blend > 0.5){
        gl_FragColor = col;
    } else {
        gl_FragColor = col2;
    }
};

所以,我只是根据统一变量在两个颜色值之间进行选择。很简单(这是一个测试),但是当 blend 时,我得到了全黑 ,而不是预期的行为。

OpenGL 代码:

m_sampler0location = m_shader.FindUniform("sampler0");
m_sampler1location = m_shader.FindUniform("sampler1");
m_blendlocation = m_shader.FindUniform("blend");

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
m_extensions.glUniform1iARB(m_sampler0location, 0);
glBindTexture(GL_TEXTURE_2D, Texture0.Handle);  
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
m_extensions.glUniform1iARB(m_sampler1location, 1);
glBindTexture(GL_TEXTURE_2D, Texture1.Handle);
glBegin(GL_QUADS);
    //lower left
    glTexCoord2f(0, 0);
    glVertex2f(-1.0, -1.0);
    //upper left
    glTexCoord2f(0, maxCoords0.t);
    glVertex2f(-1.0, 1.0);
    //upper right
    glTexCoord2f(maxCoords0.s, maxCoords0.t);
    glVertex2f(1.0, 1.0);
    //lower right
    glTexCoord2f(maxCoords0.s, 0);
    glVertex2f(1.0, -1.0);
glEnd()

着色器在这一切之前被编译和绑定。该过程中的所有健全性检查都表明一切正常。 正如我所说,着色器程序中col 的值反映了纹理中的片段; col2 的值为黑色。显示的纹理是最后一个活动纹理 - 如果我将最后一个 glBindTexture 更改为绑定 Texture0.Handle,则纹理会更改。根据 Bahbar 的回复修复。

事实上,即使我在着色器的最后一行添加了gl_FragColor.r = blend; 之类的内容,场景也会呈现全黑。但是,如果我注释掉调用glActiveTexture(GL_TEXTURE1);,着色器将再次工作,并且相同的纹理出现在sampler0 和sampler1 中。

发生了什么事?有问题的行glActiveTexture(GL_TEXTURE1); 似乎工作得很好,随后的glGetIntegerv(GL_ACTIVE_TEXTURE, &anint) 就证明了这一点。为什么它会如此可怕地破坏一切?我已经尝试升级我的显示驱动程序。

【问题讨论】:

  • 您找到解决问题的方法了吗?我有完全相同的问题。
  • 是的,标记的解决方案对我有用。

标签: opengl textures glsl


【解决方案1】:

这是一个基本的 GLUT 示例(在 OS X 上编写,根据需要进行调整),它生成两个棋盘格纹理,加载带有两个采样器的着色器,并通过对每个采样器进行着色(一个红色,一个蓝色)和混合来组合它们。看看这是否适合你:

#include <stdio.h>
#include <stdlib.h>

#include <GLUT/glut.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>

#define kTextureDim 64

GLuint t1;
GLuint t2;

/* adapted from the red book */
GLuint makeCheckTex() {
    GLubyte image[kTextureDim][kTextureDim][4]; // RGBA storage

    for (int i = 0; i < kTextureDim; i++) {
        for (int j = 0; j < kTextureDim; j++) {
            int c = ((((i & 0x8) == 0) ^ ((j & 0x8)) == 0))*255;
            image[i][j][0]  = (GLubyte)c;
            image[i][j][1]  = (GLubyte)c;
            image[i][j][2]  = (GLubyte)c;
            image[i][j][3]  = (GLubyte)255;
        }
    }

    GLuint texName;
    glGenTextures(1, &texName);    
    glBindTexture(GL_TEXTURE_2D, texName);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureDim, kTextureDim, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);

    return texName;
}

void loadShader() {
#define STRINGIFY(A) #A

    const GLchar* source = STRINGIFY(

                                     uniform sampler2D tex1;
                                     uniform sampler2D tex2;

                                     void main() {
                                         vec4 s1 = texture2D(tex1, gl_TexCoord[0].st);
                                         vec4 s2 = texture2D(tex2, gl_TexCoord[0].st + vec2(0.0625, 0.0625));
                                         gl_FragColor = mix(vec4(1, s1.g, s1.b, 0.5), vec4(s2.r, s2.g, 1, 0.5), 0.5);
                                     }

                                     );

    GLuint program = glCreateProgram();
    GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);

    GLint logLength;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar* log = (GLchar*)malloc(logLength);
        glGetShaderInfoLog(shader, logLength, &logLength, log);
        printf("Shader compile log:\n%s\n", log);
        free(log);
    }

    glAttachShader(program, shader);  
    glLinkProgram(program);

    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar* log = (GLchar*)malloc(logLength);
        glGetProgramInfoLog(program, logLength, &logLength, log);
        printf("Program link log:\n%s\n", log);
        free(log);
    }

    GLuint t1Location = glGetUniformLocation(program, "tex1");
    GLuint t2Location = glGetUniformLocation(program, "tex2");

    glUniform1i(t1Location, 0);
    glUniform1i(t2Location, 1);

    glUseProgram(program);
}


void init()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_FLAT);

    t1 = makeCheckTex();
    t2 = makeCheckTex();

    loadShader();
}


void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, t1);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, t2);

    glBegin(GL_QUADS);
    //lower left
    glTexCoord2f(0, 0);
    glVertex2f(-1.0, -1.0);
    //upper left
    glTexCoord2f(0, 1.0);
    glVertex2f(-1.0, 1.0);
    //upper right
    glTexCoord2f(1.0, 1.0);
    glVertex2f(1.0, 1.0);
    //lower right
    glTexCoord2f(1.0, 0);
    glVertex2f(1.0, -1.0);
    glEnd();

    glutSwapBuffers();
}


void reshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-2, 2, -2, 2, -2, 2);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}


int main(int argc, char **argv)
{
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);

    glutInitWindowSize(512, 512);
    glutInitWindowPosition(0, 0);

    glutCreateWindow("GLSL Texture Blending");

    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutIdleFunc(display);

    init();

    glutMainLoop();
    return 0;
}

希望结果看起来像这样(您可以注释掉 glUseProgram 调用以查看没有着色器绘制的第一个纹理):

【讨论】:

  • 好的,这行得通。非常感谢,现在我有一个基础可以尝试找出我自己的程序中的问题。
  • 为什么shader里面的制服叫“tex0, tex1”,而调用“glGetUniformLocation”的时候却叫“tex1, tex2”?
  • 一个更好的问题可能是:这是怎么回事,即使其中一件制服的返回位置是“-1”?我已经测试将统一名称设置为任何字符串,它仍然可以工作 - 任何人都可以解释一下吗?
  • 很好,这是一个错误。我想它可以工作(尽管不能保证) b/c 最后一个纹理绑定是t2
【解决方案2】:

只是为了帮助其他可能对使用多种纹理感兴趣并且在几天寻找答案后会感到绝望的人。我发现你需要打电话

glUseProgram(program);

GLuint t1Location = glGetUniformLocation(program, "tex1");
GLuint t2Location = glGetUniformLocation(program, "tex2");

glUniform1i(t1Location, 0);
glUniform1i(t2Location, 1);

按此顺序运行(glUseProgram 是我在网上找到的 99% 示例代码的最后一条指令)。现在这可能只是我自己的情况,不会影响地球上的其他任何人,但以防万一我认为我会分享。

【讨论】:

  • 没错,手册页上写着“glUniform 对通过调用 glUseProgram() 成为当前状态的一部分的程序对象进行操作”
  • 这对我不起作用(在 OpenGL 2.0 / GLSL 1.2 中),但 glGetUniformLocation/glUseProgram/glUniform1i 对我有用 - stackoverflow.com/a/25252981/236081
  • 非常感谢!我有同样的问题。这是超级有用的
【解决方案3】:

回复很晚,但是对于遇到此问题的任何人-我遇到了同样的问题,经过短暂的摆弄后,我意识到致电glActiveTexture(GL_TEXTURE0) 可以解决此问题。 如果活动纹理单元未“重置”为零,则似乎有些东西会混淆。 这可能是依赖于系统的行为;我正在使用 Mesa 8.0.4 运行 64 位 Archlinux。

【讨论】:

  • 这解决了我也遇到的一个奇怪的相关问题。很奇怪
  • 绝对的救星!我浏览了我的代码,解构它,直到我睁大眼睛,在文档和在线的任何地方搜索,我找不到一个错误。如果可以的话,我会投票给你 x 100,约翰 :^) (win7 64bit GTX780)
【解决方案4】:

在编译着色器进行测试时,我发现了两个错误:

  1. coords 应该分配给 4 组件 gl_TexCoordst 部分,例如

    vec2 coords = gl_TexCoord[0].st;
    
  2. 着色器不应以分号结尾。

您是否在主程序中检查着色器正确编译的任何地方?您可能想通过glGetShaderglGetShaderInfoLog 查看GL_COMPILE_STATUS

【讨论】:

  • 好的,我更改了分配,但没有效果。分号是错字,所以我已将其从原始消息中删除。我已经检查了GL_COMPILE_STATUS,并且着色器在所有情况下都能正确编译和绑定,但只有在我省略glActiveTexture(GL_TEXTURE1); 行时才能真正起作用——即使我用只输出白色的单线替换整个东西。跨度>
【解决方案5】:

听起来您的glActiveTexture 呼叫不起作用。你确定你正确设置了函数指针吗?

在调用您的 glActiveTexture(GL_TEXTURE1) 后调用 glGetIntegerv(GL_ACTIVE_TEXTURE, &amp;anint) 进行验证。

glEnable(GL_TEXTURE_2D) 也没有用。着色器本身指定要使用哪些纹理单元,以及要“启用”每个单元的哪个目标。


编辑添加:

嗯,你的新情况很奇怪。您甚至不能显示红色这一事实很奇怪,尤其是(嗯,您是否将 alpha 设置为 1 只是为了确保?)。

也就是说,在完成纹理单元 1 的设置后(即在 glBindTexture 调用之后),您应该将 GL_TEXTURE0 恢复为 glActiveTexture

【讨论】:

  • 也许他正在将 ARB 扩展中的枚举与核心功能(函数)混合在一起?确实很奇怪。
  • 感谢您的快速回复。你是对的 - GL_ACTIVE_TEXTURE 设置不正确。我现在已经修复了函数指针,并且值发生了应有的变化——但现在,我得到的只是黑色。我已经根据我的新情况更新了问题。
  • @Mads Elvheim:澄清最后一句话。
  • @Bahbar :“还有 glEnable(GL_TEXTURE_2D) 没用。着色器本身指定要使用的纹理单元,以及每个单元的哪个目标要“启用””“我 90% 确定这是错误的,请问您有什么参考吗?更改活动纹理时,我总是启用目标...
  • @Calvin1602:shader_objects 扩展问题 25 间接涵盖了它。规范 3.0(引入弃用)将此列为弃用(p409,第一个项目符号,“启用所有维度的目标”)。最近的核心规范(例如 4.0)甚至没有提到 glEnable 曾经采用 GL_TEXTURE_2D (因为它控制的是固定功能)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-23
  • 1970-01-01
  • 2020-09-28
  • 2014-08-08
相关资源
最近更新 更多