2019年1月14日 星期一

關於VertexArrayObject(VAO)

關於VertexArrayObject(VAO)

前言

  VertexArrayObject是從OpenGL3.0以後加入的特性,最近發現我對它的用法有錯誤的見解,在此做個紀錄。

內容

  最近發現到我對VertexArrayObject的用法有誤,會有錯誤來自於範例很容易是以下
void main()
{
  //
  //...
  //Set up vao
  GLuint vao;
  glGenVertexArrays(1,&vao);
  glBindVertexArray(vao);
  //Set up vertex attribute
  glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
  glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(void*)(sizeof(float)*9));
  glEnableVertexAttribArray(0);
  glEnableVertexAttribArray(1);
  //
  //...
  return 0;
}

範例鐘用註解分為"Set up vao"與"Set up vertex attribute"兩個部分,在沒有VAO的特性時,只需要做"Set up vertex attribute"的部分,當有VAO的特性時就必須多做"Set up vao"的部分,這一直是我之前的理解,雖然用起來沒問題,但用法卻很容易被誤解。誤解了什麼?誤解的部分是在每個Frame要設定繪圖資料時,會執行glBindVertexArray()與"Set up vertex attribute"的部分,這個想法是錯的!正確的是每個Frame只需執行glBindVertexArray()即可,"Set up vertex attribute"的部分不需再次執行,VAO像是個"紀錄"的物件,當綁過glVertexAttribPointer()與glEnableVertexAttribArray()後會記錄下來,下次只要glBindVertexArray()後就等於做了上次的綁定,這樣可以省下每次設定物件的glVertexAttribPointer()與glEnableVertexAttribArray()。最後來比較一下用法,首先是沒有VAO特性時的用法
//Frame1  
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(void*)(sizeof(float)*9));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//Frame2
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(void*)(sizeof(float)*9));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//Frame3
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(void*)(sizeof(float)*9));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

接著是有VAO特性時的用法
//Frame1  
glBindVertexArray(vao);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(void*)(sizeof(float)*9));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//Frame2
glBindVertexArray(vao);
//Frame3
glBindVertexArray(vao);


參考資料

OpenGL 3D繪圖互動程式設計,出版者:旗標,作者:賴祐吉, 姚智原, 朱宏國作,
ISBN-13:9789863125112

沒有留言:

張貼留言