VAO和EBO解綁定的坑?

最近遇到了一個VAO和EBO的坑。

glBindVertexArray(VAO)

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

...

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

glBindVertexArray(0);

...

glBindVertexArray(VAO);

glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);//crash

如上代碼所示,我在unbind VAO之前 unbind了EBO,然後在glDrawElements處就會出現crash,必須先unbind VAO再unbind EBO,上面代碼才能如期運行。但是我有一個疑問的是對於VBO,我在unbind VAO之前先unbind了VBO就不會出現crash,想請教大家為什麼會出現這樣的狀態,是VAO和EBO之間的坑嗎,還是我沒理解對?

glBindVertexArray(VAO)

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);

...

glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindVertexArray(0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

...

glBindVertexArray(VAO);

glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);//dont crash

對於上述所說,我的理解是EBO是存在VAO裡面的,因此在unbind VAO之前unbind了EBO相當於VAO此時不在保存這個EBO了;而VBO不是保存在VAO之中的,因此不會出現這個問題。但是在unbind VAO之前unbind了VBO不相當於切斷了VAO和VBO之間的聯繫了嗎,為什麼後面draw call時VAO還能正確的讀到頂點數據?


著作權歸作者所有。

商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

作者:Vinjn張靜

鏈接:如何正確理解 opengl 的 vao ? - Vinjn張靜的回答

來源:知乎

VAO 記錄的是

  1. vertex attribute 的格式,由 glVertexAttribPointer 設置。

  2. vertex attribute 對應的 VBO 的名字, 由一對 glBindBuffer 和 glVertexAttribPointer 設置。
  3. #當前#綁定的 GL_ELEMENT_ARRAY_BUFFER 的名字,由 glBindBuffer 設置。

VAO 中並不保存#當前#綁定的 GL_ARRAY_BUFFER,VBO 和 vertex attribute 的綁定是在 glVertexAttribPointer 中完成的。

完整信息參考 Vertex Specification

如何正確理解 opengl 的 vao ? - Vinjn張靜的回答


明明是你自己把index buffer綁成0的:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

glBindVertexArray(0);

不要自己發明一個名字叫EBO,沒有這個詞。

再補充一點,index buffer和vao的關係,確實有坑。在intel卡上,index buffer不能放入vao,而nv/amd卡上可以。


EBO是你自己取得名字么

至於為什麼是錯的

是因為 一個VAO 保存一組VertexAttributeState

和一個ElementArrayBufferObject

也就是一組頂點屬性和緩衝區的bind關係和一個索引數組

你bindVAO的時候 unbind了索引數組

你那個VAO就沒有bind索引數組了

你drawElements自然是錯的

具體理解 請看下面的一個偽實現代碼

struct VertexAttributeState
{
bool bIsEnabled = false;
int iSize = 4; //This is the number of elements in each attrib, 1-4.
unsigned int iStride = 0;
VertexAttribType eType = GL_FLOAT;
bool bIsNormalized = false;
bool bIsIntegral = false;
void * pPtrOrBufferObjectOffset = 0;
BufferObject * pBufferObj = 0;
};

struct VertexArrayObjectState
{
BufferObject *pElementArrayBufferObject = NULL;
VertexAttributeState attributes[MAX_VERTEX_ATTRIB];
}

static VertexArrayObjectState *pContextVAOState = new VertexArrayObjectState();
static BufferObject *pCurrentArrayBuffer = NULL;

void glBindBuffer(enum target, uint buffer)
{
BufferObject *pBuffer = ConvNameToBufferObj(buffer);

switch(target)
{
case GL_ARRAY_BUFFER:
pCurrentArrayBuffer = pBuffer;
break;
case GL_ELEMENT_ARRAY_BUFFER:
pContextVAOState-&>pElementArrayBufferObject = pBuffer;
break;
...
}
}

void glEnableVertexAttribArray(uint index)
{
pContextVAOState-&>attributes[index].bIsEnabled = true;
}

void glDisableVertexAttribArray(uint index)
{
pContextVAOState-&>attributes[index].bIsEnabled = false;
}

void glVertexAttribPointer(uint index, int size, enum type, boolean normalized, sizei stride, const void *pointer)
{
VertexAttributeState currAttrib = pContextVAOState-&>attributes[index];

currAttrib.iSize = size;
currAttrib.eType = type;
currAttrib.iStride = stride;
currAttrib.bIsNormalized = normalized;
currAttrib.bIsIntegral = true;
currAttrib.pPtrOrBufferObjectOffset = pointer;
currAttrib.pBufferObj = pCurrentArrayBuffer;
}


推薦閱讀:

現代OpenGL是怎麼繪製曲面的?
Shader 在現在圖形管線中可以負責多少部分?
震驚!時間之神又給了這個古老的API+了0.1
初學者學習opengl是用紅寶書好還是藍寶書好?
3d引擎開發需要那些技能儲備?

TAG:OpenGL | 計算機圖形學 |