又一种Qt + OpenGL 的离屏渲染方法

 前面的博客《Qt + OpenGL + 离屏渲染》介绍了一种离屏渲染的办法:先在framebuffer里面绘制,然后把绘制的结果转化为QImage。但是这样做涉及到从显存(framebuffer)到内存QImage的传递,降低效率。本博客介绍一种新办法,从显存到显存,不必经由内存。

本文受了

http://www.cppblog.com/init/archive/2012/02/16/165778.aspx

的启发。



上代码:

pro文件

#-------------------------------------------------
#
# Project created by QtCreator 2017-12-16T21:21:01
#
#-------------------------------------------------

QT       += core gui opengl

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = frmBuff
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h

LIBS += -lopengl32 -lGLU32

h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
//#include 

class MainWindow : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

    GLuint      m_uiFBO;
    GLuint      m_uiDepthBuff;
    GLuint      m_uiTex;
protected:
    void        initializeGL();
    void        resizeGL(int, int);
    void        paintGL();
};

#endif // MAINWINDOW_H

cpp文件

#include "mainwindow.h"
#include 


MainWindow::MainWindow(QWidget *parent)
    : QOpenGLWidget(parent)
{
}

MainWindow::~MainWindow()
{

}

void MainWindow::initializeGL()
{
    initializeOpenGLFunctions();
    glGenFramebuffers(1, &m_uiFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBO);

    glGenRenderbuffers(1, &m_uiDepthBuff);
    glBindRenderbuffer(GL_RENDERBUFFER, m_uiDepthBuff);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 256, 256);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_uiDepthBuff);

    glGenTextures(1,&m_uiTex);
    glBindTexture(GL_TEXTURE_2D, m_uiTex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,256,256,0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glGenerateMipmap(GL_TEXTURE_2D);
    glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,m_uiTex,0);

    GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER);
    QMessageBox msg;
    switch( status )
    {
    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:

        msg.setText("GL_FRAMEBUFFER_UNSUPPORTED_EXT!");
        msg.exec();
        break;
    }
}

void MainWindow::paintGL()
{
    glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBO);
    glPushAttrib(GL_VIEWPORT_BIT);

    glViewport(0,0,256,256);
    glClearColor(0.0,1.0,0.0,0.0);//frambuffer black
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, m_uiTex);

    glPopAttrib();

    glBindFramebuffer(GL_FRAMEBUFFER,0);

    glClearColor( 0.9f, 0.2f, 0.2f, 1.0f );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, m_uiTex);

    GLfloat arrCubeVertices[] = {
        0,0, 0,0,0,
        0,1, 0,0.5,0,
        1,1, 0.5,0.5,0,
        1,0, 0.5,0,0,
    };
    glInterleavedArrays( GL_T2F_V3F, 0, arrCubeVertices );
    glDrawArrays( GL_QUADS, 0, 20 );
}

void MainWindow::resizeGL(int w, int h)
{

}

上面 的 例子 画出来 的 纹理不稳定--几乎 每次最小化窗口都会改变纹理的外观。下面给出另一种更稳定的绘制办法:

#include "mainwindow.h"
#include 


MainWindow::MainWindow(QWidget *parent)
    : QOpenGLWidget(parent)
{
}

MainWindow::~MainWindow()
{

}

void MainWindow::initializeGL()
{
    initializeOpenGLFunctions();
    glGenFramebuffers(1, &m_uiFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBO);

    glGenRenderbuffers(1, &m_uiDepthBuff);
    glBindRenderbuffer(GL_RENDERBUFFER, m_uiDepthBuff);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 256, 256);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_uiDepthBuff);

    glGenTextures(1,&m_uiTex);
    glBindTexture(GL_TEXTURE_2D, m_uiTex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,256,256,0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glGenerateMipmap(GL_TEXTURE_2D);
    glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,m_uiTex,0);

    GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER);
    QMessageBox msg;
    switch( status )
    {
    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:

        msg.setText("GL_FRAMEBUFFER_UNSUPPORTED_EXT!");
        msg.exec();
        break;
    }

	glPushAttrib(GL_VIEWPORT_BIT);
    glViewport(0,0,256,256);
    glClearColor(0.0,1.0,0.0,0.0);//frambuffer black
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glPopAttrib();
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void MainWindow::paintGL()
{
    glClearColor( 0.9f, 0.2f, 0.2f, 1.0f );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glLoadIdentity();
	
	GLfloat arrTex[] = {0.0,0.0,1.0, 0.0,1.0, 1.0, 0.0, 1.0};
	GLfloat arrVertex[] = {0.0,0.0, 50.0, 0.0, 50.0, 50.0, 0.0, 50.0};
    glBindTexture(GL_TEXTURE_2D, m_uiTex);

    /*GLfloat arrCubeVertices[] = {
        0,0, 0,0,0,
        0,1, 0,50,0,
        1,1, 50,50,0,
        1,0, 50,0,0,
    };*/
    //glInterleavedArrays( GL_T2F_V3F, 0, arrCubeVertices );
    //glDrawArrays( GL_QUADS, 0, 20 );
	//glBindTexture(GL_TEXTURE_2D, 0);

	glEnable(GL_TEXTURE_2D);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glTexCoordPointer(2, GL_FLOAT, 0, arrTex);
	glVertexPointer(2, GL_FLOAT, 0, &arrVertex[0]);
    glDrawArrays(GL_QUADS, 0, 4);
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glBindTexture(GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);
}

void MainWindow::resizeGL(int w, int h)
{
	glViewport(0,0,w,h);
	glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
}


在上面的例子里,我建立了framebuffer  m_uiFBO,然后建立renderbuffer m_uiDepthBuff 和 纹理  m_uiTex。

在paintGL()函数里,我先利用 语句  glBindFrameBuffer(GL_FAMEBUFFER, m_uiFBO),指定纹理作为绘制对象,把纹理填为绿色。然后调用glBindFrameBuffer(GL_FAMEBUFFER, 0),把绘制对象变更为当前窗体。此时只要把纹理的内容通过 glInterleaveArrays() 和 glDrawArrays() 绘制到屏幕右上角即可。而屏幕自身的颜色由函数glClearColor(0.9, 0.2, 0.2, 1.0);决定。


效果:

又一种Qt + OpenGL 的离屏渲染方法_第1张图片

你可能感兴趣的:(qt,opengl,opengl)