二、关于Three.js
WebGL是大部分浏览器直接支持的一种3D绘图标准,它可以创建二维图形和应用,还可以充分利用GPU,创建漂亮的、高性能的三维应用。直接使用WebGL非常复杂,Three.js库提供了一套基于WebGL的、非常易用的JavaScrip API,它源自github的一个**开源项目**,通过这些API可以直接在浏览器中创建三维场景。本文整理了一些入门资料。
三、开始
1
| <script src="three.js"></script>
|
也可以用npm安装:
npm i three
import * as THREE from 'three'
- 使用
three渲染一个3D场景需要以下必要元素:
1.场景(Scene):是物体、光源等元素的容器,要渲染的东西需要先添加进场景;
2.相机(Camera):控制视角的位置、范围以及视觉焦点的位置,一个3D环境中只能存在一个相机;
3.光源(Light):包括全局光、平行光、点光源;
4.物体对象(Mesh):包括二维物体(点、线、面)、三维物体、粒子等;
5.渲染器(Renderer):指定渲染方式,如webGL\canvas2D\Css2D\Css3D等;
非必要元素:
控制器(Control):相机控件,可通过键盘、鼠标控制相机的移动。
四、实例
基本结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| const width = window.innerWidth; const height = window.innerHeight; var renderer; var camera; var light; var scene;
function initRender() { renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(width, height); renderer.setClearColor(0xffffff, 1.0); document.body.appendChild(renderer.domElement); } function initScene() {
scene = new THREE.Scene(); } function initCamera() { camera = new THREE.PerspectiveCamera(45, width / height, 10, 10000); camera.position.set(500, 500, 500); camera.up.set(0, 1, 0); camera.lookAt(0, 0, 0); } function initLight() { light = new THREE.DirectionalLight({ color: 0xffffff }); light.position.set(1, 0, 0); scene.add(light); let pointLight = new THREE.PointLight(0xffffff); pointLight.position.set(100, 100, 100); scene.add(pointLight); let pointHelper = new THREE.PointLightHelper(pointLight, 5, 0xff0000); scene.add(pointHelper); } function initObject() { let geometry = new THREE.CylinderGeometry(100, 100, 300, 100, 100); let material = new THREE.MeshLambertMaterial({ color: 0xffff00 }); mesh = new THREE.Mesh(geometry, material); mesh.position.set(0, 0, 0); scene.add(mesh); } function initAxes() { let axes = new THREE.AxesHelper(1000); scene.add(axes); } function threeStart() { initRender(); initScene(); initCamera(); initLight(); initAxes(); initObject(); renderer.clear(); renderer.render(scene, camera); } window.onload = function () { threeStart(); };
|
结果

五、概念
坐标系
three.js中采用的是右手坐标系,坐标轴方向主要是camera.up.set(x, y, z);设置。也就是说在相机眼里(其实就是我们看的角度)哪个轴向上。理解坐标系很重要,详情请看three右手坐标系讲解。
物体、光源、控制器的添加必须使用secen.add(object)添加到场景中才能渲染出来。
1 2 3 4
| var scene; function initScene(){ scene=new THREE.Scene(); }
|
正交投影相机:
THREE.OrthographicCamera(left, right, top, bottom, near, far) // 大小不因远近而变化
透视投影相机:
THREE.PerspectiveCamera(fov, aspect, near, far) // 遵循近大远小的空间规则
一般情况下,我们使用的是透视投影相机,其参数为:
fov:垂直方向夹角(视角)
aspect:可视区域长宽比 width/height
near:渲染区域离摄像机最近的距离
far:渲染区域离摄像机最远的距离,仅在距离摄像机near和far间的区域会被渲染到canvas中
相机的位置设置:
camera.position.set(x,y,z)或camera.position = new THREE.Vector3(x, y, z);
控制相机的焦点位置,决定相机的朝向
camera.lookAt(0, 0, 0);
添加相机辅助工具来查看相机的位置
全局光:THREE.AmbientLight,影响整个scene的光源,一般是为了弱化阴影或调整整体色调,可设置光照颜色,以颜色的明度确定光源亮度;
平行光:THREE.DirectionalLight,模拟类似太阳的光源,所有被照射的区域亮度是一致的,可设置光照颜色、光照方向(通过向量确定方向),以颜色的明度确定光源亮度;
点光源:THREE.PointLight,单点发光,照射所有方向,可设置光照强度,光照半径和光颜色;
聚光灯:THREE.SpotLight,这种光源有聚光的效果,类似于台灯,吊灯,手电筒。
最简单的用法:
1 2 3 4 5
| function initLight() { light = new THREE.DirectionalLight({ color: 0xffffff }); light.position.set(1, 0, 0); scene.add(light); }
|
光影关系可以显著影响显示效果。参考资料:https://www.cnblogs.com/amy2011/p/5761174.html
3D模型
我们可以用three自由地创建一些点、线、面和几何体。或者加载一些已经做好的3D模型,three更新的很快,目前支持大部分格式的3D模型,以后会越来越多。
1 2 3 4 5 6 7 8
| function initObject() { let geometry = new THREE.CylinderGeometry(100, 100, 300, 100, 100); let material = new THREE.MeshLambertMaterial({ color: 0xffff00 }); mesh = new THREE.Mesh(geometry, material); mesh.position = new THREE.Vector3(0, 0, 0); scene.add(mesh); }
|
CylinderGeometry是柱体,控制底面边的数量可以得到近似的圆柱体,还可以创建正方体、球、环、文字等已经设定好的几何体。如果库里没有需要的,可以自己创建自定义几何体。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function initCar() { let mtlLoader = new THREE.MTLLoader(); mtlLoader.load('../../../3Dmodel/Lamborghini/Avent.mtl', (materials) => { materials.preload(); let objLoader = new THREE.OBJLoader(); objLoader.setMaterials(materials); objLoader.load('../../../3Dmodel/Lamborghini/Avent.obj', (object) => { object.scale.set(80, 80, 80); scene.add(object); }, (suc) => { console.log(((suc.loaded / suc.total) * 100) + '% OBJloaded'); }, (err) => { console.log(err); } ); }, (suc) => { console.log(((suc.loaded / suc.total) * 100) + '% MTLloaded'); }, (err) => { console.log(err); }); }
|

three.js加载外部文件需要用“loader系列”方法,通过这些方法可以加载.obj、.json、.dae等格式的模型(点击查看不同格式的模型之间的差异及优劣)。

像这种将一张图片当作一个平面的,要用Texture加载材质(纹理)。参考资料
六、简单动画
- 动画
动画有两种方式,一种是让图像动,另一种是让相机动。
一个简单的旋转:
1 2 3 4 5 6 7 8
| function animate() { var v1 = new THREE.Vector3( 1, 1, 1 ); meshAll.rotateOnAxis(v1,0.01); mesh.rotation.z -= 0.01; requestAnimationFrame(animate); renderer.render(scene,camera); stats.update(); }
|
- 性能检测
为了监控帧率,引用Stats插件来监控动画的帧率

1 2 3 4 5 6 7 8 9
| <script src="Stats.js"></script> …… function initStats() { stats = new Stats(); stats.domElement.style.position = 'absolute'; stats.domElement.style.top = '0px'; stats.domElement.style.left = '0px'; document.body.appendChild(stats.domElement); }
|
七、交互控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| function initControl() { controls = new THREE.OrbitControls(camera); controls.enableDamping = true; controls.dampingFactor = 0.3; }
|
结束
一个练习demo:一个采用 Three.js 的 3D 动画场景制作:飞行者
这些只是入门资料整理,如果想做出官网展示的那些demo,还要自己下功夫钻研!让我们一起快乐地学习吧!