初步认识OpenGL之QT

初始Opengl之QT

1. OpenGL 概述

OpenGL是一个规范,此规范有各个厂家最终实现。OpenGL的对外体现就是一个库的概念。

OpenGL现在分为核心模式和立即渲染模式(即固定的渲染管线),核心模式是OpenGL 3.3开始支持的,核心模式指可编程模式,核心模式的渲染管线(其实就是从一系列数据到最终配置图像的流程)如下:
在这里插入图片描述
其中顶点着色器片段着色器需要程序员自己实现。

若要写一个OpenGL的可视化程序则需要另外两个库的辅助GLFWGLAD

  1. GLFW的作用是用来解决图形界面显示、消息处理及用户输入处理。
  2. GLAD则使得代码可以用于不同的OpenGL驱动,即对OpenGL做的封装,使得不同系统的上层使用可以更简便的使用OpenGL

可以借助QTOpenGL的封装,实现无需配置第三方库的简便开发。

CPU数据如何与GPU数据交互,我们在程序中书写的顶点数据是在CPU中的,如果GPU要使用这些数据,我们应该明确的告诉GPU应该怎么使用。这其中涉及到VBO(Vertex Buffer Objects)VAO(Vertex Array Objects)VEO(Vertex Element Objects),其中VEO也被称为VIO(Vertex Index Objects)

  • VBO: 用来在GPU中创建内存并存储顶点数据,顶点缓冲对象类型为GL_ARRAY_BUFFER
  • VAO: 用来配置OpenGL如果解析这些内存,VAO中存储的是VBO数据类型的定义,而不存储数据本身
  • VEO: 它用来存储顶点数据的索引,绘图时根据索引进行绘制
    VBOVAOVEO的关系:
    在这里插入图片描述

VAO 存储EBOglBindBuffer的调用,但不会存储VBOglBindBuffer调用

2. QT 项目

UI界面:
在这里插入图片描述
黑色窗口为OpenGL Widget,这里对其进行了提升即修改了其继承的父类为自定的MyOpenGLWidget,在控件中右键选择提升即可操作界面如下:
在这里插入图片描述
myopenglwidget.h内容如下:

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>

class MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    explicit MyOpenGLWidget(QWidget *parent = nullptr);
    ~MyOpenGLWidget();


protected:
    virtual void initializeGL() override;
    virtual void paintGL() override;
signals:

private:
    GLuint m_VBO;
    GLuint m_VAO;

    // 这里使用非静态变量glCreateProgram会报错,目前还不清楚具体的是为什么(也可能是我环境本身的问题)
    static GLuint m_shaderProgram;
    // 这里使用非静态变量报错,目前还不清楚具体的是为什么(也可能是我环境本身的问题)
    static GLuint m_EBO;


};

#endif // MYOPENGLWIDGET_H

myopenglwidget.cpp内容如下:

#include "myopenglwidget.h"
#include <QDebug>

GLuint MyOpenGLWidget::m_shaderProgram = 0;
GLuint MyOpenGLWidget::m_EBO = 0;
MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{

}

MyOpenGLWidget::~MyOpenGLWidget()
{
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
}


GLfloat vertex[]={
    -0.5f,-0.5f,0.0f,
    0.5f,-0.5f,0.0f,
    0.0f,0.5f,0.0f
};


// 存在重复的坐标点
//GLfloat vertexRectangle[]={
//    0.5f,0.5f,0.0f,
//    0.5f,-0.5f,0.0f,
//    -0.5f,0.5f,0.0f,
//    0.5f,-0.5f,0.0f,
//    -0.5f,-0.5f,0.0f,
//    -0.5f,0.5f,0.0f
//};

GLfloat vertexRectangle[]={
    0.5f,0.5f,0.0f,
    0.5f,-0.5f,0.0f,
    -0.5f,-0.5f,0.0f,
    -0.5f,0.5f,0.0f
};

GLuint index[]={
    0,1,3,
    1,2,3
};


const char* vertexShaderSource = "#version 330 core\n"
                             "layout (location = 0) in vec3 aPos;\n"
                             "void main()\n"
                             "{\n"
                             " gl_Position = vec4(aPos,1.0f);\n"
                             "}\n\0";

const char* fragmentShaderSource="#version 330 core\n"
                             "out vec4 FragColor;\n"
                             "void main()\n"
                             "{\n"
                             " FragColor = vec4(1.0f,0.5f,0.2f,1.0f);\n"
                             "}\n\0";

void MyOpenGLWidget::initializeGL()
{
    /*
     * 初始化OpenGL的函数接口
     * 这个接口不能写在构造函数中,否则会程序运行出错,因为initializeOpenGLFunctions()中会需要窗口句柄,而窗口句柄在构造函数完成之后才会被创建
    */
    initializeOpenGLFunctions();

    // 创建VAO
    glGenVertexArrays(1,&m_VAO);
    // 创建VBO
    glGenBuffers(1,&m_VBO);

    // 绑定VAO和VBO对象
    glBindVertexArray(m_VAO);
    glBindBuffer(GL_ARRAY_BUFFER,m_VBO);

    // 为缓冲对象创建一个新的数据存储
    glBufferData(GL_ARRAY_BUFFER,sizeof(vertexRectangle),vertexRectangle,GL_STATIC_DRAW);

    // 告诉先看如何解析缓冲里的属性值
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3 * sizeof(GLfloat),(void*)0);

    // 开启VAO管理的第一个属性值
    glEnableVertexAttribArray(0);


    // 创建EBO,必须在VAO解绑之前创建,因为EBO也会被VAO所记录,但是解绑VBO却不会对VAO中的记录产生影响
    glGenBuffers(1,&m_EBO);
    // 绑定EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_EBO);
    // 给EBO分配空间,并存储数据
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(index),index,GL_STATIC_DRAW);

    // 解除EBO,若此处解绑EBO则VAO中就会不在记录EBO内容,需要在使用的时候重新绑定EBO,这里放在析构函数中解绑
    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
    // 解除VBO和VAO的绑定
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glBindVertexArray(0);



    // 创建顶点着色器
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    // 绑定着色器
    glShaderSource(vertexShader,1,&vertexShaderSource,NULL);
    // 编译顶点着色器
    glCompileShader(vertexShader);

    // 创建片段着色器
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader,1,&fragmentShaderSource,NULL);
    // 编译片段着色器
    glCompileShader(fragmentShader);

    // 链接 shaders
    m_shaderProgram = glCreateProgram();
    glAttachShader(m_shaderProgram,vertexShader);
    glAttachShader(m_shaderProgram,fragmentShader);
    glLinkProgram(m_shaderProgram);

    //释放
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    // 指定绘图的模式,这里设定为GL_LINE,此模式只绘制线框而不进行填充
    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

}

void MyOpenGLWidget::paintGL()
{
    // 设置Clear的属性
    glClearColor(0.2f,0.3f,0.3f,1.0f);
    // 使用
    glClear(GL_COLOR_BUFFER_BIT);

    // 使用shader
    glUseProgram(m_shaderProgram);
    // 绑定VAO
    glBindVertexArray(m_VAO);
    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_EBO);
    // 绘制图形
    //glDrawArrays(GL_TRIANGLES,0,3);
    /*
     * 根据索引绘制
     * 若没有创建EBO,最后一个参数可以直接传递索引的数组
    */
    glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0/*&index*/);
    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
    // 解除VAO
    glBindVertexArray(0);

}

mainwindow.cpp内容如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setCentralWidget(ui->openGLWidget);
}

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

其他代码均为存在修改,运行效果如下:
在这里插入图片描述

  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值