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.