mcpField
T
threejs-core-scene-graph

threejs-core-scene-graph

github.com/impertio-studio開発23138 回インストール30 週間前に更新
リポジトリ

threejs-core-scene-graph について

threejs-core-scene-graphは、Three.jsのシーングラフを扱う開発者向けのリファレンススキルです。オブジェクト階層、変換、走査、レンダリングレイヤー、リソース管理上の注意点を解説します。

主な機能

  1. 01Object3Dの階層と変換
  2. 02Scene、Group、Meshの使い方
  3. 03走査とワールド行列の更新
  4. 04描画とレイキャスト用レイヤー
  5. 05シーンのフォグと環境設定
  6. 06リソース解放時の注意点

活用シーン

  1. 01Three.jsシーン内のオブジェクト整理
  2. 02親の変更時にワールド位置を維持
  3. 03フレーム途中でワールド座標を取得
  4. 04オブジェクトとGPUリソースの安全な管理

インストール

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

$npx skills add https://github.com/impertio-studio/three.js-claude-skill-package --skill threejs-core-scene-graph

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

.gitkeep
references/
anti-patterns.md
examples.md
methods.md

詳細

threejs-core-scene-graph

クイックリファレンス

シーングラフの階層
クラス継承元目的
Object3DEventDispatcherすべての 3D オブジェクトの基底クラスです。トランスフォーム、階層構造、走査機能を提供します
SceneObject3Dルートコンテナーです。背景、環境、フォグ、overrideMaterial を追加します
GroupObject3D追加機能を持たない、意味的なコンテナーです。論理的なグループ化に使用します
MeshObject3Dジオメトリ + マテリアルです。シーン内で主要な可視オブジェクトです
CameraObject3Dビュープロジェクションです。行列を更新するため、必ずシーンに追加してください
LightObject3D照明です。レンダリングするため、必ずシーンに追加してください
Object3D のコアプロパティ
プロパティ型デフォルト説明
positionVector3(0,0,0)親に対するローカル位置
rotationEuler(0,0,0,'XYZ')ローカル回転です。quaternion と連動しており、一方を変更すると必ずもう一方も更新されます
quaternionQuaternion(0,0,0,1)クォータニオンによるローカル回転です。rotation と連動しています
scaleVector3(1,1,1)ローカルスケールです。不均一なスケールは法線の歪みを引き起こします
visiblebooleantruefalse の場合、レンダリング時にオブジェクトとすべての子孫がスキップされます
layersLayerslayer 0レンダリングとレイキャスティングを選択的に行うための 32 ビットビットマスクです
castShadowbooleanfalseオブジェクトが影を落とすかどうか
receiveShadowbooleanfalseオブジェクトが影を受けるかどうか
frustumCulledbooleantrueスカイボックスや必ずレンダリングする必要があるオブジェクトでは false に設定します
renderOrdernumber0値が大きいほど後にレンダリングされます。透明度のソートに使用します
namestring""人が読めるラベルです。検索には getObjectByName() を使用します
userDataobject{}アプリケーション固有のカスタムデータ辞書です
識別プロパティ
プロパティ型説明
uuidstring読み取り専用の RFC 4122 v4 識別子です。自動生成されます
idnumber自動インクリメントされる整数です。実行セッションごとに一意です
namestringユーザーが設定します。一意の識別子としては絶対に使用しないでください
typestring読み取り専用のクラス名です(例:"Mesh"、"Group")
重要な警告

children 配列を直接変更してはいけません。必ず add()、remove()、clear()、または attach() を使用してください。直接変更すると、内部管理(親参照、イベントディスパッチ)が壊れます。

traverse() の実行中に children 配列を変更してはいけません。オブジェクトを先に収集し、走査が完了してから変更してください。走査中に追加すると、予測不能な反復処理が発生します。

ワールド座標を維持する必要のあるオブジェクトの親を変更するときに、add() を使用してはいけません。代わりに必ず attach() を使用してください。add() はローカルトランスフォームを維持し、attach() はワールドトランスフォームを維持します。

同じフレーム内で位置/回転/スケールを変更した後、先に updateWorldMatrix(true, false) を呼び出さずに matrixWorld を読み取ってはいけません。次のレンダリングまたは明示的な更新が行われるまで、ワールド行列は古い状態です。

手動で破棄せずに Three.js オブジェクトを userData に保存してはいけません。dispose() は userData を自動的にはクリーンアップしません。

オブジェクトを削除するときに、テクスチャ、ジオメトリ、マテリアルの破棄を忘れてはいけません。remove() と clear() はシーングラフから切り離すだけで、GPU メモリを解放しません。


階層メソッド

add() と attach() の違い — 重要
import { Scene, Group, Mesh, BoxGeometry, MeshStandardMaterial } from 'three';

const scene = new Scene();
const groupA = new Group();
const groupB = new Group();
groupA.position.set(10, 0, 0);
groupB.position.set(0, 5, 0);
scene.add(groupA, groupB);

const mesh = new Mesh(new BoxGeometry(), new MeshStandardMaterial());
mesh.position.set(0, 0, 0);
groupA.add(mesh);
// mesh world position = (10, 0, 0) -- inherited from groupA

// WRONG: add() preserves LOCAL transform -- mesh jumps to (0, 5, 0) world
groupB.add(mesh); // auto-removes from groupA first

// CORRECT: attach() preserves WORLD transform -- mesh stays at (10, 0, 0) visually
groupA.add(mesh); // reset
groupB.attach(mesh); // mesh.position is recalculated to maintain world position
remove()、removeFromParent()、clear()
// Remove specific children
group.remove(meshA, meshB);

// Remove self from parent (safe when parent is null)
mesh.removeFromParent();

// Remove ALL children -- ALWAYS prefer over manual iteration
group.clear();

エッジケース: オブジェクトが子ではない場合でも、remove() は例外をスローせず、何もせずに終了します。


走査

// Depth-first traversal of ALL descendants
scene.traverse((object) => {
  if (object.isMesh) {
    object.castShadow = true;
  }
});

// Skip invisible objects and their subtrees
scene.traverseVisible((object) => {
  // only visits objects where visible === true
});

// Walk UP to root (does NOT include the starting object)
mesh.traverseAncestors((ancestor) => {
  console.log(ancestor.name);
});

// Find by name, id, or arbitrary property
const wall = scene.getObjectByName('north-wall');
const obj = scene.getObjectById(42);
const selectable = scene.getObjectByProperty('userData', { selectable: true });

パフォーマンス: すべての検索メソッドは O(n) です。頻繁に検索する場合は、必ず参照をキャッシュしてください。


行列システム

自動モード(デフォルト)

レンダラーは各レンダリングの前にシーンで updateMatrixWorld() を呼び出し、再帰的に次の処理を行います。

  1. 各オブジェクトで updateMatrix() を呼び出します(位置/回転/スケールから matrix を合成します)。
  2. matrixWorld = parent.matrixWorld * matrix を計算します。
手動モード(パフォーマンス最適化)
// For static objects -- skip per-frame matrix recomputation
object.matrixAutoUpdate = false;
object.matrix.compose(position, quaternion, scale);
object.matrixWorldNeedsUpdate = true;
フレームの途中でワールド空間の値を読み取る
import { Vector3, Quaternion } from 'three';

object.position.set(10, 0, 0);
object.updateWorldMatrix(true, false); // update parents first

const worldPos = new Vector3();
object.getWorldPosition(worldPos);

const worldQuat = new Quaternion();
object.getWorldQuaternion(worldQuat);

const worldScale = new Vector3();
object.getWorldScale(worldScale);

const worldDir = new Vector3();
object.getWorldDirection(worldDir);
座標変換
// MUTATION WARNING: both methods modify the input vector in-place
const localPoint = new Vector3(5, 0, 0);
object.localToWorld(localPoint); // localPoint is now in world coordinates

const worldPoint = new Vector3(15, 3, 0);
object.worldToLocal(worldPoint); // worldPoint is now in object's local coordinates

Scene クラス

import { Scene, Color, Fog, FogExp2, TextureLoader } from 'three';

const scene = new Scene();
scene.background = new Color(0x222222);         // solid color
scene.environment = hdrTexture;                  // IBL for all PBR materials
scene.environmentIntensity = 1.5;                // boost environment lighting
scene.environmentRotation.set(0, Math.PI, 0);   // rotate environment
scene.fog = new Fog(0xcccccc, 10, 100);         // linear fog
scene.overrideMaterial = depthMaterial;          // debug: force all objects to one material
プロパティ型デフォルト説明
backgroundColor | Texture | CubeTexture | nullnullシーンの背景
environmentTexture | nullnull独自の envMap を持たないすべての PBR マテリアル用の IBL 環境マップ
fogFog | FogExp2 | nullnullシーンのフォグ効果
overrideMaterialMaterial | nullnullすべてのオブジェクトにこのマテリアルを強制的に適用します
backgroundBlurrinessnumber0背景のぼかし(0~1)
backgroundIntensitynumber1背景の明るさの倍率
backgroundRotationEuler(0,0,0)背景の回転
environmentIntensitynumber1環境マップの明るさの倍率
environmentRotationEuler(0,0,0)環境マップの回転

Fog

Fog(線形補間)
import { Fog } from 'three';
scene.fog = new Fog(0xffffff, 10, 200); // color, near, far
FogExp2(指数密度)
import { FogExp2 } from 'three';
scene.fog = new FogExp2(0xffffff, 0.01); // color, density

マテリアルとの相互作用: すべてのマテリアルには fog プロパティがあります(デフォルト:true)。ShaderMaterial と RawShaderMaterial のデフォルトは fog: false です。カスタムシェーダーにフォグを反映させるには、必ず fog: true を設定し、フォグのシェーダーチャンクを手動で含める必要があります。


Group

Group は追加機能を持たずに Object3D を拡張します。オブジェクトを整理するためのセマンティックなコンテナーとしてのみ存在します。

import { Group } from 'three';

const buildingGroup = new Group();
buildingGroup.name = 'building-01';
buildingGroup.add(walls, roof, foundation);
scene.add(buildingGroup);

// Transform all children together
buildingGroup.position.set(50, 0, 0);
buildingGroup.rotation.y = Math.PI / 4;

Mesh

Mesh は BufferGeometry と Material を組み合わせて、可視の表面を作成します。

import { Mesh, BoxGeometry, MeshStandardMaterial } from 'three';

const mesh = new Mesh(
  new BoxGeometry(1, 1, 1),
  new MeshStandardMaterial({ color: 0x00ff00 })
);

// Multi-material with geometry groups
const materials = [materialA, materialB];
geometry.addGroup(0, 36, 0);   // start, count, materialIndex
geometry.addGroup(36, 36, 1);
const multiMesh = new Mesh(geometry, materials);

// Morph targets
mesh.morphTargetInfluences[0] = 0.5; // blend between base and morph target

Layers システム

選択的なレンダリングとレイキャスティングのための32ビットビットマスクシステムです。

import { Layers } from 'three';

// Objects are on layer 0 by default
mesh.layers.set(1);        // ONLY layer 1 (removes from layer 0)
mesh.layers.enable(2);     // add layer 2 (keep layer 1)
mesh.layers.disable(1);    // remove layer 1
mesh.layers.toggle(3);     // flip layer 3

// Camera renders only objects with overlapping layers
camera.layers.enable(1);   // camera now sees layers 0 AND 1

// Test overlap
const visible = camera.layers.test(mesh.layers); // true if any layer overlaps

使用例:

  • レイヤー0:デフォルトで表示されるオブジェクト
  • レイヤー1:ヘルパー/ギズモ(本番環境のカメラでは無効にします)
  • レイヤー2:ブルーム専用オブジェクト(選択的なポストプロセッシング)
  • レイヤー3~31:カスタム用途(衝突グループ、選択セット、LOD グループ)

lookAt() の動作の違い

// Camera: points NEGATIVE-Z toward target (looks AT the target)
camera.position.set(0, 5, 10);
camera.lookAt(0, 0, 0);

// Non-camera objects: points POSITIVE-Z toward target
mesh.lookAt(targetPosition);

position を設定した後は、必ず lookAt() を呼び出してください。現在の位置から回転を計算します。


参考リンク

公式ソース

コメント