锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

OpenGL红宝书的部分学习记录

时间:2023-12-31 23:37:02 圆形连接器p28

我看的OpenGL红宝书为:

  • 《OpenGL编程指南》-- 原书第9版
  • OpenGL Programming Guide – The Official Guide to Learning OpenGL, Version 4.5 with SPIR-V Ninth Edition

一直觉得OpenGL初学者看不到红宝书。

它更适合基础和理解OpenGL阅读底层开发人员的公司。因为如果你不知道开发OpenGL底层的人,在一些没有解释的部分,或者说话有问题的部分,你不能详细理解原则。(给你写邮件OpenGL开发团队吗?我估计我会忽略它。对他们来说,这可能是一个新手问题。所以我说不适合初学者)

虽然有解释部分API还有衍生功能 说明有关原理,但有些原理没有说明,如下:6 Chapter 中的 : textureLod中不支持mipmap,那lod参数与mipmap有什么关系,或者说lod没有解释它有什么用,会对采样过程产生什么影响。

当然,如果你感兴趣,你也可以买一本书,就像我一样,虽然在阅读的过程中,很多不理解,书没有进一步解释,所以我在阅读的同时不理解部分,但有一些知识点,即使去查阅,也很难查阅。

本文只是个人学习过程中记录一个觉得比较重点,且说的清晰一些的内容。

看完这本书,我最大的感受就是:为什么很多接口要这样设计,很难理解和使用?估计是因为底层硬件的限制。(不懂硬件原理)

Chapter 1 – OpenGL 概述

  • p1 OpenGL 应用程序编程结构(Application Programming Interface, API),它是一个软件库,可以访问图形硬件设备的特性。
    • 其实我自己的理解就是 用户Application层与底层显示处理设备驱动层的一个封装使用层。这样用户层就可以通过OpenGL调用显示处理设备的驱动程序。
  • p8 OpenGL 渲染管线
    • 粗略概述:顶点数据 顶点着色器 细分控制着色器 细分计算着色器 几何着色器 图元设置? 切割和剪切 光栅化? 片元着色器
  • p9 上述所有阶段都有概述

Chapter 2 – 着色器基础

  • p25 OpenGL可编程管道
    • 顶点着色阶段
    • 细分着色阶段
    • 几何着色阶段
    • OpenGL 着色器的最后阶段:片元着色阶段
    • 计算着色阶段
  • p27 OpenGL着色语言概述
    • 使用GLSL着色器(基本结构)的设
    • p28~30 着色语言的基本数据类型, float, double, int, uint, bool, vec2/3/4, ivec2/3/4, uvec2/3/4, bvec2/3/4, mat2/3/4x2/3/4
    • p33~34 存储限制符: const, in, out, bniform, buffer, shared
类型修饰符 描述
const 将变量定义为只读形式。如果它最初使用编译常量,它本身就会成为编译常量
in 将此变量设置为着色器阶段的输入变量
out 将此变量设置为着色器阶段的输出变量
uniform 将该变量设置为用户应用程序传输给着色器的数据,是给定图元的常量
buffer 设置应用程序共享的可读写内存。该内存也作为着色器中存储缓存(storage buffer)使用
shared 设置变量是当地工作组(local work group)它只能用于计算着色器
  • (2 chapter 占位)
    • p36~37 算术操作符
    • p38 流控制
    • p38~39 循环语句
    • p39 函数
    • p40 参数限制符 in, const in, out, inout
访问修饰符 描述
in 将数据复制到函数中(如果没有指定的修改符,默认为这种形式)
const in 将只读数据复制到函数中
out 从函数中获取值(因此输入函数的值未定义)
inout 将数据复制到函数中,并返回函数中修改的数据
  • (2 chapter 占位)
    • p40~42 不变性的计算 invariant, precise 限制符
    • p42 着色器预处理器
预处理器命令 描述
#define 同下
#undef 控制常量和宏的定义类似于C语言的预处理器命令
#if 同下
#ifdef 同下
#ifndef 同下
#else 同下
#elif 同下
#endif 与C语言预处理器命令和代码条件编译defined操作符相似。证书表达式或#只能用于条件表达式。defined定义的值
#error tex 强制编译器text在着色器的信息日志中插入文本内容(直到你知道第一个换行符)
#pragma options 控制编译器的特定选项
#extension options 设置编译器支持特定GLSL扩展功能
#version number 设置使用的设置GLSL版本名称
#line options 设置诊断行号
  • (2 chapter 占位)
    • p43 宏定义 -
    • 无参数 #define NUM_ELEMENTS 10
    • 有参数 #define LPos(n) gl_LightSource[(n)].position
宏名称 描述
__LINE__ 默认情况下,已处理的所有换行符的数量也可以添加到#line命令修改
__FILE__ 当前处理的源字符串编号
__VERSION__ OpenGL着色语言版本的整数表示形式
  • (2 chapter 占位)
    • p44 编译器的控制 #pragma,如:
      • #pragma optimize(on)
      • #pragma optimize(off)
      • #pragma debug(on)
      • #pragma debug(off)
    • p44全局着色器编译选项 #extension extension_name :
      • 或者是#extension all :
      • directive可以是以下的值
命令 描述
requrie 如果无法支持给定的扩展功能,或者被设置为all,则提示错误
enable 如果无法支持给定的扩展功能,则给出警告;如果设置为all,则提示错误
warn 如果无法支持给定的扩展功能,或者在编译过程中使用了任何扩展,则给出警告
disable 禁止支持给定的扩展(即强制编译器不提供对扩展功能的支持),或者如果设置为all则禁止所有的扩展支持,之后当代码中涉及蛇者个扩展使用时,提示警告或者错误
  • (2 chapter 占位)
    • p45 数据块接口
uniform b { 
        		// 限定符可以为uniform、in、out或者buffer
	vec4 v1;	// 块中的变量列表
	bool v2;	// ...
};				// 访问匿名块成员是使用v1、v2
// 或者
uniform b { 
        		// 限定符可以为uniform、in、out或者buffer
	vec4 v1;	// 块中的变量列表
	bool v2;	// ..
} name;			// 访问有名块成员时使用name.v1、name.v2
  • (2 chapter 占位)
    • p54 着色器的编译
      • 字符串⇒ glShader Source⇒ 着色器源代码⇒ glCompileShader⇒ 着色器对象⇒ glCreateShader⇒ glAttachShader⇒ glCreateProgram⇒ 着色器程序⇒ glLinkProgram⇒ 可执行的着色器程序⇒ glUseProgram
      • 对于每个着色器程序,我们都需要在应用程序中通过下面的步骤进行设置。
        • 创建一个着色器对象。
        • 将着色器源代码编译为对象。
        • 验证着色器的编译是否成功。
      • 然后需要将多个着色器对象链接为一个着色器程序,包括
        • 创建一个着色器程序。
        • 将着色器对象关联到着色器程序。
        • 链接着色器程序。
        • 判断着色器的连接过程是否成功完成。
        • 使用着色器来处理顶点和片元。
    • p64 SPIR-V 形式的着色器
      • 与GLSL 形式的着色器相比,有以下几点优势:
        • 更好的可移植性。因为语法上更严格。
        • 多种源语言支持。可以使用其他语言来编写,再生产SPIR-V。
        • 减少发布尺寸。对函数、等其他共用的数据抽象出来。
        • 保护源代码。因为SPIR-V可读性底,而想将SPIR-V反编译成GLSL也是可以的,但会有法律许可的问题,所有就有保护性。(但这点有点鸡肋)

Chatper 3 – OpenGL 绘制方式

  • p70 OpenGL图元
    • 点,线,条带线,循环线,独立三角形,三角形条带,三角形扇面
      void glPolygonMode(GLenum face, GLenum mode); – 控制多边形的正面与背面绘制模式。参数face必须是GL_FRONT_AND_BACK,而mode可以是GL_POINT、GL_LINE或者GL_FILL,它们分别设置多边形的绘制模式是点集、轮廓线还是填充模式。默认情况下,正面和背面的绘制都使用填充模式来完成。
图元类型 glPolygonMode中mode参数(OpenGL枚举量)
GL_POINTS
线 GL_LINES
条带线 GL_LINE_STRIP
循环线 GL_LINE_LOOP
独立三角形 GL_TRIANGLES
三角形条带 GL_TRIAGNLES_STRIP
三角形扇面 GL_TRIANGLES_FAN
  • (3 chapter 占位)
    • p75~86 OpenGL 缓存数据
    • p86~92 顶点规范
    • p92~111 OpenGL 的绘制命令
      • p102 多实例渲染 需要了解一下(GPU Instancing)

Chapter 4 – 颜色、像素和片元

  • p113 基本颜色理论

物理世界中,光是由光子(photon)所组成的,简单来说,也就是细小的例子沿着一条直线路径进行运动 ( 1 ) ^{(1)} (1),每个粒子都有自己的“色彩”,使用物理学来定量描述,也就是例子的波长(或者频率) ( 2 ) ^{(2)} (2)

我们可以看到的光子在可见光光谱中都有对应的波长,范围从大约390纳米(紫色)到720纳米(红色)。这一范围内的所有颜色组成了七色彩虹:紫色、靛蓝、蓝色、绿色、黄色、橙色、红色。

人的眼睛里包含了名为视杆细胞的光敏感结构。视杆细胞对于光的强度(intensity)是敏感的,而视椎细胞对于光强不是很敏感,反而能够区分出光的不同波长(wavelength)。现金的研究认为视椎细胞一共有三种,每一种都对光波长的某个波段敏感。通过计算这三种视椎细胞的响应结果,大脑可以感知多种不同的颜色,而不只是组成彩虹的七种颜色。举例来说,理想的白色光是由全部可见波长的等量光子所组成的。与之相比,激光就是一种单频光,也就是说所有光子的频率都相等。

那么,这与计算机图形学以及OpenGL又有说明关系呢?现代显示设备对于可以显示的颜色有着更严格的范围规定–可见光谱当中只有一部分是可用的(虽然设备也在不断改进这一点)。实际上,设备可以显示的颜色范围通常是由它的色域来表示的。OpenGL所支持的绝大多数显示设备都会使用一种组合三原色的方法来构成颜色值,三原色也就是红色、绿色和蓝色,它们构成了显示设备的整个颜色域。我们将其称作RGB颜色空间,并且使用这三个值的组合来表达每一种颜色。我们只使用三种颜色来表达可见光谱中的如此庞大的一个范围的理由是,这三种颜色非常接近与人眼光锥细胞的响应曲线的中心区域。

OpenGL 当中,通常会在这三个颜色分量之外再增加第四个alpha分量(我们会在4.4.6节中介绍),因此可以成为RGBA颜色空间。作为RGB的一种补充,OpenGL还支持sRGB颜色空间。我们会在讨论帧缓存对象与纹理贴图的时候再次讲解与sRGB相关的内容。

注意:颜色空间的种类还有很多,例如HSV(色调-饱和度-值,Hue-Saturation-Value),或者CMYK(青-品红-黄-黑,Cyan-Magenta-Yellow-Black)。如果数据保存在一个不同于RGB的颜色空间中,那么你需要将它转换到RGB(或者sRGB)空间,然后再使用OpenGL进行处理。

  • ( 1 ) ^{(1)} (1) 当然,重力的影响忽略不计。
  • ( 2 ) ^{(2)} (2) 光子的频率和波长可以通过方程式 c = v l c=vl c=vl来表达,其中c表示光传播的速度 ( 3 × 1 0 8 m / s ) (3 \times 10^8 m/s) (3×108m/s),v表示光子的频率,l表示波长。当然,也有很多人对于光的波粒二象性有自己的看法,这些纹理不妨以后坐下来慢慢讨论。
  • (4 chapter 占位)
    • p114~121 缓存用途
      • 颜色缓存(color buffer)
      • 深度缓存(depth buffer)
      • 模板缓存(stencil buffer)
    • p121~138 片元的测试与操作
      • 剪切测试(scissor test)
      • 多重采样的片元操作
      • 模板测试(stencil test)
      • 深度测试(depth test)
      • 融混(blending)
      • 逻辑操作
    • p139 多重采样
      • 红宝书没有说清楚这点,我自己理解为:多重采样开启的话,例如,SSAA,MSAA中,都是将屏幕上每个像素,最终都以n个指定多重采样配置指定的多重采样缓存来插值算出来的(会根据多边形覆盖的采样点的计算,具体可以看看下面我给出的连接)。(颜色,深度,模板,都会多重缓存),例如,原来是400400的屏幕,要是你multisampler为4,那就是(4400)(4400) ⇒ 16001600的(颜色、深度、模板光栅化缓存大小),需要的显示设备的内存会多出很多倍,比你设置的n要多n+3+被以上,其中这个3就至少包含:颜色,深度,模板,所以开启多重采样一定要留意的你硬件是否支持。
        • 关于多重采样,你可以看看微软的光栅化规则中的MSAA的规则:Rasterization Rules – Multisample Anti-Aliasing Rasterization Rules*
        • 对多重采样(MSAA)原理的一些疑问?
        • [译]Vulkan教程(33)多重采样
        • Multisampling in pipeline
        • OpenGL-抗锯齿

Chapter 5 – 视口变换、裁减、剪切与反馈

也可以看看我之前写的变换顺序的总结:OpenGL Transformation 几何变换的顺序概要(MVP,NDC,Window坐标变换过程)

  • p148 观察视图
    基本上来说,
    显示器本身是一个平面的、固定的,二维矩形区域,但是模型却是一个三维空间的几何体。本章我们将学习如何将模型的三维坐标投影到固定的二维屏幕坐标上。
    将三维空间的模型投影到二维的关键方法,就是齐次坐标(homogeneous coordinate)的应用、矩阵乘法的线性变换方法,以及视口映射。我们将在下文中详细讨论这些方法。
    • p148 相机模型
      使用相机(或者计算机)的主要步骤列举如下:
      • 将相机移动到准备拍摄的位置,将它对准某个方向(视图变换,view transform)。
      • 将准备拍摄的对象移动到场景中必要的位置上(模型变换,model transform)。
      • 设置相机的焦距,或者调整缩放比例(投影变换,projection transform)。
      • 拍摄照片(应用变换结果)。
      • 对结果图像进行拉伸或者挤压,将它变换到需要的图片大小(视口变换,viewport transform)。对3D图形来说,这里同样需要对深度信息进行拉伸或者挤压(深度范围的缩放)。这一步与第3步不一样,后者只是选择捕捉场景的范围大小,并不是对结果的拉伸。
    • p150 视椎体 – 这个就不想写了,可以去查阅本书概述。或是百度。
    • p151 视椎体的剪切 – 同上
    • p151 正交投影,你可以理解为没有使用透视除法。(在OpenGL或是DX中的管线有处理这部,在vs后,在primitive assembly前),可查考,我之前的软光栅器,就是这么处理的:用C# Bitmap作为画布写个3D软渲染器
    • p152 用户变换 – 就是值顶点、细分、几何着色器对顶点的几何变换,如果没写细分、几何着色器的话,那么就全都在顶点着色器中处理。就是对gl_Position赋什么样的值,如:gl_Position=Transform*Vertex;就看Transform的uniform变量是个什么矩阵,可以是单位矩阵,那么gl_Postion就是等价于Vertex的值,就是model/object space上的坐标;如果Transform是model矩阵,那gl_Position就是world space上的坐标;如果Transform是model view矩阵,那gl_Position就是world view space上的坐标;如果Transform是model view projection矩阵,那gl_Position就是world view projection space – 就是clip coordinate坐标。通常Transform是一个mvp(world view projection)的矩阵。
    • p153 矩阵乘法的回顾(不写,看本书或是百度)。
    • p155 齐次坐标
      三维数据可以通过三维向量与3x3矩阵的乘法操作,来完成缩放和旋转的线性变换。
      但是,对三维笛卡尔坐标的平移(移动/滑动)操作是无法通过与3x3矩阵的乘法操作来完成的。我们还需要一个额外的向量,将点(0,0,0)移动到另一个位置。这一步叫做仿射变换(affine transformation),它不属于线性变换(你应该还记得线性变换的一个重要规律,它总是将(0,0,0)映射到(0,0,0))。加入这个额外的运算过程意味着我们将无法再运用线性变换的各种优势,例如将多个变换过程合成为一个变换。因此,我们需要找到一种方法,通过使用线性变换来表达平移过程。幸运的是,只要将数据置入四维坐标空间当中,仿射变换就回归成为一种简单的线性变换了(也就是说,我们可以直接使用4x4矩阵的乘法来完成模型的移动操作了)。
      举例来说,将数据沿着 y y y轴移动0.3,假设第四个向量坐标为1.0,则有:
      [ 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 ] ( x y z 1.0 ) → ( x y + 0.3 z 1.0 ) \begin{bmatrix} 1.0 & 0.0 & 0.0 & 0.0\\ 0.0 & 1.0 & 0.0 & 0.0\\ 0.0 & 0.0 & 1.0 & 0.0\\ 0.0 & 0.0 & 0.0 & 1.0 \end{bmatrix} \begin{pmatrix} x\\y\\z\\1.0 \end{pmatrix} \to \begin{pmatrix} x\\y+0.3\\z\\1.0 \end{pmatrix} 1.00.00.00.00.01.00.00.00.00.01.00.00.00.00.01.0xyz1.0xy+0.3z1.0
      在这里可以了解到,这个额外的第四分量其实是用来实现透视投影变换的。
      齐次坐标总是有一个额外的分量,并且如果所有的分量都除以一个相同的值,那么将不会改变它所表达的坐标位置。
      举例来说,一下所有的坐标都表达了同一个点:
      ( 2.0 , 3.0 , 5.0 , 1.0 ) ( 4.0 , 6.0 , 10.0 , 2.0 ) ( 0.2 , 0.3 , 0.5 , 0.1 ) (2.0,3.0,5.0,1.0)\\ (4.0,6.0,10.0,2.0)\\ (0.2,0.3,0.5,0.1) (2.0,3.0,5.0,1.0)(4.0,6.0,10.0,2.0)(0.2,0.3,0.5,0.1)
      这样的话,齐次坐标所表达的其实是方向而不是位置;对一个方向值的缩放不会改变方向本身。
      在一个笛卡尔坐标中: ( x , y , z ) (x,y,z) (x,y,z),我们可以直接添加第四个w分量: ( x , y , z , w ) (x,y,z,w) (x,y,z,w),并设置值为1.0来实现齐次坐标的简历:
      ( 2.0 , 3.0 , 5.0 ) → ( 2.0 , 3.0 , 5.0 , 1.0 ) (2.0,3.0,5.0)\to(2.0,3.0,5.0,1.0) (2.0,3.0,5.0)(2.0,3.0,5.0,1.0)
      然后可以让前三个分量来除以第四个分量,并且将其舍弃,以重新得到笛卡尔坐标。
      ( 4.0 , 6.0 , 10.0 , 2.0 ) 除 以 w ⟶ ( 2.0 , 3.0 , 5.0 , 1.0 ) 舍 弃 w ⟶ ( 2.0 , 3.0 , 5.0 ) (4.0,6.0,10.0,2.0) \begin{matrix} 除以w\\ \longrightarrow \end{matrix} (2.0,3.0,5.0,1.0) \begin{matrix} 舍弃w\\ \longrightarrow \end{matrix} (2.0,3.0,5.0) (4.0,6.0,10.0,2.0)w(2.0,3.0,5.0,1.0)w(2.0,3.0,5.0)
      透视变换会将w分量修改为1.0以外的值。如果w更大,那么坐标将位于更远的位置。当OpenGL准备显示几何体的时候,它会使用最后一个分量除以前三个分量,从而将齐次坐标重新变换到三维的笛卡尔坐标。因此距离更远的物体(w值更大)的笛卡尔坐标也会更小,从而绘制的比例也就更小。w为0.0表示(x,y)坐标位于无限近的位置(物体与观察点非常近,以至于它的透视效果是无限大的)。这样可能会产生无法预知的结果。而从理论上来说,使用负数的w值并没有错误,例如下面的坐标值就表达同一个点。
      ( 2.0 , 3.0 , 5.0 , 1.0 ) ( − 2.0 , − 3.0 , − 5.0 , − 1.0 ) (2.0,3.0,5.0,1.0)\\ (-2.0,-3.0,-5.0,-1.0) (2.0,3.0,5.0,1.0)(2.0,3.0,5.0,1.0)
      但是负数whi可能会图形管线的某些环节带来麻烦,尤其是可能会与其他的整数w值进行插值计算,而得到的结果有可能非常接近或者正好为0.0.要避免这个问题,最简单的方法就是保证w值总是整数。
    • p157~167 线性变换与矩阵
      • p157 平移
      • p161 旋转
      • p163 透视
      • p166 正交投影
    • p167 法线变换
    • p168 矩阵
      • p169 OpenGL中矩阵的行与列
    • 170 OpenGL变换
      • p171 视口
      • p171 多视口
      • p171~172 高级技巧:z的精度 (废话多,建议另搜索)
      • p172 高级技巧:用户裁减和剪切(废话多,建议另搜索)
      • p173 OpenGL变换的控制
    • p174 transform feeback 是OpenGL管线中,顶点处理阶段结束之后,图元装配和光栅化之前的一个步骤。transform feedback可以重新捕获即将装配为图元(点、线段、三角形)的顶点,然后将它们的部分或者全部属性传递到缓存对象中。(就是可以将vertex shader postprocessing 到 rasterization 之间的shader 变量可以写入到application指定的缓存对象中,以便于app阶段获取使用)
      • p175 transform feedback 对象
        • void glCreateTransformFeedbacks(GLsizei n, GLuint* ids);创建n个新的transform feedback对象并且将生成的名称记录到数组ids中。

        • void glBindTransformFeedback(GLenum target, GLuint id);将一个名称为id的transform feedback对象绑定到目标target上,目标的值必须是GL_TRANSFORM_FEEDBACK。

        • GLboolean glIsTransformFeedback(GLenum id);如果id是一个已有的transform feedback对象的名称,那么返回GL_TRUE,否则返回GL_FALSE。

        • void glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids);删除n个transform feedback对象,其名称保存在数组ids中。如果ids的某个元素不是transform feedback对象的名称,或者设置为0,那么都会被直接忽略,不会给出提示。

      • p176 transform feedback缓存
        • void glTransformFeedbackBufferBase(GLuint fbx, GLuint index, GLuint buffer);将名为buffer的缓存对象绑定到名为xfb的transform feedback对象上,其索引通过index设置。如果index为0,那么buffer将被绑定到默认的transform feedback对象的绑定点。

        • void glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);将缓存对象buffer的一部分绑定到名为xfb的transform feedback对象的绑定点索引index上。offset和size的单位均为字节,它们设置了要绑定的缓存对象的范围。如果xfb为0,那么buffer将绑定到默认的transform feedback对象的绑定点。

        • void glBindBuffersRange(GLenum target, GLuint firest, GLsizei count, const GLuint *buffer, const GLintptr *offset, const GLsizeiptr *sizes);绑定来自一个或者多个缓存的多个范围值,对应于target所指定的目标绑定点。first表示绑定缓存范围的第一个索引值,count表示要绑定的数量。这里的buffers、offsets、sizes参数分别对应于数组中的count个缓存名称,count个起始地址偏移量,count个绑定范围的大小。offsets和sizes中保存的数值是采样字节方式设置的。这里的每一个范围数据都是通过offsets和sizes中对应元素指定的,然后绑定到target所制定的索引位置,从first开始计数。如果buffers为NULL,那么offsets和sizes将被忽略,同时target的索引绑定点上所有绑定关系会被删除。从功能上来说,glBindBuffersRange()等于:for(i=0;i

      • p179 配置transform feedback的变量
        • p179 通过OpenGL API配置transform feedback的变量
          • void glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar ** varyings, GLenum bufferMode);设置使用varyings来记录transform feedback的信息,所用的程序通过program来指定。count设置varyings数组中所包含的字符串的数量,它们存储的也是所有要捕获的变量的名称。bufferMode设置的是捕获变量的模式–可以是分离模式(GL_SEPARATE_ATTRIBS)或者交叉模式(GL_INTERLEAED_ATTRIBS)。

        • p183 通过着色器配置transform feedback的变量
      • p185 transform feedback的启动和停止
        • void glBeginTransformFeedback(GLenum primitiveModel);设置transform feedback准备记录的图元类型。primitiveMode必须是GL_POINTS、GL_LINES或者GL_TRIANGLES。在这之后的绘制命令中的图元类型必须与这里的primitiveMode相符,或者几何着色器(如果存在的话)的输出类型必须与primitiveMode相符。

        • voi glPauseTransformFeedback(void);暂停transform feedback对变量的记录。我们可以通过glResumeTransformFeedback()重新启动transform feedback。

        • void glResumeTransformFeedback(void);重新启动一个之前通过glPauseTransformFeedback()暂停的transform feedback过程。

        • void glEndTransformFeedback(void);完成transform feedback模式下的变量记录过程。

      • p 187 transform feedback的示例:粒子系统

Chapter 6 – 纹理与帧缓存

第六章的纹理内容太多,我还是只记录部分就好。

  • p193 纹理综述
  • p194 基本纹理类型
    纹理目标和对应的采样器类型
目标(GL_TEXTURE_*) 采样器类型 维度
1D sampler1D 一维
1D_ARRAY sampler1DArray 一维数组
2D sampler2D 二维
2D_ARRAY sampler2DArray 二维数组
2D_MULTISAMPLE sampler2DMs 二维多重采样
3D sampler3D 三维
CUBE samplerCube 立方体映射纹理
ARRAY samplerCubeArray 立方体映射纹理数组
RECTANGLE samplerRect 二维长方形
BUFFER samplerBuffer 一维缓存
  • p195 创建并初始化纹

相关文章