ThreeJS-相机

2,318 阅读6分钟

这是我参与8月更文挑战的第30天,活动详情查看:8月更文挑战

Camera相机

相机是Three.js抽象出来的一个对象,使用此对象,我们可以定义显示的内容,并且可以通过移动相机位置来显示不同的内容。 下面讲解一下Three.js中的相机的通用属性和常用的相机对象。

我们常用的相机正交相机(OrthographicCamera)和透视相机(PerspectiveCamera)两种相机,用于来捕获场景内显示的物体模型。它们有一些通用的属性和方法:

由于相机都是继承至THREE.Object3D对象的,所以像设置位置的position属性、rotation旋转和scale缩放属性,可以直接对相机对象设置。我们甚至还可以使用add()方法,给相机对象添加子类,移动相机它的子类也会跟随着一块移动,我们可以使用这个特性制作一些比如HUD类型的显示界面。

target 焦点属性和lookAt()方法

这两个方法的效果一定,都是调整相机的朝向,可以设置一个THREE.Vector3(三维向量)点的位置:

camera.target = new THREE.Vector3(0, 0, 0);
camera.lookAt(new THREE.Vector3(0, 0, 0));

上面两个都是朝向了原点,我们也可以将相机的朝向改为模型网格的position,如果物体的位置发生了变化,相机的焦点方向也会跟随变动:

var mesh = new THREE.Mesh(geometry, material);
camera.target = mesh.position;  // 小技巧
//或者
camera.lookAt(mesh.position);

OrthographicCamera 正交相机

使用正交相机OrthographicCamera渲染出来的场景,所有的物体和模型都按照它固有的尺寸和精度显示,一般使用在工业要求精度或者2D平面中,因为它能完整的显示物体应有的尺寸。

上面的图片可以清晰的显示出正交相机显示的范围,它显示的内容是一个立方体结构,通过图片我们发现,只要确定topleftrightbottomnearfar六个值,我们就能确定当前相机捕获场景的区域,在这个区域外面的内容不会被渲染,所以,我们创建相机的方法就是:

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

下面我们创建了一个显示场景中相机位置前方长宽高都为4的盒子内的物体的正交相机:

var orthographicCamera = new THREE.OrthographicCamera(-2, 2, 2, -2, 0, 4);
// 一般不需要将相机放置到场景当中,如果需要添加子元素等一些特殊操作,还是需要add到场景内
scene.add(orthographicCamera); 

正常情况相机显示的内容需要和窗口显示的内容同样的比例才能够显示没有被拉伸变形的效果:

var frustumSize = 1000; //设置显示相机前方1000高的内容
var aspect = window.innerWidth / window.innerHeight; //计算场景的宽高比
var orthographicCamera = new THREE.OrthographicCamera( 
  frustumSize * aspect / - 2, 
  frustumSize * aspect / 2,
  frustumSize / 2, 
  frustumSize / - 2, 
  1,
  2000 
); //根据比例计算出left,top,right,bottom的值

我们也可以动态的修改正交相机的一些属性,注意修改完以后需要调用相机updateProjectionMatrix()方法来更新相机显存里面的内容:

var frustumSize = 1000; //设置显示相机前方1000高的内容
var aspect = window.innerWidth / window.innerHeight; //计算场景的宽高比
var orthographicCamera = new THREE.OrthographicCamera(); //实例化一个空的正交相机
orthographicCamera.left = frustumSize * aspect / - 2; //设置left的值
orthographicCamera.right = frustumSize * aspect / 2; //设置right的值
orthographicCamera.top = frustumSize / 2; //设置top的值
orthographicCamera.bottom = frustumSize / - 2; //设置bottom的值
orthographicCamera.near = 1; //设置near的值
orthographicCamera.far = 2000; //设置far的值

//注意,最后一定要调用updateProjectionMatrix()方法更新
orthographicCamera.updateProjectionMatrix();

由于浏览器的窗口是可以随意修改,我们有时候需要监听浏览器窗口的变化,然后获取到最新的宽高比,再重新设置相关属性:

var aspect = window.innerWidth / window.innerHeight; //重新获取场景的宽高比

//重新设置left right top bottom 四个值
orthographicCamera.left = frustumSize * aspect / - 2; //设置left的值
orthographicCamera.right = frustumSize * aspect / 2; //设置right的值
orthographicCamera.top = frustumSize / 2; //设置top的值
orthographicCamera.bottom = frustumSize / - 2; //设置bottom的值

//最后,记得一定要更新数据
orthographicCamera.updateProjectionMatrix();

//显示区域尺寸变了,我们也需要修改渲染器的比例
renderer.setSize(window.innerWidth, window.innerHeight);

PerspectiveCamera 透视相机

透视相机是最常用的也是模拟人眼的视角的一种相机,它所渲染生成的页面是一种近大远小的效果。

我们先看看渲染的范围是如何生成的:

  • 首先,我们需要确定一个fov值,这个值是用来确定相机前方的垂直视角,角度越大,我们能够查看的内容就越多。
  • 然后,我们又确定了一个渲染的宽高比,这个宽高比最好设置成页面显示区域的宽高比,这样我们查看生成画面才不会出现拉伸变形的效果,这时,我们可以确定了前面生成内容的范围是一个四棱锥的区域。
  • 最后,我们需要确定的就是相机渲染范围的最小值near和最大值far,注意,这两个值都是距离相机的距离,确定完数值后,相机会显示的范围就是一个近小远大的四棱柱的范围,我们能够看到的内容都是在这个范围内的。
  • 通过上面的原理,我们需要通过设置fov垂直角度,aspect视角宽高比例和near最近渲染距离far最远渲染距离,就能够确定当前透视相机的渲染范围。

下面,是一个透视相机的创建:

var perspectiveCamera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
scene.add( perspectiveCamera );

我们设置了前方的视角为45度,宽度和高度设置成显示窗口的宽度除以高度的比例即可,显示距离为1到1000距离以内的物体。

透视相机的属性创建完成后我们也可以根据个人需求随意修改,但是注意,相机的属性修改完成后,以后要调用updateProjectionMatrix()方法来更新:

var perspectiveCamera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
scene.add( perspectiveCamera );

//下面为修改当前相机属性
perspectiveCamera.fov = 75; //修改相机的fov
perspectiveCamera.aspect = window.innerWidth/window.innerHeight; //修改相机的宽高比
perspectiveCamera.near = 100; //修改near
perspectiveCamera.far = 500; //修改far

//最后更新
perspectiveCamera.updateProjectionMatrix();

如果当前场景浏览器的显示窗口变动了,比如修改了浏览器的宽高后,我们需要设置场景自动更新,下面是一个常用的案例:

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight; //重新设置宽高比
    camera.updateProjectionMatrix(); //更新相机
    renderer.setSize(window.innerWidth, window.innerHeight); //更新渲染页面大小
}
window.onresize = onWindowResize;

相机插件

下载地址: github.com/mrdoob/thre…

使用方法:选择摄像机,并实例化

function initControl() {
    control = new THREE.OrbitControls(camera, renderer.domElement);
}

执行init方法

function init() {  // 3d三要素
    initRenderer();   // 渲染
    initScene();  // 场景
    initCamera();  // 相机

    initMesh();  // 物体

    initControl();
    animate();  // 旋转,动画
}

在每一帧执行update

function animate() {
    requestAnimationFrame(animate); //循环调用函数

    mesh.rotation.x += 0.01; //每帧网格模型的沿x轴旋转0.01弧度  半圈是180度
    mesh.rotation.y += 0.02; //每帧网格模型的沿y轴旋转0.02弧度
    stats.update();
    control.update();
    renderer.render(scene, camera); //渲染界面
}