• QT学习日记20——OpenGL简介


    学习视频链接

    OpenGL,Qt实现:1入门篇(已更完)_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1UL411W71w?p=9&vd_source=0471cde1c644648fafd07b54e303c905目录

    一、简单的理论

    1.1 什么是 OpenGL?

    1.2 核心模式 (core-profile)

    1.3 立即渲染模式 (Immediate mode)

    1.4 状态机

    1.5 对象

    二、实战项目

    2.1 搭建平台

    2.2 VAO 和 VBO

    2.3 编译链接着色器

    2.4 索引缓冲对象

    三、练习


    一、简单的理论

    1.1 什么是 OpenGL?

    1、Open Graphics Library 是一个由 Khronos 组织制定并维护的规范 (Specification)

    2、OpenGL 核心是一个 C 库,同时也支持多种语言的派生

    1.2 核心模式 (core-profile)

    3.2 版本和以后版本出现的核心模式也叫可编程管线,提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程

     上图中灰色是不可变成的,3.2 版本以前都是灰色的。上图中的几何着色器也可以不用我们自己来写

    1.3 立即渲染模式 (Immediate mode)

    早期的 OpenGL 使用的模式 (也就是固定渲染管线),OpenGL 的大多数功能都被库隐藏起来,容易使用和理解,但是效率太低,开发者很少能控制 OpenGL 如何进行计算。因此从 OpenGL3.2 开始,推出核心模式

    1.4 状态机

    OpenGL 自身是一个巨大的状态机:描述该如何操作的所有变量的大集合

    OpenGL 的状态通常补称为上下文 (Cotext)

    状态设置函数 (State-changing Function)

    状态应用的函数 (State-using Function)

    我们通过改变一些上下文变量来改变 OpenGL 状态,从而告诉 OpenGL 如何去绘图

    1.5 对象

    一个对象是指一些选项的信号,代表 OpenGL 状态每一个子集

    1. struct object_name {
    2. GLFloat option1;
    3. GLunit option2;
    4. GLchar[] name;
    5. };

    通常把 OpenGL 上下文比作一个大的结构体,包含很多子集:

    1. // OpenGL的状态
    2. struct OpenGL_Context{
    3. ...
    4. object object_Window_Target; // 窗口大小、支持的颜色位数等信息
    5. ...
    6. };

    当前状态只有一份,如果每次显示不同的效果,都要重新配置,会很麻烦。这时候我们就需要一些小助理 (对象),帮忙记录某些状态的信息,方便复用。

    e.g. 如果我们有 10 种子集,每隔子集有 10 种不同的状态,那么我们将需要 100 个助理 (对象)

    1. // 创建对象
    2. GLuint objectId = 0;
    3. glGenObject(1, &objectId); // 给小助理(对象)一个编号
    4. // 绑定对象至上下文
    5. glBindObject(GL_WINDOW_TARGET, objectId);
    6. // 设置GL_WINDOW_TARGET对象的一些选项
    7. glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
    8. glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
    9. // 将上下文的 GL_WINDOW_TARGET 对象设回默认
    10. glBindObject(GL_WINDOW_TARGET, 0); // 小助理已经记录了上面的内容,可以休息了,需要的时候唤醒就可以了
    11. // 一旦我们重新绑定这个对象到 GL_WINDOW_TARGET 位置,这些选项就会重新生效

    二、实战项目

    2.1 搭建平台

    2.2 VAO 和 VBO

    1、图示

    2、标准化设备坐标 (Normalized Device Coordinates, NDC)

    顶点着色器中处理过后,就应该是标准化设备坐标了,x、y 和 z 的值在 1.0 到 1.0 的小段空间 (立方体)。落在范围外的坐标都会被裁剪。

    3、顶点着色器:

    (1) 它会在 GPU 上创建内存,用于储存我们的顶点数据

            通过顶点缓冲对象 (Vertex Buffer 0b jects, VBO) 管理,顶点缓冲对象的缓冲类型是 GL ARRAY_BUFFER

    (2) 配置 OpenGL 如何解释这些内存

            通过顶点数组对象(Vertex Array Objects, VAO) 管理,数组里的每一个项都对应一个属性的解析

    OpenGL 允许我们同时绑定多个缓冲,只要它们是不同的缓冲类型。(每一个缓冲类型类似于前面说的子集,每个 VBO 是一个小助理)

    VAO 并不保存实际数据,而是放顶点结构定义

    4、编写代码

    1. #include "openglwidget.h"
    2. float vertices[] = {
    3. -0.5f, -0.5f, 0.0f,
    4. 0.5f, -0.5f, 0.0f,
    5. 0.0f, 0.5f, 0.0f
    6. };
    7. // 创建VBO和VAO对象,并赋予ID
    8. unsigned int VAO, VBO;
    9. OpenGLWidget::OpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
    10. {
    11. }
    12. // 初始化的槽函数
    13. // 在第一次调用paintGL()或resizeGL()之前调用一次,然后在小部件被分配新的QGLContext时调用一次
    14. void OpenGLWidget::initializeGL()
    15. {
    16. initializeOpenGLFunctions();
    17. glGenVertexArrays(1, &VAO);
    18. glGenBuffers(1, &VBO);
    19. glBindBuffer(GL_ARRAY_BUFFER, 0);
    20. glBindVertexArray(0);
    21. // 当前绑定到target的缓冲区对象创建一个新的数据存储
    22. // 如果data不是NULL,则使用来自此指针的数据初始化数据存储
    23. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    24. // 告知显卡如何解析缓冲里的属性值
    25. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    26. // 开启VAO管理的第一个属性值
    27. glEnableVertexAttribArray(0);
    28. glBindBuffer(GL_ARRAY_BUFFER, 0);
    29. glBindVertexArray(0);
    30. }
    31. void OpenGLWidget::resizeGL(int w, int h)
    32. {
    33. }
    34. void OpenGLWidget::paintGL()
    35. {
    36. glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    37. glClear(GL_COLOR_BUFFER_BIT);
    38. glBindVertexArray(VAO);
    39. glDrawArrays(GL_TRIANGLES, 0, 3);
    40. }

    目前程序还不能绘制出图像

    2.3 编译链接着色器

    1. #include "openglwidget.h"
    2. float vertices[] = {
    3. -0.5f, -0.5f, 0.0f,
    4. 0.5f, -0.5f, 0.0f,
    5. 0.0f, 0.5f, 0.0f
    6. };
    7. // 创建VBO和VAO对象,并赋予ID
    8. unsigned int VAO, VBO;
    9. unsigned int shaderProgram;
    10. const char* vertexShaderScource =
    11. "#version 330 core\n"
    12. "layout (location = 0) in vec3 aPos;\n"
    13. "void main()\n"
    14. "{\n"
    15. "gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    16. "}\n\0";
    17. const char* fragmentShaderScource =
    18. "#version 330 core\n"
    19. "out vec4 FragColor;\n"
    20. "void main()\n"
    21. "{\n"
    22. "FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    23. "}\n\0";
    24. OpenGLWidget::OpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
    25. {
    26. }
    27. // 初始化的槽函数
    28. // 在第一次调用paintGL()或resizeGL()之前调用一次,然后在小部件被分配新的QGLContext时调用一次
    29. void OpenGLWidget::initializeGL()
    30. {
    31. initializeOpenGLFunctions();
    32. glGenVertexArrays(1, &VAO);
    33. glGenBuffers(1, &VBO);
    34. // 绑定VBO和VAO对象
    35. glBindVertexArray(VAO);
    36. glBindBuffer(GL_ARRAY_BUFFER, VBO);
    37. // 当前绑定到target的缓冲区对象创建一个新的数据存储
    38. // 如果data不是NULL,则使用来自此指针的数据初始化数据存储
    39. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    40. // 告知显卡如何解析缓冲里的属性值
    41. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    42. // 开启VAO管理的第一个属性值
    43. glEnableVertexAttribArray(0);
    44. glBindBuffer(GL_ARRAY_BUFFER, 0);
    45. glBindVertexArray(0);
    46. unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    47. glShaderSource(vertexShader, 1, &vertexShaderScource, NULL);
    48. glCompileShader(vertexShader);
    49. unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    50. glShaderSource(fragmentShader, 1, &fragmentShaderScource, NULL);
    51. glCompileShader(fragmentShader);
    52. shaderProgram = glCreateProgram();
    53. glAttachShader(shaderProgram, vertexShader);
    54. glAttachShader(shaderProgram, fragmentShader);
    55. glLinkProgram(shaderProgram);
    56. glDeleteShader(vertexShader);
    57. glDeleteShader(fragmentShader);
    58. }
    59. void OpenGLWidget::resizeGL(int w, int h)
    60. {
    61. }
    62. void OpenGLWidget::paintGL()
    63. {
    64. glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    65. glClear(GL_COLOR_BUFFER_BIT);
    66. glUseProgram(shaderProgram);
    67. glBindVertexArray(VAO);
    68. glDrawArrays(GL_TRIANGLES, 0, 3);
    69. }

    2.4 索引缓冲对象

    1、索引缓冲对象 (Element Buffer Object, EBO, 也叫 Index Buffer Object, IBO) 可以绘制两个三角形来组成一个矩形 (OpenGL 主要处理三角形)。这会生成下面的顶点的集合:

    2、使用以前的方法画 

    添加语句画出线条

    3、现在的方法画

    再 VAO 解除绑定前绑定 EBO: 

    4、图示

    目标是 GL_ELEMENT_ARRAY_BUEFER 的时候,VAO 会储存 glBindBuffer 的函数调用。这也意味着它也会储存解绑调用。

    VAO 不会存储 GL_ARRAY_BUFFER (VBO) 的 glBindBuffer 的函数调用

     3 中如果提前提前解绑 VAO 上图的黄色线就没有了

    三、练习

  • 相关阅读:
    借势热点:如何快速讲今日热点跟我们的视频结合起来?支招三把斧
    5分钟搞懂布隆过滤器,掌握亿级数据过滤算法
    无需编写一行代码,实现任何方法的流量防护能力
    OpenGeometry 开源社区特聘子虔科技云CAD专家 共建云几何内核
    【SNMP】snmp trap 与介绍、安装、命令以及Trap的发送与接收java实现
    操作系统OPT算法(最佳页面替换算法)
    java 根据身份证号码判断性别
    500代码行代码手写docker-设置网络命名空间
    oracle 11g impdp命令导入dmp文件
    MVC第三波书店购物车Model
  • 原文地址:https://blog.csdn.net/HuanBianCheng27/article/details/125890698