【问题标题】:Calling glActiveTexture(GL_TEXTURE1) before update() on a QOpenGLWidget causes textures to appear black在 QOpenGLWidget 上的 update() 之前调用 glActiveTexture(GL_TEXTURE1) 会导致纹理显示为黑色
【发布时间】:2020-07-18 18:19:52
【问题描述】:

QOpenGLWidgetQOpenGLFunctions_4_5_Core 继承时,如果我在调用update() 之前调用glActiveTexture(GL_TEXTURE1)(或任何其他非零数字),则屏幕上的纹理将完全显示为黑色。

相关代码sn-ps:

void OpenGLWidget::paintGL() {
    if (fp) {
        // First paint seems to always happen before the first update
        qDebug() << "First Paint";
        fp = false;
    }
    glClear(GL_COLOR_BUFFER_BIT);

    unsigned int tex;
    glGenTextures(1, &tex);

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

    QImage img = QImage("textures/awesomeface.png").convertToFormat(QImage::Format_RGBA8888).mirrored();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());

    glTextureParameteri(tex, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTextureParameteri(tex, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTextureParameteri(tex, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTextureParameteri(tex, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glUseProgram(frame_shader.get_id());

    glBindVertexArray(frame_vao);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    // Clean up
    glDeleteTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindVertexArray(0);

    // This doesn't cause the textures to be black
    glActiveTexture(GL_TEXTURE1);
}

还有mainloop函数:

void OpenGLWidget::main_loop() {
    if (fu) {
        qDebug() << "First Update";
        fu = false;
    }

    // This causes the textures to completely black
    // Change GL_TEXTURE1 to GL_TEXTURE0 (or get rid of it glActiveTexture
    // completely) and textures will work once again
    glActiveTexture(GL_TEXTURE1);
    update();
}

着色器仍然可以绘制到屏幕上;如果我在片段着色器中设置纯色,颜色将正确显示到屏幕上。似乎只有用户制作的纹理完全变黑了。

我没有收到任何 OpenGL 错误。

完整的 MRE 可以在以下位置找到:https://github.com/Luminic/MRE_QOpenGLWidget_glActiveTexture_GL_TEXTURE1_before_update

有谁知道是什么导致了这种奇怪的行为?

【问题讨论】:

  • 你所做的在这里是未定义的行为,引用 QtOpenGLWidget 的文档:“当调用 paintGL()resizeGL()initializeGL() 时,你的小部件的 OpenGL 渲染上下文是当前的。如果你需要要从其他地方调用标准的 OpenGL API 函数(例如,在您的小部件的构造函数或您自己的绘图函数中),您必须先调用 makeCurrent()。”不确定这将如何产生此处观察到的效果,但请注意 QT 在底层保留了一个渲染到纹理机制以渲染到窗口,您可能会在那里搞砸一些事情。

标签: c++ opengl qt5 qtopengl


【解决方案1】:

为什么这应该是奇怪的行为?告诉 OpenGL 使用硬件的纹理单元 1 仅绘制黑色内容是完全合理的,因为在您的代码中,您没有附加到该单元的纹理。这 glActiveTexture(GL_TEXTURE1) 命令将活动纹理单元设置为 1。在创建纹理之前,您绑定了单元 0,因此纹理存在于那里。完全不设置此参数与将其设置为 0 相同,因为这是默认单位。在 glActiveTexture 之后调用 glBindTexture 也可以解决您的问题!

【讨论】:

  • 在paintGL中我设置glActiveTexture(GL_TEXTURE0),在帧缓冲区中我在绑定点0处绘制纹理,所以glActiveTexture(GL_TEXTURE1)不应该有效果。此外,如果我将图像绑定到 GL_TEXTURE1 并在帧缓冲区中的绑定点 1 处绘制纹理,则纹理仍然显示为黑色。
  • 这个paintGL函数是只调用一次还是每帧都重新加载纹理?检查 tex 的值也很有用,看看它是否有效。
  • update 通过 Qt 间接调用 paintGL。我不能直接调用paintGL,否则不会绑定帧缓冲区。 main_loop() 每帧都会被调用,所以paintGL 也是如此。当我检查 id 时,纹理是有效的纹理。我知道每帧创建然后删除纹理并不是最好的主意,但这只是为了显示奇怪的行为。如果我在 initializeGL 中创建纹理并在每一帧都绘制它,则会发生相同的行为。
猜你喜欢
  • 1970-01-01
  • 2023-02-03
  • 1970-01-01
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 2012-07-14
  • 2020-04-17
相关资源
最近更新 更多