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() 從緩衝區中將定點數據賦值給頂點數組。

  緩衝區的創建與頂點數組相同,Create 函數是成批地創建緩存的,它接受的是一個數組和它的大小,結果是把創建的緩衝區的編號寫入給出的數組中。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章