@(Graphics)[OpenGL, OpenGLES]
OpenGL/GLES Notes
EGL
opengl和host app window system之间的glue层
使用egl进行绑定例程中, 主要创建的对象包括
- display device:
eglGetDisplay
使用default即可 - config object: 包含了当前render相关的所有参数, 包括target的buffer格式, frame组成, onscreen/offscreen等, 通过
eglGetConfigs
或eglChooseConfig
进行查询, 获取一个合适的config - rendering surface: 根据onscreen/offscreen区分, 使用
eglCreateWindowSurface
或eglCreatePbufferSurface
. 前者需要传入一个平台相关的window对象(例如Windows上就是HWND). 需要额外指定surface的模式参数, 例如单/双缓冲, frame的大小等 - rendering context: 包含了所有的gl state.
eglCreateContext
. 可以实现context共享, 但是一般用不到. 需要额外的context参数, 主要是opengl/es的版本 - 把context和surface绑定:
eglMakeCurrent
iOS Apple自己有提供context: EAGLContext
, 创建非常简单, 不需要使用到EGL.
Program Object & Shaders
从Host app向Shader传递数据有2种主要形式
- attribute
- uniform
Attributes
attribute的数据处理时是per vertex的, 但我们可以给所有vertex赋予不同, 也可以给相同的值. (后者在OpenGLES3.0 PG这本书中称为 constant vertex attribute)
当program编译并完成之后, 其attribute入参的相关meta data都确定了, 可以通过一些列query方法抽取.
- 调用
glGetProgram
提供GL_ACTIVE_ATTRIBUTES
和GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
, 可以获知indexCount
和max name length - 调用
glGetActiveAttrib
可以一次性获取到attribute的name, type, size等参数. 调用时的index一定是属于0..<indexCount
range内
注意: OpenGL里对类似
GL_MAX_VERTEX_ATTRIBS
这类state限制的解释: 都是以vec4为单位的, 如果出现数组或者struct或者mat4, 是按复数倍来计算的. 因此最终programmer真正能使用的active attribute的参数个数可能会少于GL_MAX_VERTEX_ATTRIBS
. 即: 仍然是从0开始递增计数, 但上限会更小.
但一般host app在给shader提供具体data时, 并不会从program从头开始query参数来决定如何提供data, 而是根据先验的知识(例如location, name等)来决定提供data的方式.
- attribute的layout location和index不是一个概念, index一定从0开始以step为1递增, 但location可以在shader中, 用
layout(location = x)
指定. 同时当一个attribute的size较大时, 相邻index的attribute的location差大于1, 具体规则可以理解成一个vec4会加1, array中的每个元素一定按vec4的stride进行align - 如果知道attribute名, 也可以通过
glGetAttribLocation
进行获取 - 也可以在program link之前, 预先用
glBindAttribLocation
指定某个name的location(但不可以和layout qualifier冲突) - 获取location后, 调用
glVertexAttrib
或glVertexAttribPointer
传递数据. 后者可以进一步把将对应的data buffer绑定到GL_ARRAY_BUFFER
/GL_ELEMENT_ARRAY_BUFFER
. 对同一个location, constant/array(包含VBO)这2种模式可以同时指定, 通过glEnableVertexAttribArray
启用后者
VAO: vertex array pointer
如上所述, 在GLES3.0前, 有三种提供vertex attributes的方式
- constant vertex attribute
glVertexAttrib
- client vertex array
glVertexAttribPointer
withglEnableVertexAttribArray
- VBO,
glVertexAttribPointer
with buffer bound toGL_ARRAY_BUFFER
/GL_ELEMENT_ARRAY_BUFFER
事实上, 上述API更改的是当前active的VAO对象. 通过预先配置好不同的VAO, 并且实时切换, 可以快速提供一组新的对象给GPU绘制.
默认有一个VAO(id是0), glGenVertexArrays
可以生成额外的, 不同的VAO用glBindVertexArray
切换
Uniforms
Uniforms是全局constant, vertex shader和fragment shader中每次执行都获取相同的值. 但uniform有2种定义方式.
- 使用
uniform Type identifier;
定义的uniform, 位于匿名的default uniform group - 也可以通过
uniform Name{ Type identifier; }
方式定义一个实名为Name的uniform group.- 使用
layout(std140)
可以使用标准化的布局, 便于在host app中准备数据
- 使用
和vertex attributes一样, 可以从program中获取大量信息
- 调用
glGetProgram
提供GL_ACTIVE_UNIFORMS
和GL_ACTIVE_UNIFORM_MAX_LENGTH
, 可以获知indexCount
和max name length. 这边获取的param是所有包含于任何default/named uniform group的uniforms的值. - 以index为
0..<indexCount
范围内的值调用glGetActiveUniform
可以一次性获取uniform的name, type, size等参数, 这一点和attribute类似. 除此之外, 还可以调用glGetActiveUniformsiv
批量获取一组index的信息, 这个方法主要支援的是隶属于named uniform block的uniforms, 可以额外获取该uniform隶属的uniform block的index, 以及其在block中的offset/stride等属性; 如果对default uniform block中的uniform调用此方法, 上面这些参数值只能取到-1.
named uniform block是gles 3.0新增概念, 对于uniform block本身也有metadata可以获取
- 调用
glGetProgram
提供GL_ACTIVE_UNIFORM_BLOCKS
和GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH
, 可以获取block的indexCount
和max name Length. 不包括default uniform block. - 提供
0..<indexCount
范围内的值, 给glGetActiveUniformBlockName
可以获取到block的name, 而glGetActiveUniformBlockiv
可以获取到更多param, 包括buffer binding, size; 最终要的属性是该bblock所包含的uniform列表, 可以按uniform的global index进行索引.
Host app提供uniform data和attribute也有两种方式, trivial value/buffer. 同样我们一般拥有先验知识: uniform的name. 而想要提供数据, 无论如何, 也都需要首先获取到shader中uniform的位置.
- 对于default uniform block中的uniform, 和attribute类似, 需要获取location, 该值和index不是一个概念:
-
glGetUniformLocation
可以根据uniform的name查询location - 获取到location后, 使用
glUniform
传递data即可
-
- 对于named uniform block, 即使已经获取到了成员的index(无论是通过
glGetUniformIndices
直接由name获取, 还是通过获取到block index后, 使用glGetActiveUniformBlock
间接获取), 也无法通过glGetUniformLocation
获取location.- 必须在通过
glGetActiveUniformBlock
获取到uniform block的index后, 调用glUniformBlockBinding
将该block和一个user-defined的binding point联系起来. - 紧接着, 将一个bind到
GL_UNIFORM_BUFFER
target的data buffer, 通过glBindBufferBase
/glBindBufferRange
和该binding point进行关联. 此时buffer中的data即可传递. (事实上这2个方法可以同时bind到这个index binding point, 同时bind到这个target; 因此有时可以省去一次单独的glBindBuffer
)
- 必须在通过
Buffers
in gpu/ opengl controlled
Types
- uniform (block )buffer
- vertex array buffer
- vertex element buffer
Copy
gpu memory 1 -> gpu memory 2
Map
gpu memory -> client
DrawCalls
drawArrays
drawElements
- instanced drawing
- drawing query object
- Q: if we enable instance divisor on an indexed per-vertex attribute, what will happen?
A: it will behavior as per-instance, ignoring indexing
- Q: if we enable instance divisor on an indexed per-vertex attribute, what will happen?
Shaders
Vertex Shader
Fragment Shader
- gl_PointCoord, 用于GL_POINTS绘制时, 如果VS输出的gl_PointSize大于1, 则每个fragment会指示自己位于整个point的哪个位置.
- 注意: 左上角为0, 0, 右下角为1, 1. 此坐标系为OpenGL特例! .
- 可以方便用来实现point sprite的纹理渲染
网友评论