首页 > 技术文章 > QT+OpenGL(01)--实现三角形渲染

gispathfinder 2019-05-21 23:39 原文

1.openglwidget.ui


<ui version="4.0">
 <author/>
 <comment/>
 <exportmacro/>
 <class>OpenGLWidget</class>
 <widget class="QWidget" name="OpenGLWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
 </widget>
 <pixmapfunction/>
 <connections/>
</ui>


2. openglwidget.h

#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H

#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <GL/gl.h>
#include <qopengl.h>
#include <qopenglfunctions.h>
#include <qopenglshaderprogram.h>

namespace Ui {
class OpenGLWidget;
}

class OpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT


public:
    QOpenGLShaderProgram* program;
    GLuint programId;
    GLuint verVbo;
    GLuint indexVbo;
    GLuint colorVbo;
    GLuint  matrixLocation;
    GLuint vertexLocation;
    GLuint clorLocation;
    QMatrix4x4  projection;
    GLsizei vVerticesLen;
    GLsizei triIndexLen;
    GLsizei colorsLen ;

    GLuint triIndexs[3] = {0, 1, 2};
    GLfloat vertex[6] = {
        -0.5f, 0.0f,
        0.5f, 0.0f,
        0.0f, 0.5f,
    };
    GLfloat colors[12] = {1.0f, 0.0f, 0.0f, 1.0f,
                        0.0f, 1.0f, 0.0f, 1.0f,
                        0.0f, 0.0f, 1.0f, 1.0f,
                       };

    explicit OpenGLWidget(QWidget *parent = nullptr);
    ~OpenGLWidget();


//    //三角形顶点坐标
//    GLfloat* vertex;

//    //三角形顶点索引
//    GLuint* triIndexs;

//    //三角形顶点颜色
//    GLfloat* colors;


private:
    Ui::OpenGLWidget *ui;
protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int w, int h);
    void initVbo();
};

#endif // OPENGLWIDGET_H


3. openglwidget.cpp

#include "openglwidget.h"
#include "ui_openglwidget.h"
#include <GL/gl.h>
#include <qopengl.h>
#include <qopenglfunctions.h>
#include <qopenglshaderprogram.h>



OpenGLWidget::OpenGLWidget(QWidget *parent) :
    QOpenGLWidget(parent),
    ui(new Ui::OpenGLWidget)
{
    ui->setupUi(this);
}



OpenGLWidget::~OpenGLWidget()
{
    delete ui;
}

void OpenGLWidget::initializeGL()
{
    //调用内容初始化函数
    initializeOpenGLFunctions();

    program = new QOpenGLShaderProgram(this);

    if(!program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader/vertexshader.vect")){
        printf("no found vertexshader.vert");
        return;
    }
    if(!program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader/fragmentshader.frag")){
        printf("no found fragmentshader.frag");
        return;
    }
    if(!program->link()){
        printf("no link");
        return;
    }
    if(!program->bind()){
        printf("no bind");
        return;
    }

    // 获取shaderprogram的id号,然后可以通过id号获取一些属性...
    programId = program->programId();
    printf("programId: %d", programId);
    // 从shaderprogram里面获取变量标识
    matrixLocation = glGetUniformLocation(programId, "matrix");
    vertexLocation = glGetAttribLocation(programId, "vPosition");
    clorLocation = glGetAttribLocation(programId, "vColor");

    initVbo();
}
void OpenGLWidget::initVbo(){

    // 计算获得数组长度
    vVerticesLen = sizeof(vertex)/sizeof(GLfloat);
    triIndexLen = sizeof(triIndexs)/sizeof(GLuint);
    colorsLen = sizeof(colors)/sizeof(GLfloat);

    // 初始化顶点buffer并装载数据到显存


    glGenBuffers(1, &verVbo);
    glBindBuffer(GL_ARRAY_BUFFER, verVbo);
    glBufferData(GL_ARRAY_BUFFER, vVerticesLen * sizeof(GLfloat), vertex, GL_STATIC_DRAW);

    // 初始化索引buffer并装载数据到显存
    glGenBuffers(1, &indexVbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVbo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, triIndexLen * sizeof(GLuint), triIndexs, GL_STATIC_DRAW);

    // 初始化颜色buffer并装载数据到显存
    glGenBuffers(1, &colorVbo);
    glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
    glBufferData(GL_ARRAY_BUFFER, colorsLen * sizeof(GLfloat), colors, GL_STATIC_DRAW);
}


void OpenGLWidget::resizeGL(int w, int h)
{
    //当窗口大小改变时,调整界面坐标显示高度和宽度
    glViewport(0, 0, w, h);

    // 模型矩阵重置
    projection.setToIdentity();
    // 透视投影
    qreal aspect = qreal(w) / qreal(h ? h : 1);
    projection.perspective(60.0f, aspect, 1.0f, 100.0f);
    // 增加了模型矩阵,需要做一定偏移量,保证物体刚开始渲染出来时可以被看到!
    projection.translate(0.0f, 0.0f, -2.0f);

}

void OpenGLWidget::paintGL()
{
    //清除之前图形并将背景设置为黑色(设置为黑色纯粹个人爱好!)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    // shader传入模型视图矩阵 projection可以理解为建立了一个坐标系空间,可以再这个空间内设置图形
    glUniformMatrix4fv(matrixLocation, 1, GL_FALSE, projection.data());

    // shader绑定并启用颜色数组buffer
    glBindBuffer(GL_ARRAY_BUFFER,colorVbo);
    glVertexAttribPointer(clorLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(clorLocation);
    // 颜色值rgba,所以每四个float值作为一个颜色值,如果只是希望rgb,取三个值作为颜色值即可!


    // shader绑定并启用顶点数组buffer
    glBindBuffer(GL_ARRAY_BUFFER, verVbo);
    glVertexAttribPointer( vertexLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(vertexLocation);

    // shader绑定并顶点索引数组buffer - 索引无需启用
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,indexVbo);
    glDrawElements(GL_TRIANGLES, triIndexLen, GL_UNSIGNED_INT, 0);

    // 解绑buffer、关闭启用顶点、颜色数组
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glDisableVertexAttribArray(vertexLocation);
    glDisableVertexAttribArray(clorLocation);

}


4. vertexshader.vect

//vertexshader.vert
uniform mat4 matrix;
in vec4 vPosition;
in vec4 vColor;
out vec4 fColor;

void main(void)
{
    fColor = vColor;
    gl_Position = matrix * vPosition;
}


5. fragmentshader.frag

//fragmentshader.frag
in vec4 fColor;

void main(void)
{
    gl_FragColor = fColor;
}


------------------------------------------------------------------------------------------------------

推荐阅读