OpenGL and QtQuick texture issues

I am developing a simple QQuickItem implementation in C ++ based on the "openglunderqml" example that ships with Qt. I made some changes to use different shaders and two textures that I load. The idea is that the shaders will overlap between the two textures (which are essentially just images that I have loaded into textures).

When I put this QQuickItem on my own in a QML file and run it, everything works fine. The images are crossfading with each other (I tweaked the properties to be crossfaded) and everything looks great. However, if I place other elements such as text, the text does not display as expected - only small, odd-shaped blocks. If I place an image, things get really weird. Instead of rendering the QQuickItem it should display, it displays full screen and upside down. As far as I can tell, the other image is never loaded.

I think I must be not doing what I should be, but I have no idea what. Note that the first block of code contains shaders and render objects, the second contains the loadNewTexture () function that loads a new image into the texture (called only once for each texture, not for each render), and the third contains the QtQuick.qml file.

Here is the opengl code (in the QQuckItem :: Paint method):

// Builds the OpenGL shaders that handle the crossfade
if (!m_program) {
    m_program = new QOpenGLShaderProgram();
    // Shader loads coordinate positions
    m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
                                       "attribute vec2 position;"
                                       "varying vec2 texcoord;"
                                       "void main() {"
                                       "    gl_Position = vec4(position, 0.0, 1.0);"
                                       "    texcoord = position * vec2(0.5) + vec2(0.5);"
                                       "}");

    // Shader does the crossfade
    m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
                                       "uniform lowp float xfade;"
                                       "uniform sampler2D textures[2];"
                                       "varying vec2 texcoord;"
                                       "void main() {"
                                       "    gl_FragColor = mix("
                                       "        texture2D(textures[0], texcoord),"
                                       "        texture2D(textures[1], texcoord),"
                                       "        xfade"
                                       "    );"
                                       "}");

    m_program->bindAttributeLocation("vertices", 0);
    m_program->link();

    connect(window()->openglContext(), SIGNAL(aboutToBeDestroyed()),
            this, SLOT(cleanup()), Qt::DirectConnection);
}

m_program->bind();

// Loads corner vertices as triangle strip
m_program->enableAttributeArray(0);
float values[] = {
    -1, -1,
     1, -1,
    -1,  1,
     1,  1
};
m_program->setAttributeArray(0, GL_FLOAT, values, 2);

// Loads the fade value
m_program->setUniformValue("xfade", (float) m_thread_xfade);

glEnable(GL_TEXTURE_2D);

// Check if a new texture needs to be loaded
if (!new_source_loaded && !m_adSource.isEmpty())
    new_source_loaded = loadNewTexture(m_adSource);

// Loads texture 0 into the shader
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
m_program->setUniformValue("textures[0]", 0);

// Loads texture 1 into the shader
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
m_program->setUniformValue("textures[1]", 1);

// Sets the OpenGL render area to the space given to this components
glViewport((GLint) this->x(), (GLint) this->y(), (GLint) this->width(), (GLint) this->height());

// Sets some parameters
glDisable(GL_DEPTH_TEST);

// Sets the clear color (backround color) to black
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);

// Draws triangle strip
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);

// Cleans up vertices
m_program->disableAttributeArray(0);
m_program->release();

      

LoadNewTexture () function:

bool AdRotator::loadNewTexture(QUrl source) {
    // Load the image from source url
    QImage image(source.path());

    // Check that the image was loaded properly
    if (image.isNull()) {
        qDebug() << QString("AdRotator::loadTexture: Loading image from source: ") << source.toString() << QString(" failed.");
        return false;
    }

    // Update this as the active texture
    active_texture = !active_texture;

    // Convert into GL-friendly format
    QImage GL_formatted_image = QGLWidget::convertToGLFormat(image);

    // Check that the image was converted properly
    if (image.isNull()) {
        qDebug() << QString("AdRotator::loadTexture: Converting image from source: ") << source.toString() << QString(" failed.");
        return false;
    }

    // Generate the texture base
    glGenTextures(1, &textures[active_texture]);
    glBindTexture(GL_TEXTURE_2D, textures[active_texture]);

    // Give texture parameters (scaling and edging options)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     GL_CLAMP_TO_EDGE);

    // Load pixels from image into texture
    glTexImage2D(
        GL_TEXTURE_2D, 0,           /* target, level of detail */
        GL_RGBA,                    /* internal format */
        GL_formatted_image.width(), GL_formatted_image.height(), 0,           /* width, height, border */
        GL_RGBA, GL_UNSIGNED_BYTE,   /* external format, type */
        GL_formatted_image.bits()   /* pixels */
    );

    if (textures[active_texture] == 0) qDebug() << QString("New Texture post-load failed.");

    return true;
}

      

Qml file:

import QtQuick 2.0

Item {
    width: 1920
    height: 1080

    /* Image{} element breaks things
    Image {
        id: image1
        x: 0
        y: 0
        anchors.rightMargin: 0
        anchors.bottomMargin: 0
        anchors.leftMargin: 0
        anchors.topMargin: 0
        sourceSize.height: 1080
        sourceSize.width: 1920
        anchors.fill: parent
        fillMode: Image.PreserveAspectCrop
        source: "images/background.png"
    }*/

    /* The QQuickItem */
    ImageCrossfader {
        x: 753
        y: 107
        width: 1150
        height: 865
    }
}

      

+3


source to share


1 answer


I recently did almost the same exercise and (without executing my code and only processing one texture). I think I have an idea of ​​what you missed: you have to make sure that your final OpenGL autoserver stays at the end of your draw function (more or less) exactly as you found it at the beginning . You released your shader program and turned off the array attribute, but you did not cancel two textures in two texture units. The following at the end of your drawing element function should do the trick:

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);

      



In addition, two more comments:

  • Note that your image image1 from the QML file will hide the ImageCrossfader element entirely (if I'm not mistaken when interpreting the anchors property). Anything you add to your QML scene will be drawn over your opengl lining (hence the name;)).

  • You can safely remove all calls to glEnable (), glDisable (), and glBlendFunc (). In fact, removing them should make your code safer, because the less you change, the fewer changes you have to remember to come back.

+3


source







All Articles