cesiumjs-camera について
CesiumJSでカメラ表示やナビゲーションを実装する開発者向けのリファレンススキルです。地理的な範囲やランドマークに応じた位置・向きの選び方を説明します。
主な機能
- 01カメラの向きと高度の指針
- 02setViewによる即時配置
- 03flyToによるアニメーション移動
- 04ターゲットのフレーミングとlookAtロック
- 05ホーム表示と参照座標系の制御
活用シーン
- 01都市や地域の初期ビュー設定
- 02ランドマークへのフライト演出
- 03オフセット視点からのターゲット表示
- 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では、Cartesiandestinationはカメラの最終位置であり、カメラが見るべき地点ではありません。 「ロサンゼルスへ飛ぶ」や「エッフェル塔を表示する」といった要求では、指定された座標をフレームに収める対象として扱ってください。即時表示には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 の方位角の基準となる方角:
| 見る位置... | カメラが向く方向... | 方位角(度) | 方位角(ラジアン) |
|---|---|---|---|
| 南 | 北 | 0 | 0 |
| 西 | 東 | 90 | Math.PI / 2 |
| 北 | 南 | 180 | Math.PI |
| 東 | 西 | 270 | 3 * 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 }));
パフォーマンスのヒント
duration: 0を指定したflyToよりsetViewを優先してください -- トゥイーン処理のオーバーヘッドを回避できます。- 毎フレーム
heading/pitch/rollを読み取るのは避けてください -- 読み取りのたびに ENU 変換が計算されます。キャッシュするか、direction/upベクトルを使ってください。 changedイベントをスロットリングしてください --percentageChangedを大きくします(例:0.5)。lookAtのロックは必ず解除してください --lookAtTransform(Matrix4.IDENTITY)。- 短い飛行では
maximumHeightを設定してください -- 宇宙までズームアウトするのを防ぎます。 - 高度に合わせて移動量を調整してください -- カメラの高さで割ると、自然な速度になります。
- 地下のビューを表示した後は、衝突判定を再び有効にしてください --
enableCollisionDetection = true。 - ツアーの各地点には高度 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 にします。縁/壁のエンティティポリゴンと川のポリラインを追加して、地形を見やすくします。 |
| 目標にロックする | lookAt | lookAtTransform(Matrix4.IDENTITY) で必ず解除してください。直後に呼び出す場合でも含めてください |
| カメラツアー(複数地点) | flyTo の連鎖 | complete コールバックを使用し、高度を 600 m 以上に保ちます |
| 地上/ストリートビュー | setView | 3D 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、データソース