1. 程式人生 > >OpenGL學習筆記:常用物件的建立及使用

OpenGL學習筆記:常用物件的建立及使用

·頂點陣列物件(Vertex Array Object,VAO)

頂點陣列物件(Vertex Array Object,VAO),用來記錄頂點的資訊,如:位置、資料格式、紋理座標等。使用VAO的好處是:在配置繪製物件的頂點屬性時,你只需要配置一次(VAO會自動記錄你的設定),想要繪製物件時,繫結相應的VAO就可以了。這使得在不同繪製物件之間切換變得非常簡單,只需要繫結相應的VAO就行了。建立和使用VAO的程式碼如下:

//建立1個VAO並繫結 
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

//do something 設定頂點資訊

//這裡的x根據自己的頂點資訊來設定
glVertexAttribPointer(0, x, GL_FLOAT, GL_FALSE, x * sizeof(float), (void*)0);
//這個函式的呼叫位置比較靈活,在繫結後且解綁前且繪製前呼叫即可。
glEnableVertexAttribArray(0);
//解綁VAO
glBindVertexArray(0);

//do something

//刪除無用物件,通常在程式退出前呼叫
glDeleteVertexArrays(1, &VAO);

注意:
1.OpenGL的核心模式要求我們使用VAO,如果我們繫結VAO失敗,核心模式下的OpenGL會拒絕繪製任何東西;
2.考慮到效能的原因,頂點著色器的屬性變數預設是關閉的,所以頂點的屬性資料在頂點著色器中是不可見的,即使資料已經上傳到GPU中。當呼叫glEnableVertexAttribArray後,頂點著色器中才可以訪問頂點的屬性資料。呼叫glVertexAttribPointer只是建立CPU和GPU之間的邏輯連線,把CPU中的資料上傳至GPU。但是,頂點著色器能否讀取、使用資料,由是否呼叫glEnableVertexAttribArray決定。

·頂點緩衝物件(Vertex Buffer Object,VBO)

頂點緩衝物件(Vertex Buffer Object,VBO),本質上是GPU儲存空間裡的一塊快取區。這塊快取區有它的"名字"(就是呼叫建立函式的返回值),OpenGL在GPU的某處記錄著這個"名字"和"名字"對應的視訊記憶體地址。使用VBO的好處是:我們可以一次性地傳送一大批資料到GPU上,而不是多次傳送。從CPU把資料傳送到GPU相對較慢,所以我們一次要傳送儘可能多的資料。當資料傳送到GPU的記憶體後,頂點著色器幾乎能立即訪問到頂點資料,這是大大提高了效率。建立和使用VAO的程式碼如下:

//通常在前面會先建立一個數據陣列和建立、繫結一個VAO

//建立1個VBO並繫結
unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//這裡的vertices是事先定義好的資料陣列
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

//解綁VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);

//do something

//刪除無用物件,通常在程式退出前呼叫
glDeleteBuffers(1, &VBO);

注意:
1.在VBO的建立和繫結資料階段,不知道也沒必要知道它存的是資料的意義(是座標、顏色還是其他),資料的型別是在渲染階段的定義的。

·索引緩衝物件(Element Buffer Object,EBO)

索引緩衝物件(Element Buffer Object,EBO或稱Index Buffer Object,IBO),EBO實際上是一個頂點資訊的索引表,它首先把頂點資訊按0-x(x是頂點數 - 1)編號,然後建立一個由若干個i(i的取值範圍為0-x,數量視情況而定)組成的索引表。在繪製圖像的時候,會根據這個索引表來繪製。使用VBO的好處是:如果有些繪製的點是相同的,你只需要定義一次,然後在索引表中引用,不需要繪製幾次定義幾次。建立和使用EBO的程式碼如下:

//通常在前面會完成頂點資料的定義並繫結到一個VBO,而且會建立一個索引表陣列

//建立1個索引緩衝物件並繫結
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
//這裡的indices是事先定義好的索引表陣列
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

//do something

//繪製時
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
//這裡的param1-4,根據實際情況呼叫
glDrawElements(param1, param2, param3, param4);

//刪除無用物件,通常在程式退出前呼叫
glDeleteBuffers(1, &EBO);