前面已經介紹過了webgl,WebGL入門教程(一)-初識webgl(http://www.cnblogs.com/bsman/p/6128447.html),也知道了如何繪製一個點,接下來就用webgl畫出一個三角形。javascript
效果圖:css
在WebGL入門教程(一)-初識webgl中,知道如何繪製一個點html
//繪製一個點 gl.drawArrays(gl.POINTS, 0, 1);
可是圖形是有多個點組成,那麼就應該考慮如何繪製多個點,WebGL提供了一種很方便的機制,緩衝區對象(buffer object),它是WebGL系統中的一塊內存區域,它能夠一次性向着色器傳入多個頂點的數據,而後將這些數據保存在其中,供頂點着色器使用。java
首先先找到三個點,操做步驟:web
1.建立HTML5 canvascanvas
2.獲取畫布 canvas 的 ID數組
3.獲取WebGL緩存
4.編譯着色器post
5.使用緩衝區對象向頂點傳入多個頂點數據性能
6.繪製圖像
以上1~4參考:http://www.cnblogs.com/bsman/p/6128447.html
4.編譯着色器
修改頂點着色器,去掉gl_PointSize,這個只有繪製點的時候纔有用
//頂點着色器程序 var VSHADER_SOURCE = "attribute vec4 a_Position;" + "void main() {" + //設置座標 "gl_Position = a_Position; " + "} ";
5.使用緩衝區對象向頂點傳入多個頂點數據又分爲五步
5.1建立緩衝區對象
//建立緩衝區對象 var vertexBuffer = gl.createBuffer();
5.2綁定緩衝區對象
//將緩衝區對象綁定到目標 gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
其中gl.ARRAY_BUFFER表示緩衝區對象包含了頂點的數據,要是換成gl.ELEMENT_ARRAY_BUFFER則表示包含了頂點的索引;vertexBuffer表示上一步建立的緩存區對象。
5.3將數據寫入緩衝區對象
//向緩衝區寫入數據 gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
其中:gl.ARRAY_BUFFER表示目標;vertices表示寫入緩存區對象的數據(類型化數組);第三個參數有3種(
gl.STATIC_DRAW:表示只會向緩存區對象寫入一次數據,但須要繪製不少次;
gl.STREAM_DRAW:表示只會向緩存區對象寫入一次數據,而後繪製若干次;
gl.DYNAMIC_DRAW:表示會向緩存區對象屢次寫入數據,並繪製不少次;
)
其中第二個參數,類型化數組是WEBGL爲了優化性能引入的一種特殊的數組,該數組不支持push,pop有(
Int8Array :8位整形數
UInt8Array :8位無符號整形數
Int16Array :16位整形數
UInt8Array :16位無符號整形數
Int32Array :32位整形數
UInt8Array :32位無符號整形數
Float32Array :單精度32位浮點數
Float64Array :雙精度64位浮點數
)屬性方法有get(index)、set(index,value)、set(array,offset)、length
這種數組必定要new,不然報錯,錯誤信息以下:
GL ERROR :GL_INVALID_OPERATION :glDrawArrays: attempt to access out of range vertices in attribute 0
例如:
var vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);
5.4將緩衝區對象分配給一個attribute變量
//將緩衝區對象分配給a_Position變量 gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
第一個參數:指定待分配attribute變量的存儲位置
第二個參數:指定緩存區中每一個頂點的份量個數(1~4)
第三個參數:類型有,gl.UNSIGNED_BYTE無符號字節,gl.SHORT短整數,gl.UNSIGNED_SHORT無符號短整數,gl.INT整型,gl.UNSIGNED_INT無符號整型,gl.FLOAT浮點型。
第四個參數:表示是否將非浮點型的數據歸到[0,1][-1,1]區間
第五個參數:相鄰兩個頂點的字節數。默認爲0
第六個參數:表示緩存區對象的偏移量(以字節爲單位),就是attribute變量從緩衝區中的何處開始存儲。
5.5開啓attribute變量
//鏈接a_Position變量與分配給它的緩衝區對象 gl.enableVertexAttribArray(a_Position);
就是開啓attribute變量,是緩存區對attribute變量分配生效,使頂點着色器可以訪問緩衝區內的數據。
6.繪製圖像
WebGL能夠繪製的圖形有:
點 | gl.POINTS | 一系列點,繪製v0,v1……。 |
線段 | gl.LINES | 一系列單獨的線段,繪製(v0,v1),(v2,v3)……若是是奇數,最後一個省略。 |
線條 | gl.LINE_STRIP | 一系列鏈接的線段,繪製(v0,v1),(v1,v2),(v2,v3)……除了第一個和最後一個,其餘的點點便是起點又是終點。 |
迴路 | gl.LINE_LOOP | 一系列鏈接的線段,繪製(v0,v1),(v1,v2),(v2,v3)……(vn,v0),最後一個點會鏈接起點。 |
三角形 | gl.TRIANGLES | 一系列單獨的三角形,繪製(v0,v1,v2),(v3,v4,v5)……若是不是3的倍數,剩下的將會被忽略。 |
三角帶 | gl.TRIANGLES_STRIP | 一系列鏈接的三角形,繪製(v0,v1,v2),(v2,v1,v3),(v2,v3,v4)……以此類推,第二個是(v2,v1,v3)而不是(v1,v2,v3)是爲了保持繪製按照逆時針繪製 |
gl.drawArrays(gl.TRIANGLES, 0, n);
完整代碼:
html代碼
<!DOCTYPE html> <html> <head> <meta lang="en"> <meta charset="UTF-8"> <title>WebGL study</title> <link href="../ClickedPoints/style.css"> <script type="text/javascript" src="../Triangle/js.js"></script> </head> <body> <canvas id="canvas" width="200px" height="200px"></canvas> </body> </html>
javascript代碼
/** * Created by HBX on 2016/12/3. */ window.onload = function () { //頂點着色器程序 var VSHADER_SOURCE = "attribute vec4 a_Position;" + "void main() {" + //設置座標 "gl_Position = a_Position; " + "} "; //片元着色器 var FSHADER_SOURCE = "void main() {" + //設置顏色 "gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);" + "}"; //獲取canvas元素 var canvas = document.getElementById('canvas'); //獲取繪製二維上下文 var gl = canvas.getContext('webgl'); if (!gl) { console.log("Failed"); return; } //編譯着色器 var vertShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertShader, VSHADER_SOURCE); gl.compileShader(vertShader); var fragShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragShader, FSHADER_SOURCE); gl.compileShader(fragShader); //合併程序 var shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertShader); gl.attachShader(shaderProgram, fragShader); gl.linkProgram(shaderProgram); gl.useProgram(shaderProgram); //獲取座標點 var a_Position = gl.getAttribLocation(shaderProgram, 'a_Position'); if (a_Position < 0) { console.log('Failed to get the storage location of a_Position'); return; } var n = initBuffers(gl,shaderProgram); if(n<0){ console.log('Failed to set the positions'); return; } // 清除指定<畫布>的顏色 gl.clearColor(0.0, 0.0, 0.0, 1.0); // 清空 <canvas> gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0, n); } function initBuffers(gl,shaderProgram) { var vertices = new Float32Array([ 0.0, 0.5, -0.5, -0.5, 0.5, -0.5 ]); var n = 3;//點的個數 //建立緩衝區對象 var vertexBuffer = gl.createBuffer(); if(!vertexBuffer){ console.log("Failed to create the butter object"); return -1; } //將緩衝區對象綁定到目標 gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer); //向緩衝區寫入數據 gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW); //獲取座標點 var a_Position = gl.getAttribLocation(shaderProgram, 'a_Position'); //將緩衝區對象分配給a_Position變量 gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); //鏈接a_Position變量與分配給它的緩衝區對象 gl.enableVertexAttribArray(a_Position); return n; }