mcpField
C
cesiumjs-models-particles

cesiumjs-models-particles

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

cesiumjs-models-particles について

CesiumJSでglTF/GLBモデルやパーティクル効果を扱う開発者向けのスキルガイドです。モデルの読み込み、アニメーション、ノード変換、スタイル設定、パーティクルシステムを説明します。

主な機能

  1. 01glTF/GLBモデルの読み込みと配置
  2. 02モデルのアニメーションとノード制御
  3. 03モデルのスタイル設定とフィーチャー選択
  4. 04パーティクル効果の作成

活用シーン

  1. 01CesiumJSシーンへのモデル配置とアニメーション
  2. 02フィーチャーID付きモデルのスタイル設定
  3. 03煙、炎、雨のエフェクト作成

インストール

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

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

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

同梱ファイルREFERENCE.md

詳細

CesiumJS モデル、glTF、パーティクルエフェクト

バージョンの基準:CesiumJS v1.144。

クイックリファレンス

クラス目的
Model低レベルの glTF/GLB プリミティブ。modelMatrix で配置します
ModelAnimationモデル上で実行中のアニメーションインスタンス
ModelAnimationCollectionmodel.activeAnimations にあるコレクション
ModelNode変換を変更できる名前付きノード
ModelFeatureフィーチャー ID 付きモデルのフィーチャー単位のスタイル設定/ピッキング
EdgeDisplayModeModel/Cesium3DTileset 上で、ドラフト版 glTF のエッジ可視性のレンダリングを制御します
ParticleSystemビルボードベースのパーティクルマネージャー(火、煙、雨)
Particle位置、速度、寿命を持つ単一のパーティクル
ParticleBurstスケジュールされたパーティクルの一斉放出
BoxEmitter / CircleEmitterボックス領域内/平らな円盤内から放出します
ConeEmitter / SphereEmitter円錐の先端から/球体内から放出します

Entity API では ModelGraphics を通じてモデルを公開します(cesiumjs-entities を参照)。Primitive API では、modelMatrix、アニメーション、ノード変換を完全に制御するために Model.fromGltfAsync を使用します。


glTF/GLB モデルの読み込み

常に非同期ファクトリーを使用してください。コンストラクターを直接呼び出さないでください。

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

const model = await Model.fromGltfAsync({ url: "path/to/model.glb" });
viewer.scene.primitives.add(model);
公開サンプルモデル

CesiumJS には、ion トークンなしで使用できるサンプルモデルが付属しています。

https://raw.githubusercontent.com/CesiumGS/cesium/main/Apps/SampleData/models/CesiumAir/Cesium_Air.glb
https://raw.githubusercontent.com/CesiumGS/cesium/main/Apps/SampleData/models/CesiumMan/Cesium_Man.glb
https://raw.githubusercontent.com/CesiumGS/cesium/main/Apps/SampleData/models/CesiumMilkTruck/CesiumMilkTruck.glb

CesiumJS 1.143 は、v1 属性コーデックと COLOR フィルターを含め、KHR_meshopt_compression を自動的にデコードします。デコーダーや非公開のローダーヘルパーをインポートしないでください。圧縮 glTF、CAD 形式の線/点/エッジ、または定 LOD テクスチャを読み込む場合は、対応状況とオーサリングの全マトリックスについて REFERENCE.md をお読みください。同じローダーの動作は、3D Tiles 内の glTF コンテンツにも適用されます。

方位を指定したモデルの配置
const position = Cartesian3.fromDegrees(-123.074, 44.050, 5000);
const hpr = new HeadingPitchRoll(CesiumMath.toRadians(135), 0, 0);

const model = await Model.fromGltfAsync({
  url: "CesiumAir.glb",
  modelMatrix: Transforms.headingPitchRollToFixedFrame(position, hpr),
  minimumPixelSize: 128,  // never smaller than 128 px on screen
  maximumScale: 20000,    // cap for minimumPixelSize enlargement
  scale: 2.0,             // uniform scale multiplier
});
viewer.scene.primitives.add(model);

ビジュアル評価時のフレーミング: モデルのスクリーンショットでは、モデル全体がフレーム内に収まり、下端で切れずに認識できる必要があります。公開サンプルの航空機では minimumPixelSize を 256-400 に設定し、控えめな silhouetteColor/silhouetteSize を追加して、既知のモデル位置を明示的な座標で狙うようにカメラを配置してください。モデルがフレームより下に表示される浅いピッチは避けてください。また、Model プリミティブに対してバージョン依存の動作をする viewer.flyTo(model) に頼らないでください。

モデルの外観の歪みを防ぐ

スケールが非均一に適用された場合や、向きの行列が正しく構築されていない場合、モデルが引き伸ばされたり歪んだりして見えることがあります。よくある注意点:

  • 地面に沿った向きの設定には、必ず Transforms.headingPitchRollToFixedFrame(または Entity API の headingPitchRollQuaternion)を使用してください。 手動で作成したクォータニオンは、ピッチ/ロールの軸を反転させ、シルエットを垂直方向に引き伸ばすことがよくあります。
  • サイズには(均一な)scale を使用し、非均一な Matrix4.fromScale は使わないでください。 modelMatrix に組み込まれた非均一スケールはモデルを歪ませます。Matrix4.fromScale は、モデル全体ではなく、ノード単位の調整(例:単一の砲塔を引き伸ばす)に使用してください。
  • minimumPixelSize には適切な maximumScale を組み合わせてください。 上限がないと、遠くにある小さなモデルがフレームいっぱいに拡大され、カメラが近いときに細長く見えることがあります。
Model.fromGltfAsync の主なオプション
オプション型デフォルト
urlstring|Resource必須
modelMatrixMatrix4IDENTITY
scalenumber1.0
minimumPixelSizenumber0.0
maximumScalenumber--
showbooleantrue
color / colorBlendMode / colorBlendAmountColor / ColorBlendMode / number-- / HIGHLIGHT / 0.5
edgeDisplayModeEdgeDisplayModeSURFACES_ONLY
silhouetteColor / silhouetteSizeColor / numberRED / 0.0
shadowsShadowModeENABLED
heightReferenceHeightReferenceNONE
customShaderCustomShader--
idany--
allowPickingbooleantrue

準備状態とライフサイクル

fromGltfAsync は glTF JSON の解析後に解決されますが、WebGL リソースはまだ読み込み中の場合があります。アニメーション、ノード、または boundingSphere にアクセスする前に、readyEvent を待ってください。

const model = await Model.fromGltfAsync({ url: "robot.glb" });
viewer.scene.primitives.add(model);

model.readyEvent.addEventListener(() => {
  console.log("Bounding sphere:", model.boundingSphere);
});
// Synchronous check
if (model.ready) { const bs = model.boundingSphere; }

アニメーション

model.activeAnimations(ModelAnimationCollection)で管理します。

名前を指定して再生/すべて再生
model.readyEvent.addEventListener(() => {
  // Single animation
  const anim = model.activeAnimations.add({
    name: "Walk",                          // glTF animation name
    loop: Cesium.ModelAnimationLoop.REPEAT, // NONE | REPEAT | MIRRORED_REPEAT
    multiplier: 1.0,                       // playback speed (must be > 0)
  });
  anim.start.addEventListener((m, a) => console.log(`Started: ${a.name}`));

  // Or play all animations at once
  model.activeAnimations.addAll({
    loop: Cesium.ModelAnimationLoop.REPEAT,
    multiplier: 0.5,
  });
});

追加の add オプション:index、reverse、startTime、stopTime、delay、removeOnStop、animationTime(カスタム時間コールバック)。

アニメーションを進めるには、viewer.clock.shouldAnimate = true が必要です。 クロックが停止していると、歩行中のキャラクターはポーズの途中で固まって見えます(キーフレームの切り替わり目では、歪んで見える場合もあります)。

アニメーションイベント
animation.start.addEventListener((model, animation) => { });
animation.update.addEventListener((model, animation, time) => { });
animation.stop.addEventListener((model, animation) => { });
// Collection-level
model.activeAnimations.animationAdded.addEventListener((model, anim) => { });
model.activeAnimations.remove(animation); // remove one
model.activeAnimations.removeAll();        // remove all

モデルノード

名前付きノードのトランスフォームを上書きして、手続き型アニメーション(例:砲塔の回転)を行います。

model.readyEvent.addEventListener(() => {
  const node = model.getNode("Turret");
  node.matrix = Cesium.Matrix4.fromScale(
    new Cesium.Cartesian3(5.0, 1.0, 1.0), node.matrix
  );
});

プロパティ:name(読み取り専用)、id(読み取り専用インデックス)、show(ブール値)、matrix(Matrix4 -- 元の状態に戻して glTF アニメーションを再度有効にするには、undefined に設定します)。


色付け、シルエット、フィーチャーピッキング

// Tint + silhouette
model.color = Cesium.Color.RED.withAlpha(0.5);
model.colorBlendMode = Cesium.ColorBlendMode.MIX;
model.colorBlendAmount = 0.5;
model.silhouetteColor = Cesium.Color.YELLOW;
model.silhouetteSize = 2.0;
エッジ表示モード(実験的、1.142 以降)

ドラフト版の EXT_mesh_primitive_edge_visibility 拡張を使用する glTF アセットでは、 EdgeDisplayMode によって、拡張で提供されるエッジを非表示にするか、サーフェス上に合成するか、 単独でレンダリングするかを制御します。この拡張を持たないモデルには影響しません。

import { EdgeDisplayMode, Model } from "cesium";

const model = await Model.fromGltfAsync({
  url: "/models/cad-part.glb",
  edgeDisplayMode: EdgeDisplayMode.SURFACES_AND_EDGES,
});
viewer.scene.primitives.add(model);

model.edgeDisplayMode = EdgeDisplayMode.EDGES_ONLY;       // CAD-style wireframe
model.edgeDisplayMode = EdgeDisplayMode.SURFACES_ONLY;    // default

glTF に EXT_mesh_features または EXT_structural_metadata が含まれる場合、ピッキングは ModelFeature を返します。

const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((movement) => {
  const picked = viewer.scene.pick(movement.endPosition);
  if (picked instanceof Cesium.ModelFeature) {
    picked.getPropertyIds().forEach((name) => {
      console.log(`${name}: ${picked.getProperty(name)}`);
    });
    picked.color = Cesium.Color.YELLOW;
  }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

高さ参照

// Primitive API -- scene is required for height reference
const model = await Model.fromGltfAsync({
  url: "truck.glb",
  heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
  scene: viewer.scene,
});

// Entity API
viewer.entities.add({
  position: Cartesian3.fromDegrees(-75.59, 40.03),
  model: { uri: "truck.glb", heightReference: Cesium.HeightReference.CLAMP_TO_GROUND },
});

値:NONE、CLAMP_TO_GROUND、RELATIVE_TO_GROUND、CLAMP_TO_TERRAIN、RELATIVE_TO_TERRAIN、CLAMP_TO_3D_TILE、RELATIVE_TO_3D_TILE。


パーティクルシステム

ParticleSystem はビルボードベースのエフェクトを描画します。modelMatrix(ワールド)と emitterModelMatrix(ローカルオフセット)で位置を指定します。

パーティクルシステムを追加する前に、必ず viewer.clock.shouldAnimate = true を設定してください -- パーティクルはクロックが動作しているときだけ移動します。クロックが停止していると、噴出方向のある煙ではなく、放出元の位置に静止した「塊」が表示されます。

見やすい垂直の噴煙を生成する

よくある失敗例は、上昇する柱状の噴煙ではなく、拡散した球状の塊が描画されることです。噴煙を垂直に見せるには、次の点に注意してください。

  • 上向きに偏った速度を得るには、CircleEmitter または細い ConeEmitter を使用します。 SphereEmitter と BoxEmitter は全方向に放出するため、塊のような形になります。
  • 速度を強く上向きに偏らせます -- 放出器のローカル +Z は modelMatrix フレーム内で上向きです。Transforms.eastNorthUpToFixedFrame を使って modelMatrix を設定し、+Z がローカルの上向きになるようにします。
  • minimumParticleLife / maximumParticleLife は数秒(例:1.5-4.0)に設定します。 粒子が消える前に十分な距離を進み、目に見える柱を形成できます。
  • 粒子のスケールを寿命に応じて変化させます(startScale を小さく、endScale をその 3~6 倍にする)。実際の煙のように、噴煙が高さとともに広がります。
  • 放出器の設置範囲は、見える噴煙より小さくします。 火口の煙には、小さな円盤または点状の放出源を使います。地面に大きな楕円があると、放出源の目印ではなく、それ自体が主題のように見えます。
  • 噴煙を大きくしてクリッピングを解消しようとしないでください。 上端が切れる場合は、まずカメラの距離を大きくするか、粒子の寿命、速度、または endScale を下げます。噴煙でフレームの四辺すべてを埋めないようにしてください。
  • スクリーンショットを撮る前に、シミュレーション時間を数秒進めてください -- 噴煙が形成されるまで時間が必要です。クロックを進めるか、viewer.clock.shouldAnimate = true に設定して待ちます。
煙の軌跡
import { ParticleSystem, CircleEmitter, Color, Cartesian2, Transforms, Cartesian3 } from "cesium";

viewer.clock.shouldAnimate = true; // required -- particles don't move on a stopped clock

const smokeSystem = new ParticleSystem({
  image: "smoke.png",
  startColor: Color.LIGHTGRAY.withAlpha(0.7),
  endColor: Color.WHITE.withAlpha(0.0),
  startScale: 1.0,
  endScale: 5.0,
  emissionRate: 10,
  minimumSpeed: 1.0,
  maximumSpeed: 4.0,
  minimumParticleLife: 1.2,
  maximumParticleLife: 3.0,
  imageSize: new Cartesian2(25, 25), // pixel size
  emitter: new CircleEmitter(2.0),   // radius in meters
  modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-75.157, 39.978)),
  lifetime: 16.0,
  loop: true,
});
viewer.scene.primitives.add(smokeSystem);
火山/火口の煙の調整

Mount St. Helens のような地形規模の煙を表現する場合は、斜めからのカメラアングルと控えめなソースマーカーを使用します。マーカーは、巨大な地面の円盤にならずに発生源の位置を示す必要があります。また、地形が下に見える状態で、噴煙全体がフレーム内に収まるようにします。

import { ParticleSystem, CircleEmitter, Color, Cartesian2, Transforms, Cartesian3 } from "cesium";

viewer.clock.shouldAnimate = true;

const sourcePosition = Cartesian3.fromDegrees(-122.1944, 46.1914, 2549);

viewer.entities.add({
  position: sourcePosition,
  point: {
    pixelSize: 10,
    color: Color.ORANGE,
    outlineColor: Color.BLACK,
    outlineWidth: 2,
  },
});

const craterSmoke = new ParticleSystem({
  image: createRadialParticle(48, "rgba(180,180,180,0.75)"),
  startColor: Color.LIGHTGRAY.withAlpha(0.65),
  endColor: Color.WHITE.withAlpha(0.0),
  startScale: 0.8,
  endScale: 4.0,
  emissionRate: 35,
  minimumSpeed: 20.0,
  maximumSpeed: 45.0,
  minimumParticleLife: 2.0,
  maximumParticleLife: 4.0,
  imageSize: new Cartesian2(22, 22),
  emitter: new CircleEmitter(35.0),
  modelMatrix: Transforms.eastNorthUpToFixedFrame(sourcePosition),
  lifetime: 20.0,
  loop: true,
});
viewer.scene.primitives.add(craterSmoke);

viewer.trackedEntity = undefined;
viewer.camera.lookAt(
  sourcePosition,
  new Cesium.HeadingPitchRange(
    Cesium.Math.toRadians(35),
    Cesium.Math.toRadians(-22),
    6500
  )
);

地名で指定された発生源の上に煙を配置するプロンプトでは、次のパターンを使用します。

  • プロンプトで地面のフットプリントが明示的に求められている場合を除き、ellipse よりも point または小さなビルボードマーカーを優先します。
  • 噴煙の頂部、底部、ソースマーカーを同時に表示します。 粒子が描画されていても、噴煙がフレームから切れていたり、マーカーがなかったりするのは構図上の失敗です。
  • 背の高い噴煙には斜めのピッチを使用します。 真下に近い視点では、垂直方向のボリュームが平坦になり、灰色の塊のように見えます。
エミッターの種類
import { BoxEmitter, CircleEmitter, ConeEmitter, SphereEmitter } from "cesium";

new BoxEmitter(new Cesium.Cartesian3(10, 10, 10));  // 3D box, velocity outward
new CircleEmitter(2.0);                              // flat disk, velocity +Z
new ConeEmitter(Cesium.Math.toRadians(30));          // cone tip, velocity toward base
new SphereEmitter(5.0);                              // sphere, velocity radiates out
粒子バースト
const firework = new ParticleSystem({
  image: getParticleCanvas(),
  startColor: Color.RED,
  endColor: Color.RED.withAlpha(0.0),
  particleLife: 1.0,
  speed: 100.0,
  imageSize: new Cartesian2(7, 7),
  emissionRate: 0,  // bursts only
  emitter: new SphereEmitter(0.1),
  bursts: [
    new Cesium.ParticleBurst({ time: 0.0, minimum: 100, maximum: 200 }),
    new Cesium.ParticleBurst({ time: 2.0, minimum: 50, maximum: 100 }),
    new Cesium.ParticleBurst({ time: 4.0, minimum: 200, maximum: 300 }),
  ],
  lifetime: 6.0,
  loop: false,
  modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-75.597, 40.038)),
});
viewer.scene.primitives.add(firework);
更新コールバック(重力/風)

updateCallback は、重力などの力を適用するため、粒子ごとに毎フレーム実行されます。

const gravityScratch = new Cesium.Cartesian3();
function applyGravity(particle, dt) {
  Cesium.Cartesian3.normalize(particle.position, gravityScratch);
  Cesium.Cartesian3.multiplyByScalar(gravityScratch, -9.8 * dt, gravityScratch);
  particle.velocity = Cesium.Cartesian3.add(particle.velocity, gravityScratch, particle.velocity);
}

const system = new ParticleSystem({
  image: "smoke.png",
  emissionRate: 20,
  emitter: new ConeEmitter(Cesium.Math.toRadians(45)),
  updateCallback: applyGravity,
  modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-105, 40, 1000)),
});
viewer.scene.primitives.add(system);
地図が見えるようにパーティクルエフェクトを構図に収める

パーティクルエフェクトは、空や特徴のない背景ではなく、下にある地図を背景に目立たせる必要があります。よくある構図上の失敗は次の2つです。

  1. カメラが近すぎる+ピッチが浅い → 噴煙がフレームを埋め尽くし、その背後に地図が隠れます。
  2. カメラが急角度すぎる/真下に近い → 背の高い噴煙が塊のように平坦になり、発生源の形状が正しく見えません。

viewer.camera.lookAt と HeadingPitchRange を使用してエミッターを基準にし、地図のコンテキストが見える斜めの視点に調整します。

const position = Cartesian3.fromDegrees(-122.1944, 46.1914, 2549);
viewer.trackedEntity = undefined;
viewer.camera.lookAt(
  position,
  new Cesium.HeadingPitchRange(
    Cesium.Math.toRadians(35),   // heading
    Cesium.Math.toRadians(-22),  // oblique pitch preserves plume height
    6500                         // increase range until top and base fit
  )
);

ガイドライン:

  • 地図のコンテキストを垂直方向の広がりより重視する、地面に沿う短いエフェクトには、-35°から-60°のピッチを使用します。
  • 垂直方向のボリュームが重要な背の高い噴煙(火山の噴煙柱など)には、-10°から-30°のピッチを使用します。
  • エミッターの位置にビルボードまたはポイントを配置して、マーカー/発生源がフレーム内にあることを確認します。カメラの設定が適切でない場合、スクリーンショットにマーカーが表示されず、問題が明らかになります。
  • 噴煙の周囲に背景の地形が見える状態を保ちます。 粒子が画像の複数の端に触れている場合は、スクリーンショットを撮る前に、粒子のスケール、寿命、速度を小さくするか、カメラの距離を大きくしてください。
  • lookAt の前に viewer.trackedEntity = undefined を設定します。そうしないと、追跡対象のエンティティの参照フレームによってカメラの変換が上書きされます。

移動するモデルへのパーティクルのアタッチ

scene.preUpdate を介して、毎フレーム modelMatrix を同期します。ローカルオフセット(排気管など)には emitterModelMatrix を使用します。

const entity = viewer.entities.add({
  position: sampledPosition,
  orientation: new Cesium.VelocityOrientationProperty(sampledPosition),
  model: { uri: "truck.glb", minimumPixelSize: 64 },
});

// Local offset to exhaust pipe
const trs = new Cesium.TranslationRotationScale();
trs.translation = new Cesium.Cartesian3(-4.0, 0.0, 1.4);
const emitterModelMatrix = Cesium.Matrix4.fromTranslationRotationScale(trs, new Cesium.Matrix4());

const exhaust = new ParticleSystem({
  image: "smoke.png",
  startColor: Color.GRAY.withAlpha(0.7),
  endColor: Color.TRANSPARENT,
  emissionRate: 8,
  speed: 2.0,
  particleLife: 1.5,
  imageSize: new Cartesian2(20, 20),
  emitter: new CircleEmitter(0.5),
  emitterModelMatrix: emitterModelMatrix,
});
viewer.scene.primitives.add(exhaust);

viewer.scene.preUpdate.addEventListener((scene, time) => {
  exhaust.modelMatrix = entity.computeModelMatrix(time, new Cesium.Matrix4());
});

Canvas ベースのパーティクル画像

画像ファイルを読み込む代わりに、パーティクルテクスチャを動的に生成します。放射状グラデーションを使うと、煙や水のエフェクトに柔らかくリアルなエッジを付けられます。

// Soft radial-gradient particle (smoke, water, fog)
function createRadialParticle(size = 32, colorStop = "rgba(200,200,200,0.9)") {
  const c = document.createElement("canvas");
  c.width = c.height = size;
  const ctx = c.getContext("2d");
  const half = size / 2;
  const grad = ctx.createRadialGradient(half, half, 0, half, half, half);
  grad.addColorStop(0, colorStop);
  grad.addColorStop(1, "rgba(0,0,0,0)");
  ctx.fillStyle = grad;
  ctx.fillRect(0, 0, size, size);
  return c;
}

// Solid circle (high-contrast, fireworks, sparks)
function createCircleImage(size = 20) {
  const c = document.createElement("canvas");
  c.width = c.height = size;
  const ctx = c.getContext("2d");
  ctx.beginPath();
  ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
  ctx.fillStyle = "#fff";
  ctx.fill();
  return c;
}

// Pass canvas directly as image
new ParticleSystem({ image: createRadialParticle(), /* ...other options */ });

名前付きの色では足りない場合、特定のパーティクルの色には Color.fromCssColorString を使用します。

startColor: Cesium.Color.fromCssColorString("#66ccff").withAlpha(0.95),
endColor: Cesium.Color.WHITE.withAlpha(0.0),

Entity API モデル(ModelGraphics)

よりシンプルなユースケースでは、Entity API を通じてモデルを追加します(詳しくは cesiumjs-entities を参照してください)。

const entity = viewer.entities.add({
  name: "Aircraft",
  position: Cartesian3.fromDegrees(-123.074, 44.050, 5000),
  orientation: Cesium.Transforms.headingPitchRollQuaternion(
    Cartesian3.fromDegrees(-123.074, 44.050, 5000),
    new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(135), 0, 0)
  ),
  model: {
    uri: "CesiumAir.glb",
    minimumPixelSize: 128,
    maximumScale: 20000,
    silhouetteColor: Color.RED,
    silhouetteSize: 2.0,
  },
});
viewer.trackedEntity = entity;

viewer.trackedEntity による構図上のトレードオフ: 追跡するとモデルは中央に配置されますが、バウンディングスフィアから自動計算された距離が使用されるため、コンテキストが不足した近すぎるショットになりがちです。モデルと地図のコンテキスト(地形、ランドマーク、ラベル)の両方が求められるプロンプトでは、viewer.camera.flyTo/lookAt を使って位置を手動で指定し、先に viewer.trackedEntity = undefined を設定してください。


GPM 拡張(NGA_gpm_local)

CesiumJS は、NGA Geospatial Positioning Metadata glTF 拡張を実験的にサポートしています。型は AnchorPointDirect、AnchorPointIndirect、CorrelationGroup、GltfGpmLocal、Spdcf です。NGA_gpm_local を含む glTF の読み込み時に自動的に解析されます。API は実験段階であり、変更される可能性があります。


パフォーマンスのヒント

  1. .gltf より .glb を使用する -- バイナリ形式では余分な HTTP リクエストを回避でき、転送データ量も小さくなります。
  2. Draco 圧縮を有効にする(KHR_draco_mesh_compression)と、メッシュを 80~90% 小さくできます。
  3. KTX2/Basis テクスチャを使用する(KHR_texture_basisu)と、GPU 圧縮テクスチャを利用できます。寸法は 2 のべき乗にしてください。
  4. minimumPixelSize は慎重に設定する -- 値を大きくすると、遠くにあるモデルが強制的に拡大され、描画コストが増加します。
  5. シルエットの数を制限する -- シルエット付きのモデルごとに描画パスが追加されます。256 を超えるとステンシルアーティファクトが発生する場合があります。
  6. 一時的な Matrix4 オブジェクトを再利用する -- パーティクルシステムを移動するエンティティに同期する際、フレームごとの割り当てを避けられます。
  7. エミッションレートをエフェクトの密度に合わせる -- 噴水や炎のような密度の高い噴出には 200~1000/s のレートが必要になる場合があります。拡散する煙には 10~60/s が適しています。対象ハードウェアでプロファイリングしてください。
  8. ピクセルサイズのパーティクルを優先する(sizeInMeters: false、デフォルト)-- メートルサイズのパーティクルは近距離で描画コストが高くなります。
  9. パーティクルシステムに有限の lifetime を設定する -- Number.MAX_VALUE(デフォルト)では、プールがクリーンアップされません。
  10. 装飾用モデルではピッキングを無効にする -- 操作の必要がないモデルで allowPicking: false にすると、GPU メモリを節約できます。
  11. 使い終わったら破棄する -- viewer.scene.primitives.remove(model) の後に model.destroy() を呼び出すと、WebGL リソースを解放できます。

関連項目

  • cesiumjs-custom-shader -- Model.customShader 向けの GLSL 作成(構造体のリファレンス、フィーチャー ID、メタデータ、頂点の変位)
  • cesiumjs-materials-shaders -- ImageBasedLighting、モデル向けのポストプロセスステージ
  • cesiumjs-entities -- Entity API の ModelGraphics、データソース、時間依存プロパティ
  • cesiumjs-3d-tiles -- Cesium3DTileset(内部で Model を使用)、クリッピング、スタイリング

コメント