如何使用QOpenGLWidget解决GL_INVALID_OPERATION错误

How can I solve GL_INVALID_OPERATION error with QOpenGLWidget?

本文关键字:INVALID 错误 OPERATION GL 何使用 QOpenGLWidget 解决      更新时间:2023-10-16

我有一个OpenGL三维纹理和一个2d纹理,我想将它们组合到片段着色器中。整个UI是用QOpenGLWidget完成的,这大大简化了工作流程。现在我有个问题。一旦我尝试做这样的事情:

vec4 col = texture(tex, uvCoord);
outColor = texture(lookUp, col.rgb);

在我的片段着色器中,在绘制几何体的过程中,我得到了一个GL_INVALID_OPERATION错误。绘制矩形四边形后,方法paintGL((中就会出现错误。如果我在碎片着色器中执行此操作:

outColor = texture(lookUp, uvCoord);

我没有得到错误,我在显示的窗口中看到了预期的颜色。如果能给我提供任何可以搜索解决方案的提示,我将不胜感激。

#include "tex3dtest.h"

Tex3dtest::Tex3dtest(QWidget *parent)
: QMainWindow(parent)
{
setCentralWidget(new ImageGLWidget());
}
ImageGLWidget::ImageGLWidget(QWidget* parent) : QOpenGLWidget(parent)
{
texture = Q_NULLPTR;
setFixedSize(512, 512);
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3, 3);
setFormat(format);
}
ImageGLWidget::~ImageGLWidget()
{}

const int LUT3D_EDGE_SIZE = 32;
void ImageGLWidget::printError(GLuint error)
{
switch (error)
{
case GL_NO_ERROR:
qDebug() << "NoError";
break;
case GL_INVALID_ENUM:
qDebug() << "OpenGL ERROR: GL_INVALID_ENUM";
break;
case GL_INVALID_VALUE:
qDebug() << "OpenGL ERROR: GL_INVALID_VALUE";
break;
case GL_INVALID_OPERATION:
qDebug() << "OpenGL ERROR: GL_INVALID_OPERATION";
break;
case GL_STACK_OVERFLOW:
qDebug() << "OpenGL ERROR: GL_STACK_OVERFLOW";
break;
case GL_STACK_UNDERFLOW:
qDebug() << "OpenGL ERROR: GL_STACK_UNDERFLOW";
break;
case GL_OUT_OF_MEMORY:
qDebug() << "OpenGL ERROR: GL_OUT_OF_MEMORY";
break;
}
}
void ImageGLWidget::createTexture()
{
qDebug() << "ImageGLWidget::createTexture";
GLenum err;
int num3Dentries = 3 * LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE;
textureContent.resize(num3Dentries);
for (unsigned int i = 0; i < num3Dentries; i++)
textureContent[i] = ((float)i)/num3Dentries * 100.0f;
texture = new QOpenGLTexture(QOpenGLTexture::Target::Target3D);
bool is3d = texture->hasFeature(QOpenGLTexture::Feature::Texture3D);
texture->setFormat(QOpenGLTexture::TextureFormat::RGB32F);
texture->setSize(LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE);
texture->allocateStorage(QOpenGLTexture::PixelFormat::RGB, QOpenGLTexture::PixelType::Float32);
texture->setMagnificationFilter(QOpenGLTexture::Linear);
texture->setMinificationFilter(QOpenGLTexture::Linear);
texture->setWrapMode(QOpenGLTexture::ClampToEdge);
texture->setData(QOpenGLTexture::PixelFormat::RGB, QOpenGLTexture::PixelType::Float32, &textureContent[0]);
int num2Dentries = 256 * 256 * 3;
textureContent1.resize(num2Dentries);
for (unsigned int i = 0; i < num2Dentries; i++)
textureContent1[i] = ((float)rand())/RAND_MAX;
texture1 = new QOpenGLTexture(QOpenGLTexture::Target::Target2D);
texture1->setFormat(QOpenGLTexture::TextureFormat::RGB32F);
texture1->setSize(256, 256, 0);
texture1->allocateStorage(QOpenGLTexture::PixelFormat::RGB, QOpenGLTexture::PixelType::Float32);
texture1->setMagnificationFilter(QOpenGLTexture::Linear);
texture1->setMinificationFilter(QOpenGLTexture::Linear);
texture1->setWrapMode(QOpenGLTexture::ClampToEdge);
texture1->setData(QOpenGLTexture::PixelFormat::RGB, QOpenGLTexture::PixelType::Float32, &textureContent1[0]);
}
static const float vertexData[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-1.0f,  1.0f, 0.0f, 0.0f, 1.0f,
1.0f,  1.0f, 0.0f, 1.0f, 1.0f,
1.0f,  1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f
};
static const char *vtxVBO =
"#version 330n"
"layout(location = 0) in vec3 position;n"
"layout(location = 1) in vec2 uv;n"
"out vec2 uvCoord;n"
"void main()n"
"{n"
"   gl_Position = vec4(position, 1.0);n"
"   uvCoord = uv;n"
"}n";
static const char *frgVBO =
"#version 330n"
"in vec2 uvCoord;n"
"out vec4 outColor;n"
"uniform sampler2D tex;n"
"uniform sampler3D lookUp;n"
"void main()n"
"{n"
"   vec4 col = texture(tex, uvCoord);n"
"   outColor = texture(lookUp, col.rgb);n"
"// outColor = texture(tex, uvCoord);n"
"}n";
void ImageGLWidget::initializeGL()
{
GLenum err;
qDebug() << "initializeGL";
initializeOpenGLFunctions();
createTexture();
program = new QOpenGLShaderProgram();
program->addShaderFromSourceCode(QOpenGLShader::Vertex, vtxVBO);
program->addShaderFromSourceCode(QOpenGLShader::Fragment, frgVBO);
program->link();
program->bind();
vertexbuffer.create();
vertexbuffer.bind();
vertexbuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexbuffer.allocate(vertexData, sizeof(float) * 6 * 5);
vao.create();
vao.bind();
program->enableAttributeArray(0);
program->enableAttributeArray(1);
int stride = 5 * sizeof(float);
int uvOffset = 3 * sizeof(float);
program->setAttributeBuffer(0, GL_FLOAT, 0, 3, stride);
program->setAttributeBuffer(1, GL_FLOAT, uvOffset, 2, stride);
vao.release();
vertexbuffer.release();
program->release();
}
void ImageGLWidget::paintGL()
{
qDebug() << "ImageGLWidget::paintGL";
GLenum err;
glClear(GL_COLOR_BUFFER_BIT);
texture->bind();
texture1->bind();
program->bind();
vao.bind();
glDrawArrays(GL_TRIANGLES, 0, 6);
vao.release();
program->release();
}

头文件是这样的:

#pragma once
#include <QtWidgets/QMainWindow>
#include <qopenglwidget.h>
#include <qopenglfunctions.h>
#include <qopenglshaderprogram.h>
#include <qopengltexture.h>
#include <qopenglvertexarrayobject.h>
#include <qopenglbuffer.h>
class Tex3dtest : public QMainWindow
{
Q_OBJECT
public:
Tex3dtest(QWidget *parent = Q_NULLPTR);
private:
};

class ImageGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT;
public:
ImageGLWidget(QWidget* parent = Q_NULLPTR);
~ImageGLWidget();
virtual void initializeGL();
virtual void paintGL();
void printError(GLuint error);
void createTexture();
private:
QOpenGLShaderProgram *program;
QOpenGLTexture *texture;
QOpenGLTexture *texture1;
QOpenGLVertexArrayObject vao;
QOpenGLBuffer vertexbuffer;
std::vector<float> textureContent;
std::vector<float> textureContent1;
};

该问题可以通过在着色器程序中设置统一值来解决。在initializeGL中,我添加:

programOCIO->bind();
texture2DLoc = programOCIO->uniformLocation("tex");
texture3DLoc = programOCIO->uniformLocation("lookUp");

后来在paintGL方法中,我添加了:

glActiveTexture(GL_TEXTURE0);
texture->bind();
glActiveTexture(GL_TEXTURE1);
lut3dTex->bind();
programOCIO->setUniformValue(texture2DLoc, 0);
programOCIO->setUniformValue(texture3DLoc, 1);

现在运行良好。