2013-01-10 109 views
19

我正在寫一個使用OpenGL(通過OpenTK與C#)的小圖形引擎。OpenGL,VAOs和多個緩衝區

要定義頂點屬性,我有一個VertexDeclaration類,其中有一個VertexElement結構數組,映射到glEnableVertexAttribArray/glVertexAttribPointer調用。另外,爲了支持多個頂點流,我有一個特殊的結構,它包含一個頂點緩衝區,頂點聲明,頂點偏移量和實例頻率(如XNA的VertexBufferBinding結構)。

目前,只要調用繪圖電話,我遍歷所有的頂點集流和 結合其頂點緩衝區,應用頂點聲明,禁用不用的頂點屬性和繪製圖元。

我想使用VAO將glEnableVertexAttribArray調用緩存到它們中,每當應用頂點流時,綁定VAO並更改其數組緩衝區綁定。

這是VAO的正確用法嗎?

回答

34

這是VAO的正確用法嗎?

否。

glVertexAttribPointeruses the buffer object that was bound to GL_ARRAY_BUFFERat the moment the function was called。所以,你不能做到這一點:

glVertexAttribPointer(...); 
glBindBuffer(GL_ARRAY_BUFFER, bufferObject); 
glDrawArrays(...); 

這將使用bufferObject;當最初調用glVertexAttribPointer時,它將使用與GL_ARRAY_BUFFER綁定的任何內容。

VAO捕獲此狀態。因此,VAO將針對每個頂點屬性存儲被調用時綁定到GL_ARRAY_BUFFER的任何緩衝區對象。這允許你做這樣的事情:

glBindVertexArray(VAO); 
glBindBuffer(GL_ARRAY_BUFFER, buffer1); 
glVertexAttribPointer(0, ...); 
glVertexAttribPointer(1, ...); 
glBindBuffer(GL_ARRAY_BUFFER, buffer2); 
glVertexAttribPointer(2, ...); 

屬性0和1將來自buffer1和屬性2將來自buffer2。 VAO現在可以捕獲所有狀態。要渲染,你只是這樣做:

glBindVertexArray(VAO); 
glDraw*(); 

總之,如果你想要更改屬性的存儲來自於OpenGL,則還必須更改它的格式。即使格式相同,您也必須再次撥打glVertexAttribPointer

:此討論假定您使用新ARB_vertex_attrib_binding。或者,正如其他人所知,「Exactly how Direct3D does vertex attribute binding.」如果您恰好使用提供此擴展的實現,則可以有效地執行您正在討論的內容,因爲屬性格式不與緩衝對象的存儲綁定。另外,glVertexAttribPointer的折磨邏輯消失了。

一般來說,我們在OpenGL世界中解決這個問題的方法是將盡可能多的東西放在同一個緩衝區對象中。如果不這樣做,只需爲每個對象使用一個VAO。

+0

感謝這個偉大的答案。那麼'glBufferData'步驟在哪裏起作用?在使用'glVertexAttribPointer'之前,你不必先緩衝數據嗎?對不起,我對OpenGL很陌生 –