2013-02-19 152 views
3

我正在開發的C++基礎上使用Qt來了「openglunderqml」例如一個簡單的QQuickItem實現。我做了一些修改,以使用不同的着色器和兩個我加載的紋理。其思想是着色器將在兩個紋理之間交叉淡入淡出(實際上這只是我加載到紋理中的圖像)。OpenGL和QtQuick紋理問題

當我把這個QQuickItem單獨一個QML文件中並運行它,一切工作正常。圖像在彼此之間交叉淡入淡出(我已經設置了一個屬性動畫來保持它們淡入淡出),一切都很好。但是,如果我放置其他元素(如文本),則文本無法正確呈現 - 只是形狀奇怪的塊。如果我把圖像放進去,事情變得很奇怪。而不是呈現它應該呈現的框的QQuickItem,它呈現全屏並顛倒。據我所知,其他圖像從未加載。

我想我一定是沒有做的東西,我是應該的,但我不知道是什麼。請注意,第一個代碼塊包含着色器和渲染材料,第二個代碼塊包含將新圖像加載到紋理中的函數loadNewTexture()(每個紋理只調用一次 - 不是每次渲染),第三個包含QtQuick .qml文件。

赫雷什OpenGL的代碼(QQuckItem內:: Paint方法):

// 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()函數:

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

回答

3

我最近做了幾乎相同的練習,並且(實際上並沒有運行你的代碼,只處理過一個紋理)想我可能有一個想法,你錯過了什麼:你必須確保你的OpenGL的狀態機在您的油漆功能(或多或少)完全相同的留底,你發現它在一開始。你確實釋放了着色器程序並禁用了數組屬性,但沒有解除你的兩個紋理單元中的兩個紋理。在您的油漆成員函數結束下面應該做的伎倆:

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

除此之外,另外兩個意見:

  • 請注意,從QML文件的此搜索圖像將完全隱藏ImageCrossfader項目(如果我沒有錯誤地解釋錨點屬性)。您添加到您的QML現場一切都將得到畫的OpenGL下墊(因此而得名;))。

  • 您可以安全地刪除所有glEnable()glDisable()函數glBlendFunc()調用。實際上,刪除它們應該使你的代碼更安全,因爲你改變得越少,你必須記住要恢復的變化越少。

+0

這無疑是正確的方向邁出的一步。現在,當與其他QML元素結合使用時,圖像不會顯示爲顛倒和全屏,也不會打印任何圖像。我覺得這樣比較好,但我仍然必須忽略一些阻止它發揮出色的東西。 請注意,我已經對其進行了單獨測試,它似乎可以正常工作,但即使我將兩個ImageCrossfader元素放在一個QML文件中,也只顯示一個。還有什麼想法?非常感謝btw! – 2013-02-21 05:16:34

+0

上面提到的4行(在繪製函數結束時)不應該影響您自己的QQuickItem紋理的可見性。但是按照我自己的建議,我換了兩個'glActiveTexture(...)'調用,所以紋理單元0在最後被激活。 如果它仍然不起作用,你可以讓整個項目在某個地方訪問嗎? 由於兩者都調用glClear(),所以有兩個* GL底層*項不起作用。這種方法對於呈現QML場景的一個(填充)背景真的非常有意義。 – axxel 2013-02-21 12:48:38

+0

你先生,很棒。事實證明,我只是不明白調用glClear()會清除整個屏幕,而不僅僅是glViewport。最後一個問題:是否有一種很好的方法來清除我用glViewport()調用設置的視口? (注意:它正在切換活動紋理調用的順序) – 2013-02-21 17:58:13