核心提示:下面,就从一个实例开始讲解,这个实例绘制了一个彩色立方体,且实现了键盘与鼠标的交互,shift+鼠标左键或中建是旋转立方体,shift+鼠标右键是平移立方体,shift+鼠标滚轮缩放立方体,其效果图如...
下面,就从一个实例开始讲解,这个实例绘制了一个彩色立方体,且实现了键盘与鼠标的交互,shift+鼠标左键或中建是旋转立方体,shift+鼠标右键是平移立方体,shift+鼠标滚轮缩放立方体,其效果图如下:
接下来就详细地附上程序和注释。
1 HTML文档
其中,MV.js与cuon-matrix.js是相关地矩阵运算库,button用于添加底部地交互按。
interactiveCube.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>webgl-interactive-cube</title> <script type="text/javascript" src="libs/initShader.js"></script> <script type="text/javascript" src="libs/webgl-utils.js"></script> <script type="text/javascript" src="libs/MV.js"></script> <script type="text/javascript" src="libs/cuon-matrix.js"></script> <script type="text/javascript" src="js/cube/interactiveCube.js"></script> </head> <body> <canvas id="WebGL-mouseCube" width="1000" height="680"></canvas> <br/> <p><strong>鼠标操作: “shift+左键和中键旋转” “shift+右键平移” “shift+滚轮缩放”</strong></p> <button id ="xRotate">绕x轴旋转</button> <button id ="yRotate">绕y轴旋转</button> <button id ="zRotate">绕z轴旋转</button> <button id ="sRotate">开始/停止旋转</button> </body> </html>
2 interactiveCube.js文件
/** * Created by wjh on 2017/10/31. */ //定义变量 //用于绘制模型 var canvas, gl; var numVertices = 36; var points = [], colors = []; //用于HTML按钮交互 var xAixs = 0; var yAixs = 1; var zAixs = 2; var axis = 0; var theta = [0,0,0]; var currentAngle = [0.0, 0.0]; var rotate = false; var thetaLoc; //鼠标键盘交互 var isShiftDown = false;//用于shift+鼠标键交互 var vRotateMatrix, rotateMatrix, u_rotateMatrix;//旋转 var vTranslateMatrix, translateMatrix, u_translateMatrix, Tx = 0, Ty = 0;//平移 var vScalingMatrix, scalingMatrix, u_scalingMatrix, factor = 0, Sx = 1, Sy = 1, Sz = 1;//缩放 window.onload = function cube (){ canvas = document.getElementById('WebGL-mouseCube'); // gl = WebGLUtils.setupWebGL(canvas); gl = canvas.getContext('experimental-webgl',{antialias:true}); colorCube(); if(!gl){ console.log('浏览器不支持WebGL'); } //设置视口大小 gl.viewport(0,0,canvas.width,canvas.height); //清除canvas gl.clearColor(0, 0, 0, 1.0); //消除隐藏面 gl.enable(gl.DEPTH_TEST); //初始化着色器 var program = initShaders(gl,"shader/cube/mouseCubeVshader.glsl","shader/cube/fragmentShader.glsl"); gl.useProgram(program);//将着色器程序设置为有效 //颜色数据 var cBuffer = gl.createBuffer();//创建缓冲区对象 gl.bindBuffer(gl.ARRAY_BUFFER,cBuffer);//绑定对象 gl.bufferData(gl.ARRAY_BUFFER,flatten(colors),gl.STATIC_DRAW);//向缓冲区对象写入数据 var vColor = gl.getAttribLocation(program, 'vColor');//获取着色器中的Attribute变量 gl.vertexAttribPointer(vColor, 4, gl.FLOAT,false,0,0);//将缓冲区对象分配给attribute变量 gl.enableVertexAttribArray(vColor);//建立attribute变量与缓冲区之间的连接 //顶点数据 var vBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,vBuffer); gl.bufferData(gl.ARRAY_BUFFER,flatten(points),gl.STATIC_DRAW); var vPosition = gl.getAttribLocation(program, 'vPosition'); gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false,0,0); gl.enableVertexAttribArray(vPosition); //旋转变换矩阵 vRotateMatrix = gl.getUniformLocation(program,'vRotateMatrix'); rotateMatrix = new Matrix4(); rotateMatrix.setPerspective(45,canvas.width/canvas.height,1.0,10000); rotateMatrix.lookAt(1.0,1.0,2.0, 0.0,0.0,0.0, 0.0,1.0,0.0); initMouseControl(canvas,currentAngle); //平移矩阵 vTranslateMatrix = gl.getUniformLocation(program, 'vTranslateMatrix'); translateMatrix = new Matrix4(); //缩放矩阵 vScalingMatrix = gl.getUniformLocation(program,'vScalingMatrix'); scalingMatrix = new Matrix4(); thetaLoc = gl.getUniformLocation(program, 'theta'); //添加交互按钮的函数功能 document.getElementById('xRotate').onclick = function (){ axis = xAixs; };//绕x轴 document.getElementById('yRotate').onclick = function (){ axis = yAixs; };//绕y轴 document.getElementById('zRotate').onclick = function (){ axis = zAixs; };//绕z轴 document.getElementById('sRotate').onclick = function (){ rotate = !rotate; };//控制是否旋转 //添加键盘监听事件 document.addEventListener('keydown',onDocumentKeyDown,false); document.addEventListener('keyup',onDocumentKeyUp,false); //绘制渲染 render(); }; //立方体与的顶点索引和面 function colorCube(){ quad( 1, 0, 3, 2 ); quad( 2, 3, 7, 6 ); quad( 3, 0, 4, 7 ); quad( 6, 5, 1, 2 ); quad( 4, 5, 6, 7 ); quad( 5, 4, 0, 1 ); } function quad(a, b, c, d) { var vertices = [ vec4( -0.25, -0.25, 0.25, 1.0 ), vec4( -0.25, 0.25, 0.25, 1.0 ), vec4( 0.25, 0.25, 0.25, 1.0 ), vec4( 0.25, -0.25, 0.25, 1.0 ), vec4( -0.25, -0.25, -0.25, 1.0 ), vec4( -0.25, 0.25, -0.25, 1.0 ), vec4( 0.25, 0.25, -0.25, 1.0 ), vec4( 0.25, -0.25, -0.25, 1.0 ) ]; var vertexColors = [ [ 0.0, 0.0, 0.0, 1.0 ], // black [ 1.0, 0.0, 0.0, 1.0 ], // red [ 1.0, 1.0, 0.0, 1.0 ], // yellow [ 0.0, 1.0, 0.0, 1.0 ], // green [ 0.0, 0.0, 1.0, 1.0 ], // blue [ 1.0, 0.0, 1.0, 1.0 ], // magenta [ 0.0, 1.0, 1.0, 1.0 ], // cyan [ 1.0, 1.0, 1.0, 1.0 ] // white ]; var indices = [a,b,c,a,c,d]; for (var i=0; i=0&&Sy>=0&&Sz>=0) { u_scalingMatrix = new Matrix4(); u_scalingMatrix.set(scalingMatrix); u_scalingMatrix.scale(Sx, Sy, Sz); gl.uniformMatrix4fv(vScalingMatrix, false, u_scalingMatrix.elements); } gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); if(rotate)theta[axis] += 0.8;//绕坐标轴运动的旋转角 gl.uniform3fv(thetaLoc, theta); gl.drawArrays(gl.TRIANGLES, 0, numVertices);//绘制图形 requestAnimFrame( render );//动画 }
3 着色器文件代码
(1).顶点着色器mouseCubeVshader.glsl
attribute vec4 vPosition; attribute vec4 vColor; varying vec4 fColor; uniform mat4 vRotateMatrix; uniform mat4 vTranslateMatrix; uniform mat4 vScalingMatrix; uniform vec3 theta; void main() { vec3 angles = radians( theta ); vec3 c = cos( angles ); vec3 s = sin( angles ); mat4 rx = mat4(1.0, 0.0, 0.0, 0.0, 0.0, c.x, s.x, 0.0, 0.0, -s.x, c.x, 0.0, 0.0, 0.0, 0.0, 1.0 ); mat4 ry = mat4(c.y, 0.0, -s.y, 0.0, 0.0, 1.0, 0.0, 0.0, s.y, 0.0, c.y, 0.0, 0.0, 0.0, 0.0, 1.0 ); mat4 rz = mat4(c.z, s.z, 0.0, 0.0, -s.z, c.z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ); fColor = vColor; gl_Position = vScalingMatrix * vTranslateMatrix * vRotateMatrix * rz * ry * rx * vPosition; // gl_Position.x = -gl_Position.x; // gl_Position.y = -gl_Position.y; // gl_Position.z = -gl_Position.z; }
(2) 片元着色器fragmentShader.glsl
precision mediump float; varying vec4 fColor; void main() { gl_FragColor = fColor; }
以上正式一个可交互地旋转立方体地完整代码实例。