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
Gdzie są twoje dyrektywy "# version"? – genpfault
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