簡介
前一篇Part1我們已經介紹完如何建置Shader以及GLSL,緊接著我們要瞭解的是Program和Buffer的建置。內文
所有GL繪製的程式碼都需要由Program來處理,而繪製的程式碼就是我們前一篇撰寫Shader的GLSL,這是很簡單的道理,若只有程式碼而沒有程序(Program)去驅動它的話,那也是無法繪製出任何東西(可以再回頭看看我繪製的流程圖)。Buffer在Lesson 1也介紹過了,它就是含有幾何圖形頂點位置以及顏色資料的暫存器,也就是說要繪製的圖形或物體的資料全都存在Buffer裡頭,而Program會從Buffer讀取資料後,再由Shader的GLSL來去處理這些資料,進而繪製出開發者想要的圖形或物體。那麼,我們就先來看看如何建置Program吧!程式碼如下:
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('ERROR linking program!', gl.getProgramInfoLog(program));
return;
}
gl.validateProgram(program);
if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) {
console.error('ERROR validating program!', gl.getProgramInfoLog(program));
return;
}
首先.createProgram()這個函式就是用來建立程序(Program)並初始程序,非常淺顯易懂。而.attachShader()就如同上述所敘,要告知有哪些著色器(Shader)要交給程序來執行。至於.linkProgram()文獻上並沒有對此有太多的講解,可以視為硬體與程序之間的連結。接著後續就是查看程序連結狀況以及驗正程序是否有問題,這裡就不再多介紹了。
再來就是建立Buffer了,也就是我們要告知程序我們想繪製的圖形或物體了,而我們要繪製的圖形就是三角形,那麼我們就來在Buffer裡設置三角形的資訊吧!程式碼如下:
var triangleVertices = [
0.0, 0.5, 0.0, //座標X,Y,Z
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0
];
var triangleVertexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);
var positionAttribLocation = gl.getAttribLocation(program, 'aVertexPosition');
gl.vertexAttribPointer(
positionAttribLocation, // Attribute location
3, // Number of elements per attribute
gl.FLOAT, // Type of elements
gl.FALSE,
3 * Float32Array.BYTES_PER_ELEMENT, // Size of an individual vertex
0 // Offset from the beginning of a single vertex to this attribute
);
gl.enableVertexAttribArray(positionAttribLocation);
首先我們來看triangleVertices這個陣列裡的元素,我們後續會告知程序(Program)是每三個元素一組來表示三維座標。而這裡的元素是以浮點數來表示座標,其座標系統如下圖所示:
.createBuffer()相信這個函式沒什麼好說明的,如同前述Program。.bindBuffer()主要是告知Buffer裡頭的資料是什麼類型,典型常見的就是GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY_BUFFER,前者類型是用來表示頂點位置,後者類型是用來表點頂指數(之後會再說明)。.bufferData()第一個參數跟.bindBuffer()第一個參數是一樣的,有點重複的感覺,主要也是讓程序知道Buffer的資料屬性是為何,但是整體來看.bufferData()才是真正建立Buffer資料的函式,而第二個參數是告知資料型態,以float32Array資料型態存在Buffer中,意思就是陣列(Array)中每個元素都是32bits的浮點數型態,最後參數就是告知用途(Usage),gl.STATIC_DRAW意思就是資料只會被修改一次,但資料可以被多次繪製。
再來就是一個很重要的環節,Buffer的資料我們已經設置完畢,但是要怎麼讓程序(Program)知道該如何去應用Buffer裡的資料?讀到資料之後,又要怎麼去照GLSL程式碼來執行繪製?這個部分也不會太難,回去看看上頭的程式碼,
var positionAttribLocation = gl.getAttribLocation(program, 'aVertexPosition');
從函式名稱.getAttribLocation應該就可以了解,這個函式就是在讓程序知道頂點位置的資料要參照GLSL中宣告的哪一個變數,可以再回去看看我們寫的GLSL,點頂位置我們宣告的變數就是aVertexPosition。而.vertexAttribPointer每一個參數我已經有用註解的方式說明,這裡就不再多做介紹了。 終於,我們最後就是要來告知程序繪製的圖形,以及啟用程序,這個部分非常簡單,GL已經寫好這樣的函式,我們只需呼叫即可,程式碼如下:
gl.useProgram(program);
gl.drawArrays(gl.TRIANGLES, 0, 3);
留言
張貼留言