# 相机

[CameraControls](https://vjmap.com/map3d/api/classes/CameraControls.html) 用于对相机进行控制操作。

通过 [app.cameraControl](https://vjmap.com/map3d/api/classes/App.html#cameraControl) 来访问.

::: warning 
当`map3d`做为`vjmap`的一个3D图层展示时，因为相机是与`vjmap`二维地图的相机保持同步的，所以相机操作只能通过`vjmap`的`Map`去操作相机。这种模式不创建相机控制器，`app.cameraControl` 为 `undefined`（调用其方法抛 TypeError）；程序化设视角用 `app.setCameraLookAt(position, lookAt)`（地图模式内部转为 `map.setFreeCameraOptions`）或直接操作 vjmap 的 `map`。
::: 

## 示例

### 基本用法
<mapFrame>
<pre>
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));
</pre>
</mapFrame>

## 轨道旋转

CameraControls 使用球面坐标进行轨道旋转。

如果您的相机是 Y 轴向上，则方位角将是 y 轴旋转的角度，而极角将是垂直位置的角度。

![](https://vjmap.com/blogimages/image-20240531144630796.png)

`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`\* | `CameraControls.ACTION.TRUCK`| `CameraControls.ACTION.OFFSET`| `CameraControls.ACTION.DOLLY`| `CameraControls.ACTION.ZOOM`|`CameraControls.ACTION.NONE` |
| `mouseButtons.right` | `CameraControls.ACTION.ROTATE`| `CameraControls.ACTION.TRUCK`\* | `CameraControls.ACTION.OFFSET`| `CameraControls.ACTION.DOLLY`| `CameraControls.ACTION.ZOOM`|`CameraControls.ACTION.NONE` |
| `mouseButtons.wheel`¹ | `CameraControls.ACTION.ROTATE`| `CameraControls.ACTION.TRUCK`| `CameraControls.ACTION.OFFSET`| `CameraControls.ACTION.DOLLY`| `CameraControls.ACTION.ZOOM`|`CameraControls.ACTION.NONE` |
| `mouseButtons.middle`² | `CameraControls.ACTION.ROTATE`| `CameraControls.ACTION.TRUCK`| `CameraControls.ACTION.OFFSET`| `CameraControls.ACTION.DOLLY`\* | `CameraControls.ACTION.ZOOM`|`CameraControls.ACTION.NONE` |

1. 鼠标滚轮事件用于在 Mac 上“上/下/左/右”滚动“上/下”
2. 鼠标点击滚轮事件“按钮”

- \* 是默认值。
- 的默认值为`mouseButtons.wheel`：
    - `DOLLY`对于透视相机。
    - `ZOOM`对于正交相机，无法设置`DOLLY`。

| 移动端手指 | 行为 |
| --- | --- |
| `touches.one` | `CameraControls.ACTION.TOUCH_ROTATE`\* | `CameraControls.ACTION.TOUCH_TRUCK`| `CameraControls.ACTION.TOUCH_OFFSET`|`CameraControls.ACTION.DOLLY` |
| `touches.two` | `ACTION.TOUCH_DOLLY_TRUCK`| `ACTION.TOUCH_DOLLY_OFFSET`| `ACTION.TOUCH_DOLLY_ROTATE`| `ACTION.TOUCH_ZOOM_TRUCK`| `ACTION.TOUCH_ZOOM_OFFSET`| `ACTION.TOUCH_ZOOM_ROTATE`| `ACTION.TOUCH_DOLLY`| `ACTION.TOUCH_ZOOM`| `CameraControls.ACTION.TOUCH_ROTATE`| `CameraControls.ACTION.TOUCH_TRUCK`| `CameraControls.ACTION.TOUCH_OFFSET`|`CameraControls.ACTION.NONE` |
| `touches.three` | `ACTION.TOUCH_DOLLY_TRUCK`| `ACTION.TOUCH_DOLLY_OFFSET`| `ACTION.TOUCH_DOLLY_ROTATE`| `ACTION.TOUCH_ZOOM_TRUCK`| `ACTION.TOUCH_ZOOM_OFFSET`| `ACTION.TOUCH_ZOOM_ROTATE`| `CameraControls.ACTION.TOUCH_ROTATE`| `CameraControls.ACTION.TOUCH_TRUCK`| `CameraControls.ACTION.TOUCH_OFFSET`|`CameraControls.ACTION.NONE` |

- \* 是默认值。
- `touches.two`和的默认值为`touches.three`：
    - `TOUCH_DOLLY_TRUCK`对于透视相机。
    - `TOUCH_ZOOM_TRUCK`对于正交相机，无法设置`TOUCH_DOLLY_TRUCK`和`TOUCH_DOLLY`。

## 方法

### [rotate](https://vjmap.com/map3d/api/classes/CameraControls.html#rotate)

旋转方位角（水平）和极角（垂直）。  
每个值都添加到当前值。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `azimuthAngle` | `number` | 方位角旋转的角度。以弧度为单位。 |
| `polarAngle` | `number` | 极坐标旋转角度，单位为弧度。 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

如果只想旋转一个轴，请为要旋转的轴设置一个角度，并`0`为另一个轴设置一个角度。

```js
rotate( 20 * THREE.MathUtils.DEG2RAD, 0, true );
```

---

### [rotateAzimuthTo](https://vjmap.com/map3d/api/classes/CameraControls.html#rotateAzimuthTo)

将方位角（水平）旋转到给定角度并保持相同的极角（垂直）目标。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `azimuthAngle` | `number` | 方位角旋转的角度。以弧度为单位。 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

---

###  [rotatePolarTo](https://vjmap.com/map3d/api/classes/CameraControls.html#rotatePolarTo)

将极角（垂直）旋转到给定角度并保持相同的方位角（水平）目标。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `polarAngle` | `number` | 极坐标旋转角度，单位为弧度。 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

---

### [rotateTo](https://vjmap.com/map3d/api/classes/CameraControls.html#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](https://vjmap.com/map3d/api/classes/CameraControls.html#dolly)

移动相机位置。（指将镜头移近或远离主体进行缩放）

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `distance` | `number` | 移动距离 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

---

### [dollyTo](https://vjmap.com/map3d/api/classes/CameraControls.html#dollyTo)

将摄影机位置移动至指定距离。（指将镜头移近或远离主体进行缩放）

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `distance` | `number` | 移动距离 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

---

### [dollyInFixed](https://vjmap.com/map3d/api/classes/CameraControls.html#dollyInFixed)

拉近镜头，但不改变目标与相机之间的距离，而是移动目标位置。  
为拉远镜头指定负值。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `distance` | `number` | 移动距离 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [zoom](https://vjmap.com/map3d/api/classes/CameraControls.html#zoom)

放大/缩小相机。该值添加到相机缩放。使用和  
设置的限制`.minZoom` `.maxZoom`

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `zoomStep` | `number` | 缩放比例 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

您还可以使用`camera.zoom`属性来实现放大功能。  
例如

```js
const zoomIn  = () => cameraControls.zoom(   camera.zoom / 2, true );
const zoomOut = () => cameraControls.zoom( - camera.zoom / 2, true );
```

### [zoomTo](https://vjmap.com/map3d/api/classes/CameraControls.html#zoomTo)

将相机放大/缩小至指定比例。该值会覆盖相机缩放。使用和  
设置的限制`.minZoom` `.maxZoom`

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `zoom` | `number` | 缩放比例 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [pan](https://vjmap.com/map3d/api/classes/CameraControls.html#pan)

使用当前方位角平移相机。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `x` | `number` | 水平平移量 |
| `y` | `number` | 垂直平移量 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [lookInDirectionOf](https://vjmap.com/map3d/api/classes/CameraControls.html#lookInDirectionOf)

朝给定点方向看。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `x` | `number` | 点 x |
| `y` | `number` | 点 y |
| `z` | `number` | 点 z |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [setFocalOffset](https://vjmap.com/map3d/api/classes/CameraControls.html#setFocalOffset)

使用屏幕平行坐标设置焦点偏移。  
`z`与 Dolly 不同，它不会对正交摄影产生影响。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `x` | `number` | 水平偏移量 |
| `y` | `number` | 垂直偏移量 |
| `z` | `number` | 深度偏移量。结果与 Dolly 相同，但不受`minDistance`和的影响`maxDistance` |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [setOrbitPoint](https://vjmap.com/map3d/api/classes/CameraControls.html#setOrbitPoint)

不移动相机即可设置轨道点。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `targetX` | `number` | 轨道中心位置 x |
| `targetY` | `number` | 轨道中心位置 y |
| `targetZ` | `number` | 轨道中心位置 z |

### [forward](https://vjmap.com/map3d/api/classes/CameraControls.html#forward)

前进/后退。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `distance` | `number` | 向前/向后移动的量。负值表示向后移动 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [moveTo](https://vjmap.com/map3d/api/classes/CameraControls.html#moveTo)

移动`target`位置到给定点。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `x` | `number` | x 坐标移动中心位置 |
| `y` | `number` | y 坐标移动中心位置 |
| `z` | `number` | z 坐标移动中心位置 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [elevate](https://vjmap.com/map3d/api/classes/CameraControls.html#elevate)

向上/向下移动。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `height` | `number` | 向上/向下移动的量。负值表示向下移动 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [fitToBox](https://vjmap.com/map3d/api/classes/CameraControls.html#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](https://vjmap.com/map3d/api/classes/CameraControls.html#fitToSphere)

将视口与对象的球体或边界球体相适应。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `sphereOrMesh` | `THREE.Sphere`|`THREE.Mesh` | 边界球体以适合视图。 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [fitToRect](https://vjmap.com/map3d/api/classes/CameraControls.html#fitToRect)

将视口与矩形大小相适应。
| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `rect` | `{width: number;height: number;center: [number, number, number],normal: [number, number, number]}`  | 矩形参数 |

### [setLookAt](https://vjmap.com/map3d/api/classes/CameraControls.html#setLookAt)

`target`从来看`position`。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `positionX` | `number` | 相机位置 x。 |
| `positionY` | `number` | 相机位置 y。 |
| `positionZ` | `number` | 相机位置 z。 |
| `targetX` | `number` | 轨道中心位置 x。 |
| `targetY` | `number` | 轨道中心位置y。 |
| `targetZ` | `number` | 轨道中心位置 z。 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [lerpLookAt](https://vjmap.com/map3d/api/classes/CameraControls.html#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](https://vjmap.com/map3d/api/classes/CameraControls.html#setPosition)

根据给定位置设置角度和距离。  
的别名`setLookAt()`，不改变目标。因此继续注视当前目标

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `positionX` | `number` | 从 x 位置观察。 |
| `positionY` | `number` | 从 y 位置观察。 |
| `positionZ` | `number` | 从 z 位置观察。 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [setTarget](https://vjmap.com/map3d/api/classes/CameraControls.html#setTarget)

设置注视的目标位置。  
的别名`setLookAt()`，不改变位置。从而保持相同的位置。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `targetX` | `number` | 注视的位置 x。 |
| `targetY` | `number` | 查看的位置 y。 |
| `targetZ` | `number` | 注视的位置 z。 |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [setBoundary](https://vjmap.com/map3d/api/classes/CameraControls.html#setBoundary)

设置包围相机目标的边界框`box3`。`THREE.Box3`

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `box3` | `THREE.Box3?` | 边界区域。没有删除边界的参数。 |

### [setViewport](https://vjmap.com/map3d/api/classes/CameraControls.html#setViewport)

设置（或取消设置）当前视口。  
当您想要`dollyToCursor`同时使用渲染器视口和功能时，请设置此项。

参见：[THREE.WebGLRenderer.setViewport()](https://threejs.org/docs/#api/en/renderers/WebGLRenderer.setViewport)

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `vector4` | `THREE.Vector4?` | 代表视口的 Vector4，或者`undefined`用于取消设置它。 |

### [getTarget](https://vjmap.com/map3d/api/classes/CameraControls.html#getTarget)
返回相机所观察的轨道中心位置。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `out` | `THREE.Vector3` | 接收 Vector3 实例来复制结果 |
| `receiveEndValue` | `boolean` | 是否接收转换结束坐标或当前坐标。默认为`true` |

### [getPosition](https://vjmap.com/map3d/api/classes/CameraControls.html#getPosition)

返回相机位置。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `out` | `THREE.Vector3` | 接收 Vector3 实例来复制结果 |
| `receiveEndValue` | `boolean` | 是否接收转换结束坐标或当前坐标。默认为`true` |

### [getSpherical](https://vjmap.com/map3d/api/classes/CameraControls.html#getSpherical)

返回轨道的球面坐标。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `out` | `THREE.Vector3` | 接收 Spherical 实例复制结果 |
| `receiveEndValue` | `boolean` | 是否接收转换结束坐标或当前坐标。默认为`true` |

### [getFocalOffset](https://vjmap.com/map3d/api/classes/CameraControls.html#getFocalOffset)

返回焦点偏移，即相机在屏幕平行坐标中平移的距离。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `out` | `THREE.Vector3` | 接收 Vector3 实例来复制结果 |
| `receiveEndValue` | `boolean` | 是否接收转换结束坐标或当前坐标。默认为`true` |

### [saveState](https://vjmap.com/map3d/api/classes/CameraControls.html#saveState)

将当前相机位置设置为默认位置。返回完整 `CameraState` 对象（字段：`cameraPosition`/`cameraTarget`/`cameraZoom`/`cameraUp`/`cameraFocalOffset`——vjmap3d@2.0.0）。

### [loadState](https://vjmap.com/map3d/api/classes/CameraControls.html#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](https://vjmap.com/map3d/api/classes/CameraControls.html#normalizeRotations)

将相机方位角旋转标准化为 0 至 360 度之间。

### [reset](https://vjmap.com/map3d/api/classes/CameraControls.html#reset)

将所有旋转和位置重置为默认值。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `enableTransition` | `boolean` | 是否平稳移动或立即移动 |

### [update](https://vjmap.com/map3d/api/classes/CameraControls.html#update)

更新相机位置和方向。这应该在您的 tick 循环中调用，并`true`在需要重新渲染时返回。

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `delta` | `number` | 上次更新调用之间的时间差 |

### [updateCameraUp](https://vjmap.com/map3d/api/classes/CameraControls.html#updateCameraUp)

当您改变相机向上矢量时，运行`.updateCameraUp()`以同步。

### [applyCameraUp](https://vjmap.com/map3d/api/classes/CameraControls.html#applyCameraUp)

将当前相机向上方向应用于相机。  
轨道系统将使用当前位置重新初始化。

### [shake](https://vjmap.com/map3d/api/classes/CameraControls.html#shake)

相机抖动

| 名称 | 类型 | 描述 |
| --- | --- | --- |
| `duration` | `number` | 每次持续时长 (ms)  默认 1000 |
| `frequency` | `number` | 抖动频率 默认 10 |
| `strength` | `number` | 强度 默认 1 |
| `isLoop` | `number` | 是否循环抖动 默认 false |

### [toJSON](https://vjmap.com/map3d/api/classes/CameraControls.html#toJSON)

获取 JSON 字符串中的所有状态

### [fromJSON](https://vjmap.com/map3d/api/classes/CameraControls.html#fromJSON)

用 JSON 重现控制状态。`enableTransition`其中 anim 是否为布尔值。

---

## 高级

### 归一化累积方位角

如果您需要标准化的累积方位角（介于 0 到 360 度之间），请使用[THREE.MathUtils.euclideanModulo](https://threejs.org/docs/#api/en/math/MathUtils)  
计算，例如：

```js
const TAU = Math.PI * 2;

function normalizeAngle( angle ) {

	return THREE.MathUtils.euclideanModulo( angle, TAU );

}

const normalizedAzimuthAngle = normalizeAngle( cameraControls.azimuthAngle );
```

---

### 找最短方位角旋转的绝对角度

您可能旋转了 380 度，但实际上您希望旋转 -20 度。  
要获取绝对角度，请使用以下命令：

```js
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`的方法均可用于创建复杂的动画，例如：

```js
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`，则立即返回：

```js
// will resolve immediately
await cameraControls.dollyTo( 3, false );
```