相机
相机类似现实世界中的摄像机或眼睛,它决定了场景的哪个部分可以被绘制到渲染视口上。如果不添加相机,渲染视口将什么都绘制不出来。相机由场景创建,且一个场景可以创建多个相机。
提示
可以通过为同一场景中的不同相机指定不同的 viewport 实现画中画的效果,如下图所示:
相机类型
Fantasy 3D目前提供透视投影和正交投影两种类型相机。
- 透视投影相机
透视投影相机(PerspectiveCamera)符合我们眼睛观看效果-近大远小,透视投影模型示意图如下所示:

如上图所示,近裁剪面(near),远裁剪面(far)和视角(fov)会形成一个视锥体。在视锥体内部的物体是会被投影到相机里的,也就是会绘制到渲染视口上,而视锥体外的物体则会被裁剪。
- 正交投影相机
正交投影相机(OrthographicCamera)可视区近处和远处看到的物体是等大小的。由正交投影矩阵产生的可视区称为盒装可视区,如下图所示:

如上图所示,正交投影可视区由 left、right、top、bottom 组成,Fantasy 3D 为了简化设置,提供了 frustumSize 初始化参数,对应关系如下所示:
- left = -frustumSize / 2.0
- right = frustumSize / 2.0
- top = ( frustumSize * aspectRatio ) / 2.0
- bottom = -( frustumSize * aspectRatio ) / 2.0
创建相机
- 创建透视投影相机 - 使用场景(Scene)的 createPerspectiveCamera 方法创建透视投影相机。
import { Vector3, Vector4 } from 'three';
// 创建一个透视投影相机
const camera = scene.createPerspectiveCamera( {
// 相机实体方位属性
transform: {
position: new Vector3( 0.0, 5.0, 5.0 ),
lookAt: new Vector3( 0.0, 0.0, 0.0 )
},
// 相机属性
camera: {
near: 0.1, // 近裁剪面距离
far: 1000.0, // 远裁剪面距离
viewport: new Vector3( 0, 0, 1, 1 ) // 相机单位化渲染视口范围,xy视口左上角坐标,zw视口宽高,且所有值均在[ 0~1 ]区间内
}
} );
- 创建正交投影相机 - 使用场景(Scene)的 createOrthographicCamera 方法创建正交投影相机。
import { Vector3, Vector4 } from 'three';
// 创建一个正交投影相机
scene.createOrthographicCamera( {
// 相机实体方位属性
transform: { position: new Vector3( 0.0, 10.0, 40.0 ) },
// 相机属性
camera: {
near: 1.0, // 近裁剪面距离
far: 150.0, // 远裁剪面距离
frustumSize: 50.0, // 相机视口尺寸
viewport: new Vector4( 0, 0, 1, 1 ) // 相机单位化渲染视口范围,xy视口左上角坐标,zw视口宽高,且所有值均在[ 0~1 ]区间内
}
} );
相机属性
透视投影相机组件(PerspectiveCamera)和 正交投影相机组件(OrthographicCamera)继承自 Camera。
Camera属性
- native - 获取原生 three.js 相机对象,只读属性。
import { PerspectiveCamera as PerspectiveCameraImpl } from 'three';
import { PerspectiveCamera } from '@fantasy3d/core';
// 获取透视投影相机组件
const camera = entity.getComponent( PerspectiveCamera );
// 获取原生three.js透视投影相机对象
const threeCamera = camera.native as PerspectiveCameraImpl;
import { OrthographicCamera as OrthographicCameraImpl } from 'three';
import { OrthographicCamera } from '@fantasy3d/core';
// 获取正交投影相机组件
const camera = entity.getComponent( OrthographicCamera );
// 获取原生three.js正交投影相机对象
const threeCamera = camera.native as OrthographicCameraImpl;
- priority - 相机渲染优先级,读写属性。
提示
值越小优先级越高,越优先渲染!
- viewport - 相机单位化渲染视口范围,读写属性。
提示
xy视口左上角坐标,zw视口宽高,且所有值均在 [ 0~1 ] 区间内。
pixelViewport - 相机像素渲染视口范围,只读属性,单位:像素。
renderTarget - 相机渲染目标,读写属性。
提示
默认情况下相机会将可视区内的物体绘制到渲染视口上,如果想实现一些特殊的效果(例如,离屏渲染),可以手动设置相机渲染目标。
colorTexture - 相机颜色缓冲纹理对象,只读属性。
depthTexture - 相机深度缓冲纹理对象,只读属性。
提示
colorTexture 和 depthTexture 只有在创建相机时设置 captureOptions 参数才会生效。
PerspectiveCamera属性
OrthographicCamera属性
near - 近裁剪面距离,读写属性。
far - 远裁剪面距离,读写属性。
frustumSize - 视口尺寸,读写属性。
相机方法
intersectRenderer - 渲染组件相交判断。
- 判断射线是否与指定渲染组件相交
import { Ray, Vector3 } from 'three'; import { defined } from '@fantasy3d/core'; // 创建查询射线 const ray = new Ray( new Vector3( 0.0, 0.0, 0.0 ), new Vector3( 0.0, -1.0, 0.0 ) ); // 相交判断 const intersection = camera.intersectRenderer( ray, renderer ); if ( defined( intersection ) ) { // TODO: 相交处理 } else { // TODO: 不相交处理 }
- 判断从屏幕某点发出的射线是否与指定渲染组件相交
import { Vector2 } from 'three'; import { defined } from '@fantasy3d/core'; // 相交判断 const intersection = camera.intersectRenderer( new Vector2( 20, 50 ), renderer ); if ( defined( intersection ) ) { // TODO: 相交处理 } else { // TODO: 不相交处理 }
intersectEntity - 实体相交判断。
- 判断射线是否与指定实体相交
import { Ray, Vector3 } from 'three'; import { defined } from '@fantasy3d/core'; // 创建查询射线 const ray = new Ray( new Vector3( 0.0, 0.0, 0.0 ), new Vector3( 0.0, -1.0, 0.0 ) ); // 相交判断 const intersection = camera.intersectEntity( ray, entity ); if ( defined( intersection ) ) { // TODO: 相交处理 } else { // TODO: 不相交处理 }
- 判断从屏幕某点发出的射线是否与指定实体相交
import { Vector2 } from 'three'; import { defined } from '@fantasy3d/core'; // 相交判断 const intersection = camera.intersectEntity( new Vector2( 20, 50 ), entity ); if ( defined( intersection ) ) { // TODO: 相交处理 } else { // TODO: 不相交处理 }
提示
该方法会与实体中的所有渲染组件进行相交判断,如果相交则返回距离射线起点最近的相交渲染组件,否则返回null。
raycast - 射线查询。
- 使用指定射线进行射线查询
import { Ray, Vector3 } from 'three'; import { defined } from '@fantasy3d/core'; // 创建查询射线 const ray = new Ray( new Vector3( 0.0, 0.0, 0.0 ), new Vector3( 0.0, -1.0, 0.0 ) ); // 射线查询 const results = camera.raycast( ray, QueryMask.All );
- 使用从屏幕某点发出的射线进行射线查询
import { Vector2 } from 'three'; import { defined } from '@fantasy3d/core'; // 射线查询 const results = camera.raycast( new Vector2( 20, 50 ), QueryMask.All );
提示
- 可以通过查询遮罩值(QueryMask)控制哪些渲染组件可以被射线查询,默认所有渲染组件都可以;
- 射线查询结果是一个数组且按距当前相机距离由近及远进行排序。
screenPointToRay - 通过屏幕坐标(单位:像素)构建一条射线。
screenToWorldPoint - 屏幕坐标(单位:像素)转世界坐标(单位:米)。
worldToScreenPoint - 世界坐标(单位:米)转屏幕坐标(单位:像素)。
updateWorldMatrix - 更新相机世界矩阵。
updateProjectionMatrix - 更新相机投影矩阵。
resize - 调整相机渲染视口尺寸。
相机事件
- on - 订阅事件。
import { EventType } from '@fantasy3d/core';
// 订阅“相机开始渲染”事件
camera.on( EventType.Before_Camera_Render, () => {
// TODO:事件响应
} );
- once - 订阅世界且仅响应一次。
import { EventType } from '@fantasy3d/core';
// 订阅一次“相机开始渲染”事件
camera.once( EventType.Before_Camera_Render, () => {
// TODO:事件响应
} );
- off - 取消事件订阅。
import { EventType } from '@fantasy3d/core';
// “相机开始渲染”事件订阅回调
const callback = () => {};
// 订阅“相机开始渲染”事件
camera.on( EventType.Before_Camera_Render, callback, { target: this } );
// 取消订阅“相机开始渲染”事件
camera.off( EventType.Before_Camera_Render, callback );
重要
“取消订阅”时如果不指定第二个参数,会取消该类型事件的所有订阅!
// 取消“相机开始渲染”事件的所有订阅
camera.off( EventType.Before_Camera_Render );
- emit - 分发事件。
import { EventType } from '@fantasy3d/core';
// 分发“相机开始渲染”事件
camera.emit( { type: EventType.Before_Camera_Render } );
提示
通过Camera可订阅的内置事件类型及分发时机:
事件类型 | 事件说明 |
---|---|
Before_Camera_Frame_Capture | 抓取相机帧缓冲区之前分发,逐相机分发 |
After_Camera_Frame_Capture | 抓取相机帧缓冲区之后分发,逐相机分发 |
Before_Camera_Render | 相机渲染之前分发,逐相机分发 |
After_Camera_Render | 相机渲染之后分发,逐相机分发 |
Camera_Frustum_Changed | 渲染相机视口发生改变时分发,逐相机分发 |
Camera_Changed | 渲染相机位置、朝向、远近裁剪面等属性改变时分发,逐相机分发 |