QT+OpenGL网课笔记1—基础图形显示

👇实现效果一览

在这里插入图片描述

0 准备工作

  • 新建用于openGL的C++类,命名为yourOpenGLWidget,继承选择QWidget
  • 创建好后手动修改.h和.cpp中的继承父类,如下图红框所示
  • .h文件中包OpenGL相关头文件,如下图所示
  • .h文件中重写QOpenGLWidget库下的三个protected三个虚函数,如下图下方红框所示

.h头文件
.cpp文件

  • 在ui界面中导入QOpenglWidget对象,并右键将其提升为yourOpenGLWidget类

在这里插入图片描述

  • mainWindow.cpp的构造函数中将opengl界面设置成铺满窗口:
    setCentralWidget(ui->openGLWidget);

1 使用VBO VAO显示三角形

#include "myopenglwidget.h"
unsigned int VBO, VAO;          
unsigned int vertexShader;
unsigned int fragmentShader;
unsigned int shaderProgram;

float vertices[] = {
    -0.5f, -0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
    0.0f, 0.5f, 0.0f
};

// 1顶点 着色器
const char* vertexShaderSource = "#version 330 core\n"
                                 "layout (location = 0) in vec3 aPos;\n" "void main()\n"
                                 "{\n"
                                 "gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
                                 "}\0";

// 5片段 着色器
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";

myOpenGLWidget::myOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)     // 疑问1:为什么.cpp中只有一个父类,而.h中有两个
{

}

void myOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();        // 初始化

    /* VAO */
    glGenVertexArrays(1, &VAO);     // 1个 顶点数组对象(vertex Array Object, VAO)  -> 告知显卡如何解析数据 or 操作VBO的框架
    glBindVertexArray(VAO);         // 绑定VAO

    /* VBO */
    glGenBuffers(1, &VBO);                  // 1个 顶点缓冲对象(vertex Buffer Object, VBO) -> 数据
    glBindBuffer(GL_ARRAY_BUFFER, VBO);     // 绑定VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);          // 内存的图像数据迁移至显存(缓冲区?)

    // 告知显卡如何解析缓冲区的值
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);     // 起始,每个属性长度(xyz=3),类型,是否需要归一化,周期, 偏移量

    // 开启VAO管理的第一个属性值 为什么开第一个? -> 如果vertices如果每一行有6个属性(3坐标+3颜色),且周期为3,那么这里可以为1,代表调用出颜色
    glEnableVertexAttribArray(0);

    // VBO VAO 用完解绑?
    glBindBuffer(GL_ARRAY_BUFFER, 0);       // VBO下班

    // 顶点着色器vertexShader 创建&编译
    vertexShader = glCreateShader(GL_VERTEX_SHADER);       // 创建顶点着色器
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);         // 绑定字符串中的源码
    glCompileShader(vertexShader);      // 编译

//    int success; char infoLog[512];
//    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
//    if(!success) {      // 打印报错信息
//        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
//        qDebug() << "vertex shader compilation failed\n" << infoLog;;
//    }

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

//    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
//    if(!success) {
//        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
//        qDebug() << "fragment shader compilation failed\n" << infoLog;;

//    }

    // 将两个着色器进行链接 shaderProgram
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

//    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
//    if(!success) {
//        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
//        qDebug() << "shader program linking failed\n" << infoLog;
//    }

    // 链接后删除两个着色器
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

     // 填充方式-线条填充
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    glBindVertexArray(0);       // VAO下班(VAO是ob者,他要观察所有事件都完成之后才下班,很辛苦)
}

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

}

void myOpenGLWidget::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.5f, 0.5f);       // 空指针?只set不clear,什么颜色?
    glClear(GL_COLOR_BUFFER_BIT);

    // 应用!
    glUseProgram(shaderProgram);

    glBindVertexArray(VAO);     // VAO 上班!
    glDrawArrays(GL_TRIANGLES, 0, 3);       // 画vertives中前3个顶点
}

2 使用EBO显示矩形

EBO通过索引方式减少重复顶点的绘制(6个点->4个点)

#include "myopenglwidget.h"
unsigned int VBO, VAO, EBO;     
unsigned int vertexShader;
unsigned int fragmentShader;
unsigned int shaderProgram;

// opengl基础图形是三角形,任何复杂图形都是由三角形拼接出来的
//float vertices[] = {
//    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       // 重复
//};

float vertices[] = {
    0.5f, 0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
    -0.5f, 0.5f, 0.0f,
    -0.5f, -0.5f, 0.0f
};

unsigned int indices[] = {
    0, 1, 2,
    1, 2, 3
};

// 1顶点 着色器
const char* vertexShaderSource = "#version 330 core\n"
                                 "layout (location = 0) in vec3 aPos;\n" "void main()\n"
                                 "{\n"
                                 "gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
                                 "}\0";

// 5片段 着色器
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";

myOpenGLWidget::myOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)     // 疑问1:为什么.cpp中只有一个父类,而.h中有两个
{

}

void myOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();        // 初始化

    /* VAO */
    glGenVertexArrays(1, &VAO);     // 1个 顶点数组对象(vertex Array Object, VAO)  -> 告知显卡如何解析数据 or 操作VBO的框架
    glBindVertexArray(VAO);         // 绑定VAO

    /* VBO */
    glGenBuffers(1, &VBO);                  // 1个 顶点缓冲对象(vertex Buffer Object, VBO) -> 数据
    glBindBuffer(GL_ARRAY_BUFFER, VBO);     // 绑定VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);          // 内存的图像数据迁移至显存(缓冲区?)

    // 告知显卡如何解析缓冲区的值
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);     // 起始,每个属性长度(xyz=3),类型,是否需要归一化,周期, 偏移量

    // 开启VAO管理的第一个属性值 为什么开第一个? -> 如果vertices如果每一行有6个属性(3坐标+3颜色),且周期为3,那么这里可以为1,代表调用出颜色
    glEnableVertexAttribArray(0);

    // VBO VAO 用完解绑?
    glBindBuffer(GL_ARRAY_BUFFER, 0);       // VBO下班

    // 顶点着色器vertexShader 创建&编译
    vertexShader = glCreateShader(GL_VERTEX_SHADER);       // 创建顶点着色器
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);         // 绑定字符串中的源码
    glCompileShader(vertexShader);      // 编译

//    int success; char infoLog[512];
//    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
//    if(!success) {      // 打印报错信息
//        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
//        qDebug() << "vertex shader compilation failed\n" << infoLog;;
//    }

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

//    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
//    if(!success) {
//        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
//        qDebug() << "fragment shader compilation failed\n" << infoLog;;

//    }

    // 将两个着色器进行链接 shaderProgram
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

//    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
//    if(!success) {
//        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
//        qDebug() << "shader program linking failed\n" << infoLog;
//    }

    // 链接后删除两个着色器
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

     // 填充方式-线条填充
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    /* EBO */
    glGenBuffers(1, &EBO);      // 1个 索引缓冲对象(Element Buffer Object, EBO)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);    // 传送数据至显存
//    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);   // 若EBO未下班的话,draw时候 无需索引; 反之需要索引

    glBindVertexArray(0);       // VAO下班(VAO是ob者,他要观察所有事件都完成之后才下班,很辛苦)
}

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

}

void myOpenGLWidget::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.5f, 0.5f);       // 空指针?只set不clear,什么颜色?
    glClear(GL_COLOR_BUFFER_BIT);

    // 应用!
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);     // VAO 上班!
//    glDrawArrays(GL_TRIANGLES, 0, 6);       // 画vertives中前6个顶点

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0/*&indices*/);    // 若EBO在init中没班了
//    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, &indices);        // 若EBO在init中下班, 6代表6个索引
}

3 绘制两个图形,并赋予两种填充和边界颜色

#include "youropenglwidget.h"

//unsigned int VBO, VAO, EBO;
unsigned int VBOs[2], VAOs[2], EBO;      // 同时绘制两个图形
unsigned int vertexShader;
//unsigned int fragmentShader;
unsigned int fragmentShader1, fragmentShader2;
//unsigned int shaderProgram;
unsigned int shaderProgram1, shaderProgram2;

float vertices1[] = {
    0.0f, 0.5f, 0.0f,
    0.5f, 0.0f, 0.0f,
    0.0f, 0.0f, 0.0f
};
float vertices2[] = {
    0.5f, -0.5f, 0.0f,
    0.0f, -0.5f, 0.0f,
    0.0f, -1.0f, 0.0f
};

// 1顶点 着色器
const char* vertexShaderSource = "#version 330 core\n"
                                 "layout (location = 0) in vec3 aPos;\n" "void main()\n"
                                 "{\n"
                                 "gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
                                 "}\0";

// 5片段 着色器
const char* fragmentShaderSource1 = "#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";
const char* fragmentShaderSource2 = "#version 330 core\n"
                                   "out vec4 FragColor;\n"
                                   "void main()\n"
                                   "{\n"
                                   "FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
                                   "}\n\0";

yourOpenGLWidget::yourOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{

}

void yourOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();        // 初始化
    /* VAO & VBO 初始化 */
    glGenVertexArrays(2, VAOs);     // 1个 顶点数组对象(vertex Array Object, VAO)  -> 告知显卡如何解析数据 or 操作VBO的框架
    glGenBuffers(2, VBOs);          // 1个 顶点缓冲对象(vertex Buffer Object, VBO) -> 数据

    /* 图像1: VAO & VBO 绑定 */
    glBindVertexArray(VAOs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);          // 内存的图像数据迁移至显存(缓冲区?)
    // 告知显卡如何解析缓冲区的值
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);     // 起始,每个属性长度(xyz=3),类型,是否需要归一化,周期, 偏移量
    // 开启VAO管理的第一个属性值 为什么开第一个? -> 如果vertices如果每一行有6个属性(3坐标+3颜色),且周期为3,那么这里可以为1,代表调用出颜色
    glEnableVertexAttribArray(0);
    // VBO VAO 用完解绑?
    glBindBuffer(GL_ARRAY_BUFFER, 0);       // VBO下班

    /* 图像2: VAO & VBO 绑定 */
    glBindVertexArray(VAOs[1]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 1);       // ???

    // 顶点着色器vertexShader 创建&编译
    vertexShader = glCreateShader(GL_VERTEX_SHADER);       // 创建顶点着色器
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);         // 绑定字符串中的源码
    glCompileShader(vertexShader);      // 编译
    // 片段着色器1 fragmentShader 创建&编译
    fragmentShader1 = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader1, 1, &fragmentShaderSource1, NULL);
    glCompileShader(fragmentShader1);
    // 片段着色器2 fragmentShader 创建&编译
    fragmentShader2 = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader2, 1, &fragmentShaderSource2, NULL);
    glCompileShader(fragmentShader2);

    // 将两个着色器进行链接 shaderProgram
    shaderProgram1 = glCreateProgram();
    glAttachShader(shaderProgram1, vertexShader);
    glAttachShader(shaderProgram1, fragmentShader1);
    glLinkProgram(shaderProgram1);

    shaderProgram2 = glCreateProgram();
    glAttachShader(shaderProgram2, vertexShader);
    glAttachShader(shaderProgram2, fragmentShader2);
    glLinkProgram(shaderProgram2);
    // 链接后删除两个着色器
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader1);
    glDeleteShader(fragmentShader2);
    // 填充方式-线条填充
//    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    glBindVertexArray(0);
}

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

}

void yourOpenGLWidget::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.5f, 0.5f);       // 空指针?只set不clear,什么颜色?
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(shaderProgram1);
    glBindVertexArray(VAOs[0]);     // VAO 上班!
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glUseProgram(shaderProgram2);
    glBindVertexArray(VAOs[1]);
    glDrawArrays(GL_TRIANGLES, 0, 3);
}
  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值