OpenGL和QtQuick纹理问题 [英] OpenGL and QtQuick Texture Problems

查看:430
本文介绍了OpenGL和QtQuick纹理问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个简单的QQuickItem实现在C ++基于openglunderqml例子与Qt。我做了一些修改,以使用不同的着色器和两个纹理,我加载。这个想法是着色器将交叉淡入两个纹理之间(这本质上只是我加载到纹理的图像)。

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

当我把这个QQuickItem单独放在QML文件中并运行它,一切工作正常。图像交叉淡入淡出(我设置了一个属性动画,以保持他们交叉淡化),一切似乎很好。但是,如果我把其他元素,如文本,文本不能正确呈现 - 只是很少奇怪的块。如果我把一个图像,事情变得很奇怪。代替QQuickItem渲染它应该渲染的框,它渲染全屏幕和颠倒。至于我可以告诉其他图像从来没有加载。

When I put this QQuickItem alone inside a QML file and run it, everything works fine. The images crossfade between each other (I've setup a property animation to keep them crossfading) and everything appears fine. However if I put other elements such as text, the text doesn't render properly -- just little oddly shaped blocks. If I put an image in, things get really weird. Instead of the QQuickItem rendering the the box that its supposed to render in, it renders full screen and upside down. As far as I can tell the other image is never loaded.

我想我一定不是做一些我应该是,但我不知道什么。注意,第一个代码块包含着色器和渲染东西,第二个包含将新图像加载到纹理中的函数loadNewTexture()(每个纹理只调用一次 - 不是每个渲染),第三个包含QtQuick .qml文件

I think I must be not doing something that I should be, but I've no idea what. Note that the first code block contains the shaders and rendering stuff, the second contains the function loadNewTexture() which loads a new image into a texture (only called once per texture -- not every rendering) and the third contains the QtQuick .qml file.

使用opengl代码(在QQuckItem :: Paint方法内):

Heres the opengl code (within 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()函数:

The 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文件:

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
    }
}


推荐答案

我最近做了几乎相同的练习,(没有实际运行你的代码,只处理一个纹理)我想我可能有一个想法你错过了:你必须确保你的 OpenGL状态机在你的绘画功能结束(或多或少)完全 。你确实发布了着色器程序并禁用了数组属性,但没有解除两个纹理单元中的两个纹理。以下在你的paint成员函数的结尾应该做的窍门:

I recently did pretty much the same exercise and (not having actually ran your code and only having dealt with one texture) I think I might have an idea what you missed: You have to make sure your OpenGL state machine is left at the end of your paint function (more or less) exactly as you found it at the beginning. You did release the shader program and disabled the array attribute but did not unbind the two textures in your two texture units. The following at the end of your paint member function should do the trick:

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

除此之外,还有两个注释:

Other than that, two further comments:


  • 请注意,您的 image1 来自QML文件的图片将完全隐藏您的ImageCrossfader项目(如果我没有错误地解释anchors属性)。您添加到QML场景中的所有内容都会显示在 opengl底层(因此名称为)。

  • Please note that your image1 Image from the QML file would hide your ImageCrossfader item completely (if I am not mistaken interpreting the anchors property). Everything you add to your QML scene will get painted over your opengl underlay (hence the name ;)).

您可以安全地移除所有 glEnable() glDisable() glBlendFunc实际删除它们应该使您的代码更安全,因为您改变的越少,记住要还原的更改就越少。

You can safely remove all glEnable(), glDisable() and glBlendFunc() calls. Actually removing them should make your code safer, because the less you change, the less changes you have to remember to revert.

这篇关于OpenGL和QtQuick纹理问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆