唯杰地图 logo唯杰地图
VJMAP
EN

相机

vjmap3d/references/graphics/camera.md 27.8 KB643 行
原文

CameraControls 用于对相机进行控制操作。

通过 app.cameraControl 来访问.

注意

当map3d做为vjmap的一个3D图层展示时,因为相机是与vjmap二维地图的相机保持同步的,所以相机操作只能通过vjmap的Map去操作相机。这种模式不创建相机控制器,app.cameraControl 为 undefined(调用其方法抛 TypeError);程序化设视角用 app.setCameraLookAt(position, lookAt)(地图模式内部转为 map.setFreeCameraOptions)或直接操作 vjmap 的 map。

示例

基本用法

let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
    scene: {  // 场景设置
        gridHelper: { visible: true } // 是否显示坐标网格
    }
})
const mesh = new THREE.Mesh(
	new THREE.BoxGeometry( 1, 1, 1 ),
	new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } )
);
app.scene.add( mesh );
let cameraControls = app.cameraControl;
const ui = await app.getConfigPane({ title: "相机操作", style: { width: "250px"}});
let gui = new vjmap3d.UiPanelJsonConfig();
gui.add(cameraControls, "enabled")
gui.add(cameraControls, "verticalDragToForward")
gui.add(cameraControls, "dollyToCursor")
gui.add(cameraControls, "dollyDragInverted")
gui.addButton('rotate theta 45deg' , () => cameraControls.rotate( 45 * THREE.MathUtils.DEG2RAD, 0, true ));
gui.addButton('rotate theta -90deg' , () => cameraControls.rotate( - 90 * THREE.MathUtils.DEG2RAD, 0, true ));
gui.addButton('rotate theta 360deg' , () => cameraControls.rotate( 360 * THREE.MathUtils.DEG2RAD, 0, true ));
gui.addButton('rotate phi 20deg' , () => cameraControls.rotate( 0, 20 * THREE.MathUtils.DEG2RAD, true ));
gui.addButton('pan( 0, 1 )' , () => cameraControls.pan(   1,   0, true));
gui.addButton('pan( -1, -1 )' , () => cameraControls.pan( - 1, - 1, true ));
gui.addButton('dolly  1' , () => cameraControls.dolly(   1, true ));
gui.addButton('dolly -1' , () => cameraControls.dolly( - 1, true ));
gui.addButton('zoom `camera.zoom / 2`' , () => cameraControls.zoom( app.camera.zoom / 2, true ));
gui.addButton('move to( 3, 5, 2 )' , () => cameraControls.moveTo( 3, 5, 2, true ));
gui.addButton('fit to the bounding box of the mesh' , () => cameraControls.fitToBox( mesh, true ))
gui.addButton('move to ( -5, 2, 1 )' , () => cameraControls.setPosition( - 5, 2, 1, true ));
gui.addButton('look at ( 3, 0, -3 )' , () => cameraControls.setTarget( 3, 0, -3, true ));
gui.addButton('move to ( 1, 2, 3 ), look at ( 1, 1, 0 )' , () => cameraControls.setLookAt( 1, 2, 3, 1, 1, 0, true ));
gui.addButton('move to somewhere between ( -2, 0, 0 ) -> ( 1, 1, 0 ) and ( 0, 2, 5 ) -> ( -1, 0, 0 )' , () => cameraControls.lerpLookAt( - 2, 0, 0, 1, 1, 0, 0, 2, 5, - 1, 0, 0, Math.random(), true ));
gui.addButton('shake' , () => cameraControls.shake( 1000, 10, 1, false ));
gui.addButton('reset' , () => cameraControls.reset( true ));
let state;
gui.addButton('saveState' , () => state = cameraControls.saveState());
gui.addButton('loadState' , () => {if(state) cameraControls.loadState( state )});
gui.toJson().forEach(c => ui.appendChild(c));

轨道旋转

CameraControls 使用球面坐标进行轨道旋转。

如果您的相机是 Y 轴向上,则方位角将是 y 轴旋转的角度,而极角将是垂直位置的角度。

Dolly指将镜头移近或远离主体, pan 则是平行主体移动镜头

Dolly 和 Zoom

  • 缩放涉及改变镜头焦距。在 three.js 中,缩放实际上是改变相机 FOV,而相机是静止的(不会移动)。
  • 移动摄影机通过物理移动相机来改变画面。

#特性

名称 类型 默认 描述
.camera `THREE.Perspective THREE.Orthographic` 不适用
.enabled boolean true 控件是否启用。
.active boolean false true如果控件正在主动更新则返回。
.currentAction ACTION 不适用 当前的 Getter ACTION。
.distance number 不适用 当前距离。
.minDistance number Number.EPSILON 镜头移动的最小距离。该值必须大于0
.maxDistance number Infinity 镜头移动的最大距离。
.minZoom number 0.01 最小相机变焦。
.maxZoom number Infinity 最大相机变焦。
.polarAngle number 不适用 当前极角(以弧度为单位)。
.minPolarAngle number 0 以弧度为单位。
.maxPolarAngle number Math.PI 以弧度为单位。
.azimuthAngle number 不适用 当前方位角以弧度表示¹。
.minAzimuthAngle number -Infinity 以弧度为单位。
.maxAzimuthAngle number Infinity 以弧度为单位。
.boundaryFriction number 0.0 边界的摩擦比。
.boundaryEnclosesCamera boolean false 相机位置是否应该包含在边界内。
.smoothTime number 0.25 达到目标的大致时间(以秒为单位)。值越小,达到目标越快。
.draggingSmoothTime number 0.125 拖动时的平滑时间。
.azimuthRotateSpeed number 1.0 方位旋转的速度。
.polarRotateSpeed number 1.0 极地自转速度。
.dollySpeed number 1.0 鼠标滚轮移动的速度。
.truckSpeed number 2.0 拖动速度。
.verticalDragToForward boolean true .screenSpacePanning与three.js 的 OrbitControls相同。
.dollyToCursor boolean false true启用鼠标光标坐标的推拉功能。
.dollyDragInverted boolean false true通过拖动来移动或缩放时反转方向。
.interactiveArea DOMRect 不适用 在 domElement 中设置拖动开始、触摸和滚轮启用区域。每个值都在和之间(0包括1),其中是屏幕的0左/上和右/下。1
.colliderMeshes array [] 与相机发生碰撞的网格阵列。
.infinityDolly boolean false true启用 Infinity Dolly 的滚轮和夹点功能。将其与minDistance和maxDistance³ 一起使用。
.restThreshold number 0.01 rest控制相机减速时事件触发的速度
  1. 每旋转360度,值都会增加.azimuthAngle,是累积的​​。
    360º = 360 * THREE.MathUtils.DEG2RAD = Math.PI * 2,720º = Math.PI * 4。
  2. 请注意,colliderMeshes 可能会降低性能。碰撞测试使用来自相机的 4 个射线发射器,因为近平面有 4 个角。
  3. 如果 Dolly 距离小于(或大于)minDistance(或maxDistance),infinityDolly则将保持距离并推动目标位置。

事件

CameraControls 实例发出以下事件。
要订阅,请使用cameraControl.addEventListener( 'eventname', function )。
要取消订阅,请使用cameraControl.removeEventListener( 'eventname', function )。

事件名称 说明
'controlstart' 当用户开始通过鼠标/触摸控制相机时。¹
'control' 当用户控制相机(拖动)时。
'controlend' 当用户结束控制相机时。¹
'transitionstart' 当任何类型的转换开始时,无论是用户控制还是使用带有enableTransition = true
'update' 当相机位置更新时。
'wake' 当相机开始移动时。
'rest' 当相机移动低于.restThreshold²时。
'sleep' 当相机停止移动时。
  1. mouseButtons.wheel(鼠标滚轮控制)不发出'controlstart'。内部使用滚动事件,并且滚动事件间歇发生。这意味着无法检测到“开始”和“结束” 'controlend'。mouseButtons.wheel
  2. 由于阻尼,通常_会_在相机停止移动sleep后几秒触发。如果您想在相机停止时执行某些操作(例如启用 UI、执行另一个转换),您可能需要该事件。可以使用参数进行微调。

用户输入设置

按钮 行为
mouseButtons.left CameraControls.ACTION.ROTATE*
mouseButtons.right CameraControls.ACTION.ROTATE
mouseButtons.wheel¹ CameraControls.ACTION.ROTATE
mouseButtons.middle² CameraControls.ACTION.ROTATE
  1. 鼠标滚轮事件用于在 Mac 上“上/下/左/右”滚动“上/下”
  2. 鼠标点击滚轮事件“按钮”
  • * 是默认值。
  • 的默认值为mouseButtons.wheel:
    • DOLLY对于透视相机。
    • ZOOM对于正交相机,无法设置DOLLY。
移动端手指 行为
touches.one CameraControls.ACTION.TOUCH_ROTATE*
touches.two ACTION.TOUCH_DOLLY_TRUCK
touches.three ACTION.TOUCH_DOLLY_TRUCK
  • * 是默认值。
  • touches.two和的默认值为touches.three:
    • TOUCH_DOLLY_TRUCK对于透视相机。
    • TOUCH_ZOOM_TRUCK对于正交相机,无法设置TOUCH_DOLLY_TRUCK和TOUCH_DOLLY。

方法

rotate

旋转方位角(水平)和极角(垂直)。
每个值都添加到当前值。

名称 类型 描述
azimuthAngle number 方位角旋转的角度。以弧度为单位。
polarAngle number 极坐标旋转角度,单位为弧度。
enableTransition boolean 是否平稳移动或立即移动

如果只想旋转一个轴,请为要旋转的轴设置一个角度,并0为另一个轴设置一个角度。

rotate( 20 * THREE.MathUtils.DEG2RAD, 0, true );

rotateAzimuthTo

将方位角(水平)旋转到给定角度并保持相同的极角(垂直)目标。

名称 类型 描述
azimuthAngle number 方位角旋转的角度。以弧度为单位。
enableTransition boolean 是否平稳移动或立即移动

rotatePolarTo

将极角(垂直)旋转到给定角度并保持相同的方位角(水平)目标。

名称 类型 描述
polarAngle number 极坐标旋转角度,单位为弧度。
enableTransition boolean 是否平稳移动或立即移动

rotateTo

将方位角(水平)和极角(垂直)旋转到给定的角度。
相机视图将绝对旋转到轨道轴上:

方位角

       0º
         \
 90º -----+----- -90º
           \
           180º

0º 前、90º ( Math.PI / 2) 左、-90º ( - Math.PI / 2) 右、180º ( Math.PI) 后


极角

     180º
      |
      90º
      |
      0º

极角 0 = 相机在目标正上方向下俯视;Math.PI / 2 = 水平视角;Math.PI = 相机在目标正下方仰视(看向天空)。上图的"180º 顶部 / 0º 底部"指的是视线方向(看天 / 看地),不是相机所在位置。

名称 类型 描述
azimuthAngle number 方位角旋转至。以弧度为单位。
polarAngle number 极坐标旋转角度至。以弧度为单位。
enableTransition boolean 是否平稳移动或立即移动

dolly

移动相机位置。(指将镜头移近或远离主体进行缩放)

名称 类型 描述
distance number 移动距离
enableTransition boolean 是否平稳移动或立即移动

dollyTo

将摄影机位置移动至指定距离。(指将镜头移近或远离主体进行缩放)

名称 类型 描述
distance number 移动距离
enableTransition boolean 是否平稳移动或立即移动

dollyInFixed

拉近镜头,但不改变目标与相机之间的距离,而是移动目标位置。
为拉远镜头指定负值。

名称 类型 描述
distance number 移动距离
enableTransition boolean 是否平稳移动或立即移动

zoom

放大/缩小相机。该值添加到相机缩放。使用和
设置的限制.minZoom .maxZoom

名称 类型 描述
zoomStep number 缩放比例
enableTransition boolean 是否平稳移动或立即移动

您还可以使用camera.zoom属性来实现放大功能。
例如

const zoomIn  = () => cameraControls.zoom(   camera.zoom / 2, true );
const zoomOut = () => cameraControls.zoom( - camera.zoom / 2, true );

zoomTo

将相机放大/缩小至指定比例。该值会覆盖相机缩放。使用和
设置的限制.minZoom .maxZoom

名称 类型 描述
zoom number 缩放比例
enableTransition boolean 是否平稳移动或立即移动

pan

使用当前方位角平移相机。

名称 类型 描述
x number 水平平移量
y number 垂直平移量
enableTransition boolean 是否平稳移动或立即移动

lookInDirectionOf

朝给定点方向看。

名称 类型 描述
x number 点 x
y number 点 y
z number 点 z
enableTransition boolean 是否平稳移动或立即移动

setFocalOffset

使用屏幕平行坐标设置焦点偏移。
z与 Dolly 不同,它不会对正交摄影产生影响。

名称 类型 描述
x number 水平偏移量
y number 垂直偏移量
z number 深度偏移量。结果与 Dolly 相同,但不受minDistance和的影响maxDistance
enableTransition boolean 是否平稳移动或立即移动

setOrbitPoint

不移动相机即可设置轨道点。

名称 类型 描述
targetX number 轨道中心位置 x
targetY number 轨道中心位置 y
targetZ number 轨道中心位置 z

forward

前进/后退。

名称 类型 描述
distance number 向前/向后移动的量。负值表示向后移动
enableTransition boolean 是否平稳移动或立即移动

moveTo

移动target位置到给定点。

名称 类型 描述
x number x 坐标移动中心位置
y number y 坐标移动中心位置
z number z 坐标移动中心位置
enableTransition boolean 是否平稳移动或立即移动

elevate

向上/向下移动。

名称 类型 描述
height number 向上/向下移动的量。负值表示向下移动
enableTransition boolean 是否平稳移动或立即移动

fitToBox

使用最近的轴将视口适配到对象的框或边界框。填充以单位表示。
设置cover: true为填充输入屏幕。

名称 类型 描述
box3OrMesh THREE.Box3 THREE.Mesh
enableTransition boolean 是否平稳移动或立即移动
options object 选项
options.cover boolean 是否填充输入屏幕。默认为false
options.paddingTop number 顶部填充。默认为0
options.paddingRight number 右填充。默认为0
options.paddingBottom number 底部内边距。默认为0
options.paddingLeft number 左填充。默认为0

fitToSphere

将视口与对象的球体或边界球体相适应。

名称 类型 描述
sphereOrMesh THREE.Sphere THREE.Mesh
enableTransition boolean 是否平稳移动或立即移动

fitToRect

将视口与矩形大小相适应。

名称 类型 描述
rect {width: number;height: number;center: [number, number, number],normal: [number, number, number]} 矩形参数

setLookAt

target从来看position。

名称 类型 描述
positionX number 相机位置 x。
positionY number 相机位置 y。
positionZ number 相机位置 z。
targetX number 轨道中心位置 x。
targetY number 轨道中心位置y。
targetZ number 轨道中心位置 z。
enableTransition boolean 是否平稳移动或立即移动

lerpLookAt

与 类似setLookAt,但它在两种状态之间进行插值。

名称 类型 描述
positionAX number 观察的起始位置 x。
positionAY number 观察的起始位置 y。
positionAZ number 观察的起始位置 z。
targetAX number 查看的起始位置 x。
targetAY number 查看的起始位置 y。
targetAZ number 查看的起始位置z。
positionBX number 从位置 x 开始观察并进行插值。
positionBY number 从位置 y 开始查看以进行插值。
positionBZ number 从位置 z 开始观察并进行插值。
targetBX number 查看要进行插值的位置 x。
targetBY number 查看位置 y 进行插值。
targetBZ number 查看要插入的位置 z。
t number 0闭区间内的插值因子。该值必须是介于到之间的数字1,其中1为 100%
enableTransition boolean 是否平稳移动或立即移动

setPosition

根据给定位置设置角度和距离。
的别名setLookAt(),不改变目标。因此继续注视当前目标

名称 类型 描述
positionX number 从 x 位置观察。
positionY number 从 y 位置观察。
positionZ number 从 z 位置观察。
enableTransition boolean 是否平稳移动或立即移动

setTarget

设置注视的目标位置。
的别名setLookAt(),不改变位置。从而保持相同的位置。

名称 类型 描述
targetX number 注视的位置 x。
targetY number 查看的位置 y。
targetZ number 注视的位置 z。
enableTransition boolean 是否平稳移动或立即移动

setBoundary

设置包围相机目标的边界框box3。THREE.Box3

名称 类型 描述
box3 THREE.Box3? 边界区域。没有删除边界的参数。

setViewport

设置(或取消设置)当前视口。
当您想要dollyToCursor同时使用渲染器视口和功能时,请设置此项。

参见:THREE.WebGLRenderer.setViewport()

名称 类型 描述
vector4 THREE.Vector4? 代表视口的 Vector4,或者undefined用于取消设置它。

getTarget

返回相机所观察的轨道中心位置。

名称 类型 描述
out THREE.Vector3 接收 Vector3 实例来复制结果
receiveEndValue boolean 是否接收转换结束坐标或当前坐标。默认为true

getPosition

返回相机位置。

名称 类型 描述
out THREE.Vector3 接收 Vector3 实例来复制结果
receiveEndValue boolean 是否接收转换结束坐标或当前坐标。默认为true

getSpherical

返回轨道的球面坐标。

名称 类型 描述
out THREE.Vector3 接收 Spherical 实例复制结果
receiveEndValue boolean 是否接收转换结束坐标或当前坐标。默认为true

getFocalOffset

返回焦点偏移,即相机在屏幕平行坐标中平移的距离。

名称 类型 描述
out THREE.Vector3 接收 Vector3 实例来复制结果
receiveEndValue boolean 是否接收转换结束坐标或当前坐标。默认为true

saveState

将当前相机位置设置为默认位置。返回完整 CameraState 对象(字段:cameraPosition/cameraTarget/cameraZoom/cameraUp/cameraFocalOffset——vjmap3d@2.0.0)。

loadState

加载位置做为当前相机位置。

loadState(state, enableTransition?) 只要求 cameraPosition/cameraTarget(cameraUp 缺省 (0,1,0)、cameraZoom 缺省 1、cameraFocalOffset 缺省 0,自动补齐),值须为 THREE.Vector3(或含 x/y/z 的对象)。⚠️ 传数组 [x, y, z] 时内部读 .x 得 undefined → camera.position 变 NaN,相机坏掉且所有 Marker2D/Popup2D 的 CSS2D 元素随之消失(投影出 NaN → 渲染器判定不可见)。

normalizeRotations

将相机方位角旋转标准化为 0 至 360 度之间。

reset

将所有旋转和位置重置为默认值。

名称 类型 描述
enableTransition boolean 是否平稳移动或立即移动

update

更新相机位置和方向。这应该在您的 tick 循环中调用,并true在需要重新渲染时返回。

名称 类型 描述
delta number 上次更新调用之间的时间差

updateCameraUp

当您改变相机向上矢量时,运行.updateCameraUp()以同步。

applyCameraUp

将当前相机向上方向应用于相机。
轨道系统将使用当前位置重新初始化。

shake

相机抖动

名称 类型 描述
duration number 每次持续时长 (ms) 默认 1000
frequency number 抖动频率 默认 10
strength number 强度 默认 1
isLoop number 是否循环抖动 默认 false

toJSON

获取 JSON 字符串中的所有状态

fromJSON

用 JSON 重现控制状态。enableTransition其中 anim 是否为布尔值。


高级

归一化累积方位角

如果您需要标准化的累积方位角(介于 0 到 360 度之间),请使用THREE.MathUtils.euclideanModulo
计算,例如:

const TAU = Math.PI * 2;

function normalizeAngle( angle ) {

	return THREE.MathUtils.euclideanModulo( angle, TAU );

}

const normalizedAzimuthAngle = normalizeAngle( cameraControls.azimuthAngle );

找最短方位角旋转的绝对角度

您可能旋转了 380 度,但实际上您希望旋转 -20 度。
要获取绝对角度,请使用以下命令:

const TAU = Math.PI * 2;

function absoluteAngle( targetAngle, sourceAngle ){

  const angle = targetAngle - sourceAngle
  return THREE.MathUtils.euclideanModulo( angle + Math.PI, TAU ) - Math.PI;

}

console.log( absoluteAngle( 380 * THREE.MathUtils.DEG2RAD, 0 ) * THREE.MathUtils.RAD2DEG ); // -20deg
console.log( absoluteAngle( -1000 * THREE.MathUtils.DEG2RAD, 0 ) * THREE.MathUtils.RAD2DEG ); // 80deg

创建复杂的过渡

enableTransition所有接受参数返回Promise的方法均可用于创建复杂的动画,例如:

async function complexTransition() {
	await cameraControls.rotateTo( Math.PI / 2, Math.PI / 4, true );
	await cameraControls.dollyTo( 3, true );
	await cameraControls.fitToSphere( mesh, true );
}

这将旋转相机,然后dolly,最后适应的边界球mesh。

.restThreshold可以使用和调整转换的速度和时间.smoothTime。

如果enableTransition是false,则立即返回:

// will resolve immediately
await cameraControls.dollyTo( 3, false );