<圖學玩家 第010篇 原創文>
OpenGL (Open Graphics Library) 是一種開源的跨平台計算機圖形API,可以在多種操作系統和硬體平臺上運行(Windows,macOS和Linux等)。
OpenGL屬於較底層的API,它只提供了基本的3D圖形繪制功能。開發人員需要自行管理其他細節,例如:資源管理,圖形轉換和光源的計算等等。而在開發OpenGL的程式時,會搭配基於GLSL的著色器 (Shader) 程式。
Shader
那什麼是Shader呢? 要將3D圖形輸出到2D螢幕上,OpenGL有其Pipeline。該Pipeline可以分為多個步驟,每個步驟有特定的功能,並且可以並行執行。當前GPU通常都有數千個小的核心(Core),這些核心在Pipeline的每個步驟上運行某些簡單的小程序,而這些小程序就是Shader。
該Pipeline的第一部分是Vertex Shader,以Vertex作為輸入。Vertex Shader負責將3D坐標進行座標轉換。
Vertex Shader的輸出則可以選擇性地傳遞到Geometry Shader。 Geometry Shader以Vertex的集合作為輸入,具有產生新Vertex以塑造新Primitive的能力。在上圖例子中,它從给定形狀生成第二個三角形。而這種將Vertex轉為Primitives的階段,也稱作Primitive Assembly Stage。
Geometry Shader的輸出隨後傳遞到光栅化(Rasterization)階段,在该階段將所得Primitives映射到最終屏幕上相應的像素(Pixels)上,從而產生Fragment以供Fragment Shader使用。在Fragment Shader運行之前,會剪裁掉所有在視野之外的Fragment,從而提高性能。
A fragment in OpenGL is all the data required for OpenGL to render a single pixel.
Shader則是使用GLSL語言撰寫,語法跟C語言類似。通常會有以下的格式
#version version_number
in type in_variable_name;
in type in_variable_name;
out type out_variable_name;
uniform type uniform_name;
void main()
{
// process input(s) and do some weird graphics stuff
...
// output processed stuff to output variable
out_variable_name = weird_stuff_we_processed;
}
下面為Vertex Shader的範例,每個三角形頂點Vertex都被賦予深紅色。
#version 330 core
layout (location = 0) in vec3 aPos; // the position variable has attribute position 0
out vec4 vertexColor; // specify a color output to the fragment shader
void main()
{
gl_Position = vec4(aPos, 1.0); // see how we directly give a vec3 to vec4's constructor
vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // set the output variable to a dark-red color
}
Fragment Shader單純Output來自Vertex Shader的vertexColor:
#version 330 core
out vec4 FragColor;
in vec4 vertexColor; // the input variable from the vertex shader (same name and same type)
void main()
{
FragColor = vertexColor;
}
由於Fragment Shader會內插Vertex顏色繪製到三角形上,因此結果如下圖紅色三角形:
雖然當前有更多熱門的計算機圖形API(如DirectX, Vulkan等等),但對於學習Computer Graphics的基礎來說,筆者認為OpenGL仍是非常不錯的選擇。