1. 程式人生 > >Learn OpenGL(二)——頂點輸入(Vertex Input)

Learn OpenGL(二)——頂點輸入(Vertex Input)

      開始繪製一些東西之前, 我們必須給OpenGL輸入一些頂點資料。 OpenGL是一個3D圖形庫,所以我們在OpenGL中指定的所有座標都是在3D座標裡(x、 y和z)。 OpenGL不是簡單的把你所有的3D座標變換為你螢幕上的2D畫素; OpenGL只是在當它們的3個軸(x、 y和z)在特定的-1.0到1.0的範圍內時才處理3D座標。 所有在這個範圍內的座標叫做標準化裝置座標(Normalized Device Coordinates, NDC)會最終顯示在你的螢幕上(所有出了這個範圍的都不會顯示)。
      由於我們希望渲染一個三角形, 我們指定所有的這三個頂點都有一個3D位置。 我們把它們以 GLfloat 陣列的方式定義為標準化裝置座標(也就是在OpenGL的可見區域)中。

GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};

      上面陣列可以理解為3x3的矩陣,對應NDC,為三角形三個頂點的座標:
 A1=(-0.5,-0.5,0)  A2=(0.5,-0.5,0.0)  A3=(0.0,0.5,0.0)
       由於OpenGL是在3D空間中工作的, 我們渲染一個2D三角形, 它的每個頂點都要有同一個z座標0.0。 在這樣的方式中, 三角形的每一處的深度(Depth, 譯註2)都一樣, 從而使它看上去就像2D的。


注:
標準化裝置座標(Normalized Device Coordinates, NDC)
一旦你的頂點座標已經在頂點著色器中處理過, 它們就應該是標準化裝置座標

了, 標準化裝置座標是一個x、 y和z值在-1.0到1.0的與通常的螢幕座標不同, y軸正方向上的點和(0,0)座標是這個影象的中心, 而不是左上角。 最後你希望所有(變換過的)座標都在這個座標


      你的標準化裝置座標接著會變換為螢幕空間座標(Screen-space Coordinates), 這是使用你通過`glViewport`函式提供的資料
有了這樣的頂點資料, 我們會把它作為輸入資料傳送給圖形渲染管線的第一個處理階段: 頂點著色器。 它會在GPU上建立儲存空間用於儲存我們的頂點資料, 還要配置OpenGL如何解釋這些記憶體, 並且指定如何傳送給顯示卡。 頂點著色器接著會處理我們告訴它要處理記憶體中的頂點的數量。
      通過頂點緩衝物件(Vertex Buffer Objects, VBO)

管理這個記憶體, 它會在GPU記憶體(通常被稱為視訊記憶體)中儲存大批頂點。 使用這些緩衝物件的好處是我們可以一次性的傳送一大批資料到顯示卡上, 而不是每個頂點發送一次。 從CPU把資料傳送到顯示卡相對較慢, 所以無論何處我們都要嘗試儘量一次性發送儘可能多的資料。 當資料到了顯示卡記憶體中時, 頂點著色器幾乎立即就能獲得頂點, 這非常快。
      頂點緩衝物件(VBO)是我們在OpenGL教程中第一個出現的OpenGL物件。 就像OpenGL中的其他物件一樣, 這個緩衝有一個獨一無二的ID, 所以我們可以使用 glGenBuffers 函式生成一個緩衝ID:

GLuint VBO;
glGenBuffers(1, &VBO);


OpenGL有很多緩衝物件型別, GL_ARRAY_BUFFER 是其中一個頂點緩衝物件的緩衝型別。
OpenGL允許我們同時繫結多個緩衝, 只要它們是不同的緩衝型別。 我們可以使用 glBindBuffer 函式把新建立的緩衝繫結到 GL_ARRAY_BUFFER 上:

glBindBuffer(GL_ARRAY_BUFFER, VBO);


從這一刻起, 我們使用的任何緩衝函式(在 GL_ARRAY_BUFFER 目標上)都會用來配置當前繫結的緩衝( VBO )。 然後我們可以呼叫 glBufferData 函式, 它會把之前定義的頂點資料複製到緩衝的記憶體中:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


glBufferData 是一個用來把使用者定的義資料複製到當前繫結緩衝的函式。 它的第一個引數是我們希望把資料複製到上面的緩衝型別: 頂點緩衝物件當前繫結到 GL_ARRAY_BUFFER 目標上。第二個引數指定我們希望傳遞給緩衝的資料的大小(以位元組為單位); 用一個簡單的 sizeof 計算出頂點資料就行。 第三個引數是我們希望傳送的真實資料。第四個引數指定了我們希望顯示卡如何管理給定的資料。 有三種形式:

  • GL_STATIC_DRAW : 資料不會或幾乎不會改變。
  • GL_DYNAMIC_DRAW : 資料會被改變很多。
  • GL_STREAM_DRAW : 資料每次繪製時都會改變。

三角形的位置資料不會改變, 每次渲染呼叫時都保持原樣, 所以它使用的型別最好是 GL_STATIC_DRAW 。 如果, 比如, 一個緩衝中的資料將頻繁被改變, 那麼使用的型別就是 GL_DYNAMIC_DRAW 或 GL_STREAM_DRAW 。 這樣就能確保圖形卡把資料放在高速寫入的記憶體部分。