[WebGL] Lesson 2 - 繪製三角形Part1(Shader)

簡介

相信有學過OpenGL或WebGL的同學們應該都很熟悉第一門課就是學如何繪製一個三角形,到底為何第一門課就是要學繪製三角形呢?相信這應該是很多初學者的疑問。原因是這在後續學習繪製3D物體時,三角形會是一個最小單位,這是最常見的繪製3D物體的方法,簡單來說,一個3D物體是由許多個三角形面組合而成的,因此如何繪製一個三角形,便是學習WebGL和OpenGL的第一門課。


內文

在”[WebGL] 兩張圖簡單理解WebGL、OpenGL程式基本繪圖流程”與”[WebGL] Lesson 1 - WebGL對相關硬體的簡介”文章中,我所畫的圖片可能還是很難體會這到底是怎樣子的流程及程式內容,這是一定的,本篇就以”[WebGL] 兩張圖簡單理解WebGL、OpenGL程式基本繪圖流程”文章中所繪製的流程,一步一步地用程式碼來解說步驟,這樣大家或許會比較有感覺些。
我們有提到WebGL是由HTML中Canvas元素開發,因此我們第一步就是利用JS來取得HTML Canvas元素,程式碼如下:
var canvas = document.getElementById(“CanvasID”);
var gl = canvas.getContext(“webgl”);
接著在建立著色器這個步驟中,我們需要建立兩個著色器,分別是Vertex Shader和Fragment Shader,這兩者的差異及各別處理內容已經有在”簡介”中提及過了,這裡就不再說明,程式碼如下:
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
這小段程式簡單易懂,不需要任何說明。再來就是要撰寫它們處理的相關內容了,我們也提到WebGL是以GLSL(OpenGL Shading Language)語言撰寫著色器,此語言是以C語言為基礎的高階著色語言,可以提供開發者對繪圖管線化作更多的直接控制。
著色器的處理順序是先由Vertex Shader告知頂點的位置之後再由Fragment Shader來著上顏色,所以我們先來看看如何用GLSL撰寫Vertex Shader,程式碼如下:

var vertexShaderText = 
"attribute vec3 aVertexPosition;   \n"+
"void main(){  \n"+
"gl_Position = vec4(aVertexPosition,1.0); \n"+
"}";
 
首先應用C語言的自定義屬性宣告一個座標向量(X,Y,Z),之後在應用GL函式庫的gl_Position函式告知頂點位置為何,至於為何gl_Position會有四個參數,這個問題比較偏向數學理論的部分,我之後會在整理介紹。
告知完頂點位置後,接著就要由Fragment Shader來對頂點進行著色,程式碼如下:

var fragmentShaderText =
"precision mediump float;  \n"+
"void main(){  \n"+
"gl_FragColor = vec4(1.0,1.0,1.0,1.0)  \n"+;
"}";
 
其中`precision mediump float;是在決定有多少的精確度給GPU使用,由高到低分別是Highp、mediump、lowp。而gl_FragColor的參數分別是R、G、B、A(alpha:不透明度),所以可以知道這段的程式碼是對每個頂點繪製白色,因此畫出來的三角形將會是白色的。
撰寫完GLSL之後,就要來設置Shader了,這個步驟就是要來讓Shader知道自己是負責哪一段程式碼,程式碼如下:

gl.shaderSource(vertexShader,vertexShaderText);
gl.shaderSource(fragmentShader,fragmentShaderText);
 
設置完,再來就是編譯(Compile)了,用來判斷Shader負責的執行的程式碼是否可以有誤,程式如下:

gl.compileShader(vertexShader);
    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
        console.error('ERROR compiling vertex shader!', gl.getShaderInfoLog(vertexShader));
        return;
    }

    gl.compileShader(fragmentShader);
    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
        console.error('ERROR compiling fragment shader!', gl.getShaderInfoLog(fragmentShader));
        return;
    }
 

參考

1. Indigo Code 的Youtube教學影片
2. Professional WebGL Programming: Developing 3D Graphics for the Web 原文電子書

留言