2013-02-19 8 views
3

Qt와 함께 제공되는 "openglunderqml"예제를 기반으로 C++에서 간단한 QQuickItem 구현을 개발 중입니다. 다른 셰이더와 두 개의 텍스처를 사용하기 위해 몇 가지 수정을했습니다. 아이디어는 셰이더가 두 텍스처 (기본적으로 텍스처에로드 된 이미지) 사이를 교차 페이딩 할 것이라는 것입니다.OpenGL 및 QtQuick 텍스처 문제

이 QQuickItem을 QML 파일 안에 넣고 실행하면 모든 것이 잘 동작합니다. 이미지는 서로간에 교차 페이드 (crossfading을 유지하기 위해 속성 애니메이션을 설정했습니다) 모든 것이 잘 보입니다. 그러나 텍스트와 같은 다른 요소를 넣으면 텍스트가 제대로 렌더링되지 않습니다. 이상한 모양의 블록 만 있습니다. 이미지를 넣으면 정말 이상해진다. QQuickItem 대신에 렌더링 할 상자를 렌더링하는 대신 전체 화면과 거꾸로 렌더링합니다. 멀리 내가 말할 수있는 한 다른 이미지는 절대로드되지 않습니다.

내가해야 할 일을하고 있지 않아야한다고 생각하지만, 나는 모릅니다. 첫 번째 코드 블록에는 쉐이더와 렌더링 항목이 포함되어 있으며 두 번째 코드에는 텍스처에 새 이미지를로드하는 loadNewTexture() 함수가 포함되어 있습니다 (모든 렌더링이 아닌 텍스처마다 한 번만 호출 됨). 세 번째 코드 블록에는 QtQuick .qml 파일 .

을 Heres합니다 (QQuckItem 내의 :: 페인트 방법)는 OpenGL 번호 :

// 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 파일에서 image1에 이미지 것 ImageCrossfader 항목을 완전히 숨기십시오 (앵커 속성을 해석하는 것으로 잘못 생각하지 않은 경우). QML 장면에 추가하는 모든 내용은 opengl 밑받침 (따라서 이름;))에 그려집니다.

  • 당신은 안전하게 모든 glEnable를 제거 할 수 있습니다(), glDisable()glBlendFunc() 통화. 실제로 제거하면 코드가 안전 해집니다. 변경이 적을수록 되돌릴 것을 기억해야하는 변경 사항이 적기 때문입니다.

+0

확실히 올바른 방향으로 이동합니다. 이제 이미지가 거꾸로 표시되는 대신 다른 QML 요소와 결합 될 때 전체 화면이 표시되는 대신 아무 것도 인쇄되지 않습니다.나는 이것이 더 나은 것처럼 느낀다. 그러나 나는 아직도 그것을 능숙하게 멈추게하는 것을 게을리해야한다. 이 테스트는 독자적으로 수행했는데 작동하는 것처럼 보입니다. 그러나 하나의 QML 파일에서 두 개의 ImageCrossfader 요소를 사용하더라도 하나만 표시됩니다. 더 이상 아이디어가 없습니까? 고마워 btw! –

+0

위의 네 줄 (페인트 기능의 끝 부분)은 자신의 QQuickItem 텍스처의 가시성에 영향을 주어서는 안됩니다. 하지만 내 자신의 조언에 따라, 나는 두 개의'glActiveTexture (...)'호출을 바꿔서, 텍스처 uni 0이 마지막에 활성화되었다. 여전히 작동하지 않는 경우 전체 프로젝트를 어딘가에 액세스 할 수 있습니까? * GL 언더 레이 * 아이템 중 두 개는'glClear()'를 호출하기 때문에 작동하지 않습니다. 이 접근법은 실제로 QML 장면의 배경을 채우는 것만으로 의미가 있습니다. – axxel

+0

선생님, 훌륭합니다. 결국 glClear()에 대한 호출이 단순히 glViewport가 아닌 전체 화면을 지우는 것을 이해하지 못했습니다. 마지막 질문 : glViewport() 호출로 설치 한 뷰포트 만 지우는 좋은 방법이 있습니까? (주 : 활성 텍스처 호출의 순서가 바뀌 었습니다.) –