什么是三维可视化页面
我们常见的网页,比如掘金、知乎、微博等都是平面的,只有长宽两个维度。三维可视化页面增加了一个新的维度--深度,利用 HTML5 的 WebGL 接口,通过 JavaScript 编程, 在网页中展示三维模型。
三维可视化页面的魅力
三维模型相比文字描述或者二维图片,更加符合日常生活中人们观察世界的感受,能给用户提供浸入式的产品体验。一些复杂的模型及数据,通过三维可视化的手段,也能更加准确完整的传递所要表达的信息。
一个精彩的 Demo:Solar-System-Motion-Simulator
什么是 Three.js
Three.js 是一个 JavaScript 3D 库,它将底层的 WebGL 进行了封装。简单调用 Three.js 的接口,就可以快速方便的构建三维可视化页面。
我相信你肯定听说过 WebGL,也听说过 canvas。如果没有听过这两个名词,可以去 MDN 简单了解一下,不熟悉 WebGL 和 canvas 不会对学习 Three.js 产生任何阻碍。
同样的,不了解图形学的知识也不会阻碍你使用 Three.js 。
学习 Three.js 需要什么知识
什么都不需要。准确的说,只要你能看懂中文(因为本文是中文写作的),还记得三角函数的知识(不记得你也可以查),会一点点 JavaScript(因为我也只会一点点 JavaScript)就够了,不需要了解 Webpack、sass 、vue、react 等工具和框架的任何知识。
开始学习吧
我知道你已经迫不及待地想要敲上几行代码,一览 Three.js 的魅力了。但在这之前,我们先要弄明白两个关键问题:
- 三维场景有什么
- 如何将三维场景展示在二维平面中
想像一下拍摄上图时的样子:我们先要找到一个拍摄的场地,另外还得有一台相机。然后准备一些棋子、一个棋盘,把棋子和棋盘摆放在场地中,准备好灯光,拿起摄像机,调整好摄像机的位子和角度。按下快门。
三维可视化网页的创建和这个步骤完全重合。
let scene = new THREE.Scene();//准备拍摄的场地
let camera = new THREE.PerspectiveCamera(fov,aspectRatio,nearPlane,farPlane);//买了个相机
camera.position.set(x,y,z)//把照相机放到(x,y,z)处
camera.lookAt(new THREE.Vector3(0,0,0)//照相机看向坐标(0,0,0)
let light = new THREE.PointLight( 0xff0000, 1, 100 );//Light 在有些时候并不是必须的。
let chessman = createChessman();//准备好棋子
chessman.position(a,b,c)//把棋子放到坐标(x,y,z)处
let chessboard = createChessboard();//准备好棋盘
chessboard.position(e,d,f)//把棋子放到坐标(e,d,f)处
scene.add(chessman);//把棋子放到空间中
scene.add(chessboard);//把棋盘放到空间中
let renderer = new THREE.WebGLRenderer();//一个渲染器,不要深究于此
renderer.render(scene,camera);//按下快门,咔嚓~拍照完成!
复制代码
上面的代码中肯定有许多你不明白的地方,不要担心,现在只需要感性的认识到搭建一个 Three.js 场景和现实生活中照相的步骤是一样的就可以了。
Three.js 的 hello world
学习编程的第一步都是 「Hello World」。Three.js 的 「Hello World」是在网页中生成一个立方体。
承载场景的元素
<script src="three.js">复制代码
先引入 three.js 并在 HTML 中创建一个承载场景的元素#container
。
把 Three.js 下载到本地,或者使用 CDN (https://cdn.bootcss.com/three.js/90/three.js) 引入。
如果你熟悉 NPM 等工具的话,可以参考这个import-via-module。
生成场景
let scene = new THREE.Scene();
复制代码
一行代码生成 Three.js 的场景。
生成照相机
Three.js 中的照相机有四种:CubeCamera、OrthographicCamera、PerspectiveCamera 和 StereoCamera。 其中常用的是 PerspectiveCamera 和 OrthographicCamera。
OrthographicCamera 是正交相机。
PerspectiveCamera 是投影相机。
关注一下 PerspectiveCamera 的四个参数:fov、aspect、near、far。
fov 是上图中的 θ ,常用的数字是45 和 60。
aspect 是宽长比,多用#container
的比例。
near 是离摄影机近的面到摄影机的距离。一般为1等很小的数字。
far 是离摄影机远的面到摄影机的距离。一般设置为 1000、10000等较大的数字。
通过这4个参数,就可以确定一个四棱台。在四棱台内的物体会被渲染,而超出四棱台范围内的物体就被裁剪掉了。
let camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);
复制代码
three.js 的坐标系
在生成 camera 的代码中,你应该注意到 near 被设置为了1,far 被设置为了1000。这并不是一个错误,千万不要写成 1px,1000px。three.js 的坐标系中表示的距离并不是真实的距离,而是一种比例关系,1和1000表示的是 far 比 near 距 camera 远1000 倍。
three.js 的坐标系符合右手定则。
我是看着电脑屏幕记住的:电脑屏幕向右是 x 正半轴,电脑屏幕向上是 y 正半轴,垂直屏幕向外是 z 正半轴。
还有一点要记住的是,新生成的任何物体,默认初始位置都是几何中心位于(0,0,0)。camera 默认看向 z 轴负半轴。
camera.position.set(0, 0, 10);
复制代码
把 camera 往 x 轴正半轴挪一点。不然 camera 默认在(0,0,0),看向 z 轴负半轴。是拍不到位于 (0,0,0) 的物体的。
先搞个渲染器
渲染器这一块比较复杂,还好 three.js 做了十分彻底的封装。我们只需要用就 ok 了。在 Three.js 中,你只会用到 WebGLRenderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
复制代码
把 renderer 的大小设置为与 scene 一致是一个不错的选择。 如果你在 MDN 查了 WebGL 相关的资料的话,一定知道需要在<canvas>
元素中使用 WebGL。
可以借由 Three.js 在 DOM 中引入<canvas>
,
document.getElementById('container').appendChild(renderer.domElement);
复制代码
也可以显式的在 HTML 页面插入<canvas>
我比较喜欢前一种,简单一些。
准备就绪,开始产生立方体
如果前面的步骤都没问题了,生成一个立方体就是一瞬间的事情。
let cubeGeometry = new THREE.BoxGeometry(1,1,1);
let cubeMaterial = new THREE.MeshBasicMaterial({
color:0xff0000;
});
let cube = new THREE.Mesh(cubeGeometry,cubeMaterial);
scene.add(cube);
renderer.render(scene,camera);
复制代码
super fast !!!
注意 .BoxGeometry
,你可能会在较老的资料上看到是 .CubeGeometry
,那是很久以前的事情了。现在生成长方体/立方体用 .BoxGeometry
。
在 Three.js 中生成一个物体只需要三步:
- 设置物体的形状
- 设置物体的材质
- 把形状和材质结合起来
最后要把生成的物体通过 scene
的add()方法添加到 scene 中。renderer 直接渲染 scene 和 camera 就 OK 了。
至于什么是形状,什么是材质,如何把形状和材质结合起来,又是很长一部分内容。我会放在其它部分详细讲解。
一些可能遇到的问题
1.页面没有效果。检查浏览器是否支持 WebGL
在 JS 文件中引入
if (Detector.webgl) {
// Initiate function or other initializations here
animate();
} else {
var warning = Detector.getWebGLErrorMessage();
document.getElementById('container').appendChild(warning);
}
复制代码
2.页面没有效果。检查浏览器console 是否报错。
3.页面没有效果。检查 Three.js 资源是否成功引用。