应用步骤
- 着色器和程序对象的概述
- 创建和编译着色器
- 创建和链接程序
【上接OpenGL ES 3.0 | 着色器源码、实例 与 管线程序源码、实例 的联系与细节 以及 各自的应用流程和相关API】 - 获取和设置统一变量
- 获取和设置属性
- 着色器编译器和程序二进制代码
统一变量和属性
-
一旦链接了
程序对象
,就可以在对象
上进行许多查询
; -
首先,需要找出
程序
中的活动统一变量
; -
统一变量(uniform)
是存储应用程序
通过OpenGL ES 3.0 API
传递给着色器
的
只读 常数值
的变量
; -
统一变量
被组合成两类统一变量块
;
第一类是命名统一变量块
,统一变量
的值 由统一变量缓冲区对象
支持;
命名统一变量块
被分配一个统一变量块索引
; -
第二类是默认的
统一变量块
,用于在命名统一变量块
之外声明的统一变量
;
和命名统一变量块
不同,
默认统一变量块
没有名称
或者统一变量块索引
; -
如果
统一变量
在顶点着色器
和片段着色器
中均有声明
,
则声明的类型
必须相同,且在两个着色器
中的值也需相同
; -
在
链接
阶段,链接程序
将为程序中 与默认统一变量块
相关的活动统一变量
指定位置
; -
这些
位置
是 应用程序 用于 加载 统一变量的标志符; -
链接程序
还将为与命名统一变量块
相关的活动统一变量
分配偏移
和跨距
(对于数组和矩阵类型的统一变量)
获取统一变量
-
查询程序中
活动统一变量
的列表(/ 数量)
;
获取 程序中 最大统一变量名称的字符数量(最大长度)
:
-
找出每个
统一变量
的细节
:-
拿到
类型
和名称
:
-
拿到
-
拿到其他指定的属性(
pname
指定的): -
用
名称
拿到位置
: -
有了
统一变量
的位置
及其类型
和数组大小
,
即可加载统一变量
的值
;
例程(查询活动统一变量的流程复盘)
统一变量缓冲区对象
- 可以使用
缓冲区对象
存储统一变量数据
,
从而在管线程序中
的着色器之间
甚至管线程序之间
共享统一变量
; - 这种
缓冲区对象
称作统一变量缓冲区对象
;
- 使用
统一变量缓冲区对象
,
可以在更新大的统一变量块
时降低API开销
;
此外,
这种方法增加了统一变量
的可用存储
,
因为可以不受默认统一变量块大小
的限制;
- 可以使用
glBufferData
、glBufferSubData
、glMapBufferRange
和glUnmapBuffer
等函数
修改缓冲区对象
中的统一变量数据
;
统一变量缓冲区对象
中,统一变量
在内存中以如下的形式出现:
-
类型为
bool、int、uint
和float
的成员 保存在 内存的特定偏移
,
分别作为单个uint、int、uint
和float
类型的分量
; -
基本数据类型
bool、int、uint
和float
的向量
保存在始于特定偏移
的连续内存位置
中,(类似数组)
第一个分量在最低偏移处
; -
(行优先、列优先的意义)
C列R行 的列优先矩阵
被 当成 C浮点列向量
的一个数组
对待,
每个向量包含R个分量。(一个列有R行)
相类似,
R行C列的行优先矩阵
被 当成 R浮点行向量
的一个数组对待,
每个向量包含C个分量。(一个行有C列)
列向量 或者 行向量 连续存储,但是有些实现的存储中可能有缺口;
矩阵中两个向量之间的偏移量
被称作列跨距
或者行跨距
(GL_UNIFORM_MATRIX_STRIDE
),
可以在链接的程序中 用glGetActiveUniformsiv
查询; -
标量、向量
和矩阵的数组
按照元素的顺序
存储于内存
中,
成员0 放在最低偏移处
;
数组
中每对元素
之间的偏移量
是一个常数
,称作数组跨距
(GL_UNIFORM_ARRAY_STRIDE
),
可以在 链接的程序中 用glGetActiveUniformsiv
查询;
- 除非使用
std140统一变量块布局(默认)
,
否则需要查询程序对象
得到字节偏移
和跨距
,
以在统一变量缓冲区对象
中设置统一变量数据
。
std140布局
保证使用 由OpenGL ES 3.0规范
定义的明确布局规范
进行特定包装
;
因此,使用std140,
即可在不同的OpenGL ES 3.0实现之间
共享统一变量块
;
【其他包装格式(如下)可能使 某些OpenGL ES 3.0实现
以比std140布局
更紧凑
的方式 打包数据】
std140例程与规范
-
与
统一变量位置值
用于引用统一变量
类似
【有了统一变量
的位置
及其类型
和数组大小
,
即可加载统一变量
的值
】,
统一变量块索引
用于引用统一变量块
,
用glGetUniformBlockIndex
检索统一变量块索引
:
-
【】用
程序句柄
、统一变量块名
,【】
【】拿到统一变量块索引
;【】 -
有了
统一变量块索引
,
可以用glGetActiveUniformBlockName
获取块名
,
用glGetActiveUniformBlockiv
获取统一变量块
的各种属性
【要获取什么属性,
由pname
指定,
在params
返回】; -
有了
统一变量块索引
,
还可以用glUniformBlockBinding
将该索引
和
程序实例
中的统一变量缓冲区绑定点【自定义的一个(点)序号】
关联;【bindingPoint】 -
可以用
glGenBuffers(bindingPoint, &bufferId)
最后,
可以用glBindBufferRange
或者glBindBufferBase
将统一变量缓冲区对象
绑定到GL_UNIFORM_BUFFER目标
和
程序实例中的统一变量块绑定点
【bindingPoint |glBindBufferBase
的 GLuint index】
编程统一变量块时,应该注意如下的限制:
顶点
或者片段着色器
使用的最大活动统一变量块
的数量
可以分别用带GL_MAX_VERTEX_UNIFORM_BLOCKS
或GL_MAX_FRAGMENT_UNIFORM_BLOCKS
参数的glGetIntegerv
查询,
所有实现中最小的支持数量为12;程序中所有着色器 使用的
最大活动统一变量块
的数量
可以用带GL_MAX_COMBINED_UNIFORM_BLOCKS
参数的glGetIntegerv
查询,
所有实现中最小的支持数量为24;每个
统一变量缓冲区
的最大可用存储量
可以
用带GL_MAX_UNIFORM_BLOCK_SIZE
参数的glGetInteger64v
查询,
返回的大小以字节数表示。
所有实现中最小的支持数量为16KB;如果违反了这些限制,程序就无法链接;
程序示例,
说明如何用前面描述的命名统一变量块LightTransform
【std140例程处】
建立一个统一变量缓冲区对象
:
【思路:
块
与自定义绑定点
关联,
创建缓冲区实例对象
,
缓冲区实例对象
绑定到与块
关联的绑定点
,即用块
建立了一个统一变量缓冲区对象
】
【!!!!!!
注意注释,关于代码的功能,注释写的很清楚
!!!!!!】
glBindBufferBase
的API 二参
要传入的是【
GLuint index
| (准备要跟 程序实例中的统一变量缓冲区绑定点 进行绑定的)绑定索引
】,而实际上 代码运用中,
传入的数值
跟传给
glUniformBlockBinding
的API 第三个参数
一样【
GLunit blockBinding
| 统一变量缓冲区对象绑定点
】,都是【bindingPoint | 绑定点】,
也就是它们两个形参位置,其实是传入的是一个东西;
因为
glUniformBlockBinding
的API 第三个参数
是自定义
的一个与索引
相关联的统一变量缓冲区绑定点
,
这个uniform block【统一变量块】
跟它的索引
、跟这个统一变量缓冲区绑定点
!三者!是【相互关联】的;
glBindBufferBase
的二参
即是这个uniform block【统一变量块】
对应的(统一变量缓冲区)绑定点
,
glBindBufferBase
便是
将buffer实例(的id)【三参】
绑定到绑定点(bindingPoint)【二参】
上来Bind the 【buffer object】 to the 【uniform block binding point】
获取和设置属性
-
除了查询
程序对象
上的统一变量信息
之外,
还需要使用程序对象
设置顶点属性
; -
对
顶点属性
的查询和统一变量查询
非常相似;
可以用GL_ACTIVE_ATTRIBUTES
查询找到活动属性列表
,
可以用glGetActiveAttrib
找到某个属性的特性
。
然后,有一组例程可用于设置顶点数组,以加载顶点属性值。
参考自:
- 《OPENGL ES 3.0编程指南(第2版)》
网友评论