首页 > 解决方案 > openGL - 无法显示图像

问题描述

学习使用 QOpenGLWidget 显示图像。但是,我遇到了一些问题。

  1. 如何将GLuint texture变量(从图像加载的实际纹理)传递到着色器脚本中?比如怎么GLuint texture绑定uniform sampler2D texture?也许我只是没有意识到我已经这样做了。
  2. attribute vec4 vertexColorIn和有什么区别uniform sampler2D texture?我认为颜色来自纹理。
  3. 我可以使用glTexCoord2f()andglVertex2f()代替glVertexAttribPointer()andglVertexAttribPointer()吗?这是因为它们对我来说似乎更好。

尽管我已经做了很多研究,但我仍然不清楚 openGL 如何显示图像的概念。我不确定我做错了什么。图像未显示

MyGLWiget.cpp

着色器脚本:

#define STR(x) #x
#define VS_LOCATION 0
#define FS_LOCATION 1

const char* vertextShader = STR(
    attribute vec4 position;
    attribute vec4 vertexColorIn;
    varying vec4 vertexColorOut;
    void main(void)
    {
        gl_Position = position;
        vertexColorOut = vertexColorIn;
    }
);

const char* fragmentShader = STR(
    varying vec4 vertexColorOut;
    uniform sampler2D texture;
    void main(void)
    {
        ??? = texture2D(???, textureOut).r // no clue how to use it
        gl_FragColor = vertexColorOut;
    }   
);

加载图像纹理:

void MyGLWiget::loadTexture(const char* file_path)
{
    img_data = SOIL_load_image(file_path, &width, &height, &channels, SOIL_LOAD_RGB);

    glEnable(GL_TEXTURE_2D);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data);

    SOIL_free_image_data(img_data);
}

初始化:

void MyGLWiget::initializeGL()
{
    initializeOpenGLFunctions();

    program.addShaderFromSourceCode(QGLShader::Vertex, vertextShader);
    program.bindAttributeLocation("position", VS_LOCATION);

    program.addShaderFromSourceCode(QGLShader::Fragment, fragmentShader);
    program.bindAttributeLocation("vertexColorIn", FS_LOCATION);

    program.link();
    program.bind();


    static const GLfloat ver[] = {
        -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f
    };

    static const GLfloat  tex[] = {
        0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f
    };

    glVertexAttribPointer(VS_LOCATION, 2, GL_FLOAT, 0, 0, ver);
    glEnableVertexAttribArray(VS_LOCATION);

    glVertexAttribPointer(FS_LOCATION, 2, GL_FLOAT, 0, 0, tex);
    glEnableVertexAttribArray(FS_LOCATION);

    program.setUniformValue("texture", texture); 
    //texture = program.uniformLocation("texture");
}

油漆GL:

我真的对这部分感到困惑。我不知道应该用什么来绘制图像。

void MyGLWiget::paintGL()
{
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, img_data);
    glUniform1i(texture, 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 1);
}

标签: qtopenglopengl-4

解决方案


如何将 GLuint 纹理变量(从图像加载的实际纹理)传递到着色器脚本中?喜欢如何将 GLuint 纹理绑定到统一的 sampler2D 纹理?也许我只是没有意识到我已经这样做了。

这将纹理绑定到纹理单元 0:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

这是无效的,因为texture不是统一的位置,所以删除这一行:

glUniform1i(texture, 0); // <-- invalid

这也是无效的,因为texture应将制服设置为纹理单元的编号:

program.setUniformValue("texture", texture); // <-- invalid

所以将其替换为:

program.setUniformValue("texture", 0); // <-- sampler2D texture uses GL_TEXTURE0

注意:我假设这里setUniformValue可以正常工作。


属性 vec4 vertexColorIn 和统一的 sampler2D 纹理有什么区别?我认为颜色来自纹理。

vertexColorIn来自 VAO,每个顶点都不同。texture是从绑定到您上面设置的纹理单元的纹理中采样的采样器。

在您的代码中,您不需要顶点颜色,但您确实需要纹理坐标。所以你的着色器应该看起来像:

const char* vertextShader = STR(
    attribute vec4 position;
    attribute vec4 texcoordIn;
    varying vec4 texcoordOut;
    void main(void)
    {
        gl_Position = position;
        texcoordOut = texcoordIn;
    }
);

const char* fragmentShader = STR(
    varying vec4 texcoordOut;
    uniform sampler2D texture;
    void main(void)
    {
        gl_FragColor = texture2D(texture, texcoordOut);
    }   
);

我可以使用 glTexCoord2f() 和 glVertex2f() 代替 glVertexAttribPointer() 和 glVertexAttribPointer() 吗?这是因为它们对我来说似乎更好。

glTexCoord2f并且glVertex2f是 OpenGL 3 中删除的遗留函数,仅在兼容性配置文件中可用。您不得使用它们。


这行是在错误的地方:

 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

他们将在您绑定纹理之后进行:

 glGenTextures(1, &texture);
 glBindTexture(GL_TEXTURE_2D, texture);
 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data);
 // sets the filtering for the bound texture:
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

由于问题被标记为:在这种情况下,您不需要设置任何制服。您可以直接在着色器中指定位置和绑定:

const char* vertextShader =
    "#version 450 core\n" STR(
    layout(location = 0) in vec4 position;
    layout(location = 1) in vec4 texcoordIn;
    layout(location = 0) out vec4 texcoordOut;
    void main(void)
    {
        gl_Position = position;
        texcoordOut = texcoordIn;
    }
);

const char* fragmentShader =
    "#version 450 core\n" STR(
    layout(location = 0) in vec4 texcoord;
    layout(binding = 0) uniform sampler2D TEX;
    layout(location = 0) out vec4 OUT;
    void main(void)
    {
        OUT = texture(TEX, texcoord);
    }   
);

推荐阅读