Reputation: 1978
I have a OpenGL 3d texture and a 2d texture which I want to combine in a fragment shader. The whole UI is done with a QOpenGLWidget which simplifies the workflow a lot. Now I have a problem. As soon as I try to do something like this:
vec4 col = texture(tex, uvCoord);
outColor = texture(lookUp, col.rgb);
In my fragment shader, I get an GL_INVALID_OPERATION error during drawing of the geometry. The error occurs in the method paintGL() as soon as the rectangle quad is drawn. If I do this in the fragment shader:
outColor = texture(lookUp, uvCoord);
I do not get the error and I see the expected color in the displayed window. I'd appreciate any hints where I can search for a solution.
#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 330\n"
"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 330\n"
"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();
}
Header file is this:
#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;
};
Upvotes: 1
Views: 574
Reputation: 1978
The problem could be solved by setting uniform values in the shader program. In initializeGL I add:
programOCIO->bind();
texture2DLoc = programOCIO->uniformLocation("tex");
texture3DLoc = programOCIO->uniformLocation("lookUp");
and later in the paintGL method I added:
glActiveTexture(GL_TEXTURE0);
texture->bind();
glActiveTexture(GL_TEXTURE1);
lut3dTex->bind();
programOCIO->setUniformValue(texture2DLoc, 0);
programOCIO->setUniformValue(texture3DLoc, 1);
What now works fine.
Upvotes: 2