openGL中的drawCall類型

? ? ? ?最近美術想了一個需求,想要實現(xiàn)全屏同時播放上千個粒子系統(tǒng)。這個需求確實挺瘋狂的,因為對于CPU粒子來說,改動很大;而對于GPU粒子來說基本不可能(?)。老大對于這個需求非常質(zhì)疑,我本人倒是很感興趣,在尋找渲染實例化對象的實例化的(InstancedBaseInstance)方法的時候,發(fā)現(xiàn)高版本openGL的很多有意思的地方。在本文,總結(jié)一下高版本openGL draw call的類型。還是之前的結(jié)論,在不考慮設備兼容性問題的時候,openGL簡直無敵,要啥有啥。
? ? ? ?封面圖來自Daniel Rákos?的GPU based dynamic geometry LOD
Direct rendering
? ? ? ?Direct rendering和其他drawcall類型最顯著的區(qū)別,就是Direct rendering的所有數(shù)據(jù)都是從CPU傳來的,而其他的渲染方式都有數(shù)據(jù)是從openGl object(GPU)傳來。
Basic Drawing

Multi-Draw
? ? ? ?創(chuàng)建或者修改VAO都是一個很費的操作,因此有了這個功能,在一個VAO中存儲多個mesh,然后批量繪制(batch)

? ? ? ?實際上相當于

Multi-Draw所有物體使用相同材質(zhì)
Base Index
? ? ? ?將多個模型存在同一個VBO中,如下所示
[A00 A01 A02 A03 A04... Ann B00 B01 B02... Bmm]
? ? ? ?glDrawArrays
的話指定start index和count就能畫出指定的模型了,glDrawElements
卻存在一些小問題,就是B的索引并非m,而是m + nn。調(diào)整一下其實沒多麻煩,但openGL還是提供了接口,可以選擇一個basevertex作為索引基礎(nn),其他的索引自動加上這個basevertex的索引

Instancing
? ? ? ?這個應該都很熟悉了,不多介紹了
void glDrawArraysInstanced( GLenum mode, GLint first,
? ?GLsizei count, GLsizei instancecount );void glDrawElementsInstanced( GLenum mode, GLsizei count,
? ?GLenum type, const void *indices, GLsizei instancecount );
gl_InstanceID
還有Instanced_Array是實例之間的唯一差距。

? ? ? ?在 openGL 4.2 版本或者支持擴展?ARB_base_instance,實例化的實例化已經(jīng)成為可能!

gl_InstanceID
不隨baseinstance變化,因此每實例差異只能靠Instanced_Array來實現(xiàn)。在 openGL 4.6 或者?ARB_shader_draw_parameters擴展的情況下,可以通過gl_BaseInstance
訪問函數(shù)中的baseinstance參數(shù)
Range
? ? ? ?“Range”版本的glDrawElements
也用來處理多個模型存儲在同一個VBO的情況,但是不會有索引數(shù)組越界的錯誤

Combinations
? ? ? ?Combinations和openGL的primitive restart特性緊密相關。
? ? ? ?Base vertex可以和MultiDraw, Range, 或 Instancing結(jié)合

? ? ? ?在openGL 4.2版本或者ARB_base_instance,BaseVertex 也能和 BaseInstance 結(jié)合

Transform feedback rendering
? ? ? ?可以使用Transform Feedback來生成頂點信息用于渲染。通常的數(shù)據(jù)流程是GPU->CPU->GPU,但有一些API允許在CPU讀取確切數(shù)據(jù)之前直接繪制。

? ? ? ?在 openGL 4.2版本或者支持ARB_transform_feedback_instanced 的設備上,上述兩個函數(shù)的實例化版本也可以使用

Indirect rendering
? ? ? ?該特性的目的是允許直接渲染GPU中的數(shù)據(jù),省去GPU->CPU->GPU的拷貝過程。運行時數(shù)據(jù)來源可能是Compute Shader,也可能是Geometry Shader + Transform Feedback,甚至可能是openCL/CUDA。
? ? ? ?所有Indirect rendering都適用于下列情況:
Indexed rendering
Base vertex (for indexed rendering)
Instanced rendering
Base instance (if OpenGL 4.2 or ARB_base_instance is available). Does not require rendering more than one instance

? ? ? ?此函數(shù)功能上等價于

? ? ? ?在openGL 4.3或者ARB_multi_draw_indirect擴展下,也可以用于multi draw

? ? ? ?對于索引渲染

? ? ? ?在功能上等價于

? ? ? ?在openGL 4.3或者ARB_multi_draw_indirect擴展下,也可以用于multi draw

Conditional rendering
? ? ? ?條件渲染就是只在某些條件下渲染,在某些條件下就不渲染。最經(jīng)典的運用就是Occlusion Query。

? ? ? ?支持的命令如下
Every function previously mentioned. IE, all functions of the form?
glDraw*
?or?glMultiDraw*
.glClear
?and?glClearBuffer
.glDispatchCompute
?and?glDispatchComputeIndirect
.
參數(shù)中mode可以是如下選項:
GL_QUERY_WAIT: OpenGL will wait until the query result is returned, then decide whether to execute the rendering command. This ensures that the rendering commands will only be executed if the query fails. Note that it is OpenGL that’s waiting, not (necessarily) the CPU.
GL_QUERY_NO_WAIT: OpenGL may execute the rendering commands anyway. It will not wait to see if the query test is true or not. This is used to prevent pipeline stalls if the time between the query test and the execution of the rendering commands is too short.
GL_QUERY_BY_REGION_WAIT: OpenGL will wait until the query result is returned, then decide whether to execute the rendering command. However, the rendered results will be clipped to the samples that were actually rasterized in the occlusion query. Thus, the rendered result can never appear outside of the occlusion query area.
GL_QUERY_BY_REGION_NO_WAIT: As above, except that it may not wait until the occlusion query is finished. The region clipping still holds.