2013-06-20 5 views
5

OpenGL을 사용하여 일부 이미지 처리를 수행하면 첫 번째 실험에서는 이 회색으로 변환되며, 위젯을 표시하려면 을 원하지 않습니다.Qt5로 오프 스크린 렌더링 (openGL)을 수행합니다.

"show()"를 호출하지 않으면 QGLWidget이 텍스처를 렌더링하지 않습니다. 위젯을 표시하지 않고 텍스처를 렌더링 할 수 있습니까? QGLWidget이이를 수행하는 데 적합한 도구입니까? 코드의

부분

#include <QDebug> 

#include "toGray.hpp" 

toGray::toGray(std::string const &vertex_file, std::string const &fragment_file, QWidget *parent) 
    :basicGLWidget(vertex_file, fragment_file, parent) //read shaders, compile them, allocate VBO 
{ 
} 

void toGray::initializeVertexBuffer() 
{ 
    std::vector<GLfloat> const vertex{ 
     -1.0f, 1.0f, 0.0f, 1.0f, 
     1.0f, 1.0f, 0.0f, 1.0f, 
     -1.0f, -1.0f, 0.0f, 1.0f, 
     1.0f, 1.0f, 0.0f, 1.0f, 
     1.0f, -1.0f, 0.0f, 1.0f, 
     -1.0f, -1.0f, 0.0f, 1.0f, 
    }; 

    initializeVertexBufferImpl(vertex); //copy the data into QOpenGLBuffer 

    QImage img(":/simpleGPGPU/images/emili.jpg"); 
    texture_addr_ = bindTexture(img); 
    resize(img.width(), img.height()); 

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

void toGray::paintGL() 
{ 
    qglClearColor(Qt::white); 
    glClear(GL_COLOR_BUFFER_BIT); 

    program_.bind(); 
    bind_buffer(); 
    program_.enableAttributeArray("qt_Vertex"); 
    program_.setAttributeBuffer("qt_Vertex", GL_FLOAT, 0, 4); 

    glActiveTexture(GL_TEXTURE0); 
    glBindTexture(GL_TEXTURE_2D, texture_addr_); 

    glDrawArrays(GL_TRIANGLES, 0, get_buffer(0).size()); 

    program_.disableAttributeArray("qt_Vertex"); 
    program_.release(); 
    glActiveTexture(0); 
    release_buffer(); 
} 

버텍스 쉐이더

attribute highp vec4 qt_Vertex; 
varying highp vec2 qt_TexCoord0; 

void main(void) 
{  
    gl_Position = qt_Vertex; 
    qt_TexCoord0 = (qt_Vertex.xy + vec2(1.0)) * 0.5; 
} 

조각 쉐이더

uniform sampler2D source; 
varying highp vec2 qt_TexCoord0; 

vec3 toGray(vec3 rgb) 
{ 
    return vec3(rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114); 
} 

void main(void) 
{   
    vec3 gray = toGray(texture2D(source, qt_TexCoord0).rgb); 
    gl_FragColor = vec4(gray, 0.0); 
} 

편집 : 렌더링 오프 스크린 할 QWindow FBO를 사용하지만, 결과는 빈 이미지입니다

코드는 컴파일 할 수 있지만 QOpenGLFrameBufferObject에 의한 QImage 반환은 비어 있습니다.

.HPP

#ifndef OFFSCREENEXP_HPP 
#define OFFSCREENEXP_HPP 

#include <QOpenGLFunctions> 
#include <QWindow> 

class QImage; 
class QOpenGLContext; 

class offScreenExp : public QWindow, protected QOpenGLFunctions 
{ 
public: 
    explicit offScreenExp(QWindow *parent = 0); 

    QImage render(); 

private: 
    QOpenGLContext *context_; 
}; 

#endif // OFFSCREENEXP_HPP 

통화 당은

#include <QImage> 
#include <QOpenGLBuffer> 
#include <QOpenGLContext> 
#include <QOpenGLFramebufferObject> 
#include <QOpenGLShaderProgram> 
#include <QString> 
#include <QWidget> 

#include <QDebug> 

#include "offScreenExp.hpp" 

offScreenExp::offScreenExp(QWindow *parent) : 
    QWindow(parent), 
    context_(nullptr) 
{ 
    setSurfaceType(QWindow::OpenGLSurface); 
    setFormat(QSurfaceFormat()); 
    create(); 
} 

QImage offScreenExp::render() 
{ 
    //create the context 
    if (!context_) { 
     context_ = new QOpenGLContext(this); 
     QSurfaceFormat format; 
     context_->setFormat(format); 

     if (!context_->create()) 
      qFatal("Cannot create the requested OpenGL context!"); 
    } 

    context_->makeCurrent(this); 
    initializeOpenGLFunctions(); 

    //load image and create fbo 
    QString const prefix("/Users/Qt/program/experiment_apps_and_libs/openGLTest/simpleGPGPU/"); 
    QImage img(prefix + "images/emili.jpg"); 
    if(img.isNull()){ 
     qFatal("image is null"); 
    } 
    QOpenGLFramebufferObject fbo(img.size()); 
    qDebug()<<"bind success? : "<<fbo.bind(); 

    //if(glCheckFramebufferStatus(fbo.handle()) != GL_FRAMEBUFFER_COMPLETE){ 
    // qDebug()<<"frame buffer error"; 
    //} 
    qDebug()<<"has opengl fbo : "<<QOpenGLFramebufferObject::hasOpenGLFramebufferObjects(); 

    //use two triangles two cover whole screen 
    std::vector<GLfloat> const vertex{ 
     -1.0f, 1.0f, 0.0f, 1.0f, 
     1.0f, 1.0f, 0.0f, 1.0f, 
     -1.0f, -1.0f, 0.0f, 1.0f, 
     1.0f, 1.0f, 0.0f, 1.0f, 
     1.0f, -1.0f, 0.0f, 1.0f, 
     -1.0f, -1.0f, 0.0f, 1.0f, 
    }; 

    //initialize vbo 
    QOpenGLBuffer buffer(QOpenGLBuffer::VertexBuffer); 
    buffer.create(); 
    buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); 
    buffer.bind(); 
    buffer.allocate(&vertex[0], vertex.size() * sizeof(GLfloat)); 
    buffer.release(); 

    //create texture 
    GLuint rendered_texture; 
    glGenTextures(1, &rendered_texture); 

    // "Bind" the newly created texture : all future texture functions will modify this texture 
    glBindTexture(GL_TEXTURE_2D, rendered_texture); 

    //naive solution, better encapsulate the format in a function 
    if(img.format() == QImage::Format_Indexed8){ 
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, img.width(), img.height(), 0, GL_RED, GL_UNSIGNED_BYTE, img.scanLine(0)); 
    }else if(img.format() == QImage::Format_RGB888){ 
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width(), img.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, img.scanLine(0)); 
    }else{ 
     QImage temp = img.convertToFormat(QImage::Format_RGB888); 
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width(), img.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, temp.scanLine(0)); 
    } 

    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); 

    glBindTexture(GL_TEXTURE_2D, 0); 

    //compile and link program 
    QOpenGLShaderProgram program; 
    if(!program.addShaderFromSourceCode(QOpenGLShader::Vertex, 
             "attribute highp vec4 qt_Vertex;" 
             "varying highp vec2 qt_TexCoord0;" 

             "void main(void)" 
             "{" 
             " gl_Position = qt_Vertex;" 
             " qt_TexCoord0 = (qt_Vertex.xy + vec2(1.0)) * 0.5;" 
             "}")){ 
     qDebug()<<"QOpenGLShader::Vertex error : " + program.log(); 
    } 

    // Compile fragment shader 
    if (!program.addShaderFromSourceCode(QOpenGLShader::Fragment, 
             "uniform sampler2D source;" 
             "varying highp vec2 qt_TexCoord0;" 

             "vec3 toGray(vec3 rgb)" 
             "{" 
             " return vec3(rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114);" 
             "}" 

             "void main(void)" 
             "{" 
             "vec3 gray = toGray(texture2D(source, qt_TexCoord0).rgb);" 
             "gl_FragColor = vec4(gray, 0.0);" 
             "}" 
             )){ 
     qDebug()<<"QOpenGLShader::Fragment error : " + program.log(); 
    } 

    // Link shader pipeline 
    if (!program.link()){ 
     qDebug()<<"link error : " + program.log(); 
    } 

    //render the texture as usual 
    //render the texture as usual 
glClearColor(0, 0, 0, 1); 
glClear(GL_COLOR_BUFFER_BIT); 
glViewport(0, 0, img.width(), img.height()); 

program.bind(); 
buffer.bind(); 
program.enableAttributeArray("qt_Vertex"); 
program.setAttributeBuffer("qt_Vertex", GL_FLOAT, 0, 4); 

glActiveTexture(GL_TEXTURE0); 
glBindTexture(GL_TEXTURE_2D, rendered_texture); 

//bind and create fbo 
QOpenGLFramebufferObject fbo(img.size()); 
qDebug()<<"bind success? : "<<fbo.bind(); 

glDrawArrays(GL_TRIANGLES, 0, buffer.size()); 
QImage result = fbo.toImage(); 

program.disableAttributeArray("qt_Vertex"); 
program.release();  
buffer.release(); 

fbo.release(); 
glActiveTexture(0); 
glBindTexture(GL_TEXTURE_2D, 0); 
context_->doneCurrent(); 

    return result; 
} 

내가 코드를 단순화하기 위해 최선을 노력하지만, 그것은 QOpenGLFramebufferObject로 렌더링을 시도, 오프 스크린 렌더링을 위해 꽤 자세한

+0

'# 버전'지시어는 어디에 있습니까? – genpfault

+0

어떤 버전을 사용해야하는지 혼란 스럽지만 #version을 지정하지 않은 경우에도 OpenGL에서 Qt를 사용하면 OpenGL 2.0을 사용하는 한 glsl을 이해할 수 있습니다. 잘못된 경우 나에게 수정하십시오. OpenGL이 매우 복잡한 newb를 발견했습니다. – StereoMatching

답변

9

여전히 , 이는 converted into a QImage 일 수 있으며, 차례로 디스크에 쉽게 저장할 수 있습니다.

그러나 렌더링 할 표면이 여전히 필요하므로 (필요) 실제로는 이러한 표면을 얻으려면 QWindow 또는 QGLWidget을 사용하십시오.

Qt 5.1에는 QOffscreenSurface이라는 새로운 클래스가 있으며 이는 아마도 여러분의 유스 케이스에 가장 적합 할 것입니다. OpenGL context의 표면을 얻으려면 QOffscreenSurface을 사용하고 QOpenGLFramebufferObject을 사용하여 FBO로 렌더링 한 다음 QOpenGLFramebufferObject::toImage()으로 호출하여 픽셀에 액세스 할 수 있습니다.

+0

감사합니다. "OpenGL Window example", OpenGL 컨텍스트를 연구 중이며 FBO가 무엇인지 이해하려고합니다. (OpenGL이 매우 복잡하다고 생각하는 유일한 사람입니까?). 내가 원하는 것을하기. qml2도 사용하기 쉽습니다. 그래픽에 대한 더 많은 힘이 필요하면 OpenGL과 같은 지식이 필요합니다. – StereoMatching

관련 문제