WebGL开发与应用
上QQ阅读APP看书,第一时间看更新

2.1 Three.js引擎中的基本概念

2.1.1 三维坐标系

三维坐标系是进行Web3D开发的基础(图2-1中,红、绿、蓝三条射线分别代表了x、y、z轴),在Three.js中,三维坐标系统如下(右手系):

图2-1 三维坐标系

x轴:水平向右;

y轴:垂直向上;

z轴:垂直与屏幕向外;

原点:画布中心,即坐标(0,0,0)。

举例来说,图2-1中空心圆饼的坐标是(10,0,0),空心圆环的坐标是(-5,0,-5),此处的数值单位本身意义并不大,它只是表示了一个相对位置,但通常用米做单位可以达到最好的效果,尤其是在从建模工具导出模型到Three.js时。

需要注意的是,这样的坐标系统与大多数的三维建模软件(如3Dmax、Revit)都是不同的,它们一般在水平面上使用x轴和y轴,在垂直方向上使用z轴,因此,从这些建模软件中导出模型到Three.js中时,要进行y轴和z轴的变换。

2.1.2 透视摄像机

摄像机定义了三维空间到二维屏幕的投影方式,用“摄像机”这样一个类比,可以使我们直观地理解这一投影方式,它反映了在一个3D场景中哪部分内容可以显示在用户画布上。

一个典型的透视摄像机(Perspective Camera)包含4个参数,比如:

其中,fov代表摄像机的视野广度;w/h代表摄像机的宽高比,实践中一般设置为画布本身的宽高比;near代表近视点,小于这个距离的对象不能显示;far代表远视点,大于这个距离的对象不能显示。通过改变摄像机的位置、朝向和角度,即可改变画布中的内容,比如:

这两行代码的意思是将摄像机置于画布正外侧5 m的位置上,朝向原点。

2.1.3 正交投影摄像机

使用透视摄像机获得的结果类似于人眼在真实世界中所看到的效果(近大远小),如图2-2所示;而使用正交投影摄像机获得的结果则像在几何课上所画的效果,对于在三维空间内平行的线,投影到二维空间中也一定是平行的,如图2-3所示。一般说来,对于制图、建模软件通常使用正交投影,这样不会因为投影而改变物体比例;而对于其他大多数应用通常使用透视投影,因为这更接近人眼的观察效果。当然,摄像机的选择并没有对错之分,可以根据应用的特性选择一个效果更佳的摄像机。

图2-2 透视摄像机

图2-3 三维空间内平行的线

正交投影摄像机(Orthographic Camera)设置起来较为直观,它的构造函数是:

这6个参数分别代表正交投影摄像机拍摄到的空间的6个面的位置,这6个面围成一个长方体,我们称其为视景体(Frustum),如图2-4所示。只有在视景体内部的物体才可能显示在屏幕上,而视景体外的物体会在显示之前被裁剪掉。

图2-4 正交投影摄像机视景体

2.1.4 基本3D元素

1.场景

场景(Scene)就是一个三维空间,任何3D对象都必须被加入到场景中才能显示,一个典型的场景如scene=new THREE.Scene();。

2.渲染器

显示在用户屏幕上的内容最终是靠渲染器(Renderer)渲染出来的,该对象封装了核心的WebGL原生API,一个典型的渲染器如renderer=new THREE.WebGLRenderer({antialias:true});。

3.灯光

在WebGL的三维空间中,存在点光源和聚光灯两种类型,而且,作为点光源的一种特例还存在平行光源(无限远光源),作为光源的参数还可以进行环境光的设置。作为对应,Three.js中可以设置点光源(Point Light)、聚光灯(Spot Light)、平行光源(Direction Light)和环境光(Ambient Light)。在一个场景中可以设置多个光源,基本上都会是环境光和其他几种光源进行组合。如果不设置环境光,那么光线照射不到的面会变得过于黑暗。一些典型的光源如:

4.网格

网格(Mesh)是Three.js中最重要、最常用的一种3D对象,绝大多数情况下,使用该对象来完成3D场景的布置,一个网格对象需要两个初始化参数,分别是几何(geometry)和材质(material),比如:var mesh=new THREE .Mesh(geometry,material)。

5.几何

几何(Geometry)对象定义一个3D对象的几何形状。一些基本的几何体在Three.js中有预先定义,比如:

6.材质

材(Material)用于反映一个3D对象的外观表现,如纹理图片、透明度、颜色、反射度等。比如:

2.1.5 动画原理

Three.js使用requestAnimationFrame关键函数来实现基本的动画功能,这是在HTML5中新引进的一个函数,类似于setTimeOut或setInterval函数,但两者有本质区别。setInterval函数以固定的时间间隔重绘制画板,如果渲染过于复杂,动画时间就会延长;但request AnimationFrame函数能够根据不同情况丢弃一些插值帧,以保证动画按时完成。下面的代码说明了动画工作的基本原理:

代码运行的结果是一个立方体沿x轴不断旋转。requestAnimationFrame函数的重绘时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧,这个频率大大超过了电影动画的帧率(24帧/秒),因此可以获得更佳的动画效果。对于隐藏或不可见的元素,requestAnimationFrame将不会进行重绘,这就意味着更少的CPU、GPU和内存使用量。

因为requestAnimationFrame较为“年轻”,因而一些旧的浏览器使用的是试验期的名字:mozRequestAnimationFrame、webkitRequestAnimationFrame、msRequestAnimationFrame,为了支持这些浏览器,最好在调用之前先判断是否定义了requestAnimationFrame以及上述函数:

Window.setTimeout(callback,1000/60);的意思是,在最糟糕的情况下,浏览器会调用setTimeout函数完成动画的绘制,每秒60帧,即每帧约17ms。