WebGL使用着色器信息繪圖,着色器使用OpenGL ES(GLSL)編寫
着色器分為頂點着色器(Vertex shader)和片元着色器(Fragment shader),頂點着色器描述位置信息,片元着色器描述顏色信息
//頂點着色器 void main(){ gl_Position = vec4(0.0, 0.0, 0.0, 1.0); gl_PointSize = 10.0; } //片元着色器 void main(){ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }
gl_Position、gl_PointSize、gl_FragColor均為GLSL內置變量名
vec4描述了數據類型為4個浮點數,相應的vec1表示1個浮點數,vec2表示2個浮點數,vec3表示3個浮點數
在gl_Position中的4個數值中,前3個應該是三維坐標的x、y、z,目前還不太明白最后一個數值的意義
有了着色器信息后,就可以使用這些信息開始繪制了
<!DOCTYPE html> <html lang='zh-cmn-Hans'> <head> <meta charset='utf-8' /> <title>Canvas - WebGL</title> </head> <body> <h1>HTML5 - Canvas - WebGL</h1> <canvas id='glcanvas' width='600' height='600'></canvas> <p>在坐標原點(畫布中央)繪制一個紅色的點</p> <script id="vShader" type="x-shader/x-vertex"> void main(){ gl_Position = vec4(0.0, 0.0, 0.0, 1.0); gl_PointSize = 10.0; } </script> <script id="fShader" type="x-shader/x-fragment"> void main(){ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } </script> <script type="text/javascript"> window.onload = function(){ init(); } function init() { var canvas, gl,
vShader, fShader, shaderProgram; canvas = document.getElementById('glcanvas'); gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); if (!gl) { console.log('WebGL Fails!'); return; } try { vShader = gl.createShader(gl.VERTEX_SHADER); //創建着色器 fShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(vShader, document.getElementById('vShader').textContent); //設置着色器的源碼 gl.shaderSource(fShader, document.getElementById('fShader').textContent); gl.compileShader(vShader); //編譯着色器 gl.compileShader(fShader); shaderProgram = gl.createProgram(); //創建着色器程序 gl.attachShader(shaderProgram, vShader); //把着色器信息附加到着色器程序 gl.attachShader(shaderProgram, fShader); gl.linkProgram(shaderProgram); //連接着色器程序 gl.useProgram(shaderProgram); // gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); gl.drawArrays(gl.POINTS, 0, 1); } catch (e) { console.log('WebGL Error!') } } </script> </body> </html>
不理解的是shaderSource這個方法,為何WebGL不直接提供設置着色器的API,而要通過這樣的方法
上面的例子中着色器信息是在繪制前就設置好了的,如果要在繪制過程中設置,則需使用attribute和uniform等變量
<script id="vShader" type="x-shader/x-vertex"> attribute vec4 vp; attribute float vps; void main(){ gl_Position = vp; gl_PointSize = vps; } </script> <script id="fShader" type="x-shader/x-fragment"> uniform vec4 fc; void main(){ gl_FragColor = fc; } </script>
然后取得這些變量,並賦值
vShader = gl.createShader(gl.VERTEX_SHADER); //創建着色器 fShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(vShader, document.getElementById('vShader').textContent); //設置着色器的源碼 gl.shaderSource(fShader, document.getElementById('fShader').textContent); gl.compileShader(vShader); //編譯着色器 gl.compileShader(fShader); shaderProgram = gl.createProgram(); //創建着色器程序 gl.attachShader(shaderProgram, vShader); //把着色器信息附加到着色器程序 gl.attachShader(shaderProgram, fShader); gl.linkProgram(shaderProgram); //連接着色器程序 gl.useProgram(shaderProgram); // var vp = gl.getAttribLocation(shaderProgram, 'vp'); //取得變量 var vps = gl.getAttribLocation(shaderProgram, 'vps'); var fc = gl.getUniformLocation(shaderProgram, 'fc'); gl.vertexAttrib4f(vp, 0.5, 0.5, 0.0, 1.0); //變量賦值 gl.vertexAttrib1f(vps, 10.0); gl.uniform4f(fc, 1.0, 0.0, 0.0, 1.0); gl.drawArrays(gl.POINTS, 0, 1); //繪制點
attribute變量用於與頂點相關的數據,uniform變量用於與頂點無關的數據。書上是這么寫,但理解起來很別扭。我的理解是在3D繪圖中,每個點的坐標都會經過坐標變換最后映射到2D畫布上,這時點的坐標是經過變換后的坐標,那么這個坐標信息就要使用attribute變量,而不管怎么變換,點的顏色都是不變的,所以顏色信息使用uniform變量。
