WebGL也是HTML5規範的一部分,從本質上講它是一個增強型的圖形繪製庫,與HTML5的2D Canvas類似,只是WebGL是一個三維的繪圖標準,並且同樣使用了canvas元素。使用WebGL進行圖形渲染至少要經歷以下步驟:
1. 創建一個畫布元素。
2. 獲取畫布的上下文。
3. 初始化視口。
4. 創建一個或多個包含渲染數據的數組(通常是頂點數組)。
5. 創建一個或多個矩陣,將頂點數組變換到屏幕空間。
6. 創建一個或多個着色器來實現繪製算法。
7. 使用參數初始化着色器。
8. 繪製。
一、畫布元素與繪製上下文
使用WebGL只需要創建一個canvas元素,通過與該元素關聯的DOM對象獲取WebGL上下文:
function initWebGL(canvas){
var gl;
try{
gl=canvas.getContex("expremental-webgl");
}
catch(e){
var msg = "Error creating webgl context: "+ e.toString();
alert(msg);
throw Error(msg);
}
return gl;
}
二、視口
獲取了WebGL上下文就需要指定在哪裏繪製圖形,這就稱爲視口(viewport),調用gl的viewport()函數進行視口的初始化:
function initViewport(gl,canvas){
gl.viewport(0,0,canvas.width,canvas.height);
}
其中的四個參數爲畫布左上角和右下角的座標。
三、Buffer、ArrayBuffer和類型化數組
WebGL的繪製是由圖元組成的,圖元的種類包括三角形(三角形數組)、三角形帶(triangle strip)、點和線。圖元使用的數據數組被稱爲Buffer,定義了頂點的位置。以下代碼定義了一個1×1的正方形頂點數組。
function createSquare(gl){
var vertexBuffer;
vertexBuffer = gl.createBuffer();//創建頂點緩衝區
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);//將創建的緩衝區綁定到gl數組
var vertex = [//定義四個頂點的位置
.5, .5, 0.0,
-.5,.5, 0.0,
.5, -.5, 0.0,
-.5, -.5, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertex),gl.STATIC_DRAW);//綁定位置數據到gl數組
var square = {buffer:vertexBuffer,vertSize:3,nVerts:4,primtype:gl.TRIANGLE_TRIP};
return square;
}
其中vertSize和nVerts分別定義了一個頂點中元素的個數和頂點的個數,此例中表明有4個頂點,每個頂點3個元素。Float32Array是爲了WebGL專門引入瀏覽器的數據類型,稱爲類型化數組,是ArrayBuffer的一種,用於js中存儲二進制數據。
四、矩陣
在繪製之前需要建立兩個矩陣——模型視圖矩陣(modelview matrix)和投影矩陣(projection martrix)。模型視圖矩陣用於定義3D座標系中正方形相對於相機的位置,投影矩陣用於在着色器中將相機空間中的3D座標準環衛繪製視口的2D座標。在本例中對模型的變換是沿-z軸平移3.333個單位,即遠離相機3.333個單位,投影矩陣定義了一個45°的相機視野。
function initMatrices(){
modelViewMatrix = new Float32Array(
[1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,-3.333,1
]);
projectionMatrix = new Float32Array([
2.41421,0,0,0,
0,2.41421,0,0,
0,0,-1.002002,-1,
0,0,-0.2002002,0
]);
}
在一般開發中,很少有人會自己動手計算投影矩陣,因爲一半計算非常複雜,大多都時通過框架來完成。比較有名的框架爲glMatrix,專門在js中進行矩陣的運算。
五、着色器
着色器是一小段由類C的高級語言編寫的,一般爲GLSL ES語言,每個需要繪製的物體都要提供着色器,一個着色器可以應用於多個物體。在實際應用中通常只提供一個着色器,通過不同的參數多次複用。
着色器包括兩個部分——頂點着色器(vertex shader)和片元着色器(fragment shader),後者也被稱爲像素着色器。頂點着色器負責將物體的座標轉換到2D空間去,片元着色器負責將顏色輸出到每個轉換後的頂點像素。顏色的輸出可以爲純色、紋理、光源或者材質。
var vertexShaderSource =
" attribute vec3 vertexPos;\n"+
" uniform mat4 modelViewMatrix;\n"+
" uniform mat4 projectionMatrix;\n"+
" void main(void) {\n"+
" //返回變換並投影后的頂點數據\n"+
" gl_Position = projectionMatrix*modelViewMatrix*\n"+
" vec4(vertexPos,1.0);\n"+
" }\n";
var fragmentShaderSource =
" void main(void) {\n"+
" //返回像素顏色,這裏爲白色\n"+
" gl_FragColor = vec4(1.0,1.0,1.0,1.0);\n"+
" }\n";
六、繪製圖元
我們定義了一個函數draw()來完成圖元的繪製,在該函數中我們將接管上面定義的WebGL上下文以及正方形對象。首先函數會清理一下畫布並用黑色填充作爲背景色。將頂點數組綁定到上下文中,使用着色器並把頂點數組和矩陣作爲輸入傳給着色器。最後調用WebGL的drawArrays()繪製正方形。
function draw(gl,obj){
//用黑色清空背景
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
//設置頂點數組
gl.bindBuffer(gl.ARRAY_BUFFER,obj.buffer);
//設置着色器
gl.useProgram(shaderProgram);
//設置着色器參數:頂點座標、投影矩陣和模型視圖矩陣
gl.vertexAttribPointer(shaderVertexPositionAttribute,obj.vertSize,gl.FLOAT,false,0,0);
gl.uniformMatrix4fv(shaderProjectionMatrixUniform,false,projectionMatrix);
gl.uniformMatrix4fv(shaderModelViewMatrixUniform,false,modelViewMatrix);
//繪製物體
gl.drawArrays(obj.primtype,0,obj.nVerts);
}
最終的繪製結果如圖所示: