第四章 使用three.js加载以图片为纹理的模型(上)
在前言中我们介绍过,我们一般不用three.js自带的三维模型创建函数去拼凑我们想要的三维模型,而是使用类似Blender一样的三维建模工具去定制三维模型,然后导出为three.js可以识别的jason格式,加载显示。通过这种方式,我们可以构建较为原始的三维模型在浏览器端显示,比如我们前面看到的马克杯模型。如果单纯依靠三维建模去逼近现实世界中的形体外观是很难的,细节的修缮将给3D建模带来巨大的工作量,同时也会导致模型的加载器计算量巨大,不仅对人还是机器都是巨大的挑战。
好在我们可以另辟蹊径,不去追求模型的精细度,而在模型的纹理上做文章,尤其当我们用真实物体的照片作为模型纹理的时候,3D模型的效果立刻就得到了极大的提高,比如这个箱体模型:
如果不考虑外表图片纹理,它只是一个简单的立方体模型。加上纹理之后,几乎和我们在一些制作精良的3D游戏中见到的箱体所差无几了。下面我们来分析它的代码:
1 //兼容各种浏览器的animation函数 2 window.requestAnimFrame = (function(callback){ 3 return window.requestAnimationFrame || 4 window.webkitRequestAnimationFrame || 5 window.mozRequestAnimationFrame || 6 window.oRequestAnimationFrame || 7 window.msRequestAnimationFrame || 8 function(callback){ 9 window.setTimeout(callback, 1000 / 60); 10 }; 11 })(); 12 13 // 实现旋转的动画函数 14 function animate(lastTime, angularSpeed, three){ 15 // 动画更新时以时间为基准 16 var date = new Date(); 17 var time = date.getTime(); 18 var timeDiff = time - lastTime; 19 // 角度以弧度为单位 20 var angleChange = angularSpeed * timeDiff * 2 * Math.PI / 1000; 21 three.cube.rotation.y += angleChange; 22 lastTime = time; 23 24 // 重新渲染 25 three.renderer.render(three.scene, three.camera); 26 27 // 角度参数在第一次调用时设定 28 requestAnimFrame(function(){ 29 animate(lastTime, angularSpeed, three); 30 }); 31 } 32 33 window.onload = function(){ 34 var angularSpeed = 0.2; 35 var lastTime = 0; 36 37 // 渲染器 38 var renderer = new THREE.WebGLRenderer(); 39 renderer.setSize(window.innerWidth, window.innerHeight); 40 document.body.appendChild(renderer.domElement); 41 42 // 摄像机 43 var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000); 44 camera.position.z = 700; 45 46 // 场景 47 var scene = new THREE.Scene(); 48 49 // 以图片为纹理的材质,这是关键点 50 var material = new THREE.MeshLambertMaterial({ 51 map: THREE.ImageUtils.loadTexture("crate.jpg") 52 }); 53 54 // 立方体模型 55 var cube = new THREE.Mesh(new THREE.CubeGeometry(300, 300, 300), material); 56 cube.overdraw = true; 57 scene.add(cube); 58 59 // 加入环境光 60 var ambientLight = new THREE.AmbientLight(0x555555); 61 scene.add(ambientLight); 62 63 // 加入方向光 64 var directionalLight = new THREE.DirectionalLight(0xffffff); 65 directionalLight.position.set(1, 1, 1).normalize(); 66 scene.add(directionalLight); 67 68 // 把以上创建3D模型的要素都包装成一个对象 69 var three = { 70 renderer: renderer, 71 camera: camera, 72 scene: scene, 73 cube: cube 74 }; 75 76 // 使用onload回调函数启动动画,这样能保证图片被完全加载后才开始旋转 77 var textureImg = new Image(); 78 textureImg.onload = function(){ 79 animate(lastTime, angularSpeed, three, this); 80 }; 81 textureImg.src = "crate.jpg"; 82 };
与之对应的html代码如下:
1 <!DOCTYPE HTML> 2 <html lang="en"> 3 <head> 4 <style> 5 body { 6 margin: 0px; 7 overflow: hidden; 8 } 9 </style> 10 </head> 11 <body> 12 <script src="http://mrdoob.github.com/three.js/build/three.min.js"></script> 13 <script src="LoadCrate.js"></script> 14 </body> 15 </html>
这个纹理图片可以在这里下载:http://www.html5canvastutorials.com/demos/webgl/html5_canvas_webgl_texture/crate.jpg
这篇文章也参考自:http://www.html5canvastutorials.com/webgl/html5-canvas-webgl-texture-with-three-js/
作为一个系列中的一篇,相信这篇文章能够让初学者有效的向前推进一步,迈向three.js自由应用的大门!
在下一篇里,我们将分析如何给一个用Blender制作的,较为复杂的模型贴图显示在浏览器端。
另外,实践中我们发现,可以使用Chrome浏览器加载本地的WebGL模型中的素材,只需要在启动Chrome的时候加上一下参数:--allow-file-access-from-files --disable-web-security
或许只加--allow-file-access-from-files就足够了。方法如下图所示:
这样以来我们就可以随意选择自己偏爱的浏览器去调试three.js程序了。