2013-06-20 19 views
5

Używanie OpenGL do przetwarzania obrazu, pierwszy eksperyment to przekonwertować kolorowy obraz na szary, wszystko jest w porządku, ale nie chcę, aby wyświetlał widżet.Wykonaj renderowanie poza ekranem (openGL) za pomocą Qt5

Jeśli nie wywołasz "show()", QGLWidget nie zacznie renderować tekstury. Czy mogę wyświetlić teksturę bez wyświetlania widżetu? Czy QGLWidget jest odpowiednim narzędziem do tego?

część kodów

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

vertex shader

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

fragment shader

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

Edit: użyj QWindow FBO zrobić poza ekranem render, ale wynik jest pusty obraz

kody mogą się kompilować, ale powrót QImage przez QOpenGLFrameBufferObject jest pusty.

.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 

.cpp

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

staram mojej mocy, aby uprościć kody, ale wciąż jest dość rozwlekły

+0

Gdzie są twoje dyrektywy "# version"? – genpfault

+0

Jestem mylący o której wersji powinienem użyć, ale dowiaduję się, że nawet ja nie określam #version, Qt z openGL może zrozumieć glsl tak długo, jak długo trzymam się opengl es 2.0. Proszę mnie poprawić, jeśli się mylę, przez newba, który odkrył, że OpenGL jest bardzo skomplikowany. – StereoMatching

Odpowiedz

9

Na niewidocznej renderowania, spróbuj renderowania w QOpenGLFramebufferObject , który może być converted into a QImage, który z kolei można łatwo zapisać na dysku.

Do tego jednak trzeba jeszcze uczynić na powierzchnię (jak tego wymaga QOpenGLContext::makeCurrent()), więc jedynym wyborem jest rzeczywiście za pomocą QWindow lub QGLWidget aby uzyskać taką powierzchnię.

W Qt 5.1 pojawi się nowa klasa o nazwie QOffscreenSurface, która prawdopodobnie będzie najbardziej odpowiednia dla Twojego zastosowania. Aby uzyskać powierzchnię dla swojej OpenGL context, należy użyć powierzchni OpenGL context, a następnie zrenderować ją do serwera FBO przy użyciu QOpenGLFramebufferObject, a następnie wywołać QOpenGLFramebufferObject::toImage(), aby uzyskać dostęp do pikseli.

+0

Dziękuję, uczę się "przykładu OpenGL Window", kontekstu OpenGL i próbuję zrozumieć, czym jest FBO, dość skomplikowane rzeczy (jestem jedynym, który uważa, że ​​OpenGL jest bardzo skomplikowany?). Będę zamieszczał odpowiedzi, jeśli potrafię wymyślić jak robić to, co chcę. Nawet qml2 jest łatwy w użyciu, kiedy potrzebujesz więcej mocy na temat grafiki, znajomość OpenGL wygląda jak należy. – StereoMatching

Powiązane problemy