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)
頂點緩衝物件(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 。 這樣就能確保圖形卡把資料放在高速寫入的記憶體部分。