three相机原理
1.认识相机
在Threejs中相机的表示是THREE.Camera,它是相机的抽象基类,其子类有两种相机,分别是正投影相机THREE.OrthographicCamera和透视投影相机THREE.PerspectiveCamera。
1.1正投影相机
正交投影就是平行投影,所有的投影方向都是平行的,不会交于一点,投影对象相对于摄像机的距离对投影的结果是没有影响的,也就是说物体不离摄像头多远,投影出来的尺寸都是一样的
比如一个物体要正交投影到xy平面上,那么把物体的各个顶点坐标垂直的投射到xy平面。这是最简单的一种投影方法,投影后没有距离感,比如一个正方体,一个面的坐标是(0,0,z),(1,0,z),(1,1,z),(0,1,z)投影到xy平面就是一个正方形,无论z的值是多少,垂直投影到xy平面都是一样的坐标(0,0)(1,0)(1,1)(0,1)。
1.1.1正投影的构造函数
正投影的构造函数如下所示:OrthographicCamera( left, right, top, bottom, near, far )
结合下面两张图,我们来看看,各个参数的意思。
1、 left参数
left:左平面距离相机中心点的垂直距离。从图中可以看出,左平面是屏幕里面的那个平面。
2、 right参数
right:右平面距离相机中心点的垂直距离。从图中可以看出,右平面是屏幕稍微外面一点的那个平面。
3、 top参数
top:顶平面距离相机中心点的垂直距离。上图中的顶平面,是长方体头朝天的平面。
4、 bottom参数
bottom:底平面距离相机中心点的垂直距离。底平面是头朝地的平面。
5、near参数
near:近平面距离相机中心点的垂直距离。近平面是左边竖着的那个平面。near属性表示的是从距离相机多远的位置开始渲染,一般情况会设置一个很小的值。 默认值0.1
6、far参数
far:远平面距离相机中心点的垂直距离。远平面是右边竖着的那个平面。far属性表示的是距离相机多远的位置截止渲染,如果设置的值偏小小,会有部分场景看不到。 默认值1000
代码如下:
/**
* 相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
注意:左右边界的距离与上下边界的距离比值与画布的渲染窗口的宽高比例要一致,否则三维模型的显示效果会被单方向不等比例拉伸。
三维场景中坐标值不在三维空间中的网格模型不会被渲染出来,会被剪裁掉,比如你把上面代码中far参数的值从1000更改为420,你会发现长方体的一部分无法显示。
OrthographicCamera构造函数本质上是对WebGL投影矩阵的封装,宽度width、高度height越大,三维模型顶点的位置坐标就会越大,超出可视区域的网格模型就会被剪裁掉, 不会再显示在屏幕上,大家还可以看到参数left与right、参数式top与bottom互为相反数,这样做的目的是能够是lookAt指向的对象能够显示在canvas画布的中间位置。
1.2正投影相机
透视投影,投影的结果除了与几何体的角度有关,还和距离相关, 人的眼睛观察世界就是透视投影,比如你观察一条铁路距离越远你会感到两条轨道之间的宽度越小。如下图的木棍距离不同会导致投影长度不同。
1.2.1透视投影相机的构造函数
透视投影相机的构造函数如下所示:PerspectiveCamera( fov, aspect, near, far )
结合下这两张图,我们来看看,各个参数的意思。
1、视角fov:这个最难理解,我的理解是,眼睛睁开的角度,即,视角的大小,如果设置为0,相当你闭上眼睛了,所以什么也看不到,如果为180,那么可以认为你的视界很广阔,但是在180度的时候,往往物体很小,因为他在你的整个可视区域中的比例变小了。视角越大,中间的物体越小,这是因为,视角越大,看到的场景越大,那么中间的物体相对于整个场景来说,就越小了。你还可以试一试睁大您的眼睛,努力挣得最大,你发现周围的物体看不清了,这就是眼大不清的原理,你无法集中注意力,而且你视图看到你前面的所有物体,你的焦距无法固定,所以场景非常模糊。虽然你也许感觉不了非常明显,你前面的某一件物体确实缩小了,但在计算机固定大小的屏幕上,显示更多更大的场景,毫无疑问,每一件物体显示是缩小了。当到达179度的时候,three.js真的傻了,他已经完全不明白你要看什么了,他已经将你要看的场景设为无穷大了,所以每一件物体相对于无穷大来说,基本在屏幕中无法显示了。
2、近平面near:这个呢,表示你近处的裁面的距离。near属性表示的是从距离相机多远的位置开始渲染,一般情况会设置一个很小的值。 默认值0.1
3、远平面far:这个呢,表示你远处的裁面。far属性表示的是距离相机多远的位置截止渲染,如果设置的值偏小小,会有部分场景看不到。 默认值1000
4、纵横比aspect:aspect表示渲染窗口的长宽比,如果一个网页上只有一个全屏的canvas画布且画布上只有一个窗口,那么aspect的值就是网页窗口客户区的宽高比。
/**
* 相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
var camera = new THREE.PerspectiveCamera(45, k, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
camera对象的基类是Object3D,具有.posiiotn属性,通过position属性设置相机的位置。 lookAt方法用来指定相机拍摄对象的坐标位置,.lookAt()方法的参数是Vector3对象,可以手动定义new THREE.Vector3(x,y,z), 实际开发的时候,你希望相机对准那个对象,就返回那个对象的位置属性值,比如上面代码中的scene.position, 就表示返回scene的位置坐标,如果把scene换成网格模型对象就是mesh.position,上面的网格模型是一个立方体, 具体的position属性值就是立方体的几何中心。通过观察点的位置和lookAt方法指向的位置就可以计算出相机的拍摄角度。
对于的透视投影,相机位置与lookAt指向的观察目标位置越小,场景中的三维模型放大倍数越大,同时超出的部分会被剪裁掉, 比如更改上面代码camera.position.set(100,200,200);为(100, 150, 100),测试结果你会发现立方体几何体放大显示,超出区域被剪裁。
如果是观察一个产品外观效果,相机就位于几何体的外面,如果是室内漫游预览,就把相机放在房间三维模型的内部。