WebGL交互式立方體
在本章中,我們將舉一個例子來演示如何繪製3D魔方,可以用鼠標控制旋轉。
示例 - 繪製一個互動立方體
下面的程序展示瞭如何使用鼠標控制旋轉的立方體 -
<script>
/\*============= Creating a canvas ======================\*/
var canvas = document.getElementById('my\_Canvas');
gl = canvas.getContext('experimental-webgl');
/\*========== Defining and storing the geometry ==========\*/
var vertices = \[
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
-1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
-1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
-1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1,
\];
var colors = \[
5,3,7, 5,3,7, 5,3,7, 5,3,7,
1,1,3, 1,1,3, 1,1,3, 1,1,3,
0,0,1, 0,0,1, 0,0,1, 0,0,1,
1,0,0, 1,0,0, 1,0,0, 1,0,0,
1,1,0, 1,1,0, 1,1,0, 1,1,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0
\];
var indices = \[
0,1,2, 0,2,3, 4,5,6, 4,6,7,
8,9,10, 8,10,11, 12,13,14, 12,14,15,
16,17,18, 16,18,19, 20,21,22, 20,22,23
\];
// Create and store data into vertex buffer
var vertex\_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY\_BUFFER, vertex\_buffer);
gl.bufferData(gl.ARRAY\_BUFFER, new Float32Array(vertices), gl.STATIC\_DRAW);
// Create and store data into color buffer
var color\_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY\_BUFFER, color\_buffer);
gl.bufferData(gl.ARRAY\_BUFFER, new Float32Array(colors), gl.STATIC\_DRAW);
// Create and store data into index buffer
var index\_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT\_ARRAY\_BUFFER, index\_buffer);
gl.bufferData(gl.ELEMENT\_ARRAY\_BUFFER, new Uint16Array(indices), gl.STATIC\_DRAW);
/\*=================== SHADERS =================== \*/
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl\_Position = Pmatrix\*Vmatrix\*Mmatrix\*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl\_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX\_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT\_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderprogram = gl.createProgram();
gl.attachShader(shaderprogram, vertShader);
gl.attachShader(shaderprogram, fragShader);
gl.linkProgram(shaderprogram);
/\*======== Associating attributes to vertex shader =====\*/
var \_Pmatrix = gl.getUniformLocation(shaderprogram, "Pmatrix");
var \_Vmatrix = gl.getUniformLocation(shaderprogram, "Vmatrix");
var \_Mmatrix = gl.getUniformLocation(shaderprogram, "Mmatrix");
gl.bindBuffer(gl.ARRAY\_BUFFER, vertex\_buffer);
var \_position = gl.getAttribLocation(shaderprogram, "position");
gl.vertexAttribPointer(\_position, 3, gl.FLOAT, false,0,0);
gl.enableVertexAttribArray(\_position);
gl.bindBuffer(gl.ARRAY\_BUFFER, color\_buffer);
var \_color = gl.getAttribLocation(shaderprogram, "color");
gl.vertexAttribPointer(\_color, 3, gl.FLOAT, false,0,0) ;
gl.enableVertexAttribArray(\_color);
gl.useProgram(shaderprogram);
/\*==================== MATRIX ====================== \*/
function get\_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle\*.5)\*Math.PI/180);//angle\*.5
return \[
0.5/ang, 0 , 0, 0,
0, 0.5\*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2\*zMax\*zMin)/(zMax-zMin), 0
\];
}
var proj\_matrix = get\_projection(40, canvas.width/canvas.height, 1, 100);
var mo\_matrix = \[ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 \];
var view\_matrix = \[ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 \];
view\_matrix\[14\] = view\_matrix\[14\]-6;
/\*================= Mouse events ======================\*/
var AMORTIZATION = 0.95;
var drag = false;
var old\_x, old\_y;
var dX = 0, dY = 0;
var mouseDown = function(e) {
drag = true;
old\_x = e.pageX, old\_y = e.pageY;
e.preventDefault();
return false;
};
var mouseUp = function(e){
drag = false;
};
var mouseMove = function(e) {
if (!drag) return false;
dX = (e.pageX-old\_x)\*2\*Math.PI/canvas.width,
dY = (e.pageY-old\_y)\*2\*Math.PI/canvas.height;
THETA+= dX;
PHI+=dY;
old\_x = e.pageX, old\_y = e.pageY;
e.preventDefault();
};
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mouseup", mouseUp, false);
canvas.addEventListener("mouseout", mouseUp, false);
canvas.addEventListener("mousemove", mouseMove, false);
/\*=========================rotation================\*/
function rotateX(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv1 = m\[1\], mv5 = m\[5\], mv9 = m\[9\];
m\[1\] = m\[1\]\*c-m\[2\]\*s;
m\[5\] = m\[5\]\*c-m\[6\]\*s;
m\[9\] = m\[9\]\*c-m\[10\]\*s;
m\[2\] = m\[2\]\*c+mv1\*s;
m\[6\] = m\[6\]\*c+mv5\*s;
m\[10\] = m\[10\]\*c+mv9\*s;
}
function rotateY(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m\[0\], mv4 = m\[4\], mv8 = m\[8\];
m\[0\] = c\*m\[0\]+s\*m\[2\];
m\[4\] = c\*m\[4\]+s\*m\[6\];
m\[8\] = c\*m\[8\]+s\*m\[10\];
m\[2\] = c\*m\[2\]-s\*mv0;
m\[6\] = c\*m\[6\]-s\*mv4;
m\[10\] = c\*m\[10\]-s\*mv8;
}
/\*=================== Drawing =================== \*/
var THETA = 0,
PHI = 0;
var time\_old = 0;
var animate = function(time) {
var dt = time-time\_old;
if (!drag) {
dX \*= AMORTIZATION, dY\*=AMORTIZATION;
THETA+=dX, PHI+=dY;
}
//set model matrix to I4
mo\_matrix\[0\] = 1, mo\_matrix\[1\] = 0, mo\_matrix\[2\] = 0,
mo\_matrix\[3\] = 0,
mo\_matrix\[4\] = 0, mo\_matrix\[5\] = 1, mo\_matrix\[6\] = 0,
mo\_matrix\[7\] = 0,
mo\_matrix\[8\] = 0, mo\_matrix\[9\] = 0, mo\_matrix\[10\] = 1,
mo\_matrix\[11\] = 0,
mo\_matrix\[12\] = 0, mo\_matrix\[13\] = 0, mo\_matrix\[14\] = 0,
mo\_matrix\[15\] = 1;
rotateY(mo\_matrix, THETA);
rotateX(mo\_matrix, PHI);
time\_old = time;
gl.enable(gl.DEPTH\_TEST);
// gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR\_BUFFER\_BIT | gl.DEPTH\_BUFFER\_BIT);
gl.uniformMatrix4fv(\_Pmatrix, false, proj\_matrix);
gl.uniformMatrix4fv(\_Vmatrix, false, view\_matrix);
gl.uniformMatrix4fv(\_Mmatrix, false, mo\_matrix);
gl.bindBuffer(gl.ELEMENT\_ARRAY\_BUFFER, index\_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED\_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
這將產生以下結果(運行上面的代碼,可用鼠標點或拖動中間的立方體,看看其效果) -