
随着软硬件的发展,在 PC 和移动端浏览器上进行 web 3D 开发的条件已经基本成熟了,出现了不少 js 3D 库,Threejs 是 js 3D 库中的佼佼者。国内也有企业开始做一些应用尝试,某宝 2016 年双 11 就用 ThreeJS 做了一个比较酷炫的 3D 宣传页面刷爆了朋友圈。
下图是用 Threejs 绘制的一个 3D 立方体动画的截图,在这个 demo 里,立方体会动态的旋转,threeJS 30 行代码就可以完成这么一个 demo。Threejs 让没有丰富 3D 编程经验的 web 前端开发人员,也可以快速上手开发 web 3D 应用。

Threejs 是什么
官网对 Threejs 的介绍非常简单:“Javascript 3D library”。openGL 是一个跨平台 3D/2D 的绘图标准,WebGL 则是 openGL 在浏览器上的一个实现。web 前端开发人员可以直接用 WebGL 接口进行编程,但 WebGL 只是非常基础的绘图 API,需要编程人员有很多的数学知识、绘图知识才能完成 3D 编程任务,而且代码量巨大。Threejs 对 WebGL 进行了封装,让前端开发人员在不需要掌握很多数学知识和绘图知识的情况下,也能够轻松进行 web 3D 开发,降低了门槛,同时大大提升了效率。
Threejs 应用场景举例
1、web 3D 游戏

2、3D 模型展示
下图的例子中,用户可以跟浏览器交互,通过鼠标操作 360 度查看汽车,点击车门进入到车内,查看车内立体视图,如同身临其境。

3、数据可视化

4、web vr

Threejs 的基本要素
3D 编程跟 2D 编程有较大不同,因此需要掌握一些 3D 编程的基本概念。Threejs 的基本要素包括以下几个方面:场景、相机、光、物体。
场景:是一个三维空间,所有物品的容器。可以把场景想象成一个空房间,接下来我们会往房间里面放要呈现的物体、相机、光源。

相机:Threejs 必须要有往场景中添加一个相机,相机用来确定观察位置、方向、角度,相机看到的内容,就是我们最终在屏幕上看到的内容。在程序运行过程中,可以调整相机的位置、方向、角度。想象一下,在房间里放了一个摄像机,你不在房间里面,但可以远程控制相机移动,摄像机传给远程电脑上展示出来的画面,就是 Threejs 在屏幕上呈现的画面。
光:假如没有光,摄像机看不到任何东西,因此需要往场景中添加光源。为了跟真实世界更加接近,Threejs 支持模拟不同光源,展现不同光照效果,有点光源、平行光、聚光灯、环境光等。
物体:有了场景、相机、光,就可以往场景中放物体了,在 Threejs 中,物体由形状和材质两部分组成,形状决定物品的轮廓,材质则是物体的材料和质感。
渲染
Threejs 绘制的东西,最终需要在屏幕一块矩形画布上显示出来。为了实现动画效果,我们需要有一个重绘机制。由于视神经元的反应速度问题,图像消失后仍然会在人眼残留 1/24 秒,只要一秒内绘制的帧数超过 24 就能实现流畅的动画效果。Threejs 提供了重绘接口,我们有两种方式去调用接口实现重绘。一种是 setInterval,以固定的时间间隔去调用,可以用于我们对渲染帧数要求比较高的场景,但事实上由于 Javascript 是单线程的,这种方式并不能 100%保证相同的时间间隔调用,如果浏览器繁忙可能会导致 setInterval 的延迟执行;第二种方式是 requestAnimationFrame,让浏览器自行根据当前 cpu 负载等情况决定何时重绘,达到最佳帧率。
位置
为了方便描述位置,引入了坐标系,Threejs 使用的是右手坐标系,如下图所示。坐标系的原点位于渲染画布的几何中心。我们对物体的位置的描述,也是指物体的几何中心的位置。

相机
相机有正交投影相机和透视投影相机两种。透视投影跟人眼看到的世界是一样的,近大远小;正交投影则远近都是一样的大小,三维空间中平行的线,投影到二维空间也一定是平行的。大部分场景都适合使用透视投影相机,因为跟真实世界的观测效果一样;在制图、建模等场景适合使用正交投影相机,方便观察模型之间的大小比例。
Threejs 中的相机跟真实世界的相机不完全一样,这里相机的可见区域是一个立方体,称为相机的示景体。
正交投影相机
示景体是一个长方体,由 6 个参数确定:THREE.OrthographicCamera(left, right, top, bottom, near, far),这 6 个参数规定了相机示景体的左、右、上、下、前、后六个面的位置。

透视投影相机
示景体是一个梯形体,由四个参数确定:THREE.PerspectiveCamera(fov, aspect, near, far)

fov 是相机在竖直方向的张角,aspect 则是宽高比,即 width/height,通常设为画布的宽高比,near 和 far 分别是近平面和远平面与相机的距离。
投影的大小
考虑一种比较简单的场景,相机示景体的远近平面和坐标系中的 xy 平面平行,从而示景体远近平面上的内容刚好可以垂直投影到画布上,并且示景体中与 xy 平面平行的任何一个平面,投影到画布上刚好等于画布大小。假如透视投影相机的近平面的大小为 axb,远平面大小为 2ax2b,则一张 axb 大小的纸放在近平面上,投影到画布时刚好铺满整张画布;放到远平面上则只能占据画布面积的 1/4(远平面的面积是近平面的 4 倍)。正是因为透视投影相机的示景体近小远大,才会导致同样一个物品放在不同位置显示出近大远小的效果。而正交投影相机因为远近平面大小一样,所以同一个物品距离相机的远近不影响物体在画布上投影展示的大小。
物体
物体由几何形状(Geometry)和材质(Material)组成。同样的几何形状,不同材质构成了不同物体,比如球状,有篮球、玻璃球、水晶球等。
形状
Threejs 提供了一些常见的几何形状,有三维的也有二维的,三维的比如长方体、球体、圆柱体、环等,二维的比如长方形、圆形、扇形等。如果默认提供的形状不能满足需求,也可以自定义,通过定义顶点和顶点之间的连线绘制自定义几何形状,更复杂的模型还可以用建模软件建模后导入。
计算机是如何绘制几何形状的呢?我们知道,计算机只能绘制直线,那么曲线和 3D 形状如何绘制出来呢?
1、绘制圆形。如下图所示,通过绘制多边形实现近似的圆形效果,当多边形的边数足够多的时候,两条边之间的过渡就显得平滑,多边形看起来就足够圆了。

2、绘制 3D 模型。常用的做法是用三角形组成的网格来模拟,如下图所示,用足够多的三角形时,兔子的身体看起来就足够平滑,跟真实兔子比较接近。著名的斯坦福兔子模型用了 69451 个三角形。

材质
Threejs 提供了几种比较有代表性的材质,常用的有漫反射、镜面反射两种材质,还可以引入外部图片,贴到物体表面,称为纹理贴图。
外部模型
现实世界丰富多彩,不是 Threejs 的几种默认几何形状和材质所能表达的,实际运用中,很多时候需要用到外部模型,通过 3D 建模软件构建物体的三维模型并导出模型文件,Threejs 导入模型文件进行使用。

光照
光源主要是以下几种:1)环境光,所有角度看到的亮度一样,通常用来为整个场景指定一个基础亮度,没有明确光源位置;2)点光源,一个点发出的光源,照到不同物体表面的亮度线性递减;3)平行光,亮度与光源和物体之间的距离无关,只与平行光的角度和物体所在平面有关;4)聚光灯,投射出的是类似圆锥形的光线。
小结
本文对 Threejs 编程做了一下简单介绍,目的是让读者对 Threejs 编程有个基本认识。纸上得来终觉浅,绝知此事要躬行!建议到 Threejs 官网首页看看那些有趣的 demo,着手写一些简单的 demo 进行实践。目前 web 3D 应用因为浏览器渲染性能、模型体积过大等原因,并没有大规模使用起来,只限于在品牌宣传等部分领域尝试使用。我刚好经历过浏览器 2D 数据可视化绘图由 flash 向 JS 转变的过程(2012 年前后),相信随着软硬件性能的提升和网络速度的提升,web 3D 应用也会慢慢的推广使用起来。
作者介绍:
朱海洋,高级工程师,增值产品部 QQ 会员营收团队负责人,目前团队负责 QQ 会员、靓号、SVIP+、大王超会等项目,有丰富的 Web 前端架构经验。
本文转载自公众号小时光茶舍(ID:gh_7322a0f167b5)。
原文链接:
https://mp.weixin.qq.com/s/-8DtRxuFYpH1gKezVlhjDw
评论