你的位置:首页 > 网页设计

[网页设计]Web3D编程入门总结——WebGL与Three.js基础介绍


1 /*在这里对这段时间学习的3D编程知识做个总结,以备再次出发。计划分成“webgl与three.js基础介绍”、“面向对象的基础3D场景框架编写”、“模型导入与简单3D游戏编写”三个部分,其他零散知识以后有机会再总结。*/ 2 /*第一部分,webgl与three.js基础介绍,要求读者掌握JavaScript入门知识*/ 3 //webgl原理:通过JavaScript语言在浏览器端生成glsl代码,把glsl代码送入显卡执行,把执行结果显示在浏览器中 4 //简单例程: 5 //根据Tony Parisi著《WebGL入门指南》第一章修改而来(简称T) 6 window.onload=webGLStart; 7 var gl; 8 function webGLStart() 9 {   10   var canvas = document.getElementById("can_main");//canvas是html5下的绘图标签,可以支持3D绘图 11   gl=initGL(canvas);//初始化“绘制上下文”,以后的绘制都要通过它进行 12   var square=createSquare(gl);//建立一个演示用的四边形,包括顶点坐标,顶点数组格式和顶点绘制方法 13   var matrix=initMatrices();//定义两个矩阵 14    15   var shaderProgram=initShaders();//定义着色器程序(glsl) 16  17   draw(gl,square,matrix,shaderProgram);//调用显卡进行绘制 18   onLoad();//稍后用来触发three.js方式的绘图 19 } 20 function initGL(canvas){ 21   var gl; 22   try 23   { 24     gl = canvas.getContext("experimental-webgl");//从canvas中获取webgl上下文 25     gl.viewport(0,0,canvas.width,canvas.height);//设置视口 26   } 27   catch(e) 28   { 29     var msg="Error creating WebGL Context!: "+ e.toString(); 30     alert(msg); //弹出错误信息    31   } 32   return gl; 33 } 34 function createSquare(gl) 35 { 36   var vertexBuffer=gl.createBuffer();//建立一个顶点缓存 37   gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer); 38   var verts = [ 39     1.0, 1.0, 0.0, 40     -1.0, 1.0, 0.0, 41     1.0, -1.0, 0.0, 42     -1.0, -1.0, 0.0 43   ];//把三维空间中的四个顶点存储在一个一维数组中 44   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);//把数组元素的存储方式设为“32位浮点数” 45   var square={buffer:vertexBuffer,vertSize:3,nVerts:4,primtype:gl.TRIANGLE_STRIP};  //使用一个JavaScript对象返回信息:使用vertexBuffer缓存顶点信息,三维空间顶点,共四个顶点,使用“三角形带”图元绘制方法 46   return square; 47 } 48 function initMatrices() 49 { 50   //定义姿态矩阵,即所有物体共用的相对于原点的位置和姿态 51   var modelViewMatrix=new Float32Array( 52     [1,0,0,0, 53       0,1,0,0, 54       0,0,1,0, 55       0,0,-30.333,1] 56   ); 57   //定义投影矩阵,即物体近大远小的透视程度 58   var projectionMatrix=new Float32Array([ 59     2.41421,0,0,0, 60     0,2.41421,0,0, 61     0,0,-1.002002,-1, 62     0,0,-0.2002002,0 63   ]); 64   var matrix={mvm:modelViewMatrix,pjm:projectionMatrix}; 65   return matrix; 66 } 67 function initShaders() 68 { 69   /*着色器(Shader)位于显卡上,分为顶点着色器和片元着色器两种,数量各以千记。 70   其中顶点着色器运行顶点着色器程序,负责对每个顶点的位置颜色信息的计算; 71   片元着色器运行片元着色器程序,负责对顶点之间的内容进行“插值”,得出每个像素的颜色; 72   顶点着色器+片元着色器+光栅化=显卡渲染管线*/ 73   //顶点着色器 74   var vertexShaderSource= 75     " attribute vec3 vertexPos;\n"+ 76     " uniform mat4 modelViewMatrix;\n"+ 77     " uniform mat4 projectionMatrix;\n"+ 78     " void main(void) {\n"+ 79     " //返回变换并投影后的顶点数据\n"+ 80     " gl_Position=projectionMatrix*modelViewMatrix*vec4(vertexPos,1.0);\n"+ 81     " }\n"; 82   //片元着色器 83   var fragmentShaderSource= 84     " void main(void){\n"+ 85     " //返回像素颜色:永远输出白色\n"+ 86     " gl_FragColor=vec4(1.0,1.0,1.0,1.0);\n"+ 87     " }\n"; 88   //glsl的注释是“//” 89  90   //这里是对shader代码的编译 91   var vertexShader=gl.createShader(gl.VERTEX_SHADER); 92   gl.shaderSource(vertexShader, vertexShaderSource); 93   gl.compileShader(vertexShader); 94   if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { 95     alert(gl.getShaderInfoLog(shader)); 96   } 97  98   var fragmentShader=gl.createShader(gl.FRAGMENT_SHADER); 99   gl.shaderSource(fragmentShader, fragmentShaderSource);100   gl.compileShader(fragmentShader);101   if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {102     alert(gl.getShaderInfoLog(shader));103   }104 105   //对glsl进行连接106   var shaderProgram = gl.createProgram();107   gl.attachShader(shaderProgram, vertexShader);108   gl.attachShader(shaderProgram, fragmentShader);109   gl.linkProgram(shaderProgram);110   gl.getProgramParameter(shaderProgram, gl.LINK_STATUS);111 112   return shaderProgram;//返回编译连接之后的着色器程序113 }114 function draw(gl,obj,matrix,shaderProgram)//这里只进行了一个物体的一次绘制,事实上obj完全可以是一个物体数组115 {116   gl.clearColor(0.0,0.0,0.0,1.0);//使用完全不透明的黑色清屏117   gl.clear(gl.COLOR_BUFFER_BIT);118 119   gl.bindBuffer(gl.ARRAY_BUFFER,obj.buffer);//将gl对象与这个物体的缓存暂时绑定120 121   gl.useProgram(shaderProgram);//让gl使用上面定义的着色器程序122 123   gl.enableVertexAttribArray(gl.getAttribLocation(shaderProgram, "vertexPos"));//告诉WebGL我们将通过一个array提供顶点信息124   gl.vertexAttribPointer(gl.getAttribLocation(shaderProgram, "vertexPos"),obj.vertSize,gl.FLOAT,false,0,0);//提供顶点信息,顶点信息被保存在顶点着色器的vertexPos属性里(变量映射)125   gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, "projectionMatrix"),false,matrix.pjm);126   gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, "modelViewMatrix"),false,matrix.mvm);//将两个矩阵的信息发送给显卡127 128   gl.drawArrays(obj.primtype,0,obj.nVerts);//通知显卡按照顶点数组画图129 }

 

 1 //为提高编程效率,人们编写了一些基于WebGL的绘图引擎,Three.js是其中应用较广的一种: 2 //使用Three.js实现同样的绘制 3 function onLoad() 4 { 5   var container=document.getElementById("container"); 6  7   //Three.js定义的“场景”对象 8   var scene=new THREE.Scene(); 9   //进行WebGL兼容性判断10   if(webglAvailable()){11     var renderer=new THREE.WebGLRenderer();12   }else{13     var renderer=new THREE.CanvasRenderer();//对于环境支持html5但不支持webgl的情况,可以尝试使用更慢一些的2Dcanvas来软件绘图,但效果差强人意14   }15   renderer.setSize(container.offsetWidth,container.offsetHeight);//render可以看成是对canvas的一种扩展16   container.appendChild(renderer.domElement);17 18   //定义相机,类似于WebGL中的定义投影矩阵,19   var camera=new THREE.PerspectiveCamera(45,container.offsetWidth/container.offsetHeight,1,4000);20   camera.position.set(0,0,30.3333);//起原版中姿态矩阵的共用部分的作用,但不同的是:这里是观察者向相反的方向移动了。21   scene.add(camera);//相机对象被添加到了场景中,可以认为场景对象是用来与显卡进行交互的东西,其中包含了变量映射22 23   var geometry=new THREE.PlaneGeometry(2,2);//库中包含预制的几何体,通过少量参数即可生成完整的顶点数组,这里是一个宽高为二的四边形24   var mesh=new THREE.Mesh(geometry,new THREE.MeshBasicMaterial());//赋予这个几何体材质,材质对应反光性25   scene.add(mesh);26 27   renderer.render(scene,camera);// 渲染28 }29 function webglAvailable()30 {//webgl的绘图是建立在显卡的基础上的,如果这台计算机没有显卡,或者浏览器不支持和显卡的通信,webgl上下文的建立将会失败31   try{32     var canvas=document.createElement("canvas");33     return !!(window.WebGLRenderingContext34     &&(canvas.getContext("webgl")||canvas.getContext("experimental-webgl"))35     );36   }catch(e){37     return false;38   }39 }

 1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4   <meta charset="UTF-8"> 5   <title>webgl与three.js基础介绍</title> 6 </head> 7 <body> 8   <!--在canvas中使用webglAPI绘制--> 9   <canvas id="can_main" width="500" height="500"10       style="width:500px;height:500px;float: left"></canvas>11   <!--使用Three.js库绘制-->12   <div id="container" style="width:500px;height:500px;background-color: #000000;float: left"></div>13 </body>14 15 <script>16   17 </script>18 <!---->19 <script src="mygl1.js"></script>20 <script src="mygl1b.js"></script>21 22 <!--引用three.js库文件-->23 <!--three库是由多个文件联合成的一个大库,链接方式不同、库版本不同会产生不同的库文件!!-->24 25 <!--这个版本旧一些但是只需要引用一个文件-->26 <!--https://github.com/tparisi/WebGLBook/tree/master/libs-->27 <!--script src="../LIBS/Three.js"></script-->28 29 <!--这个版本较新但需要引用额外的文件-->30 <!--https://github.com/mrdoob/three.js/tree/master/build-->31 <!--https://github.com/mrdoob/three.js/tree/master/examples/js/renderers-->32 <script src="three.min.js"></script>33 <script src="Projector.js"></script>34 <script src="CanvasRenderer.js"></script>35 36 </html>

 

 1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <title>加入光照、纹理、运动效果</title> 5 <meta charset="UTF-8"> 6 <!--稍微复杂一点的场景,根据Giles Thomas的learningwebgl.com第七章修改而来(简称G)--> 7 <!--一个数学库用来实现一些数学计算--> 8 <script src="glMatrix-0.9.5.min.js" type="text/javascript"></script> 9 <!--google的一个帧动画辅助库--> 10 <script src="webgl-utils.js" type="text/javascript"></script> 11  12 <!--G把着色器代码放在了script标签里--> 13 <script id="shader-vs" type="x-shader/x-vertex"> 14   attribute vec3 aVertexPosition;//顶点位置数组 15   attribute vec3 aVertexNormal;//法线向量数组 16   attribute vec2 aTextureCoord;//纹理坐标数组 17  18   uniform mat4 uMVMatrix;//模型姿态矩阵 19   uniform mat4 uPMatrix;//投影矩阵 20   uniform mat3 uNMatrix; 21  22   uniform vec3 uAmbientColor;//环境光 23  24   uniform vec3 uLightingDirection;//方向光方向 25   uniform vec3 uDirectionalColor;//方向光颜色 26  27   uniform bool uUseLighting;//是否使用光照 28 //在glsl中,attribute和uniform是输入顶点着色器的只读常量,varying是从顶点着色器中输入片元着色器的变量 29 //vec3是含有三个分量的元素组成的数组,mat4是4*4矩阵   30   varying vec2 vTextureCoord; 31   varying vec3 vLightWeighting;//顶点光照 32  33   void main(void) { 34     gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);//顶点位置数组经过模型姿态矩阵和投影矩阵变化后得到顶点位置 35     vTextureCoord = aTextureCoord; 36      37     if (!uUseLighting) { 38       vLightWeighting = vec3(1.0, 1.0, 1.0);//如果选择不使用光照则设为最强白光 39     } else { 40       vec3 transformedNormal = uNMatrix * aVertexNormal;//对法线向量数组进行姿态变换 41       float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0);//按照法线方向和方向光方向计算反射光强度 42       vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;//反射光加环境光得到顶点光照情况,这里使用的是最简单的光照模型,没有涉及材质。       43     } 44   } 45 </script> 46 <script id="shader-fs" type="x-shader/x-fragment"> 47   precision mediump float;//显卡处理浮点数的精度 48  49   varying vec2 vTextureCoord; 50   varying vec3 vLightWeighting; 51  52   uniform sampler2D uSampler;//二维纹理句柄 53  54   void main(void) { 55     vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));//根据纹理坐标对纹理进行切割 56     //OpenGL标准显卡为提高模型缩放时的渲染效率,需要为模型纹理建立多个逐渐缩小的缩略图,受此限制图片的边长必须为2的整数次方,但实际纹理基本不会符合此要求,所以实际纹理图片会把不规则纹理放在规则图片中,再使用纹理坐标进行切割提取 57     gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a);//纹理颜色乘以光照,再加上透明度信息作为实际片元颜色 58   } 59 </script> 60 <!--gl_FragColor是glsl的保留字,表示片元着色器的输出--> 61  62  63 <!--程序入口在webGLStart()函数--> 64 <script type="text/javascript"> 65  66 var gl; 67 //初始化weblg上下文 68 function initGL(canvas) { 69   try { 70     gl = canvas.getContext("experimental-webgl"); 71     gl.viewportWidth = canvas.width; 72     gl.viewportHeight = canvas.height; 73   } catch (e) { 74   } 75   if (!gl) { 76     alert("Could not initialise WebGL, sorry :-("); 77   } 78 } 79  80 //生成着色器代码 81 function getShader(gl, id) { 82   var shaderScript = document.getElementById(id); 83   if (!shaderScript) { 84     return null; 85   } 86  87   var str = ""; 88   var k = shaderScript.firstChild; 89   while (k) { 90     if (k.nodeType == 3) { 91       str += k.textContent; 92     } 93     k = k.nextSibling; 94   } 95  96   var shader; 97   if (shaderScript.type == "x-shader/x-fragment") { 98     shader = gl.createShader(gl.FRAGMENT_SHADER); 99   } else if (shaderScript.type == "x-shader/x-vertex") {100     shader = gl.createShader(gl.VERTEX_SHADER);101   } else {102     return null;103   }104 105   gl.shaderSource(shader, str);//根据网页标签里的内容去生成shader program内容106   gl.compileShader(shader);107 108   if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {109     alert(gl.getShaderInfoLog(shader));110     return null;111   }112 113   return shader;114 }115 116 117 var shaderProgram;//用来和显卡交互的对象,是很多属性的结合体118 //初始化着色器119 function initShaders() {120   var fragmentShader = getShader(gl, "shader-fs");121   var vertexShader = getShader(gl, "shader-vs");//根据标签内容编译着色器代码122 123   shaderProgram = gl.createProgram();124   gl.attachShader(shaderProgram, vertexShader);125   gl.attachShader(shaderProgram, fragmentShader);//把两个着色器的代码分别装填到shaderProgram中126   gl.linkProgram(shaderProgram);//连接着色器代码127 128   if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {//通过gl的属性验证连接是否成功129     alert("Could not initialise shaders");130   }131 132   gl.useProgram(shaderProgram);133   //下面是需要传给显卡的参数(变量映射),通过这种方式把JavaScript中的变量和glsl中的输入量关联起来134   shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");135   gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);136 137   shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");138   gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute);139 140   shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");141   gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);142 143   shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");144   shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");145   shaderProgram.nMatrixUniform = gl.getUniformLocation(shaderProgram, "uNMatrix");146   shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");147   shaderProgram.useLightingUniform = gl.getUniformLocation(shaderProgram, "uUseLighting");148   shaderProgram.ambientColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientColor");149   shaderProgram.lightingDirectionUniform = gl.getUniformLocation(shaderProgram, "uLightingDirection");150   shaderProgram.directionalColorUniform = gl.getUniformLocation(shaderProgram, "uDirectionalColor");151 }152 153 154 //处理载入的图片文件155 function handleLoadedTexture(texture) {156   gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);157 158   gl.bindTexture(gl.TEXTURE_2D, texture);159   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);//将图片对象变成纹理对象160   gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);//图片放大或扭曲时的插值方式161   gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);162   gl.generateMipmap(gl.TEXTURE_2D);//缩略图163 164   gl.bindTexture(gl.TEXTURE_2D, null);165 }166 167 168 var crateTexture;169 var neheTexture;170 //载入图片文件171 function initTexture() {172   crateTexture = gl.createTexture();173   crateTexture.image = new Image();174   crateTexture.image.onload = function () {//onload事件代表图片载入完成175     handleLoadedTexture(crateTexture)176   }177   crateTexture.image.src = "crate.gif";//使用google chrome进行本地测试时注意跨域设置!!178 179   neheTexture = gl.createTexture();180   neheTexture.image = new Image();181   neheTexture.image.onload = function () {182     handleLoadedTexture(neheTexture)183   }184   neheTexture.image.src = "nehe.gif";185   //这里载入了两个图片,其实完全可以把两幅图片合在一起使用纹理坐标切割选择186 }187 188 189 var mvMatrix = mat4.create();190 var mvMatrixStack = [];191 var pMatrix = mat4.create();192 193 //考虑到场景中存在多个物体,它们的姿态矩阵有公用的部分也有私有的部分,故在设置私有部分时把共有部分入栈194 function mvPushMatrix() {195   var copy = mat4.create();196   mat4.set(mvMatrix, copy);197   mvMatrixStack.push(copy);198 }199 //设置完私有部分后将共有部分出栈,再去设置下一个物体200 function mvPopMatrix() {201   if (mvMatrixStack.length == 0) {202     throw "Invalid popMatrix!";203   }204   mvMatrix = mvMatrixStack.pop();205 }206 207 //三个矩阵的变量映射208 function setMatrixUniforms() {209   gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);//投影210   gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);//顶点211 212   var normalMatrix = mat3.create();//法线213   mat4.toInverseMat3(mvMatrix, normalMatrix);214   mat3.transpose(normalMatrix);215   gl.uniformMatrix3fv(shaderProgram.nMatrixUniform, false, normalMatrix);216 }217 218 //角度转化为弧度,webgl默认支持弧度219 function degToRad(degrees) {220   return degrees * Math.PI / 180;221 }222 223 224 225 var xRot = 0;226 var xSpeed = 3;227 228 var yRot = 0;229 var ySpeed = -3;230 231 var z = -5.0;232 233 //键盘处理,通过这种方式可以处理同时按下多个按键234 var currentlyPressedKeys = {};235 236 function handleKeyDown(event) {237   currentlyPressedKeys[event.keyCode] = true;238 }239 240 241 function handleKeyUp(event) {242   currentlyPressedKeys[event.keyCode] = false;243 }244 245 246 function handleKeys() {247   if (currentlyPressedKeys[33]) {248     // Page Up249     z -= 0.05;250   }251   if (currentlyPressedKeys[34]) {252     // Page Down253     z += 0.05;254   }255   if (currentlyPressedKeys[37]) {256     // Left cursor key257     ySpeed -= 1;258   }259   if (currentlyPressedKeys[39]) {260     // Right cursor key261     ySpeed += 1;262   }263   if (currentlyPressedKeys[38]) {264     // Up cursor key265     xSpeed -= 1;266   }267   if (currentlyPressedKeys[40]) {268     // Down cursor key269     xSpeed += 1;270   }271 }272 273 var cubeVertexPositionBuffer;274 var cubeVertexNormalBuffer;275 var cubeVertexTextureCoordBuffer;276 var cubeVertexIndexBuffer;277 var cubeVertexIndexBuffer2;278 //初始化缓存279 function initBuffers() {280   cubeVertexPositionBuffer = gl.createBuffer();281   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);282   //一个正方形的顶点数组283   vertices = [284     // Front face285     -1.0, -1.0, 1.0,286     1.0, -1.0, 1.0,287     1.0, 1.0, 1.0,288     -1.0, 1.0, 1.0,289 290     // Back face291     -1.0, -1.0, -1.0,292     -1.0, 1.0, -1.0,293     1.0, 1.0, -1.0,294     1.0, -1.0, -1.0,295 296     // Top face297     -1.0, 1.0, -1.0,298     -1.0, 1.0, 1.0,299     1.0, 1.0, 1.0,300     1.0, 1.0, -1.0,301 302     // Bottom face303     -1.0, -1.0, -1.0,304     1.0, -1.0, -1.0,305     1.0, -1.0, 1.0,306     -1.0, -1.0, 1.0,307 308     // Right face309     1.0, -1.0, -1.0,310     1.0, 1.0, -1.0,311     1.0, 1.0, 1.0,312     1.0, -1.0, 1.0,313 314     // Left face315     -1.0, -1.0, -1.0,316     -1.0, -1.0, 1.0,317     -1.0, 1.0, 1.0,318     -1.0, 1.0, -1.0,319   ];320   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);321   cubeVertexPositionBuffer.itemSize = 3;322   cubeVertexPositionBuffer.numItems = 24;323 324   //正方形每个面的法线向量325   cubeVertexNormalBuffer = gl.createBuffer();//法线向量326   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexNormalBuffer);327   var vertexNormals = [328     // Front face329     0.0, 0.0, 1.0,330     0.0, 0.0, 1.0,331     0.0, 0.0, 1.0,332     0.0, 0.0, 1.0,333 334     // Back face335     0.0, 0.0, -1.0,336     0.0, 0.0, -1.0,337     0.0, 0.0, -1.0,338     0.0, 0.0, -1.0,339 340     // Top face341     0.0, 1.0, 0.0,342     0.0, 1.0, 0.0,343     0.0, 1.0, 0.0,344     0.0, 1.0, 0.0,345 346     // Bottom face347     0.0, -1.0, 0.0,348     0.0, -1.0, 0.0,349     0.0, -1.0, 0.0,350     0.0, -1.0, 0.0,351 352     // Right face353     1.0, 0.0, 0.0,354     1.0, 0.0, 0.0,355     1.0, 0.0, 0.0,356     1.0, 0.0, 0.0,357 358     // Left face359     -1.0, 0.0, 0.0,360     -1.0, 0.0, 0.0,361     -1.0, 0.0, 0.0,362     -1.0, 0.0, 0.0363   ];364   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals), gl.STATIC_DRAW);365   cubeVertexNormalBuffer.itemSize = 3;366   cubeVertexNormalBuffer.numItems = 24;367 368   //每个面的纹理坐标369   cubeVertexTextureCoordBuffer = gl.createBuffer();370   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);371   var textureCoords = [372     // Front face373     0.0, 0.0,374     1.0, 0.0,375     1.0, 1.0,376     0.0, 1.0,377 378     // Back face379     1.0, 0.0,380     1.0, 1.0,381     0.0, 1.0,382     0.0, 0.0,383 384     // Top face385     0.0, 1.0,386     0.0, 0.0,387     1.0, 0.0,388     1.0, 1.0,389 390     // Bottom face391     1.0, 1.0,392     0.0, 1.0,393     0.0, 0.0,394     1.0, 0.0,395 396     // Right face397     1.0, 0.0,398     1.0, 1.0,399     0.0, 1.0,400     0.0, 0.0,401 402     // Left face403     0.0, 0.0,404     1.0, 0.0,405     1.0, 1.0,406     0.0, 1.0407   ];408   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);409   cubeVertexTextureCoordBuffer.itemSize = 2;410   cubeVertexTextureCoordBuffer.numItems = 24;411 412   //顶点绘制顺序,即存在24个顶点,分别使用其中的哪几个顶点绘制三角形413   //因为使用了两个纹理句柄,这里将正方形分成了两个物体,降低了效率414   cubeVertexIndexBuffer = gl.createBuffer();415   gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);416   var cubeVertexIndices = [417     //0, 1, 2,   0, 2, 3,  // Front face418     //4, 5, 6,   4, 6, 7,  // Back face419     //8, 9, 10,   8, 10, 11, // Top face420     12, 13, 14,  12, 14, 15, // Bottom face421     16, 17, 18,  16, 18, 19, // Right face422     20, 21, 22,  20, 22, 23 // Left face423   ];424   gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);425   //cubeVertexIndexBuffer.itemSize = 1;426   //cubeVertexIndexBuffer.numItems = 36;427 428   cubeVertexIndexBuffer2 = gl.createBuffer();429   gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer2);430   var cubeVertexIndices2 = [431     0, 1, 2,   0, 2, 3,  // Front face432     4, 5, 6,   4, 6, 7,  // Back face433     8, 9, 10,   8, 10, 11 // Top face434     //12, 13, 14,  12, 14, 15, // Bottom face435     //16, 17, 18,  16, 18, 19, // Right face436     //20, 21, 22,  20, 22, 23 // Left face437   ];438   gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices2), gl.STATIC_DRAW);439 }440 441 //场景绘制442 function drawScene() {443   gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);444   gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);445 446   //光照447   var lighting = document.getElementById("lighting").checked;448   gl.uniform1i(shaderProgram.useLightingUniform, lighting);449   //从html中读取光照设置450   if (lighting) {451     gl.uniform3f(452         shaderProgram.ambientColorUniform,453         parseFloat(document.getElementById("ambientR").value),454         parseFloat(document.getElementById("ambientG").value),455         parseFloat(document.getElementById("ambientB").value)456     );457     var lightingDirection = [458       parseFloat(document.getElementById("lightDirectionX").value),459       parseFloat(document.getElementById("lightDirectionY").value),460       parseFloat(document.getElementById("lightDirectionZ").value)461     ];462     var adjustedLD = vec3.create();463     vec3.normalize(lightingDirection, adjustedLD);464 465     vec3.scale(adjustedLD, -1);466     gl.uniform3fv(shaderProgram.lightingDirectionUniform, adjustedLD);467     gl.uniform3f(468         shaderProgram.directionalColorUniform,469         parseFloat(document.getElementById("directionalR").value),470         parseFloat(document.getElementById("directionalG").value),471         parseFloat(document.getElementById("directionalB").value)472     );473   }474 475   //变换姿态矩阵,创造出物体运动效果476   mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);477   mat4.identity(mvMatrix);478   mat4.translate(mvMatrix, [0.0, 0.0, z]);479   mat4.rotate(mvMatrix, degToRad(xRot), [1, 0, 0]);480   mat4.rotate(mvMatrix, degToRad(yRot), [0, 1, 0]);481   setMatrixUniforms();//考虑到多个物体的变化,这个矩阵设置加入在绘制之前,如果需要在另一个位置绘制物体,就再设置一次姿态矩阵482 483   //顶点数组变量映射484   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);485   gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);486   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexNormalBuffer);487   gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, cubeVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0);488   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);489   gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);490 491   //纹理与顶点索引492   gl.activeTexture(gl.TEXTURE0);493   gl.bindTexture(gl.TEXTURE_2D, crateTexture);494   gl.uniform1i(shaderProgram.samplerUniform, 0);//传给着色器495 496   gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);497   gl.drawElements(gl.TRIANGLES, 18, gl.UNSIGNED_SHORT, 0);//与上一例程中的“三角形带”方式不同,包含顶点绘制顺序时使用drawElements方法绘制498 499   gl.activeTexture(gl.TEXTURE1);500   gl.bindTexture(gl.TEXTURE_2D, neheTexture);501   gl.uniform1i(shaderProgram.samplerUniform, 1);//传给着色器,替换了上一个samplerUniform变量的值502 503   gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer2);504   gl.drawElements(gl.TRIANGLES, 18, gl.UNSIGNED_SHORT, 0);505 }506 507 508 var lastTime = 0;509 //根据延迟时间计算动画效果,使得动画效果不受帧率影响510 function animate() {511   var timeNow = new Date().getTime();512   if (lastTime != 0) {513     var elapsed = timeNow - lastTime;514 515     xRot += (xSpeed * elapsed) / 1000.0;516     yRot += (ySpeed * elapsed) / 1000.0;517   }518   lastTime = timeNow;519 }520 521 522 function tick() {523   requestAnimFrame(tick);//在浏览器认为可以时重调循环,这样可以随着系统负载情况不同产生动态帧率524   handleKeys();//处理键盘525   drawScene();//绘制场景526   animate();//帧动画527 }528 529 530 function webGLStart() {531   var canvas = document.getElementById("lesson07-canvas");532   initGL(canvas);//上下文533   initShaders();//着色器534   initBuffers();//缓存535   initTexture();//纹理536 537   gl.clearColor(0.0, 0.0, 0.0, 1.0);538   gl.enable(gl.DEPTH_TEST);//深度探测打开,webgl认为被遮挡的三角形将不被渲染,处理半透明物体时需关掉深度探测539 540   document.onkeydown = handleKeyDown;//声明键盘事件541   document.onkeyup = handleKeyUp;542 543   tick();//绘制循环544 }545 /*可以看到,随着页面复杂度的提高,webglAPI绘制方法的变量映射和glsl代码越来越多,因此在实际应用中往往使用运行库对这部分代码进行封装。至于顶点数组、法线向量、纹理坐标、纹理图片则使用标准绘制函数或模型文件进行封装*/546 </script>547 548 549 </head>550 551 552 <body onload="webGLStart();">553 <a href="http://learningwebgl.com/blog/?p=684">&lt;&lt; Back to Lesson 7</a><br>554 555 <canvas width="500" height="500" id="lesson07-canvas" style="border: currentColor; border-image: none;"></canvas>556 557 <br>558 <input id="lighting" type="checkbox" checked=""> Use lighting<br>559 (Use cursor keys to spin the box and <code>Page Up</code>/<code>Page Down</code> to zoom out/in)560 561 <br>562 <h2>Directional light:</h2>563 564 <table style="padding: 10px; border: 0px currentColor; border-image: none;">565   <tbody><tr>566     <td><b>Direction:</b>567     <td>X: <input id="lightDirectionX" type="text" value="-0.25">568     <td>Y: <input id="lightDirectionY" type="text" value="-0.25">569     <td>Z: <input id="lightDirectionZ" type="text" value="-1.0">570   </tr>571   <tr>572     <td><b>Colour:</b>573     <td>R: <input id="directionalR" type="text" value="0.8">574     <td>G: <input id="directionalG" type="text" value="0.8">575     <td>B: <input id="directionalB" type="text" value="0.8">576   </tr>577   </tbody></table>578 579 <h2>Ambient light:</h2>580 <table style="padding: 10px; border: 0px currentColor; border-image: none;">581   <tbody><tr>582     <td><b>Colour:</b>583     <td>R: <input id="ambientR" type="text" value="0.2">584     <td>G: <input id="ambientG" type="text" value="0.2">585     <td>B: <input id="ambientB" type="text" value="0.2">586   </tr>587   </tbody></table>588 589 <a href="http://learningwebgl.com/blog/?p=684">&lt;&lt; Back to Lesson 7</a>590 591 592 593 </body></html>

 

 1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <title>使用Three.js实现上述效果</title> 5 <meta charset="UTF-8"> 6   <link rel="stylesheet" href="../css/webglbook.css" />  7   <script src="Three.js"></script> 8   <script src="webgl-utils.js"></script> 9   <script> 10    11   var renderer = null,  12     scene = null,  13     camera = null, 14     cube = null, 15     animating = false; 16    17   function onLoad() 18   { 19     // Grab our container div 20     //取得作为容器的div,事实上容器不局限于div标签 21     var container = document.getElementById("container"); 22  23     // Create the Three.js renderer, add it to our div 24     //建立Three.js渲染器,并把它加入容器div中 25     renderer = new THREE.WebGLRenderer( { antialias: true } ); 26     renderer.setSize(container.offsetWidth, container.offsetHeight); 27     container.appendChild( renderer.domElement ); 28  29     // Create a new Three.js scene 30     //建立一个Three.js场景 31     scene = new THREE.Scene(); 32  33     // Put in a camera 34     //引入一个相机 35     camera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 4000 ); 36     camera.position.set( 0, 0, 3 ); 37  38     // Create a directional light to show off the object 39     //建立一个方向光来照亮场景中的物体 40     var light = new THREE.DirectionalLight( 0xffffff, 1.5); 41     light.position.set(0, 0, 1); 42     scene.add( light ); 43  44     // Create a shaded, texture-mapped cube and add it to the scene 45     //建立一个具有阴影效果和纹理效果的立方体,并把它加入到场景中 46     // First, create the texture map 47     //第一步,建立纹理图片(Three.js不要求图片尺寸是2的整数次方) 48     var mapUrl = "molumen_small_funny_angry_monster.jpg"; 49     var map = THREE.ImageUtils.loadTexture(mapUrl); 50      51     // Now, create a Phong material to show shading; pass in the map 52     //建立一个Phong类型的材质对象来表现光照和阴影;把这个材质传入纹理图中 53     var material = new THREE.MeshPhongMaterial({ map: map }); 54  55     // Create the cube geometry 56     //建立一个默认的几何体 57     var geometry = new THREE.CubeGeometry(1, 1, 1); 58  59     // And put the geometry and material together into a mesh 60     //把“多边形”和“材质”组合成一个“网格” 61     cube = new THREE.Mesh(geometry, material); 62  63     // Turn it toward the scene, or we won't see the cube shape! 64     //稍微旋转一下物体,否则我们看不出立体的效果! 65     cube.rotation.x = Math.PI / 5; 66     cube.rotation.y = Math.PI / 5; 67  68     // Add the cube to our scene 69     //把物体加入到场景中 70     scene.add( cube ); 71  72     // Add a mouse up handler to toggle the animation 73     //添加鼠标监听 74     addMouseHandler(); 75  76     // Run our render loop 77     //启动渲染循环 78     run(); 79   } 80  81   function run() 82   { 83     // Render the scene 84     //渲染场景,renderer是canvas的绘制上下文,scene是变量映射接口,camera是姿态矩阵和投影矩阵的结合 85     renderer.render( scene, camera ); 86  87     // Spin the cube for next frame 88     //旋转物体生成下一帧画面 89     if (animating) 90     { 91       cube.rotation.y -= 0.01; 92     } 93        94     // Ask for another frame 95     //请求下一帧(循环) 96     requestAnimFrame(run);   97   } 98  99   function addMouseHandler()100   {101     var dom = renderer.domElement;102     103     dom.addEventListener( 'mouseup', onMouseUp, false);104   }105   106   function onMouseUp  (event)107   {108     event.preventDefault();109 110     animating = !animating;111   }  112   113   </script>114 115 </head>116 <body onLoad="onLoad();" style="">117   <center><h1>Welcome to WebGL!</h1></center>118   <div id="container" style="width:95%; height:80%; position:absolute;"></div>119   <div id="prompt" style="width:95%; height:6%; bottom:0; text-align:center; position:absolute;">Click to animate the cube</div>120 121 </body>122 </html>