標籤:turn body code opengl fragment 繪圖 element points canvas
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變數。
學習WebGL:著色器、繪製一個點