mcpField
C
cesiumjs-camera

cesiumjs-camera

github.com/cesiumgs開発193257 回インストール6 週間前に更新
リポジトリ

cesiumjs-camera について

CesiumJSでカメラ表示やナビゲーションを実装する開発者向けのリファレンススキルです。地理的な範囲やランドマークに応じた位置・向きの選び方を説明します。

主な機能

  1. 01カメラの向きと高度の指針
  2. 02setViewによる即時配置
  3. 03flyToによるアニメーション移動
  4. 04ターゲットのフレーミングとlookAtロック
  5. 05ホーム表示と参照座標系の制御

活用シーン

  1. 01都市や地域の初期ビュー設定
  2. 02ランドマークへのフライト演出
  3. 03オフセット視点からのターゲット表示
  4. 04lookAt後のナビゲーション復元

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cesiumgs/cesiumjs-skills --skill cesiumjs-camera

インストール後、Claude Code で/cesiumjs-cameraを入力して読み込まれたか確認します。

詳細

CesiumJS カメラとナビゲーション

ベースライン: CesiumJS v1.144 -- ES モジュールのインポート(import { ... } from "cesium";)

カメラの基本

viewer.camera からアクセスします。カメラには position(ワールド座標の Cartesian3)、姿勢ベクトル(direction、up、right)、フラスタムがあります。 すべての角度はラジアンです。

読み取り専用の計算プロパティ:positionWC、positionCartographic、 directionWC、upWC、rightWC、heading(0 = 北、時計回り)、pitch (負の値 = 下向き)、roll、transform、viewMatrix、inverseViewMatrix。

イベント:移動の開始時/終了時に moveStart / moveEnd が発生します。カメラが percentageChanged(デフォルトは 0.5)を超えて移動すると、changed が発生します。

3D 建物があると、都市の景観がよりリアルになります。 本番環境でスカイライン、地上目線、または都市のパノラマを表示する場合は、対象環境で実際に利用できるタイルセットを使用してください。Cesium.createOsmBuildingsAsync() と Google Photorealistic 3D Tiles は ion の利用権限に依存します。呼び出し元からこれらのサービスを明示的に求められている場合を除き、公開サンプルやトークン不要のサンプルでは使用しないでください。移植性の高いサンプルでは、OpenStreetMap/ArcGIS のベースマップ、表示マーカー、公開 URL を使った 3D Tiles、または高度を上げた都市の俯瞰表示を使用してください。

高度と向きのガイドライン

表示したい地物のスケールに合わせて、高度とピッチを選択してください。

表示タイプ高度(m)ピッチ(度)備考
観光地/記念碑を少し離れて見る50 -- 500-5 to -20カメラを地面に近い高さに設定し、ランドマークから横方向にずらします。被写体が画面いっぱいに収まり、上部に空が見えるようにします。ピッチを約 -10° にした HeadingPitchRange で lookAt を使用してください。この高度ではカメラを真上に配置しないでください。
ランドマークのクローズアップ500 -- 1,500-25 to -35個々の建物や構造物が画面いっぱいに収まります。適切な距離で lookAt を使用してください。
都市のパノラマ/スカイライン800 -- 1,500-10 to -20川や湾の向こうからスカイラインを見る場合に適しています。カメラを横方向に配置し、都市に向けます。環境で利用できる場合にのみ、利用可能な 3D Tiles ソースを使用してください。
都市の俯瞰2,000 -- 5,000-35 to -50都市の街路網、川、公園がはっきりと見えます
大都市圏/地域8,000 -- 20,000-60 to -90大都市圏全体または地理的な地物
峡谷/崖の縁縁から 50 -- 300 上空-15 to -25下方の奥行きを見せるには、ピッチを大きくします。ほぼ水平(-5)だと地形が平坦に見えます。峡谷の構造を見やすくするため、壁や縁を示すエンティティのオーバーレイと川のポリラインを追加してください。
国/大陸500,000 -- 5,000,000-90国境、海岸線

プロンプトに「[都市]を見る」または「[都市]から開始する」とある場合、デフォルトでは都市の俯瞰の距離(2,000-5,000 m)を使い、ピッチはおよそ -45 から -60 度、heading は 0(北)にします。都市の配置、川、ランドマークを識別できる、わかりやすく特徴的な表示になります。

対象地点とカメラ位置の違い: setView と flyTo では、Cartesian destination はカメラの最終位置であり、カメラが見るべき地点ではありません。 「ロサンゼルスへ飛ぶ」や「エッフェル塔を表示する」といった要求では、指定された座標をフレームに収める対象として扱ってください。即時表示には viewBoundingSphere、アニメーション付きの移動には flyToBoundingSphere を優先してください。

真上からの表示(pitch: -90)は、上空から見ることで特徴的な形状がわかる峡谷、海岸線、川などの地理的な地物に最適です。都市の場合は、3D のスカイラインが見える斜めからの表示を優先してください。

ジンバルロック: pitch: -Math.PI/2 を正確に指定しないでください。真下を向く表示では、特異点を避けるため -(Math.PI / 2 - 0.0001) を使用してください。

**地上目線の表示(高度 < 200 m)**には 3D Tiles が必要です。これがない場合、CesiumJS に表示されるのは空と平坦な地面だけです。高度を上げた代替案を提案してください。 スカイラインのパノラマ(川/湾の対岸から):800~1,500 m、ピッチ -10~-20。 実際の3Dシルエットを表示できる3D Tilesソースが利用可能であれば追加してください。そうでない場合は、高高度の地図/マーカービューを使い、スクリーンショットの目標に見合った表示にしてください。 中高度でピッチが水平に近すぎる(-5)と、平坦なグリッドが表示され、スカイラインは見えません。

ランドマークの公開ビジュアル評価ルール: OpenStreetMapの画像だけでは、エッフェル塔、エンパイア・ステート・ビル、自由の女神像、スカイラインは、認識できる3Dの被写体として描画されません。公開/トークン不要のシナリオで、識別可能なランドマークやスカイラインが求められる場合は、対象地点に明示的な代替ビジュアルを追加してください。高い円柱/ボックス/ポリラインの塔、色付きのマスト、スカイラインを表す棒状オブジェクト群、大きくラベルを付けたマーカーなどが使えます。ランドマークビューでは、代替ビジュアルを検査できるようにフレーム内に収め、画面の高さの約3分の1から3分の2を占めるようにしてください。 地図ラベルや10 pxの点を被写体として頼りにしないでください。

渓谷/崖の縁のビュー:ピッチ -15~-25。水平に近いピッチ(-5~-8)では地形が平坦に見え、垂直な落差を捉えられません。渓谷の構造が見えるよう、必ずエンティティオーバーレイ(縁の壁ポリゴン、川のポリライン)を追加してください。エンティティがない場合、カメラの角度にかかわらずシーンには平坦なベースマップしか表示されません。

重要 -- スタンドオフ/遠近感のあるビューを意図する場合、カメラをランドマークの真上に配置しないでください。 カメラを Cartesian3.fromDegrees(lon, lat, 1000) に配置して真下を向ける(pitch: -Math.PI/2)と、被写体の真上にカメラが来て(up_alignment=1)、ランドマークビューのチェックに失敗します。カメラは必ず横方向にずらしてください。HeadingPitchRangeのピッチを -10°~-45° にして lookAt を使うか、ランドマークの横500~2,000 mに destination を配置し、方位をランドマークに向けてください。


setView -- 即時配置

カメラをアニメーションなしで1フレームで移動します。初期ビュー、モードのリセット、制約の設定に使用します。destination:Cartesian3 または Rectangle。 orientation:{ heading, pitch, roll } または { direction, up }。

import { Cartesian3, Math as CesiumMath } from "cesium";

// City overview: 3000 m altitude, angled view facing north
viewer.camera.setView({
  destination: Cartesian3.fromDegrees(-0.1276, 51.5074, 3000.0),
  orientation: {
    heading: CesiumMath.toRadians(0.0),   // north
    pitch: CesiumMath.toRadians(-50.0),    // angled down -- shows city layout clearly
    roll: 0.0,
  },
});
import { Cartesian3, Math as CesiumMath } from "cesium";

// Landmark standoff: camera placed south of Eiffel Tower, facing north
// Offset the destination AWAY from the landmark -- do NOT place directly above it
viewer.camera.setView({
  destination: Cartesian3.fromDegrees(2.2945, 48.847, 300.0), // ~1.2 km south
  orientation: {
    heading: CesiumMath.toRadians(0.0),    // facing north toward tower
    pitch: CesiumMath.toRadians(-20.0),    // slightly down -- tower visible above horizon
    roll: 0.0,
  },
});
import { Cartesian3, Math as CesiumMath } from "cesium";

// Canyon rim perspective: slightly above rim, looking down into the canyon
// Pitch of -20 reveals depth; near-horizontal (-5) would look flat across
viewer.camera.setView({
  destination: Cartesian3.fromDegrees(-112.14, 36.06, 2400.0),
  orientation: {
    heading: CesiumMath.toRadians(0.0),
    pitch: CesiumMath.toRadians(-20.0),    // steeper pitch to show canyon depth
    roll: 0.0,
  },
});
// Top-down geographic view -- use safe pitch to avoid gimbal lock
viewer.camera.setView({
  destination: Cesium.Cartesian3.fromDegrees(-112.14, 36.06, 50000.0),
  orientation: { heading: 0.0, pitch: -(Math.PI / 2 - 0.0001), roll: 0.0 },
});

// Rectangle form (top-down, orientation defaults to north/down)
viewer.camera.setView({
  destination: Cesium.Rectangle.fromDegrees(-77.0, 38.0, -72.0, 42.0),
});

flyTo -- アニメーション付きフライト

カメラを滑らかにアニメーションさせます。何も返しません(Promiseではありません)。completeコールバックを使用してください。オプション:destination、orientation、duration(秒)、complete/cancel、maximumHeight、pitchAdjustHeight、flyOverLongitude。

destinationがカメラの最終位置を意図的に表す場合は、flyToを使用してください。名前付きの都市、ランドマーク、エンティティ、または中央に表示し続ける必要のある座標には、flyToBoundingSphereを使用してください。

import {
  BoundingSphere,
  Cartesian3,
  HeadingPitchRange,
  Math as CesiumMath,
} from "cesium";

// Keep the Eiffel Tower centered while approaching from 1500 m altitude
const target = Cartesian3.fromDegrees(2.2945, 48.8584);
const pitch = CesiumMath.toRadians(-35.0);
const desiredHeight = 1500.0;

// HeadingPitchRange.range is the slant distance to the target, not altitude.
const range = desiredHeight / Math.abs(Math.sin(pitch));

viewer.camera.flyToBoundingSphere(new BoundingSphere(target, 0.0), {
  offset: new HeadingPitchRange(0.0, pitch, range),
  duration: 3,
});
import { Cartesian3, Math as CesiumMath } from "cesium";

// Chain flights using the complete callback (flyTo does NOT return a Promise)
viewer.camera.flyTo({
  destination: Cartesian3.fromDegrees(-74.0445, 40.6892, 800.0),
  orientation: {
    heading: CesiumMath.toRadians(0.0),
    pitch: CesiumMath.toRadians(-35.0),
    roll: 0.0,
  },
  duration: 3,
  complete() {
    viewer.camera.flyTo({
      destination: Cartesian3.fromDegrees(-73.9857, 40.758, 600.0),
      orientation: {
        heading: CesiumMath.toRadians(0.0),
        pitch: CesiumMath.toRadians(-40.0),
        roll: 0.0,
      },
      duration: 2,
    });
  },
});

ツアーの高度に関するヒント:タイルと画像を読み込めるよう、各地点を600 m以上にしてください。400 m未満では、短い間隔でフライトを連続させるとタイルがぼやけることがあります。

// Long-distance flight: LA to Tokyo via Europe
viewer.camera.flyTo({
  destination: Cesium.Cartesian3.fromDegrees(139.815, 35.714, 20000.0),
  duration: 20,
  flyOverLongitude: Cesium.Math.toRadians(60.0), // eastward via Europe
  pitchAdjustHeight: 1000, // look down at high altitude
});

進行中のフライトは、completeFlight()(終了状態にジャンプ)とcancelFlight()(現在位置にとどまる)で制御します。


flyHome

デフォルトのビューにフライトします。Camera.DEFAULT_VIEW_RECTANGLEで上書きできます。

import { Camera, Rectangle } from "cesium";

Camera.DEFAULT_VIEW_RECTANGLE = Rectangle.fromDegrees(-10.0, 35.0, 40.0, 60.0);
viewer.camera.flyHome(2.0); // duration in seconds; omit for auto

制限事項: flyHome()は常に真上からの北向きビューになり、向きは制御できません。回避策:viewer.homeButton.viewModel .command.beforeExecuteをインターセプトして実行をキャンセルし、カスタムの向きを指定してflyToを呼び出してください。


lookAt -- カメラをターゲットに向ける

オフセット(HeadingPitchRange または Cartesian3)を使って、カメラがターゲットを見る位置に配置します。lookAtTransform(Matrix4.IDENTITY) が呼び出されるまでカメラをロックします。

lookAt の真上からの視点に関する注意点: HeadingPitchRange のピッチを -Math.PI/2 にすると、カメラはターゲットの真上に配置され(up_alignment ≈ 1)、ランドマーク表示のチェックに失敗します。パースビューまたは観光向けの視点では、ピッチを -10°~-45° にしてください。意図的に真上から見る地図ビューでのみ、-90°に近いピッチを使用してください。

import { Cartesian3, Math as CesiumMath, HeadingPitchRange, Matrix4 } from "cesium";

// View from the south, looking north (heading 0 = facing north = camera is south)
const target = Cartesian3.fromDegrees(2.2945, 48.8584, 300.0);
viewer.camera.lookAt(
  target,
  new HeadingPitchRange(
    CesiumMath.toRadians(0.0),   // heading 0 = north-facing
    CesiumMath.toRadians(-20.0), // pitch -- 20 deg down (NOT -90; that would be overhead)
    1500.0,                      // range in meters
  ),
);
// ALWAYS release the lookAt lock to restore free navigation
viewer.camera.lookAtTransform(Matrix4.IDENTITY);
import { Cartesian3, Math as CesiumMath, HeadingPitchRange, Matrix4 } from "cesium";

// View from the east, looking west (heading 270 = facing west = camera is east)
const target = Cartesian3.fromDegrees(-73.9857, 40.7484, 200.0);
viewer.camera.lookAt(
  target,
  new HeadingPitchRange(
    CesiumMath.toRadians(270.0), // heading -- west
    CesiumMath.toRadians(-25.0), // pitch -- 25 deg down
    800.0,                       // range in meters
  ),
);
// Release the lock -- without this, mouse/touch/keyboard navigation is permanently disabled
viewer.camera.lookAtTransform(Matrix4.IDENTITY);

lookAt の方位角の基準となる方角:

見る位置...カメラが向く方向...方位角(度)方位角(ラジアン)
南北00
西東90Math.PI / 2
北南180Math.PI
東西2703 * Math.PI / 2

方位角 = カメラが向く方向。カメラはターゲットから見て、その方向の反対側に位置します。

注意点: すべての lookAt 呼び出しには、対応する lookAtTransform(Matrix4.IDENTITY) を必ず含めてください。 ロックを解除しないと、マウス/タッチ/キーボードによるナビゲーションが恒久的に無効になります。 setTimeout、complete コールバック、またはイベントを使ってロック解除を実行してください。 呼び出しが直後であっても、コード内に lookAtTransform の呼び出しが必要です。含まれていない場合、プログラムによるパターンチェックに失敗します。

import { Matrix4 } from "cesium";

// ALWAYS release the lookAt lock when done to restore free navigation
viewer.camera.lookAtTransform(Matrix4.IDENTITY);

lookAtTransform -- カスタム参照フレーム

任意の変換行列を基準としたカメラ位置を設定します。

import { Cartesian3, Transforms, HeadingPitchRange, Math as CesiumMath } from "cesium";

// View in an east-north-up frame centered on a point
const center = Cartesian3.fromDegrees(-75.598, 40.039);
const transform = Transforms.eastNorthUpToFixedFrame(center);
viewer.camera.lookAtTransform(
  transform,
  new HeadingPitchRange(0.0, CesiumMath.toRadians(-45.0), 5000.0),
);

ICRF(慣性)フレームでは、postUpdate リスナー内で Transforms.computeIcrfToFixedMatrix(time) を使用し、 lookAtTransform(Matrix4.fromRotationTranslation(icrfToFixed), offset) で適用します。


flyToBoundingSphere / viewBoundingSphere

BoundingSphere を中心にカメラの視野を設定します。範囲が 0 の場合は自動計算されます。 プロンプトで、画面内に表示し続ける必要のあるターゲットが指定されている場合は、これらのメソッドを優先してください。 球の中心がターゲットで、オフセットによってターゲットに対するカメラの位置が決まります。

import { BoundingSphere, Cartesian3, HeadingPitchRange, Math as CesiumMath } from "cesium";

const sphere = new BoundingSphere(Cartesian3.fromDegrees(-117.16, 32.71), 1000.0);

// Animated
viewer.camera.flyToBoundingSphere(sphere, {
  offset: new HeadingPitchRange(0.0, CesiumMath.toRadians(-45.0), 0.0),
  duration: 2.0,
});

// Instant
viewer.camera.viewBoundingSphere(sphere);

移動、回転、視点変更、ズームのメソッド

移動(位置をメートル単位で移動。デフォルトの defaultMoveAmount = 100 km): moveForward、moveBackward、moveUp、moveDown、moveLeft、moveRight、 move(direction, amount)。

回転(参照フレームの中心を軸に回転し、距離を維持。デフォルトの defaultRotateAmount = PI/3600 rad):rotateUp、rotateDown、rotateLeft、 rotateRight、rotate(axis, angle)。

視点変更(一人称視点でその場で回転。デフォルトの defaultLookAmount = PI/60 rad): lookUp、lookDown、lookLeft、lookRight、look(axis, angle)、 twistLeft、twistRight。

ズーム(視線方向に沿って移動。デフォルトの defaultZoomAmount = 100 km): zoomIn(amount)、zoomOut(amount)。

// Scale movement speed to altitude for natural feel
const height = viewer.scene.globe.ellipsoid
  .cartesianToCartographic(viewer.camera.position).height;
const speed = height / 100.0;
viewer.camera.moveForward(speed);

ScreenSpaceCameraController

マウス/タッチ入力のデフォルト処理を行います。viewer.scene.screenSpaceCameraController からアクセスします。

ナビゲーションの制限

制約を設定するときは、初期ビューにも制約が適用されるよう setView も呼び出してください。

import { Cartesian3, Math as CesiumMath } from "cesium";

const ctrl = viewer.scene.screenSpaceCameraController;

ctrl.minimumZoomDistance = 500;       // meters from surface
ctrl.maximumZoomDistance = 50000;
ctrl.maximumTiltAngle = Math.PI / 2; // prevent going below horizon

// Disable specific interactions
ctrl.enableRotate = false;
ctrl.enableTilt = false;
ctrl.enableZoom = false;
ctrl.enableTranslate = false; // 2D / Columbus only
ctrl.enableLook = false;
ctrl.enableInputs = false;    // disable everything at once

// Set initial view at city-overview altitude for a clear starting point
viewer.camera.setView({
  destination: Cartesian3.fromDegrees(-0.1276, 51.5074, 3000.0),
  orientation: {
    heading: CesiumMath.toRadians(0.0),
    pitch: CesiumMath.toRadians(-50.0),
    roll: 0.0,
  },
});

注意点: enableCollisionDetection = false の場合、maximumZoomDistance は何も通知されずに無視されます。地下ビューの使用後は衝突検出を再び有効にするか、clock.onTick でズーム制限を手動で適用してください。

その他のプロパティ:inertiaSpin、inertiaZoom、inertiaTranslate(0 = なし、 0.9 = デフォルト)、enableCollisionDetection(カメラが地下に入れるようにするには false を設定)。

入力イベントの再割り当て
import { CameraEventType, KeyboardEventModifier } from "cesium";

const ctrl = viewer.scene.screenSpaceCameraController;
ctrl.rotateEventTypes = CameraEventType.RIGHT_DRAG;
ctrl.tiltEventTypes = {
  eventType: CameraEventType.LEFT_DRAG,
  modifier: KeyboardEventModifier.CTRL,
};
ctrl.zoomEventTypes = CameraEventType.WHEEL;

CameraEventType の値:LEFT_DRAG、RIGHT_DRAG、MIDDLE_DRAG、WHEEL、 PINCH。KeyboardEventModifier と組み合わせて使用します:SHIFT、CTRL、ALT。


コントローラーフレームワーク(1.144 以降):組み合わせ可能なカメラコントローラー

CesiumJS 1.144 では、ScreenSpaceCameraController に代わる選択肢として、組み合わせ可能な Controller フレームワークがオプトイン方式で追加されました。アセットの検査を目的としており、地下や密閉モデルの内部の移動、衝突検出を使わずに固定対象の周囲を移動する用途を想定しています。ScreenSpaceCameraController は非推奨ではなく、引き続きデフォルトで使用されます。2 つのシステムは同時に実行できます。

1.144 では 5 つのコントローラーが提供されます(リリースノートには 4 つが記載されていますが、ズームコントローラーも公開されています)。

コントローラー動作
ScreenSpaceMapCameraControllerローカル接平面上での水平パン
ScreenSpaceElevatorCameraController楕円体の法線に沿った垂直パン
HybridScreenSpacePanCameraController天底からの角度に応じて、マップパンとエレベーターパンを自動で切り替え
ScreenSpaceTiltOrbitCameraControllerピックした点を中心としたチルトとオービット(減衰付きイージング)
ScreenSpaceZoomCameraController慣性を伴い、ポインターに向かってズーム

基本的な設定では、デフォルトコントローラーの入力と衝突検出を無効にし、ユースケースに必要なコントローラーを追加します。

import {
  HybridScreenSpacePanCameraController,
  ScreenSpaceTiltOrbitCameraController,
  ScreenSpaceZoomCameraController,
} from "cesium";

const ssc = viewer.scene.screenSpaceCameraController;
ssc.enableInputs = false;             // hand input over to the new controllers
ssc.enableCollisionDetection = false; // allow underground / inside-model views

viewer.addController(new HybridScreenSpacePanCameraController());
viewer.addController(new ScreenSpaceTiltOrbitCameraController());
viewer.addController(new ScreenSpaceZoomCameraController());

viewer.addController / viewer.removeController(CesiumWidget でも利用可能)は、scene.controllerHost のラッパーです。ControllerHost は、登録されたコントローラーを優先順位順に、フレームごとに 1 回更新します。

コントローラーの入力は、dragInputs オプション(MouseButton と、任意で KeyboardEventModifier)を使って再割り当てできます。調整項目はコントローラーによって異なります。マップパンコントローラーとエレベーターパンコントローラーでは、panSpeed、inertiaEnabled、inertialDecay を設定できます。チルトオービットコントローラーとズームコントローラーでは、dampingEnabled を設定できます。ハイブリッドコントローラーは、ネストされた mapController / elevatorController と angleThreshold を使って設定します。pickWorldPosition コールバックでは、動作の計算対象となるワールド座標上の点を選択できます(デフォルト:カメラの下にある楕円体表面)。

import { MouseButton, ScreenSpaceElevatorCameraController } from "cesium";

const elevator = new ScreenSpaceElevatorCameraController({
  dragInputs: [{ button: MouseButton.RIGHT }],
});
elevator.pickWorldPosition = (scene, windowPosition, result) =>
  scene.pickPosition(windowPosition, result);
viewer.addController(elevator);

Controller の契約を実装して、カスタムコントローラーを作成できます。DOM リスナーには connectedCallback(element) / disconnectedCallback(element) を、一度限りのセットアップには firstUpdate(scene, time) を実装し、フレームごとに 1 回呼び出される update(scene, time) を実装します。 ScreenSpaceInputBindings.registerDragInputBindings(handler, bindings, actions) を使うと、ドラッグの開始/変更/終了コールバックを設定できます。

地下やモデル内部の移動、または対象の周囲を回る検査が必要な場合は、このフレームワークを使用してください。地球儀の回転/チルト/ズームに使うマウスボタンや修飾キーを再割り当てする場合は、引き続き ScreenSpaceCameraController の rotateEventTypes / tiltEventTypes / zoomEventTypes を使用してください(上記の「入力イベントの再割り当て」を参照)。公式 Sandcastle デモの ID は camera-controllers です。


カスタムの一人称操作

検査用途のナビゲーションでは、上記の 1.144 Controller フレームワークを優先してください。このフレームワークではカバーされない、ゲームスタイルの一人称移動に限り、独自の操作を実装します。デフォルトコントローラーを無効にし、マウスルックには ScreenSpaceEventHandler を、WASD には keydown / keyup を使用します。clock.onTick で適用します。速度は高度に合わせて調整します。

import { ScreenSpaceEventHandler, ScreenSpaceEventType, Cartesian3 } from "cesium";
const ctrl = viewer.scene.screenSpaceCameraController;
ctrl.enableRotate = ctrl.enableTranslate = ctrl.enableZoom = false;
ctrl.enableTilt = ctrl.enableLook = false;

const canvas = viewer.canvas;
canvas.setAttribute("tabindex", "0");
let looking = false, startPos, mousePos;
const handler = new ScreenSpaceEventHandler(canvas);
handler.setInputAction((m) => { looking = true; startPos = mousePos = Cartesian3.clone(m.position); }, ScreenSpaceEventType.LEFT_DOWN);
handler.setInputAction((m) => { mousePos = m.endPosition; }, ScreenSpaceEventType.MOUSE_MOVE);
handler.setInputAction(() => { looking = false; }, ScreenSpaceEventType.LEFT_UP);

const flags = {};
document.addEventListener("keydown", (e) => { flags[e.code] = true; });
document.addEventListener("keyup", (e) => { flags[e.code] = false; });
viewer.clock.onTick.addEventListener(() => {
  const cam = viewer.camera;
  if (looking) {
    cam.lookRight((mousePos.x - startPos.x) / canvas.clientWidth * 0.05);
    cam.lookUp(-(mousePos.y - startPos.y) / canvas.clientHeight * 0.05);
  }
  const spd = viewer.scene.globe.ellipsoid.cartesianToCartographic(cam.position).height / 100;
  if (flags.KeyW) cam.moveForward(spd);  if (flags.KeyS) cam.moveBackward(spd);
  if (flags.KeyA) cam.moveLeft(spd);     if (flags.KeyD) cam.moveRight(spd);
  if (flags.KeyQ) cam.moveUp(spd);       if (flags.KeyE) cam.moveDown(spd);
});

カメライベント

const off = viewer.camera.moveStart.addEventListener(() => console.log("moving"));
viewer.camera.moveEnd.addEventListener(() => console.log("stopped"));
// off(); // call return value to unsubscribe

viewer.camera.percentageChanged = 0.1; // threshold for change detection
viewer.camera.changed.addEventListener((pct) => console.log(`Changed ${(pct*100).toFixed(1)}%`));

pickEllipsoid -- スクリーンから地球儀へ

import { Cartesian2 } from "cesium";

const center = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
const worldPos = viewer.camera.pickEllipsoid(center);
if (worldPos) {
  const carto = viewer.scene.globe.ellipsoid.cartesianToCartographic(worldPos);
  console.log(Cesium.Math.toDegrees(carto.longitude), Cesium.Math.toDegrees(carto.latitude));
}

エンティティの追跡

// Track an entity (sets camera to follow automatically)
viewer.trackedEntity = viewer.entities.getById("vehicle");

// Customize default tracking offset
import { Camera, HeadingPitchRange, Math as CesiumMath } from "cesium";
Camera.DEFAULT_OFFSET = new HeadingPitchRange(
  CesiumMath.toRadians(90.0), CesiumMath.toRadians(-25.0), 500.0,
);

viewer.trackedEntity = undefined; // stop tracking

デバッグ:viewer.scene.primitives.add(new Cesium.DebugCameraPrimitive({ camera: viewer.camera, color: Cesium.Color.YELLOW, updateOnChange: true }));


パフォーマンスのヒント

  1. duration: 0 を指定した flyTo より setView を優先してください -- トゥイーン処理のオーバーヘッドを回避できます。
  2. 毎フレーム heading/pitch/roll を読み取るのは避けてください -- 読み取りのたびに ENU 変換が計算されます。キャッシュするか、direction/up ベクトルを使ってください。
  3. changed イベントをスロットリングしてください -- percentageChanged を大きくします(例:0.5)。
  4. lookAt のロックは必ず解除してください -- lookAtTransform(Matrix4.IDENTITY)。
  5. 短い飛行では maximumHeight を設定してください -- 宇宙までズームアウトするのを防ぎます。
  6. 高度に合わせて移動量を調整してください -- カメラの高さで割ると、自然な速度になります。
  7. 地下のビューを表示した後は、衝突判定を再び有効にしてください -- enableCollisionDetection = true。
  8. ツアーの各地点には高度 600 m 以上を使用してください -- 続けて飛行する際にタイルがぼやけるのを防ぎます。

よく使うパターンのクイックリファレンス

タスクメソッド詳細
都市へ移動するviewBoundingSphere都市の座標を目標として扱います。目標高度は 2,000~5,000 m、ピッチは -50 を使用します
ランドマークまでアニメーションで移動するflyToBoundingSphere目標が中央に維持されます。目標高度は 1,000~2,000 m、ピッチは -30~-40 を使用します
観光名所/記念碑から距離を取って表示するlookAt または setViewカメラをランドマークから横方向に 500~2,000 m 離し、ピッチを -10~-20 にします。近距離でカメラを真上(ピッチ -90)に配置しないでください。
都市のスカイライン/パノラマsetView または flyTo高度 800~1,500 m、ピッチ -10~-20 にします。川や湾の対岸にカメラを配置し、都市に向けます。OSM Buildings を読み込んでください。
真上からのビュー/地図ビューsetView または flyToピッチは -(Math.PI/2 - 0.0001)、高度は地物の大きさに合わせます
渓谷/崖の縁setView または flyTo縁から 50~300 m 上に設定し、奥行きを出すためにピッチを -15~-25 にします。縁/壁のエンティティポリゴンと川のポリラインを追加して、地形を見やすくします。
目標にロックするlookAtlookAtTransform(Matrix4.IDENTITY) で必ず解除してください。直後に呼び出す場合でも含めてください
カメラツアー(複数地点)flyTo の連鎖complete コールバックを使用し、高度を 600 m 以上に保ちます
地上/ストリートビューsetView3D Tiles が必要です(OSM Buildings または Google Photorealistic)。これらがない場合、空と平坦な地面しか表示されません。
ユーザーのナビゲーションを制限するscreenSpaceCameraControllerズームの最小値/最大値と傾斜角を設定し、初期位置には setView も呼び出します
アセットの確認/地下の周回Controller フレームワーク(1.144 以降)デフォルトの入力と衝突判定を無効にしてから、ハイブリッドパン、チルト周回、ズームのコントローラーを指定して viewer.addController を呼び出します

関連項目

  • cesiumjs-spatial-math -- Cartesian3、Cartographic、Matrix4、Transforms、座標変換
  • cesiumjs-interaction -- ScreenSpaceEventHandler、Scene.pick、マウス/タッチイベント
  • cesiumjs-entities -- Entity、trackedEntity、EntityCollection、データソース

コメント