OpenGL shader 程式基礎

Yujiaao發表於2022-02-10

什麼是 shader ?

Shader, 即著色器,是一種類C語法的程式,用於封裝硬體相關部分的程式碼。與普通程式的區別在於 shader 是通過GPU來執行的。

需要給GPU而不是CPU寫程式的原因是GPU在處理圖形相關運算時遠遠快於CPU。

不同的 shader 程式在使用時編譯成本機硬體支援的機器指令。

shader 主要有兩種:

  • 頂點著色程式 vertex shader
  • 片段著色程式 fragment shader,也稱做畫素著色器 pixel shader

當然,不只這兩種,還有很多其他的著色器程式, 如模板著色器,幾何著色器等等。

vertex shader 用於修改(平移,旋轉,扭曲)頂點的位置: potision 和確定頂點的顏色
fragment shader 用於確定每個畫素的顏色,使用照明,材質等等

編寫 shader 程式

  • 編譯 vertex shader,到ID
  • 編譯 fragment shader,得到ID
  • 檢查是否有編譯錯誤
  • 連結以上兩個 shader 程式, 得到ID

    • 保持這個ID
    • 著色三角形時,使用這個ID
    • 不同的模型可以有不同的shader程式

舉個例子

頂點著色器 vertex shader:

in vec4 s_vPosition;
void main () {
  // 看,我不需要任何矩陣操作
  // s_vPosition 的值需要在 -1.0 和 1.0 之間
  gl_Position = s_vPosition;
}

片段著色器 fragment shader:

out vec4 s_vColor;
void main() {
   //不管三七二十一,畫素都搞成紅的!
   fColor =  vec4 (1.0, 0.0, 0.0, 1.0);
}

與C語言一樣,main函式是必須的入口函式。雙斜杆為註釋。

之所以分為這兩部分程式,主要是從效能考慮:畫一個三角形,頂點著色器只呼叫3次,但片段著色器(或畫素著色器)可能呼叫數百萬次,取決於你的三角形在螢幕上顯示的大小,包含多個畫素。

編譯著色器

可以通過呼叫一些OpenGL函式來編譯著色器程式。

編譯著色器分三步: 建立id,繫結程式碼, 編譯。

  • <GLuint> glCreateShader (<type>)

    • 建立一個著色器ID, 具有 GLuint 型別
    • GLuint ID = glCreateShader(GL_VERTEX_SHADER);
  • glShaderSource (<id>, <count>, <src code>, <lengths>)

    • 繫結程式碼到著色器程式
    • 發生在編譯之前
  • glCompileShader (<id>)

    • 編譯一部分著色器程式

建立、連結、使用著色器

上面只是搞了一個部分著色器,完整的程式需要再來四步:

  • <GLuint> glCreateProgram ()

    • 建立一個著色器程式,返回ID, 整個程式生命週期需要保持這個ID
  • glAttachShader (<prog id>, <shader id>)

    • 這個呼叫需要分別對頂點和片段著色器搞兩次
  • glLinkProgram (<prog id>)

    • 真正的連結著色器程式
  • glUseProgram (<prog id>)

    • 需要畫三角形的時候使用著色器程式

好了,就這些。詳細的例子可以看這篇文章.

什麼是 shader ?

Shader, 即著色器,是一種類C語法的程式,用於封裝硬體相關部分的程式碼。與普通程式的區別在於 shader 是通過GPU來執行的。

需要給GPU而不是CPU寫程式的原因是GPU在處理圖形相關運算時遠遠快於CPU。

不同的 shader 程式在使用時編譯成本機硬體支援的機器指令。

shader 主要有兩種:

  • 頂點著色程式 vertex shader
  • 片段著色程式 fragment shader,也稱做畫素著色器 pixel shader

當然,不只這兩種,還有很多其他的著色器程式, 如模板著色器,幾何著色器等等。

vertex shader 用於修改(平移,旋轉,扭曲)頂點的位置: potision 和確定頂點的顏色
fragment shader 用於確定每個畫素的顏色,使用照明,材質等等

編寫 shader 程式

  • 編譯 vertex shader,到ID
  • 編譯 fragment shader,得到ID
  • 檢查是否有編譯錯誤
  • 連結以上兩個 shader 程式, 得到ID

    • 保持這個ID
    • 著色三角形時,使用這個ID
    • 不同的模型可以有不同的shader程式

舉個例子

頂點著色器 vertex shader:

in vec4 s_vPosition;
void main () {
  // 看,我不需要任何矩陣操作
  // s_vPosition 的值需要在 -1.0 和 1.0 之間
  gl_Position = s_vPosition;
}

片段著色器 fragment shader:

out vec4 s_vColor;
void main() {
   //不管三七二十一,畫素都搞成紅的!
   fColor =  vec4 (1.0, 0.0, 0.0, 1.0);
}

與C語言一樣,main函式是必須的入口函式。雙斜杆為註釋。

之所以分為這兩部分程式,主要是從效能考慮:畫一個三角形,頂點著色器只呼叫3次,但片段著色器(或畫素著色器)可能呼叫數百萬次,取決於你的三角形在螢幕上顯示的大小,包含多個畫素。

編譯著色器

可以通過呼叫一些OpenGL函式來編譯著色器程式。

編譯著色器分三步: 建立id,繫結程式碼, 編譯。

  • <GLuint> glCreateShader (<type>)

    • 建立一個著色器ID, 具有 GLuint 型別
    • GLuint ID = glCreateShader(GL_VERTEX_SHADER);
  • glShaderSource (<id>, <count>, <src code>, <lengths>)

    • 繫結程式碼到著色器程式
    • 發生在編譯之前
  • glCompileShader (<id>)

    • 編譯一部分著色器程式

建立、連結、使用著色器

上面只是搞了一個部分著色器,完整的程式需要再來四步:

  • <GLuint> glCreateProgram ()

    • 建立一個著色器程式,返回ID, 整個程式生命週期需要保持這個ID
  • glAttachShader (<prog id>, <shader id>)

    • 這個呼叫需要分別對頂點和片段著色器搞兩次
  • glLinkProgram (<prog id>)

    • 真正的連結著色器程式
  • glUseProgram (<prog id>)

    • 需要畫三角形的時候使用著色器程式

好了,就這些。詳細的例子可以看這篇文章.

相關文章