OpenGL編程指南(第九版) Tiangles 學習筆記
////////////////////////////////////////////////////////////////////////////// // // Triangles.cpp // ////////////////////////////////////////////////////////////////////////////// #include "vgl.h" #include "LoadShaders.h" enum VAO_IDs { Triangles, NumVAOs }; enum Buffer_IDs { ArrayBuffer, NumBuffers }; enum Attrib_IDs { vPosition = 0 }; GLuint VAOs[NumVAOs]; GLuint Buffers[NumBuffers]; const GLuint NumVertices = 6; //----------------------------------------------------------------------------// // init // void init( void ) { glGenVertexArrays( NumVAOs, VAOs ); glBindVertexArray( VAOs[Triangles] ); GLfloat vertices[NumVertices][2] = { { -0.90f, -0.90f }, { 0.85f, -0.90f }, { -0.90f, 0.85f }, // Triangle 1 { 0.90f, -0.85f }, { 0.90f, 0.90f }, { -0.85f, 0.90f } // Triangle 2}; glCreateBuffers( NumBuffers, Buffers ); glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] ); glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0); ShaderInfo shaders[] = { { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" }, { GL_FRAGMENT_SHADER,"media/shaders/triangles/triangles.frag" }, { GL_NONE, NULL } }; GLuint program = LoadShaders( shaders ); glUseProgram( program ); glVertexAttribPointer( vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) ); glEnableVertexAttribArray( vPosition ); } //---------------------------------------------------------------------------- // // display // void display( void ) { static const float black[] = { 1.0f, 0.0f, 0.0f, 0.0f }; glClearBufferfv(GL_COLOR, 0, black); glBindVertexArray( VAOs[Triangles] ); glDrawArrays( GL_TRIANGLES, 0, NumVertices ); } //---------------------------------------------------------------------------- // // main // #ifdef _WIN32 int CALLBACK WinMain( _In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow ) #else int main( int argc, char** argv ) #endif { glfwInit(); GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL); glfwMakeContextCurrent(window); gl3wInit(); init(); while (!glfwWindowShouldClose(window)) { display(); glfwSwapBuffers(window); glfwPollEvents(); } glfwDestroyWindow(window); glfwTerminate(); }
一、環境問題
首先就是環境的問題,樣例中使用的 glCreateBuffers() 函數要求顯卡驅動支持OpenGL 4.5才可以使用,如果版本不達標會出現空指針錯誤。
解決方法:升級你的顯卡驅動, 如果驅動已經是最新,則檢查是否為雙顯卡,將獨顯(一般都是n卡)設為首選。
二、全局變量
程序在開頭位置(頭文件下邊)聲明了一些對於初學者不明覺厲的枚舉值和整型數組。
其中那些以 IDs 結尾枚舉值都是起到了索引的功能,因為 OpenGL 是使用一些整數作為對象(比如緩沖區,頂點數組等)的標記,這些整數通常沒有規律可言,因此將同類型的對象的標記存放在一個整型數組中能夠便於我們進行管理。
值得註意的是,每個索引的最後一個元素(以Num為前綴,數組名為後綴的那個元素)只起到表示對象數量的作用,沒有其他實際意義。
三、頂點數組與頂點著色器
頂點數組也是個相當令人困惑的地方。
有人會說有了頂點著色器表示頂點的信息要頂點數組有什麽用,但是仔細去看,頂點著色器只是起到一個中間處理的作用,最終進入繪制函數的仍然是頂點數組。
因此頂點數據的流向其實是這樣的:在一般數組中創建(只包含位置信息) -> 進入頂點著色器進行加工(本例程中雖然只起到了傳遞數據的作用) -> 傳入頂點數組中準備進行繪制。
此外頂點數組的創建過程也很有意思:glCreateVertexArrays() 只負責進行空間的分配 -> glBindVertexArray() 將數組選中準備進行操作 -> glVertexAttribPointer() 負責對它進行賦值。
四、緩沖區
在我理解中緩沖區大概就是一個全局可用的數據塊。
值得註意的是在頂點數據的流動中緩沖區起到了不可替代的作用。或者可以說凡是跨函數的數據操作,都用到了緩沖區:要麽是向被調用函數中傳入緩沖區的編號(之前提到的標誌),要麽是通過 glBindBuffer 將要用到的緩沖區設為激活狀態。
在本程序中使用了後者:頂點數據先從數組中被存放在緩沖區中 -> 頂點著色器再通過訪問 / 修改緩沖區進行頂點著色 -> 最後 glVertexAttribPointer() 從緩沖區中將定點數據賦值給頂點數組。
OpenGL編程指南(第九版) Tiangles 學習筆記