LearningOpenGL(二)入门

Posted by 汪洋龙 on Tuesday, June 20, 2023

1. OpenGL

  • OpenGL 仅仅是一个规范(Specification
  • OpenGL 规范没有规定实现的细节,具体的 OpenGL 库允许使用不同的实现,只要功能和结果与规范相匹配
  • 实际 OpenGL 库的开发者通常是 显卡的生产商

1.1 核心模式与立即渲染模式

  • 早期 OpenGL 使用 立即渲染模式(Immediate mode)
    • 优点:绘图方便,容易使用和理解
    • 不足:缺少灵活性,效率低
  • OpenGL3.2,废弃立即渲染模式(Immediate mode),鼓励开发者使用核心模式(Core-profile)

1.2 扩展

OpenGL 支持扩展,方便显卡公司提出新特性或者渲染的优化。

1.3 状态机

使用 OpenGL,遇到的一些状态设置函数(State-changing Function) 会改变上下文,以及 状态使用函数(State-using Function)

1.4 附加资源

2. 创建窗口

2.1 GLFW

一个针对 OpenGL 的 C 语言库,提供一些渲染物体所需最低限度接口。

2.2 GLAD

解决 OpenGL 驱动版本多,并且根据这个版本加载所有相关的 OpenGL 函数。

3. 你好,窗口

3.1 双缓冲(Double Buffer)

单缓冲存在图像闪烁问题,因为生成图像不是瞬间被绘制,而是从左到右,从上到下。

  • 前缓冲:保存最终输出的图像,它会在屏幕上显示;
  • 后缓冲:所有的渲染指令在此绘制;

所有渲染指令执行完毕之后,交换(swap)前缓冲和后缓冲,消除不真实感。

4. 你好,三角形

  • VAO:Vertex Array Object,顶点数组对象
  • VBO:Vertex Buffer Object,顶点缓冲对象
  • EBO:Element Buffer Object,元素缓冲对象
  • IBO:Index Buffer Object, 索引缓冲对象

4.1 图形渲染管线

大多译为管线(Graphics Pipeline),用来处理 3D 坐标转化为 2D 坐标,并将 2D 坐标转变为实际的有颜色的像素

4.2 管线阶段

管线阶段

  • OpenGL 着色器是用 OpenGL 着色器语言(OpenGL Shading Language, GLSL)
  • 蓝色部分代表可以注入自定义着色器

4.3 渲染过程

  • 顶点着色器:把 3D 坐标转为另一种 3D 坐标
  • 图元装配:将顶点着色器输出的顶点作为输入,把所有的点装配为指定图元形状(eg:GL_POINTS、GL_TRIANGLES、GL_LINE_STRIP)
  • 几何着色器:可以通过产生新顶点构造新的图元生成其他形状
  • 光栅化:把图元映射为最终屏幕上的像素
  • 片段着色器:计算一个像素的最终颜色,是所有 OpenGL 高级效果产生的地方。通常,包含 3D 场景数据(eg:光照、阴影、光颜色)
  • Alpha 测试和混合:检测片段对应深度值,用来判断这个像素在前还是在后。

4.4 顶点输入

  • OpenGL 仅当 3D 坐标在 3 个轴(x、y 和 z)上 -1.01.0 的范围内时才处理。
  • 这个范围内的坐标叫做标准化设备坐标
  • 定义数据之后,发送给顶点着色器
  • 通过VBO 管理内存,它会在 GPU 内存存储大量顶点
  • VBO 有一个独一无二的 ID

4.5 顶点着色器

4.6 编译着色器

  • 创建着色器对象:glCreateShader
  • 将着色器源码附加到着色器对象:glShaderSource
  • 编译:glCompileShader

4.7 片段着色器

4.8 着色器程序

  • 创建程序:glCreateProgram
  • 将之前编译的着色器附加到程序对象:glAttachProgram
  • 链接:glLinkProgram
  • 激活:glUseProgram
  • 链接到程序对象之后删除:glDeleteShader

4.9 链接顶点属性

  • 解析顶点数据:glVertexAttribPointer
  • 启用顶点数据:glEnableVertexAttribArray

4.10 顶点数组对象

4.11 元素缓冲对象

5. 着色器

OpenGL 着色器语言:GLSL。类 C 语言,为图形计算量身定制

5.1 数据类型

  • 基础类型:int float double uint bool
  • 容器类型:Vector Matrix

5.2 输入输出

  • inout 关键字定义
  • 从一个着色器向另一个着色器发送数据,必须在发送方着色器声明一个输出,在接收方着色器声明一个输入。OpenGL 会把两个变量链接在一起,实现数据发送。

5.3 Uniform

  • 全局,在每个着色器程序中独一无二
  • 被着色器程序任意着色器任意阶段访问

6. 纹理

6.1 环绕方式

  • GL_REPEAT:默认。超出即重复
  • GL_MIRRORED_REPEAT
  • GL_CLAMP_TO_EDGE
  • GL_CLAMP_TO_BORDER

6.2 纹理过滤

  • 纹理坐标不依赖分辨率
  • GL_NEAREST:默认。
  • GL_LINEAR:基于纹理坐标附近的纹理像素,计算出一个插值
  • glTexParameter* 可以指定放大缩小的过滤方式
  • glGenerateMipmaps 函数来处理多级渐远纹理(主要使用于纹理被缩小的情况)

6.3 加载创建纹理

  • stb_image.h 图像加载器,把图像转化为字节序列
  • glGenTextures 创建纹理
  • glBindTexture 绑定
  • glTexImage2D 生成

6.4 应用纹理

GLSLtexture 函数

6.5 纹理单元

7. 变换

通过多个矩阵(Matrix)对象实现变换(Transform)

7.1 GLM

  • OpenGL Mathematics 缩写
  • 一个数学库

8. 坐标系统

将坐标从一个坐标系变换到另一个坐标系,需要用到变换矩阵。

8.1 局部空间

物体所在的坐标空间

8.2 世界空间

8.3 观察空间

8.4 裁剪空间

OpenGL 期望所有坐标落在特定范围

  • 正射投影
  • 透视投影

9. 摄像机

欧拉角:俯仰角 + 偏航角 + 滚转角