カメラとコントロール

カメラはシーンをどこから見るかを決める。種類は基本的に 透視(Perspective)並行(Orthographic)の2つ。 ユーザー操作で動かす場合は addons のコントロール群が便利。

PerspectiveCamera

現実の遠近感を再現する。3D シーンの9割はこれ

const camera = new THREE.PerspectiveCamera(
  fov,    // 視野角(度)
  aspect, // 画面のアスペクト比
  near,   // 近接クリッピング距離
  far,    // 遠方クリッピング距離
)

パラメータの目安

位置・向き

camera.position.set(3, 2, 5)
camera.lookAt(0, 0, 0)            // ある点を見る
camera.lookAt(target.position)    // オブジェクトを見る

リサイズ対応(必須)

window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()      // 必ず呼ぶ
  renderer.setSize(window.innerWidth, window.innerHeight)
})

OrthographicCamera

並行投影。遠近感がない。2D 表示・ミニマップ・等角ビューに。

const aspect = window.innerWidth / window.innerHeight
const d = 5
const camera = new THREE.OrthographicCamera(
  -d * aspect,  d * aspect,    // left, right
   d,          -d,             // top, bottom
   0.1,         100,            // near, far
)
camera.position.set(0, 0, 5)
camera.lookAt(0, 0, 0)

リサイズ時は4辺すべて再計算:

window.addEventListener("resize", () => {
  const aspect = window.innerWidth / window.innerHeight
  camera.left   = -d * aspect
  camera.right  =  d * aspect
  camera.top    =  d
  camera.bottom = -d
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight)
})

ズーム

Orthographic は camera.zoom でサイズを変える。updateProjectionMatrix() を忘れない。

その他のカメラ

カメラを動かす方法

マウスでぐるぐる: OrbitControls

もっとも定番。これさえあればプロトタイプは事足りる。

import { OrbitControls } from "three/addons/controls/OrbitControls.js"

const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true     // 慣性
controls.dampingFactor = 0.05
controls.minDistance = 1
controls.maxDistance = 20
controls.maxPolarAngle = Math.PI / 2  // 地面下に潜らない
controls.target.set(0, 0, 0)

// loop で update を呼ぶ
renderer.setAnimationLoop(() => {
  controls.update()
  renderer.render(scene, camera)
})

Trackball: TrackballControls

地面の概念がない自由な回転。分子・3Dモデルビューア向き。

FPS風: PointerLockControls

カーソルをロックして視点回転。WASD等の移動は自分で書く必要がある。

import { PointerLockControls } from "three/addons/controls/PointerLockControls.js"

const controls = new PointerLockControls(camera, renderer.domElement)
document.body.addEventListener("click", () => controls.lock())

飛行: FlyControls / FirstPersonControls

飛んだり、地表を歩くように動かしたりする標準的な操作。movementSpeed 調整。

シネマティック: CameraControls

サードパーティ(camera-controls)。 OrbitControls より豊富な API(カメラを moveTorotateTofitTo 等)。

npm install camera-controls
import CameraControls from "camera-controls"
import * as THREE from "three"
CameraControls.install({ THREE })

const cc = new CameraControls(camera, renderer.domElement)
cc.fitToBox(targetObject, true)              // 対象が画面に収まる
cc.rotate(Math.PI / 4, 0, true)              // 回す
cc.dollyTo(5, true)                          // ズーム

// loop で update を呼ぶ
const clock = new THREE.Clock()
renderer.setAnimationLoop(() => {
  cc.update(clock.getDelta())
  renderer.render(scene, camera)
})

カメラを追従させる

const tmp = new THREE.Vector3()
renderer.setAnimationLoop(() => {
  target.getWorldPosition(tmp)
  camera.position.lerp(tmp.clone().add(new THREE.Vector3(0, 2, 5)), 0.1)
  camera.lookAt(tmp)
  renderer.render(scene, camera)
})

カメラを切り替える

複数カメラを使い分けたい時は、render の引数を変えるだけで良い。

renderer.render(scene, currentCamera)

DragControls — オブジェクトをドラッグ

カメラそのものではないが、シーン内のメッシュをドラッグして動かしたい時のコントロール。

import { DragControls } from "three/addons/controls/DragControls.js"

const drag = new DragControls(draggables, camera, renderer.domElement)
drag.addEventListener("dragstart", (e) => controls.enabled = false)
drag.addEventListener("dragend",   (e) => controls.enabled = true)

TransformControls — Blender 風ガイザー

位置/回転/スケールの矢印・リングが出るコントロール。シーンエディタを作るときに必須。

import { TransformControls } from "three/addons/controls/TransformControls.js"

const tc = new TransformControls(camera, renderer.domElement)
tc.attach(targetMesh)
tc.setMode("translate") // "translate" | "rotate" | "scale"
scene.add(tc)

// OrbitControls と併用するなら、ドラッグ中は orbit を止める
tc.addEventListener("dragging-changed", (e) => {
  controls.enabled = !e.value
})

FOV を動かして緊張感を出す

ズームインや「ヒッ」とする緊張演出は fov をアニメーションするだけで作れる。 updateProjectionMatrix() を忘れずに。

camera.fov = THREE.MathUtils.lerp(camera.fov, targetFov, 0.05)
camera.updateProjectionMatrix()
「カメラ酔い」を避ける

急激なカメラ動きは映像酔いを引き起こす。
- スムージング(lerp)を入れる
- FPS 視点では FOV 60〜75 を維持
- ロール(z軸回転)は最小限
- prefers-reduced-motion を尊重して動きを抑える