目录
Three 之 three.js (webgl)透视视角和正交视角,以及透视转正交的视角切换
一、简单介绍
二、实现原理
三、正投影和透视投影简单解释
四、透视相机(PerspectiveCamera)
五、正交相机(OrthographicCamera)
六、threejs中透视投影相机转换正交投影相机基本原理与代码实现
七、案例实现
八、案例代码下载
Three js 开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。
本节介绍, three.js (webgl)透视视角和正交视角,并且实现简单把当前透视角转为正交视角,然后在切换回来的透视视角的原理案例,如果有不足之处,欢迎指出,或者你有更好的方法,欢迎留言。
1、场景构建三要素,scene、camera 和 renderer
2、其中 camera ,会根据需要先创建一个透视camera,然后根据转换,切换到正交camera
3、然后通过 renderer 中 透视camera 或者 正交camera 视角渲染,从而实现透视视角转为正交视角 view 的渲染
下面对正投影相机和透视投影相机的投影算法进行简单介绍,对于初学者你有一个印象就可以,如果想深入了解,可以学习图形学或者阅读threejs官方源码src目录下文件OrthographicCamera.js
和PerspectiveCamera.js
生活中的物体都是三维的,但是人的眼睛只能看到正面,不能看到被遮挡的背面,三维几何体在人眼睛中的效果就像一张相机拍摄的二维照片,你看到的是一个2D的投影图。 空间几何体转化为一个二维图的过程就是投影,不同的投影方式意味着投影尺寸不同的算法。
- 对于正投影而言,一条直线放置的角度不同,投影在投影面上面的长短不同;
- 对于透视投影而言,投影的结果除了与几何体的角度有关,还和距离相关, 人的眼睛观察世界就是透视投影,比如你观察一条铁路距离越远你会感到两条轨道之间的宽度越小。
无论正投影还是透视投影,three.js都对相关的投影算法进行了封装, 大家只需要根据不同的应用场景自行选择不同的投影方式。使用
OrthographicCamera
相机对象的时候,three.js会按照正投影算法自动计算几何体的投影结果; 使用PerspectiveCamera
相机对象的时候,three.js会按照透视投影算法自动计算几何体的投影结果。
这一投影模式被用来模拟人眼所看到的景象,它是3D场景的渲染中使用得最普遍的投影模式。
1、构造 透视相机
new THREE.PerspectiveCamera(60, width / height, 1, 1000)
/**
* 透视投影相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
/**透视投影相机对象*/
var camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
参数 | 含义 | 默认值 |
---|---|---|
fov | fov表示视场,所谓视场就是能够看到的角度范围,人的眼睛大约能够看到180度的视场,视角大小设置要根据具体应用,一般游戏会设置60~90度 | 45 |
aspect | aspect表示渲染窗口的长宽比,如果一个网页上只有一个全屏的canvas画布且画布上只有一个窗口,那么aspect的值就是网页窗口客户区的宽高比 | window.innerWidth/window.innerHeight |
near | near属性表示的是从距离相机多远的位置开始渲染,一般情况会设置一个很小的值。 | 0.1 |
far | far属性表示的是距离相机多远的位置截止渲染,如果设置的值偏小,会有部分场景看不到 | 1000 |
2、属性
共有属性请参见其基类 Camera 。
请注意,在大多数属性发生改变之后,你将需要调用.updateProjectionMatrix来使得这些改变生效。
.aspect : Float
摄像机视锥体的长宽比,通常是使用画布的宽/画布的高。默认值是1(正方形画布)。
.far : Float
摄像机的远端面,默认值是2000。
该值必须大于near plane(摄像机视锥体近端面)的值。
.filmGauge : Float
胶片尺寸,其默认值为35(毫米)。 这个参数不会影响摄像机的投影矩阵,除非.filmOffset被设置为了一个非零的值。
.filmOffset : Float
水平偏离中心偏移量,和.filmGauge单位相同。默认值为0。
.focus : Float
用于立体视觉和景深效果的物体的距离。 这个参数不会影响摄像机的投影矩阵,除非使用了StereoCamera。 默认值是10。
.fov : Float
摄像机视锥体垂直视野角度,从视图的底部到顶部,以角度来表示。默认值是50。
.isPerspectiveCamera : Boolean
Read-only flag to check if a given object is of type PerspectiveCamera.
.near : Float
摄像机的近端面,默认值是0.1。
其有效值范围是0到当前摄像机far plane(远端面)的值之间。 请注意,和OrthographicCamera不同,0对于PerspectiveCamera的近端面来说不是一个有效值。
.view : Object
Frustum window specification or null. 这个值使用.setViewOffset方法来进行设置,使用.clearViewOffset方法来进行清除。
.zoom : number
获取或者设置摄像机的缩放倍数,其默认值为1。
3、方法
共有方法请参见其基类Camera。
.clearViewOffset () : undefined
清除任何由.setViewOffset设置的偏移量。
.getEffectiveFOV () : Float
结合.zoom(缩放倍数),以角度返回当前垂直视野角度。
.getFilmHeight () : Float
返回当前胶片上图像的高,如果.aspect小于或等于1(肖像格式、纵向构图),则结果等于.filmGauge。
.getFilmWidth () : Float
返回当前胶片上图像的宽,如果.aspect大于或等于1(景观格式、横向构图),则结果等于.filmGauge。
.getFocalLength () : Float
返回当前.fov(视野角度)相对于.filmGauge(胶片尺寸)的焦距。
.setFocalLength ( focalLength : Float ) : undefined
通过相对于当前.filmGauge的焦距,设置FOV。
默认情况下,焦距是为35mm(全画幅)摄像机而指定的。
.setViewOffset ( fullWidth : Float, fullHeight : Float, x : Float, y : Float, width : Float, height : Float ) : undefined
fullWidth — 多视图的全宽设置
fullHeight — 多视图的全高设置
x — 副摄像机的水平偏移
y — 副摄像机的垂直偏移
width — 副摄像机的宽度
height — 副摄像机的高度
在较大的viewing frustum(视锥体)中设置偏移量,对于多窗口或者多显示器的设置是很有用的。
这种投影模式下,无论物体距离相机距离远或者近,在最终渲染的图片中物体的大小都保持不变。
这对于渲染2D场景或者UI元素是非常有用的。
1、构造 正交相机
OrthographicCamera( left : Number, right : Number, top : Number, bottom : Number, near : Number, far : Number )
**
* 正投影相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 150; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
参数(属性) | 含义 |
---|---|
left | 渲染空间的左边界 |
right | 渲染空间的右边界 |
top | 渲染空间的上边界 |
bottom | 渲染空间的下边界 |
near | near属性表示的是从距离相机多远的位置开始渲染,一般情况会设置一个很小的值。 默认值0.1 |
far | far属性表示的是距离相机多远的位置截止渲染,如果设置的值偏小小,会有部分场景看不到。 默认值1000 |
2、属性
共有属性请参见其基类Camera。
请注意,在大多数属性发生改变之后,你将需要调用.updateProjectionMatrix来使得这些改变生效。
.bottom : Float
摄像机视锥体下侧面。
.far : Float
摄像机视锥体远端面,其默认值为2000。
该值必须大于near plane(摄像机视锥体近端面)的值。
.isOrthographicCamera : Boolean
Read-only flag to check if a given object is of type OrthographicCamera.
.left : Float
摄像机视锥体左侧面。
.near : Float
摄像机视锥体近端面。其默认值为0.1.
其值的有效范围介于0和far(摄像机视锥体远端面)之间。
请注意,和PerspectiveCamera不同,0对于OrthographicCamera的近端面来说是一个有效值。
.right : Float
摄像机视锥体右侧面。
.top : Float
摄像机视锥体上侧面。
.view : Object
这个值是由setViewOffset来设置的,其默认值为null。
.zoom : number
获取或者设置摄像机的缩放倍数,其默认值为1。
3、方法
共有方法请参见其基类Camera。
.setViewOffset ( fullWidth : Float, fullHeight : Float, x : Float, y : Float, width : Float, height : Float ) : undefined
fullWidth — 多视图的全宽设置
fullHeight — 多视图的全高设置
x — 副摄像机的水平偏移
y — 副摄像机的垂直偏移
width — 副摄像机的宽度
height — 副摄像机的高度
在较大的viewing frustum(视锥体)中设置偏移量,对于多窗口或者多显示器的设置是很有用的。 对于如何使用它,请查看PerspectiveCamera中的示例。
.clearViewOffset () : undefined
清除任何由.setViewOffset设置的偏移量。
.updateProjectionMatrix () : undefined
更新摄像机投影矩阵。在任何参数被改变以后必须被调用。
.toJSON (meta : Object) : Object
meta -- 包含有元数据的对象,例如对象后代中的纹理或图像
将摄像机转换为 three.js JSON Object/Scene format(three.js JSON 物体/场景格式)。
三维场景中坐标值不在三维空间中的网格模型不会被渲染出来,会被剪裁掉,比如你把上面代码中far参数的值从1000更改为420,你会发现长方体的一部分无法显示。
注意:左右边界的距离与上下边界的距离比值与画布的渲染窗口的宽高比例要一致,否则三维模型的显示效果会被单方向不等比例拉伸
构造函数
OrthographicCamera
的参数( left,right,top,bottom,near,far)
本质上是对WebGL投影矩阵的封装,宽度width
、高度height
越大,三维模型顶点的位置坐标就会越大,超出可视区域的网格模型就会被剪裁掉, 不会再显示在屏幕上,大家还可以看到参数left
与right
、参数top
与bottom
互为相反数,这样做的目的是lookAt
指向的对象能够显示在canvas画布的中间位置。
这里,假设已知透视投影相机,threejs中透视投影相机转换正交投影相机中,最重要的是根据已知透视相机的属性计算所需构造正交投影的量,即左右上下远近平面,远近平面已知(既可以使用 透视相机的远近平面),这是,就剩下计算左右和上下平面。
可以简单认为,所需的左右上下平面就是远平面和相机fov构成的矩形,如下图所示。
计算方法是得到当前透视相机到远平面的深度 depth,然后根据 fov 角度计算矩形的 top,在根据 透视相机的宽高比得到 right,再根据 top 和 bottom,right 和 left 成正反关系,最后得到所需正交相机的构造所需参数。
//1.计算透视相机到场景 scene 的深度距离 depth
let target = scene.position.clone();;
let camPos = perCamera.position.clone();
let depth = camPos.sub(target).length();
//2.得到透视相机的宽高比和垂直可视角度
let aspect = perCamera.aspect;
let fov = perCamera.fov;
//3.根据上述变量计算正交投影相机的视口矩形
let top_ortho = depth * Math.atan( (Math.PI/180)*(fov)/2);
let right_ortho = top_ortho * aspect;
let bottom_ortho = - top_ortho;
let left_ortho = - right_ortho;
//4.最后创建正交投影相机
let near = perCamera.near;
let far = perCamera.far;
orthCamera = new THREE.OrthographicCamera(
left_ortho , right_ortho ,
top_ortho , bottom_ortho ,
near, far
);
1、引入 Three js 相关 js 文件