大家可以去B站看课程的视频支持一下作者哈:

OpenGL,Qt实现:1入门篇(已更完)_哔哩哔哩_bilibili课程相关源码、PPT、安装包,完整课程合集(1:入门篇;2:基础光照;3:模型加载;4:高级OpenGL;5:高级光照 ;程序员的数学3:线性代数):https://ke.qq.com/course/package/40726?flowToken=1041265https://www.bilibili.com/video/BV1UL411W71w

准备工作

1、关于OpenGL

OpenGL是一种规范,具体的API由各个厂家自行实现的。

2、GPU渲染管线(流水线)

3、状态

个人理解为参与对输入数据的处理的属性和条件。

上面的图片中,输入三个点,不同的状态参与对输入数据的处理会输出不同的内容。

4、状态机

储存了状态的集合。

OpenGL本身是一个巨大的状态机(包含了很多状态的属性)。

OpenGL的状态一般称为上下文(Context)。

OpenGL的函数可以分为状态设置函数和状态应用函数,学习的时候可以注意这一点。

5、OpenGL对象

一个对象指的是一些选项(状态)的集合,是OpenGL状态的一个子集。

OpenGL是一个大的状态机,包含了大量状态属性,从中取出一部分构成一个对象。

例如从OpenGL的状态中取出一些窗口大小、窗口名称、窗口颜色等选项集合成一个结构体,就构成一个窗口对象。

6、对象的作用

OpenGL的状态处于变化之中,如果每次变化都需要重新配置状态则不太行,可以使用对象记录OpenGL的状态。

总之:对象就是用来记录状态的。

理解下面的代码:

// 创建对象
//uint objectId = 0;
GLuint objectId = 0;
glGenObject(1, &objectId); //给对象一个编号。glBindObject(GL_WINDOW_TARGET, objectId);// 绑定对象至上下文,objectId 记录 GL_WINDOW_TARGET 的状态// 设置 GL_WINDOW_TARGET 对象的一些状态,GL_WINDOW_TARGET 状态的改变被 objectId 记录下来了
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600); glBindObject(GL_WINDOW_TARGET, 0); //取消 GL_WINDOW_TARGET 和 objectId 的绑定......//GL_WINDOW_TARGET的其他操作//一旦 GL_WINDOW_TARGET 重新绑定 objectId,objectId 记录的 GL_WINDOW_TARGET 选项就会重新生效

创建OpenGL窗口

1、QOpenGLWidget::makeCurrent()

如上所述,OpenGL是一个大的状态机,它的当前状态只有一个,在 paintGL()、resizeGL()、initializeGL() 之外的函数中调用标准OpenGL API函数,则必须首先调用此函数以获取OpenGL状态。

2、标准化设备坐标

OpenGL为了让坐标运算不受显示器分辨率的影响,将三维坐标标准化到了[-1,1]之间。任何落在范围外的坐标都会被丢弃/裁剪,不会显示在屏幕上。

标准化设备坐标看起来就像是下面这样:

一个标准化坐标数组:

3、顶点着色器

  • 顶点着色器会在GPU的内存(显存)中储存顶点数据
  • 顶点数据通过顶点缓冲对象(Vertex Buffer Objects, VBO)管理(顶点数据实际是储存到VBO中的)。注意:顶点缓冲对象是对象,如上面所述,对象的作用是记录状态。
  • 顶点缓冲对象的缓冲类型是 GL_ARRAY_BUFFER。使用缓冲区是为了减少将内存中的数据传到显存需要的开销。将数据先放到内存中的缓冲区,数据满了再一次性传给显存。
  • 将顶点缓冲对象绑定为 GL_ARRAY_BUFFER,即可将数据传到显存。

4、顶点数组对象(Vertex Array Objects, VAO)

前面说了将数据传到显存。VAO的作用是配置OpenGL如何解释数据(记录数据是怎么定义的),有了VAO以后OpenGL才知道如何使用数据

注意:这也是对象,对象的作用是记录状态。牢记。

理解以下代码:

//1、创建VBO和VAO对象,并赋予ID
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO); //2、绑定VBO和VAO对象
glBindVertexArray(VAO);//使OpenGL知道这个uint类型的对象表示一个VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO); //为当前绑定到GL_ARRAY_BUFFER的缓冲区对象创建一个新的数据存储,使用参数三的数据初始化数据存储
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//告知显卡如何解析缓冲里的属性值:
//第0个数据:有3个值;float类型;不需要标准化;步长;偏移量是0(因为是第一个数据,所以没有偏移量)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//开启VAO管理的第一个属性值
glEnableVertexAttribArray(0); //VAO、VBO已经记录了足够的信息了,解除绑定
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0); 

关于OpenGL函数可查询:Khronos OpenGL® and OpenGL® ES Reference Pages - The Khronos Group Inchttps://www.khronos.org/registry/OpenGL-Refpages/

使用上面的代码画出一个三角形:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>class Widget : public QOpenGLWidget,QOpenGLFunctions_4_5_Core
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();protected:virtual void initializeGL();virtual void paintGL();
};
#endif // WIDGET_H
#include "widget.h"Widget::Widget(QWidget *parent): QOpenGLWidget(parent)
{
}Widget::~Widget()
{
}unsigned int VBO, VAO;
float vertices[] =
{-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f, 0.5f, 0.0f
};void Widget::initializeGL()
{initializeOpenGLFunctions();//1、创建VBO和VAO对象,并赋予IDglGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);//2、绑定VBO和VAO对象glBindVertexArray(VAO);//使OpenGL知道这个uint类型的对象表示一个VAOglBindBuffer(GL_ARRAY_BUFFER, VBO);//为当前绑定到GL_ARRAY_BUFFER的缓冲区对象创建一个新的数据存储,使用参数三的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//告知显卡如何解析缓冲里的属性值://第0个数据:有3个值;float类型;不需要标准化;步长;偏移量是0(因为是第一个数据,所以没有偏移量)glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//开启VAO管理的第一个属性值glEnableVertexAttribArray(0);//VAO、VBO已经记录了足够的信息了,解除绑定glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);
}void Widget::paintGL()
{glClearColor(0.2f,0.3f,0.3f,1.0f);glClear(GL_COLOR_BUFFER_BIT);glBindVertexArray(VAO);//绑定VAO以便知道该如何使用数据。glDrawArrays(GL_TRIANGLES,0,3);
}

这里没有定义着色器而是使用默认的着色器绘制一个三角形。

使用OpenGL原生的方式编译链接着色器

Qt 对着色器编译是有封装的,先不管它,使用OpenGL原生的方式编译链接着色器看看。

#include "widget.h"Widget::Widget(QWidget *parent): QOpenGLWidget(parent)
{
}Widget::~Widget()
{
}unsigned int VBO, VAO;
unsigned int shaderProgram;
float vertices[] =
{-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f, 0.5f, 0.0f
};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";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 Widget::initializeGL()
{initializeOpenGLFunctions();//1、创建VBO和VAO对象,并赋予IDglGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);//2、绑定VBO和VAO对象glBindVertexArray(VAO);//使OpenGL知道这个uint类型的对象表示一个VAOglBindBuffer(GL_ARRAY_BUFFER, VBO);//为当前绑定到GL_ARRAY_BUFFER的缓冲区对象创建一个新的数据存储,使用参数三的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//告知显卡如何解析缓冲里的属性值://第0个数据:有3个值;float类型;不需要标准化;步长;偏移量是0(因为是第一个数据,所以没有偏移量)glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//开启VAO管理的第一个属性值glEnableVertexAttribArray(0);//VAO、VBO已经记录了足够的信息了,解除绑定glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);//---------以下是使用自定义着色器----------------------------  //顶点着色器unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);//创建顶点着色器对象 GL_VERTEX_SHADER表示顶点着色器glShaderSource(vertexShader, 1, &vertexShaderSource,nullptr);//顶点着色器绑定源码glCompileShader(vertexShader);//编译顶点着色器int success;glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);//检查编译错误if (!success){char infoLog[512];glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);qDebug()<< "编译顶点着色器出错,错误信息:" << infoLog ;}//片段着色器unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);//创建片段着色器 GL_FRAGMENT_SHADER表示片段着色器glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);glCompileShader(fragmentShader);glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){char infoLog[512];glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);qDebug()<< "编译片段着色器出错,错误信息:" << infoLog ;}//链接两个编译好的着色器shaderProgram = glCreateProgram();//创建着色器程序对象glAttachShader(shaderProgram, vertexShader);//添加要编译的程序glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);//链接着色器glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); //检测链接错误if (!success){char infoLog[512];glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);qDebug()<< "链接着色器出错,错误信息:" << infoLog;}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);
}void Widget::paintGL()
{glClearColor(0.2f,0.3f,0.3f,1.0f);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(shaderProgram);//使用此着色器,没有这行则使用默认的着色器glBindVertexArray(VAO);//绑定VAO以便知道该如何使用数据。glDrawArrays(GL_TRIANGLES,0,3);
}

《Qt-OpenGL系列编程》课程学习记录(1):相关概念、VAO、VBO、绘制三角形、使用OpenGL原生方式编译链接着色器程序相关推荐

  1. 《Qt-OpenGL系列编程》课程学习记录(8):绘制一个长方体

    要绘制一个长方体,每一面都是图片. 为了简便,就不使用EBO了. 前面的内容是绘制一个面的,但是长方体有六个面.其实方法也是一样的,根据这个图设置坐标: float vertices[] = {//位 ...

  2. 编程课程学习_如果您想学习数据科学,请从以下编程课程之一开始

    编程课程学习 by David Venturi 大卫·文图里(David Venturi) 如果您想学习数据科学,请从以下编程课程之一开始 (If you want to learn Data Sci ...

  3. python是什么语言开发的-少儿编程有什么好处?儿童编程课程学习Python的4大原因...

    儿童编程Python是什么课程? Python是强制用一种面向对象的解释型计算机程序设计语言,它是纯粹的自由软件, 源代码和解释器CPython遵循 GPL(GNU General Public Li ...

  4. python 人工智能课程对孩子的好处_少儿编程有什么好处?儿童编程课程学习Python的4大原因...

    儿童编程Python是什么课程? Python是强制用一种面向对象的解释型计算机程序设计语言,它是纯粹的自由软件, 源代码和解释器CPython遵循 GPL(GNU General Public Li ...

  5. 1 Robotics: Aerial Robotics 第3+4周 课程学习记录及课后习题解答

    Robotics: Aerial Robotics 第3+4周 WEEK - 3 Quiz Programming Assignment: 2-D Quadrotor Control WEEK - 4 ...

  6. Windows编程课程学习笔记

    一. Windows程序内部运行机制--Windows编程课程学习笔记 二. MFC框架程序分析--Windows编程课程学习笔记 三. 简单绘图--Windows编程课程学习笔记 四. 文本编程-- ...

  7. 9宫格解锁 android_android开发图案解锁学习记录一(九宫格的绘制)

    图案解锁的原理: 九宫格解锁故名思议就是要有九个宫格:然后宫格间进行连线. 首先我们要先绘制九个点(宫格),确定位置,然后绘制不同的图案. 图案分为不同的状态:正常的状态,按下时的状态和错误的状态 当 ...

  8. opengl 创建context_OpenGL学习笔记1-创建窗口,绘制三角形

    使用GLFW创建窗口 首先引用头文件 #include <glad/glad.h> #include <GLFW/glfw3.h> //注意头文件引用的先后顺序 glfwIni ...

  9. OpenGL着色器程序解析--纹理贴图

    背景 纹理贴图意思是将任意类型的图片贴在3d模型的一个或者多个面上.图片可以是任意的但通常是一种通用的样式,比如:砖块.植物.荒芜的土地等等,可以提高场景的真实性.比较下面两幅图片:  为了实现纹理贴 ...

最新文章

  1. 各类常见的网站检查工具
  2. html块状元素高度,CSS:如何计算块元素的高度?
  3. android su中的字符串,android – 等到su中的命令完成
  4. mysql触发器 当记录的指定字段发生变化时,更新表中的另外一个字段,或者更新另外一张关联表中关联记录的字段...
  5. python爬虫天气实例scrapy_2017.08.04 Python网络爬虫之Scrapy爬虫实战二 天气预报...
  6. JavaScript中的match方法和search方法
  7. svn 中的url路径修改和 清除 svn用户名和密码
  8. python_ 学习笔记(基础语法)
  9. 《位置计算:无线网络定位》学习小结
  10. idea 安装 jclasslib 插件
  11. 分析测试电视遥控总结
  12. ERROR: Cannot uninstall ‘llvmlite‘. It is a distutils installed project and thus we cannot accuratel
  13. windows下gfortran编译error:Note: The following floating-point exceptions are signalling: IEEE_UNDERFLOW
  14. 随机向量x的协方差阵_统计不相关:两个随机向量x(?)与y(?)统计不相关,若它们的互协方差矩阵不等于零矩阵,即Cxy = O。...
  15. Gitbook详解(七)-Markdown编辑器推荐
  16. html scr 拼接,css3scr.html
  17. 一张图看懂信息化和数字化的本质区别
  18. swin-Transformer论文详解
  19. 垃圾回收相关知识(垃圾回收算法及垃圾收集器)
  20. 利用Python网络爬虫获取电影天堂视频下载链接【详细教程】

热门文章

  1. Launcher桌面负一屏实现 第一章
  2. TCP协议拥塞控制算法(Reno、HSTCP、BIC、Vegas、Westwood
  3. 常吃10种美食 牙齿更美白
  4. 锐龙调用python库的问题_【深度】关于AMD锐龙5000系列移动处理器我所知道的一切...
  5. javascript中对象_了解JavaScript中的承诺
  6. Marvelous Designer:002服装材质
  7. 【软件测试】Oracle中的rownum用法
  8. 直接在谷歌浏览器网址栏输入非网址内容搜索
  9. java 二维变长数组_java二维数组如何指定不同长度
  10. IronOCR,Crack支持全球125种语言