@(Graphics)[OpenGL, OpenGLES]
OpenGL/GLES Notes
EGL
opengl和host app window system之間的glue層
使用egl進(jìn)行綁定例程中, 主要創(chuàng)建的對象包括
- display device:
eglGetDisplay
使用default即可 - config object: 包含了當(dāng)前render相關(guān)的所有參數(shù), 包括target的buffer格式, frame組成, onscreen/offscreen等, 通過
eglGetConfigs
或eglChooseConfig
進(jìn)行查詢, 獲取一個合適的config - rendering surface: 根據(jù)onscreen/offscreen區(qū)分, 使用
eglCreateWindowSurface
或eglCreatePbufferSurface
. 前者需要傳入一個平臺相關(guān)的window對象(例如Windows上就是HWND). 需要額外指定surface的模式參數(shù), 例如單/雙緩沖, frame的大小等 - rendering context: 包含了所有的gl state.
eglCreateContext
. 可以實現(xiàn)context共享, 但是一般用不到. 需要額外的context參數(shù), 主要是opengl/es的版本 - 把context和surface綁定:
eglMakeCurrent
iOS Apple自己有提供context: EAGLContext
, 創(chuàng)建非常簡單, 不需要使用到EGL.
Program Object & Shaders
從Host app向Shader傳遞數(shù)據(jù)有2種主要形式
- attribute
- uniform
Attributes
attribute的數(shù)據(jù)處理時是per vertex的, 但我們可以給所有vertex賦予不同, 也可以給相同的值. (后者在OpenGLES3.0 PG這本書中稱為 constant vertex attribute)
當(dāng)program編譯并完成之后, 其attribute入?yún)⒌南嚓P(guān)meta data都確定了, 可以通過一些列query方法抽取.
- 調(diào)用
glGetProgram
提供GL_ACTIVE_ATTRIBUTES
和GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
, 可以獲知indexCount
和max name length - 調(diào)用
glGetActiveAttrib
可以一次性獲取到attribute的name, type, size等參數(shù). 調(diào)用時的index一定是屬于0..<indexCount
range內(nèi)
注意: OpenGL里對類似
GL_MAX_VERTEX_ATTRIBS
這類state限制的解釋: 都是以vec4為單位的, 如果出現(xiàn)數(shù)組或者struct或者mat4, 是按復(fù)數(shù)倍來計算的. 因此最終programmer真正能使用的active attribute的參數(shù)個數(shù)可能會少于GL_MAX_VERTEX_ATTRIBS
. 即: 仍然是從0開始遞增計數(shù), 但上限會更小.
但一般host app在給shader提供具體data時, 并不會從program從頭開始query參數(shù)來決定如何提供data, 而是根據(jù)先驗的知識(例如location, name等)來決定提供data的方式.
- attribute的layout location和index不是一個概念, index一定從0開始以step為1遞增, 但location可以在shader中, 用
layout(location = x)
指定. 同時當(dāng)一個attribute的size較大時, 相鄰index的attribute的location差大于1, 具體規(guī)則可以理解成一個vec4會加1, array中的每個元素一定按vec4的stride進(jìn)行align - 如果知道attribute名, 也可以通過
glGetAttribLocation
進(jìn)行獲取 - 也可以在program link之前, 預(yù)先用
glBindAttribLocation
指定某個name的location(但不可以和layout qualifier沖突) - 獲取location后, 調(diào)用
glVertexAttrib
或glVertexAttribPointer
傳遞數(shù)據(jù). 后者可以進(jìn)一步把將對應(yīng)的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更改的是當(dāng)前active的VAO對象. 通過預(yù)先配置好不同的VAO, 并且實時切換, 可以快速提供一組新的對象給GPU繪制.
默認(rèn)有一個VAO(id是0), glGenVertexArrays
可以生成額外的, 不同的VAO用glBindVertexArray
切換
Uniforms
Uniforms是全局constant, vertex shader和fragment shader中每次執(zhí)行都獲取相同的值. 但uniform有2種定義方式.
- 使用
uniform Type identifier;
定義的uniform, 位于匿名的default uniform group - 也可以通過
uniform Name{ Type identifier; }
方式定義一個實名為Name的uniform group.- 使用
layout(std140)
可以使用標(biāo)準(zhǔn)化的布局, 便于在host app中準(zhǔn)備數(shù)據(jù)
- 使用
和vertex attributes一樣, 可以從program中獲取大量信息
- 調(diào)用
glGetProgram
提供GL_ACTIVE_UNIFORMS
和GL_ACTIVE_UNIFORM_MAX_LENGTH
, 可以獲知indexCount
和max name length. 這邊獲取的param是所有包含于任何default/named uniform group的uniforms的值. - 以index為
0..<indexCount
范圍內(nèi)的值調(diào)用glGetActiveUniform
可以一次性獲取uniform的name, type, size等參數(shù), 這一點和attribute類似. 除此之外, 還可以調(diào)用glGetActiveUniformsiv
批量獲取一組index的信息, 這個方法主要支援的是隸屬于named uniform block的uniforms, 可以額外獲取該uniform隸屬的uniform block的index, 以及其在block中的offset/stride等屬性; 如果對default uniform block中的uniform調(diào)用此方法, 上面這些參數(shù)值只能取到-1.
named uniform block是gles 3.0新增概念, 對于uniform block本身也有metadata可以獲取
- 調(diào)用
glGetProgram
提供GL_ACTIVE_UNIFORM_BLOCKS
和GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH
, 可以獲取block的indexCount
和max name Length. 不包括default uniform block. - 提供
0..<indexCount
范圍內(nèi)的值, 給glGetActiveUniformBlockName
可以獲取到block的name, 而glGetActiveUniformBlockiv
可以獲取到更多param, 包括buffer binding, size; 最終要的屬性是該bblock所包含的uniform列表, 可以按uniform的global index進(jìn)行索引.
Host app提供uniform data和attribute也有兩種方式, trivial value/buffer. 同樣我們一般擁有先驗知識: uniform的name. 而想要提供數(shù)據(jù), 無論如何, 也都需要首先獲取到shader中uniform的位置.
- 對于default uniform block中的uniform, 和attribute類似, 需要獲取location, 該值和index不是一個概念:
-
glGetUniformLocation
可以根據(jù)uniform的name查詢location - 獲取到location后, 使用
glUniform
傳遞data即可
-
- 對于named uniform block, 即使已經(jīng)獲取到了成員的index(無論是通過
glGetUniformIndices
直接由name獲取, 還是通過獲取到block index后, 使用glGetActiveUniformBlock
間接獲取), 也無法通過glGetUniformLocation
獲取location.- 必須在通過
glGetActiveUniformBlock
獲取到uniform block的index后, 調(diào)用glUniformBlockBinding
將該block和一個user-defined的binding point聯(lián)系起來. - 緊接著, 將一個bind到
GL_UNIFORM_BUFFER
target的data buffer, 通過glBindBufferBase
/glBindBufferRange
和該binding point進(jìn)行關(guān)聯(lián). 此時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. 此坐標(biāo)系為OpenGL特例! .
- 可以方便用來實現(xiàn)point sprite的紋理渲染