No (or Transparent) Background for QOpenGLWidget



  • I'm using Qt 5.4.1 with QOpenGLWidget class in order to create a 3D arrow image without a background. Since I don't have a comprehensive knowledge about the subject, I have pulled the Qt's own hellogl2 example and made some (caveman style) adjustments. Here is the furthest I've achieved:

    Screenshot (Arrow rotates with mouse movements. I am trying to remove that pink background and see the rest of the widget with gradient.)

    And now, I am trying to remove the background (or make it transparent) but while I was searching it online, I saw some comments that say it is impossible to achieve that since OpenGL widget is always created first. Here are some methods I thought can make it, but never succeeded:

    • Setting Alpha value of the ClearColor function to zero.
    • Drawing a fully transparent rectangle which covers all the widget (with QPainter). You can see it in my code, commented in PaintGL() function.

    The final design will probably include a live video stream with some text labels and 3D objects on the foreground, so I cannot use inefficient workarounds.

    Although I said that it is the same code with Qt's example, here is my GLWidget class:

    /#include "glwidget.h"
    #include <QMouseEvent>
    #include <QOpenGLShaderProgram>
    #include <QCoreApplication>
    #include <math.h>
    
    GLWidget::GLWidget(QWidget *parent)
    	: QOpenGLWidget(parent),
    	  m_xRot(0),
    	  m_yRot(0),
    	  m_zRot(0),
    	  m_program(0)
    {
    	m_transparent = true;
    	m_core = false;
    
    //	 --transparent causes the clear color to be transparent. Therefore, on systems that
    //	 support it, the widget will become transparent apart from the logo.
    //	m_transparent = QCoreApplication::arguments().contains(QStringLiteral("--transparent"));
    //	if (m_transparent)
    //		setAttribute(Qt::WA_TranslucentBackground);
    
    	setAttribute(Qt::WA_TranslucentBackground,true);
    	//setAttribute(Qt::WA_OpaquePaintEvent);
    	setAttribute(Qt::WA_NoBackground, false);
    	setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint );
    }
    
    GLWidget::~GLWidget()
    {
    	cleanup();
    }
    
    QSize GLWidget::minimumSizeHint() const
    {
    	return QSize(50, 50);
    }
    
    QSize GLWidget::sizeHint() const
    {
    	return QSize(400, 400);
    }
    
    static void qNormalizeAngle(int &angle)
    {
    	while (angle < 0)
    		angle += 360 * 16;
    	while (angle > 360 * 16)
    		angle -= 360 * 16;
    }
    
    void GLWidget::setXRotation(int angle)
    {
    	qNormalizeAngle(angle);
    	if (angle != m_xRot) {
    		m_xRot = angle;
    		emit xRotationChanged(angle);
    		update();
    	}
    }
    
    void GLWidget::setYRotation(int angle)
    {
    	qNormalizeAngle(angle);
    	if (angle != m_yRot) {
    		m_yRot = angle;
    		emit yRotationChanged(angle);
    		update();
    	}
    }
    
    void GLWidget::setZRotation(int angle)
    {
    	qNormalizeAngle(angle);
    	if (angle != m_zRot) {
    		m_zRot = angle;
    		emit zRotationChanged(angle);
    		update();
    	}
    }
    
    void GLWidget::cleanup()
    {
    	makeCurrent();
    	m_logoVbo.destroy();
    	delete m_program;
    	m_program = 0;
    	doneCurrent();
    }
    
    static const char *vertexShaderSourceCore =
    		"#version 150\n"
    		"in vec4 vertex;\n"
    		"in vec3 normal;\n"
    		"out vec3 vert;\n"
    		"out vec3 vertNormal;\n"
    		"uniform mat4 projMatrix;\n"
    		"uniform mat4 mvMatrix;\n"
    		"uniform mat3 normalMatrix;\n"
    		"void main() {\n"
    		"   vert = vertex.xyz;\n"
    		"   vertNormal = normalMatrix * normal;\n"
    		"   gl_Position = projMatrix * mvMatrix * vertex;\n"
    		"}\n";
    
    static const char *fragmentShaderSourceCore =
    		"#version 150\n"
    		"in highp vec3 vert;\n"
    		"in highp vec3 vertNormal;\n"
    		"out highp vec4 fragColor;\n"
    		"uniform highp vec3 lightPos;\n"
    		"void main() {\n"
    		"   highp vec3 L = normalize(lightPos - vert);\n"
    		"   highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n"
    		"   highp vec3 color = vec3(0.39, 1.0, 0.0);\n"
    		"   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n"
    		"   fragColor = vec4(col, 1.0);\n"
    		"}\n";
    
    static const char *vertexShaderSource =
    		"attribute vec4 vertex;\n"
    		"attribute vec3 normal;\n"
    		"varying vec3 vert;\n"
    		"varying vec3 vertNormal;\n"
    		"uniform mat4 projMatrix;\n"
    		"uniform mat4 mvMatrix;\n"
    		"uniform mat3 normalMatrix;\n"
    		"void main() {\n"
    		"   vert = vertex.xyz;\n"
    		"   vertNormal = normalMatrix * normal;\n"
    		"   gl_Position = projMatrix * mvMatrix * vertex;\n"
    		"}\n";
    
    static const char *fragmentShaderSource =
    		"varying highp vec3 vert;\n"
    		"varying highp vec3 vertNormal;\n"
    		"uniform highp vec3 lightPos;\n"
    		"void main() {\n"
    		"   highp vec3 L = normalize(lightPos - vert);\n"
    		"   highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n"
    		"   highp vec3 color = vec3(0.39, 1.0, 0.0);\n"
    		"   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n"
    		"   gl_FragColor = vec4(col, 1.0);\n"
    		"}\n";
    
    void GLWidget::initializeGL()
    {
    	// In this example the widget's corresponding top-level window can change
    	// several times during the widget's lifetime. Whenever this happens, the
    	// QOpenGLWidget's associated context is destroyed and a new one is created.
    	// Therefore we have to be prepared to clean up the resources on the
    	// aboutToBeDestroyed() signal, instead of the destructor. The emission of
    	// the signal will be followed by an invocation of initializeGL() where we
    	// can recreate all resources.
    	connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup);
    
    	initializeOpenGLFunctions();
    
    	//glClearColor(0, 0, 0, m_transparent ? 0 : 1);
    	glClearColor(1, 0, 1, 0);
    
    	m_program = new QOpenGLShaderProgram;
    	m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_core ? vertexShaderSourceCore : vertexShaderSource);
    	m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, m_core ? fragmentShaderSourceCore : fragmentShaderSource);
    	m_program->bindAttributeLocation("vertex", 0);
    	m_program->bindAttributeLocation("normal", 1);
    	m_program->link();
    
    	m_program->bind();
    	m_projMatrixLoc = m_program->uniformLocation("projMatrix");
    	m_mvMatrixLoc = m_program->uniformLocation("mvMatrix");
    	m_normalMatrixLoc = m_program->uniformLocation("normalMatrix");
    	m_lightPosLoc = m_program->uniformLocation("lightPos");
    
    	// Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x
    	// implementations this is optional and support may not be present
    	// at all. Nonetheless the below code works in all cases and makes
    	// sure there is a VAO when one is needed.
    	m_vao.create();
    	QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
    	m_vao.bind();
    	//m_vao.release();
    
    	// Setup our vertex buffer object.
    	m_logoVbo.create();
    	m_logoVbo.bind();
    	m_logoVbo.allocate(m_logo.constData(), m_logo.count() * sizeof(GLfloat));
    
    	m_logoVbo.release();
    	// Store the vertex attribute bindings for the program.
    	setupVertexAttribs();
    
    	// Our camera never changes in this example.
    	m_camera.setToIdentity();
    	m_camera.translate(0, 0, -1);
    
    	// Light position is fixed.
    	m_program->setUniformValue(m_lightPosLoc, QVector3D(0, 0, 70));
    
    	m_program->release();
    }
    
    void GLWidget::setupVertexAttribs()
    {
    	m_logoVbo.bind();
    	QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
    	f->glEnableVertexAttribArray(0);
    	f->glEnableVertexAttribArray(1);
    	f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);
    	f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
    	m_logoVbo.release();
    }
    
    void GLWidget::paintGL()
    {
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glEnable(GL_DEPTH_TEST);
    	glEnable(GL_CULL_FACE);
    
    //	QPainter p(this);
    
    //	p.beginNativePainting();
    
    	m_world.setToIdentity();
    	m_world.rotate(180.0f - (m_xRot / 16.0f), 1, 0, 0);
    	m_world.rotate(m_yRot / 16.0f, 0, 1, 0);
    	m_world.rotate(m_zRot / 16.0f, 0, 0, 1);
    
    	QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
    	m_program->bind();
    	m_program->setUniformValue(m_projMatrixLoc, m_proj);
    	m_program->setUniformValue(m_mvMatrixLoc, m_camera * m_world);
    	QMatrix3x3 normalMatrix = m_world.normalMatrix();
    	m_program->setUniformValue(m_normalMatrixLoc, normalMatrix);
    
    	glDrawArrays(GL_TRIANGLES, 0, m_logo.vertexCount());
    
    	m_program->release();
    
    //	p.endNativePainting();
    
    //	p.setPen(Qt::blue);
    //	p.drawLine(rect().topLeft(), rect().bottomRight());
    }
    
    void GLWidget::resizeGL(int w, int h)
    {
    	m_proj.setToIdentity();
    	m_proj.perspective(45.0f, GLfloat(w) / h, 0.01f, 100.0f);
    }
    
    void GLWidget::mousePressEvent(QMouseEvent *event)
    {
    	m_lastPos = event->pos();
    }
    
    void GLWidget::mouseMoveEvent(QMouseEvent *event)
    {
    	int dx = event->x() - m_lastPos.x();
    	int dy = event->y() - m_lastPos.y();
    
    	if (event->buttons() & Qt::LeftButton) {
    		setXRotation(m_xRot + 8 * dy);
    		setYRotation(m_yRot + 8 * dx);
    	} else if (event->buttons() & Qt::RightButton) {
    		setXRotation(m_xRot + 8 * dy);
    		setZRotation(m_zRot + 8 * dx);
    	}
    	m_lastPos = event->pos();
    }
    

    Is there any way to do this? I have searched it on internet and even asked it on S.O. but I haven't been able to make it for days so any help is appreciated.



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.