如果OpenGL纹理当前处于活动状态,则无法呈现

时间:2016-12-28 12:31:50

标签: qt opengl

我正在使用QOpenGLWidget渲染纹理三角形,代码看起来不错,但是三角形总是变黑,我有两天的问题,直到我意外地发现了标题所说的内容。

这是代码,纹理被加载到 GL_TEXTURE0 的默认位置,除非我最后调用 glActiveTexture(GL_TEXTURE1),否则代码将无效, GL_TEXTURE1 只是一个例子,它可以是任何其他纹理槽,除了纹理实际上是那个。没有调用,对象将变黑。

    QImage ready;
    QImage image("C:/Users/Gamer/Desktop/New folder/ring.jpg");
    ready = image.convertToFormat(QImage::Format_RGBA8888);


    glGenTextures(1, &texture);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glUniform1i(glGetUniformLocation(program.programId(), "samp"), 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ready.width(), ready.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, ready.constBits());
    glGenerateMipmap(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE1)

我已经尝试了一些测试,创建多个纹理并一次显示它们,最后一个活动纹理总是黑色,除非我激活其他一些未占用的插槽。

我不知道该怎么做,我在OpenGL和Qt中打招呼,但这听起来不对。

修改

主要功能

#include "mainwindow.h"
#include <QApplication>
#include <QSurfaceFormat>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QSurfaceFormat format;
    format.setVersion(3, 3);
    format.setProfile(QSurfaceFormat::CoreProfile);
    format.setDepthBufferSize(24);
    format.setStencilBufferSize(8);
    format.setSamples(4);
    format.setSwapInterval(0);
    QSurfaceFormat::setDefaultFormat(format);

    MainWindow w;
    w.show();

    return a.exec();
}

小工具代码

#include "openglwidget.h"
#include <QOpenGLShaderProgram>
#include <QImage>
#include <QDebug>

OpenGLWidget::OpenGLWidget(QWidget *parent) :
    QOpenGLWidget(parent)
{

}

OpenGLWidget::~OpenGLWidget()
{
    glDeleteBuffers(1, &vbo);
    glDeleteVertexArrays(1, &vao);
    glDeleteTextures(1, &texture);

}

void OpenGLWidget::initializeGL()
{
    QOpenGLFunctions_3_3_Core::initializeOpenGLFunctions();

    GLfloat vertices[] = {
            0.0f, 0.75f, 0.0f,
            -0.75f, -0.75f, 0.0f,
            0.75f, -0.75f, 0.0f,
            0.5f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f
        };

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    program.addShaderFromSourceFile(QOpenGLShader::Vertex, "C:/Users/Gamer/Desktop/New folder/vertex.vert");
    program.addShaderFromSourceFile(QOpenGLShader::Fragment, "C:/Users/Gamer/Desktop/New folder/fragment.frag");
    program.link();
    program.bind();

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)36);
    glEnableVertexAttribArray(1);

    QImage ready;
    QImage image("C:/Users/Gamer/Desktop/New folder/ring.jpg");
    ready = image.convertToFormat(QImage::Format_RGBA8888);


    glGenTextures(1, &texture);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glUniform1i(glGetUniformLocation(program.programId(), "samp"), 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ready.width(), ready.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, ready.constBits());
    glGenerateMipmap(GL_TEXTURE_2D);
//    glActiveTexture(GL_TEXTURE1);

}

void OpenGLWidget::paintGL()
{
    GLfloat yellow[] = {1.0, 1.0, 0.0, 0.0};

    glClearBufferfv(GL_COLOR, 0, yellow);

    glDrawArrays(GL_TRIANGLES, 0, 3);
}

void OpenGLWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

着色器

#version 330 core

layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 coord;

out vec2 tc;

void main(void)
{
    tc = coord;
    gl_Position = vec4(pos, 1.0);
}

#version 330 core

uniform sampler2D samp;

in vec2 tc;
out vec4 color;

void main(void)
{
    color = texture(samp, tc);
}

2 个答案:

答案 0 :(得分:2)

QOpenGLWidget是一个相当复杂的抽象,它有一些你可能没想到的副作用。引自Qt5 docs

  

所有渲染都发生在OpenGL帧缓冲对象中。 makeCurrent()确保它在上下文中绑定。在paintGL()中的渲染代码中创建和绑定其他帧缓冲对象时,请记住这一点。永远不要使用ID 0重新绑定帧缓冲区。而是调用defaultFramebufferObject()来获取应该绑定的ID。

现在,这本身并不是问题。但是,查看initializeGL()方法的描述(我的重点):

  

无需调用makeCurrent(),因为调用此函数时已经完成了此操作。 请注意,此阶段尚未提供帧缓冲,因此请避免从此处发出绘制调用。将此类电话转接至paintGL()

现在,这本身仍然不是问题。但是:这意味着Qt将在initializeGL和第一个paintGL之间创建FBO。由于Qt创建纹理作为FBO的颜色缓冲区,这意味着它将重新使用当前活动的纹理单元并更改您在initializeGL 中建立的纹理绑定。

另一方面,如果你将glActiveTexture设置为单位0之外的其他东西,Qt会搞砸该单位的绑定,但由于你只使用单位0,它不会对你有任何负面影响示例

答案 1 :(得分:1)

您需要在绘制之前将纹理绑定到纹理单元。与制服不同,纹理单元状态不是程序状态的一部分。在程序启动期间尝试设置纹理单元状态是不常见的,这需要为每个程序分配不同的纹理单元(不是不可能的,它不是通常的方式)。

在绘制调用之前将以下行添加到paintGL

glBindTexture(GL_TEXTURE_2D, texture);