相信很多人都看过微软2015开发者大会,其中有一段讲解window holographic让我觉得特别惊讶,我一直以为虚拟投影暂时还是人们幻想中的一种技术,现在确实是展示在我面前,也让我有一种想要弄懂其中奥秘的激情。从2D到3D的视觉转换到底有什么不同呢?作为一名菜鸟级别的前端开发者,我决定从Three.js方面入手,去理解3D世界的构成。

相对于2D的网页,我们可以仅仅依靠我们自己的眼睛来浏览页面。但是对于3D的世界,仅仅依靠自己的眼睛还是不够,因为其中存在的“面”是无穷无尽的,所以我们需要一只特殊的眼睛“照相机”,来帮助我们浏览3D世界。

在讲解相机之前,我们需要给3D的世界来一个定位,在2D页面中,我们一般会将页面的左上角作为一个原点,这样一来,整个页面都可以通过X、Y来定位,同样的3D也是这样,下图为3D世界的坐标定位。
此处输入图片的描述

以下内容会涉及到具体代码的实现,如果有读者只想了解相机的原理,那么可以直接跳到最后一段的总结上面。

正交投影照相机

正交投影相机的效果比较直观,相当于三视图中的主(正)视图,由6个参数和相机定位决定相机的位置和可视区域,其中(right-left)代表相机的宽度,(top-bottom)代表相机的高度,near代表相机的最近点,far代表相机的最远点。其代码设置如下:

THREE.OrthographicCamera(left, right, top, bottom, near, far)

效果图如下,其中灰色部分代表可视区域,可视区域代表你能看到的地方。

此处输入图片的描述

基本设置

设置相机的基本属性:

var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);

在原点位置创建边长为1的正方体,使用wireframe作为透视观察。

var geometry = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshBasicMaterial({
        color: 0xff0000,
        wireframe: true
    })
);
scene.add(geometry);

最后得到的效果如下,这里我们只看到一个矩形,是因为生成的正方体默认在于原点,相机初始化的位置在(0,0,5),镜头默认对向-Z轴,这样一来的话,相当于看到正方体的一个侧面,也就是主视图。

此处输入图片的描述

假如将相机的near属性变为6,此时的正方体将超出相机的可视区域,效果如下
此处输入图片的描述

长宽比例的影响

这里相机的宽度和高度分别是4和3,假如将宽度设置为2,即

var camera = new THREE.OrthographicCamera(-1, 1, 1.5, -1.5, 1, 10);

得到的效果图如下:
此处输入图片的描述
可以看到水平方向被拉大

位置的影响

之前相机设置在(0,0,5)的位置,由于相机是默认面向-Z轴,可以看到正方体,假如将相机往右平移1个单位,得到效果如下:

var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.position.set(1,0,5);

此处输入图片的描述
可以看到物体向左平移了,其实这个也不难理解,就好像一个相对运动的原理一样,你往右走,对于物体来讲,实际是往左移动。

同样的我们可以将相机默认的6个参数(-2, 2, 1.5, -1.5, 1, 10)改变为(-1, 3, 1.5, -1.5, 1, 10),通过观察,可以发现和上图的效果是一样的。也说明了left、right和top、bottom的数值只决定相机的宽度和高度,一般宽度和高度的比例和渲染区域的宽高比例是一致的,不然会出现压缩或者拉伸的现象。

改变观察角度

为了能观察到整个立方体的结构,将相机的位置设为(4, -3, 5),由于相机默认拍摄的方向是Z的负轴,此时是观察不到立方体,我们可以设置相机,让它指定原点进行拍摄

camera.position.set(4, -3, 5);
camera.lookAt(new THREE.Vector3(0, 0, 0));

效果如下:
此处输入图片的描述
需要注意的是lookAt接受的是THREE.Vector3的实例,不能直接设置camera.lookAt(0, 0, 0),不然无法得到理想中的结果。

透视投影照相机

创建代码如下:

THREE.PerspectiveCamera(fov, aspect, near, far)

fov,代表竖直方向的张角(角度制)。
aspect,代表水平长度和竖直长度的比值(一般是渲染区域的长和宽)。
near,代表拍摄的最近距离。
far,代表拍摄的最远距离。

此处输入图片的描述

基本设置

创建透视投影照相机代码:

var camera = new THREE.PerspectiveCamera(45, 400 / 300, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);

创建边长为1的正方体:

var cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshBasicMaterial({
        color: 0xff0000,
        wireframe: true
    })
);
scene.add(cube);

得到的效果:
此处输入图片的描述

竖直方向张角的比例

将原来相机竖直张角45改成60,得到的效果图如下:
此处输入图片的描述

可以看到,得到的物体变小,原因是因为其张角变大,导致可视区域变大,相对于物体来说就变小。

位置影响

将相机所在的位置向右平移一位,代码设置和效果图如下,为了结果更加清晰,取消透视。

var camera = new THREE.PerspectiveCamera(45, 1000 / 1000, 1, 10);
camera.position.set(1, 0, 5);
scene.add(camera);

var cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshBasicMaterial({
        color: 0xff0000,
        wireframe: false
    })
);

此处输入图片的描述
可以从结果上面看出,物体向左平移了,原理和正交相机一样,不同的就是,物体旋转了一定的角度,但是正交投影相机并没有旋转。原因是因为正交投影相机“观察”物体的原理其实就是平行投影,而透视投影照相机的成像原理是透视投影

总结

由于笔者文笔水平有限,可能有人看到这里还是不明白相机的作用,举个简单的例子,假如你面前有一个立方体,那么无论你怎么去旋转这个立方体,你最多就只能看到3个面,而无法看到背面,这时候我们就需要一个特殊的“眼睛”,来帮助我们观察立方体的背面,而相机就是用来做这种事情的。下面有一些笔者自己写的demo演示,没有什么特别酷炫的效果:)。

此处输入图片的描述
此处输入图片的描述

  1. http://ol.weixin.qq.com/protect/users/shijiezou/three/spreads.html
  2. http://ol.weixin.qq.com/protect/users/shijiezou/three/earth.html
  3. http://ol.weixin.qq.com/protect/users/shijiezou/three/audio.html
    (上传音频文件,基本功能实现了,但是还没做优化)

相关资料:
官方文档
中文资料