什麼是 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>)
- 需要畫三角形的時候使用著色器程式
好了,就這些。詳細的例子可以看這篇文章.