1. 程式人生 > >Learn OpenGL(三)——頂點著色器(Vertext Shader)

Learn OpenGL(三)——頂點著色器(Vertext Shader)

        頂點著色器是幾個著色器中的一個, 它是可程式設計的。 現代OpenGL需要我們至少設定一個頂點著色器和一個片段著色器, 如果我們打算做渲染的話。 我們會簡要介紹一下著色器以及配置兩個非常簡單的著色器來繪製我們第一個三角形。 
        我們需要做的第一件事是用著色器語言GLSL寫頂點著色器, 然後編譯這個著色器, 這樣我們就可以在應用中使用它了。 下面你會看到一個非常基礎的頂點著色器的原始碼, 它就是使用GLSL寫的:
 

#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position.x, position.y, position.z, 1.0);
}


就像你所看到的那樣, GLSL看起來很像C語言。 每個著色器都起始於一個版本宣告。 這是因為OpenGL 3.3和更高的GLSL版本號要去匹配OpenGL的版本(GLSL420版本對應於OpenGL4.2)。 我們同樣顯式地表示我們會用核心模式(Core-profile)。

下一步, 我們在頂點著色器中宣告所有的輸入頂點屬性, 使用in關鍵字。 現在我們只關心位置(Position)資料, 所以我們只需要一個頂點屬性(Attribute)。 GLSL有一個向量資料型別, 它包含1到4個 float 元素, 包含的數量可以從它的字尾看出來。 由於每個頂點都有一個3D座標,我們就建立一個 vec3 輸入變數來表示位置(Position)。 我們同樣也指定輸入變數的位置值(Location), 這是用 layout (location = 0) 來完成的, 你後面會看到為什麼我們會需要這個位置值。



向量(Vector)
在圖形程式設計中我們經常會使用向量這個數學概念, 因為它簡明地表達了任意空間中位置和方向, 二者是有用的數學屬性。 


為了設定頂點著色器的輸出, 我們必須把位置資料賦值給預定義的 gl_Position 變數, 這個位置資料是一個 vec4 型別的。 在main函式的最後, 無論我們給 gl_Position 設定成什麼, 它都會成為著色器的輸出。 由於我們的輸入是一個3元素的向量, 我們必須把它轉換為4元素。 我們可以通過把 vec3 資料作為 vec4 初始化構造器的引數, 同時把 w 元素設定為 1.0f (我們會
在後面解釋為什麼)。這個頂點著色器可能是能想到的最簡單的了, 因為我們什麼都沒有處理就把輸入資料輸出了。 在真實的應用裡輸入資料通常都沒有在標準化裝置座標中, 所以我們首先就必須把它們放進OpenGL的可視區域內。
編譯一個著色器


我們已經寫了一個頂點著色器原始碼, 但是為了OpenGL能夠使用它, 我們必須在執行時動態編譯它的原始碼。
我們要做的第一件事是建立一個著色器物件, 再次引用它的ID。 所以我們儲存這個頂點著色器為 GLuint , 然後用 glCreateShader 建立著色器:

GLuint vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);


我們把著色器的型別提供 glCreateShader 作為它的引數。 這裡我們傳遞的引數是 GL_VERTEX_SHADER 這樣就建立了一個頂點著色器。
下一步我們把這個著色器原始碼附加到著色器物件, 然後編譯它:

glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);


glShaderSource 函式把著色器物件作為第一個引數來編譯它。 第二引數指定了原始碼中有多少個字串, 這裡只有一個。 第三個引數是頂點著色器真正的原始碼, 我們可以把第四個引數先設定為 NULL 。

注:
可能會希望檢測呼叫glCompileShader後是否編譯成功了, 是否要去修正錯誤。 檢測編譯時錯誤的方法是:

GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);


首先我們定義一個整型來表示是否成功編譯, 還需要一個儲存錯誤訊息的容器(如果有的話)。 然後我們用`glGetShaderiv`檢查是否編譯
 

if(!success)
{
   glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
   std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}


如果編譯的時候沒有任何錯誤, 頂點著色器就被編譯成功了