分析一个别人的qt+opengl例子

来源:互联网 发布:淘宝行业平均停留时间 编辑:程序博客网 时间:2024/06/05 19:43

 Qt5+OpenGL学习笔记(用Qt封装的QOpenGL系列绘制有颜色有深度的三角形→_→)

      最近学习OpenGL,虽然说Qt可以使用原生OpenGL的API,但是Qt也提供了封装的QOpenGL系列。我用原生的和封装的分别实现了一次简单渲染(都是渲染两个有深度和颜色的三角形)。

0_1455269566819_upload-0d1bbdea-3f41-4724-81d0-ea7026e3ff90

       原生的OpenGL用法我就不赘述了(主要是总结不好TvT,而且有很多资料可查)。(PS:两个程序的源码附在最后了)
       主要说一下封装的QOpenGL几个注意的地方
一、 QOpenGLBuffer类
在使用前,构造函数处可指定Buffer类型。默认为VertexBuffer。
0_1455269596523_upload-b062e1b9-be25-4642-a3d2-f8486b778375
在使用之前先要create(),之后bind到当前的OpenGL context上。
使用allocate()分配存储空间,同时可以用某个数据来初始化分配的空间。
0_1455269616250_upload-bb5bcfbf-7ef3-4352-b245-be6078a68579
相当于原生API中:

<code class="hljs" style="display: inline-block; padding: 0.5em; background-color: rgb(35, 35, 35); color: rgb(230, 225, 220); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; overflow-x: auto; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">glGenBuffers();glBindBuffer();glBufferData();</code>

二、 QOpenGLShader类
可以在构造函数的地方选择shader的类型。可以有多种方式添加源码,详情参见Qt帮助文档,很简单。
0_1455269642132_upload-085b29bb-6d54-463b-8b4c-a2ae92cf84fc
相当于原生API中:
0_1455269655462_upload-4e389e98-1405-4485-87cd-7e1eb8c6a9cd
三、 QOpenGLShaderProgram类
可以直接从文件、源码之类的添加Shader。也可以使用addShader添加现有的Shader。需要调用link()将添加到这个program的shader都链接起来。之后调用bind()使该program成为当前唯一绑定到OpenGL Context上的其它porgram将被释放(release)掉。
0_1455269673552_upload-f0c7e6ce-0dac-47cc-8cb6-dc3bd8ab55cc
相当于原生API中:
0_1455269683068_upload-add75868-51a0-43fb-b2eb-9ac7a11d3f78
之后使用enableAttributeArray来激活相应的顶点属性数组(Enables the vertex array at location in this shader program so that the value set by setAttributeArray() on location will be used by the shader program.)
0_1455269705195_upload-0abb70b2-1e80-4427-8668-07e20c23503b
相当于原生API中:
0_1455269721629_upload-9da766a0-bbd4-4075-81c3-c5d0f31a15c7

由于程序很简单,没有涉及QOpenGLContext类和其他一些类的介绍~感兴趣可以去翻阅他人的博客之类的。。。(PS:我还是喜欢用原生的。。。)

源代码传送门:
http://pan.baidu.com/s/1i3OmadZ

       不过我是看不出来有什么深度,


 main.cpp

#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}
MainWindow::~MainWindow()
{
    delete ui;
}

      看到这里,是不是感到很奇怪,就一个普通的QMainWindow,opengl的内容在哪调用?

      这个倒是看到了以前没碰到多的方法,在mainwindow.ui中

      <widget class="xiaoGLWidget" name="openGLWidget">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
      </widget>
      在UI布局中使用了一个自定义的widget,不知道他是怎么拖出来的,很神奇。


xiaoglwidget.h

#ifndef XIAOGLWIDGET_H
#define XIAOGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_3_Compatibility>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
class xiaoGLWidget : public QOpenGLWidget,protected QOpenGLFunctions_4_3_Compatibility
{
public:
    xiaoGLWidget(QWidget *parent);
    virtual ~xiaoGLWidget();
    void installShader();
    void sendDataToOpenGL();
protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int w,int h);
private:
    QOpenGLShaderProgram m_program;
    QOpenGLBuffer m_vertexBuf;
    QOpenGLBuffer m_indexBuf;
};
#endif // XIAOGLWIDGET_H

xiaoglwidget.cpp

#include "xiaoglwidget.h"
extern const char* vertexShaderCode;
extern const char* fragmentShaderCode;
xiaoGLWidget::xiaoGLWidget(QWidget *parent):m_program(this),m_indexBuf(QOpenGLBuffer::IndexBuffer)
{
}
xiaoGLWidget::~xiaoGLWidget()
{
    m_vertexBuf.destroy();
    m_indexBuf.destroy();
}
void xiaoGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    installShader();
    sendDataToOpenGL();
    glEnable(GL_DEPTH_TEST);
}
void xiaoGLWidget::paintGL()
{
    initializeOpenGLFunctions();
    glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
    glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,NULL);
}
void xiaoGLWidget::resizeGL(int w, int h)
{
}
void xiaoGLWidget::sendDataToOpenGL()
{
    initializeOpenGLFunctions();
    const GLfloat RED_TRIANGLE_DEPTH = -0.5f;
    const GLfloat BLUE_TRIANGLE_DEPTH = 0.5f;
    GLfloat verts[]={
        +0.0f, -1.0f, RED_TRIANGLE_DEPTH,
        +1.0f,+0.0f,+0.0f,
        +1.0f, +1.0f, RED_TRIANGLE_DEPTH,
        +1.0f,+0.0f,+0.0f,
        -1.0f, +1.0f, RED_TRIANGLE_DEPTH,
        +1.0f,+0.0f,+0.0f,
        +0.0f, +1.0f, BLUE_TRIANGLE_DEPTH,
        +0.0f, +0.0f, +1.0f,
        -1.0f, -1.0f, BLUE_TRIANGLE_DEPTH,
        +0.0f, +0.0f, +1.0f,
        +1.0f, -1.0f, BLUE_TRIANGLE_DEPTH,
        +0.0f, +0.0f, +1.0f,
    };
    GLushort indices[]={0,1,2,3,4,5};
    this->m_vertexBuf.create();
    this->m_indexBuf.create();
    this->m_vertexBuf.bind();
    this->m_indexBuf.bind();
    this->m_vertexBuf.allocate(verts,sizeof(verts));
    this->m_indexBuf.allocate(indices,sizeof(indices));
    m_program.enableAttributeArray(0);
    m_program.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(float)*6);
    m_program.enableAttributeArray(1);
    m_program.setAttributeBuffer(1,GL_FLOAT,sizeof(float)*3,3,sizeof(float)*6);
}
void xiaoGLWidget::installShader()
{
    QOpenGLShader vertexShader(QOpenGLShader::Vertex);
    vertexShader.compileSourceCode(vertexShaderCode);
    QOpenGLShader fragmentShader(QOpenGLShader::Fragment);
    fragmentShader.compileSourceCode(fragmentShaderCode);
    m_program.addShader(&vertexShader);
    m_program.addShader(&fragmentShader);
    m_program.link();
    m_program.bind();
}

shadercode.cpp

const char*  vertexShaderCode =
        "#version 430\r\n"
        ""
        "in layout(location=0) vec3 position;"
        "in layout(location=1) vec3 vertexColor;"
        ""
        "out vec3 theColor;"
        ""
        "void main()"
        "{"
        "   gl_Position = vec4(position, 1.0);"
        "   theColor = vertexColor;"
        "}";
const char* fragmentShaderCode =
        "#version 430\r\n"
        ""
        "out vec4 daColor;"
        "in vec3 theColor;"
        ""
        "void main()"
        "{"
        "   daColor = vec4(theColor,1.0);"
        "}";

       定义了一个widget,

class xiaoGLWidget : public QOpenGLWidget,protected QOpenGLFunctions_4_3_Compatibility

      继承自QOpenGLWidget,然后初始化opengl functions api。

      关于shader,就和我前面的第二个程序写法不同了。

QOpenGLShader vertexShader(QOpenGLShader::Vertex);
QOpenGLShader fragmentShader(QOpenGLShader::Fragment);
      创建了两个着色器之后,使用compileSourceCode来加载程序

      而之前的我是先创建一个项目对象,用项目对象的addShaderFromSourceCode来加载程序

      去看下qt的源代码实现,就是调用者和被调用者的关系。

      然后调用addShader加载进去

      之后就是link、bind

      

const GLfloat RED_TRIANGLE_DEPTH = -0.5f;
const GLfloat BLUE_TRIANGLE_DEPTH = 0.5f;

      z轴正向指向里,所以负数的会在正数上方,也就是红色在蓝色上方,哦,这就是他说的深度。

GLfloat verts[]={
        +0.0f, -1.0f, RED_TRIANGLE_DEPTH,
        +1.0f,+0.0f,+0.0f,
        +1.0f, +1.0f, RED_TRIANGLE_DEPTH,
        +1.0f,+0.0f,+0.0f,
        -1.0f, +1.0f, RED_TRIANGLE_DEPTH,
        +1.0f,+0.0f,+0.0f,
        +0.0f, +1.0f, BLUE_TRIANGLE_DEPTH,
        +0.0f, +0.0f, +1.0f,
        -1.0f, -1.0f, BLUE_TRIANGLE_DEPTH,
        +0.0f, +0.0f, +1.0f,
        +1.0f, -1.0f, BLUE_TRIANGLE_DEPTH,
        +0.0f, +0.0f, +1.0f,
    };
      这里定义了12组,为什么定义这么多?

      

this->m_vertexBuf.create();
this->m_indexBuf.create();


     这里有两个buf,干什么用的?

GLushort indices[]={0,1,2,3,4,5};

this->m_vertexBuf.allocate(verts,sizeof(verts));
this->m_indexBuf.allocate(indices,sizeof(indices));
    一个存放顶点数据,一个存放索引 ?


m_program.enableAttributeArray(0);
m_program.enableAttributeArray(1);

      使能了,那要先看下着色器,先看片段的

const char* fragmentShaderCode =
        "#version 430\r\n"
        ""
        "out vec4 daColor;"
        "in vec3 theColor;"
        ""
        "void main()"
        "{"
        "   daColor = vec4(theColor,1.0);"
        "}";
      有了之前的基础,看着就简单了,之前就知道了 120之后就没有了gl_FragColor,所以要自己定义一个输出,设置为输入的颜色,alpha为1.0f,输入即顶点着色器的颜色输出

const char*  vertexShaderCode =
        "#version 430\r\n"
        ""
        "in layout(location=0) vec3 position;"
        "in layout(location=1) vec3 vertexColor;"
        ""
        "out vec3 theColor;"
        ""
        "void main()"
        "{"
        "   gl_Position = vec4(position, 1.0);"
        "   theColor = vertexColor;"
        "}";
      颜色设置为输入的vertexColor颜色

     他这里直接使用layout(location=0)定义了位置

     使能后装载

m_program.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(float)*6);
m_program.setAttributeBuffer(1, GL_FLOAT, sizeof(float)*3, 3, sizeof(float)*6);
     (之前的我是用glVertexAttribPointer装载顶点和颜色数据的)

     这里装载前面的buffer

void setAttributeBuffer(int location, GLenum type, int offset, int tupleSize, int stride = 0);
void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)

     使能深度测试

glEnable(GL_DEPTH_TEST);

     绘制     

glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);

      

      没有看到buffer使用的地方

在使用之前先要create(),之后bind到当前的OpenGL context上。
使用allocate()分配存储空间,同时可以用某个数据来初始化分配的空间

     十二组数据,是一组顶点数据,一组颜色数据,那怎么区分的呢

setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(float)*6);
      offset = 0,第一组开始,

      tuplesize = 3,三个数据,就是第一组三个数据

      stride = sizeof(float) * 6,步幅这么长,下次去就是6个数据之后,就是第三组数据开始

setAttributeBuffer(1, GL_FLOAT, sizeof(float)*3, 3, sizeof(float)*6);
     offset = sizeof(float) * 3, 就是第二组数据的开始,

     tuplesize = 3,也就是第二组三个数据,

     stride = sizeof(float) * 6,步幅这么长,下次去就是6个数据之后,就是第四组数据开始


     取的顺序呢,indices[]={0,1,2,3,4,5}; (这个应该是这样理解?)


     退出时两个buffer销毁

m_vertexBuf.destroy();
m_indexBuf.destroy();

from: http://blog.csdn.net/fu851523125/article/details/51193528



0 0
原创粉丝点击