跳至主要內容

相机

yisky大约 7 分钟基础知识文档相机投射投影正交投影

相机类似现实世界中的摄像机或眼睛,它决定了场景的哪个部分可以被绘制到渲染视口上。如果不添加相机,渲染视口将什么都绘制不出来。相机由场景创建,且一个场景可以创建多个相机。

提示

可以通过为同一场景中的不同相机指定不同的 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

创建相机

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 ]区间内
  
  }

} );
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属性

  • near - 近裁剪面距离,读写属性。

  • far - 远裁剪面距离,读写属性。

  • fov - 视角范围,读写属性,单位:度。

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渲染相机位置、朝向、远近裁剪面等属性改变时分发,逐相机分发
上次编辑于: