シーングラフの操作
TypeScript 用の Aspose.3D FOSS のすべての 3D コンテンツは、内部にあります Scene ツリー構造のオブジェクトとして編成されています Node オブジェクトです。この階層構造を理解することは、任意の 3D ファイルを構築、ロード、処理するための基礎です。.
インストール
このガイドのコードを実行する前に、npm からパッケージをインストールしてください::
npm install @aspose/3d確実に tsconfig.json が含まれています "module": "commonjs" と "moduleResolution": "node" 正しいサブパスインポート解決のために.
シーングラフの概念
シーングラフは 3 つの層から構成されています::
| ティア | クラス | ロール |
|---|---|---|
| シーン | Scene | トップレベルコンテナ。保持します rootNode, animationClips, および assetInfo. |
| ノード | Node | 名前付きツリーノード。子ノード、エンティティ、トランスフォーム、マテリアルを持つことができます。. |
| エンティティ | Mesh, Camera, Light, … | ノードに添付されたコンテンツ。ノードは最大で1つのエンティティを保持します。. |
主要な構成要素の継承チェーンは次のとおりです::
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode は自動的に作成されます。手動で作成する必要はありません;その下に子ノードを作成します。.
ステップ 1: シーンを作成する
import { Scene } from '@aspose/3d';
const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)
新しい Scene は空のルートノードとアニメーションクリップがない状態で開始します。子ノードを添付してコンテンツを構築します。.
ステップ 2: 子ノードを追加する
使用 createChildNode() ツリーを成長させます。メソッドは新しいものを返します Node,、したがって任意のレベルからさらに呼び出しをチェーンできます::
import { Scene } from '@aspose/3d';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
console.log(scene.rootNode.childNodes.length); // 1 (parent)
console.log(parent.childNodes.length); // 1 (child)
ノード名は任意の文字列です。名前が一意である必要はありませんが、意味のある名前を付けることでトラバーサルコードのデバッグが容易になります。.
ステップ 3: メッシュを作成し頂点を設定する
Mesh は主要なジオメトリクラスです。頂点位置はプッシュして追加します Vector4 値を mesh.controlPoints,、その後呼び出します createPolygon() 頂点インデックスで面を定義します::
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4 } from '@aspose/3d/utilities';
const scene = new Scene();
const child = scene.rootNode.createChildNode('parent').createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3); // quad face using all four vertices
child.entity = mesh;
console.log(mesh.controlPoints.length); // 4
console.log(mesh.polygonCount); // 1
Vector4 は同次座標を使用します:その w 成分は 1 位置用で、 0 方向ベクトル用です。.
ステップ 4: ノードの変換を設定する
各ノードは transform プロパティを持ち、 translation, rotation,、および scaling.。設定 translation ノードを親に対して相対的に移動させるには:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;
child.transform.translation = new Vector3(2.0, 0.0, 0.0);globalTransform は、すべての祖先変換を連結して計算された、ワールド空間変換行列(読み取り専用)を提供します。.
ステップ 5: ツリーを走査する
すべてのノードを訪問する再帰関数を書きます。チェック node.entity と node.childNodes 各レベルで:
function traverse(node: any, depth = 0): void {
const indent = ' '.repeat(depth);
const entityType = node.entity ? node.entity.constructor.name : 'none';
console.log(`${indent}${node.name} [${entityType}]`);
for (const child of node.childNodes) {
traverse(child, depth + 1);
}
}
traverse(scene.rootNode);上記で作成した階層に対する出力は次のようになります:
[none]
parent [none]
child [Mesh]ルートノードの名前は空文字列です。なぜなら Scene は名前引数なしで作成します。.
エンティティにアクセスする際は、特定の型にキャストする前に必ず null チェックで保護してください。すべてのノードがエンティティを持つわけではありません。.
ステップ 6: glTF または GLB に保存する
使用 GltfSaveOptions で出力形式を制御します。設定 binaryMode = true 単一の自己完結型を生成するために .glb ファイル; そのままにしておく false JSON 用に .gltf + .bin サイドカー ペア:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;
child.transform.translation = new Vector3(2.0, 0.0, 0.0);
const saveOpts = new GltfSaveOptions();
saveOpts.binaryMode = true; // write a single .glb file
scene.save('scene.glb', GltfFormat.getInstance(), saveOpts);
console.log('Scene saved to scene.glb');渡す GltfFormat.getInstance() format 引数として渡すことで、ファイル拡張子に関係なくライブラリが正しいエンコーダを使用します。.
ヒントとベストプラクティス
- 使用する
createChildNode()構築する代わりにNode直接:createChildNode()親子関係を自動的に接続し、ツリーにノードを登録します。. - 確認する
node.entityエンティティのプロパティにアクセスする前に::多くのノード(グループノード、ボーン、ロケーター)はエンティティを持ちません。必ず null チェックやinstanceofテスト。. - 設定
translation子ノードに対して、メッシュの頂点には設定しません::変更transform.translationは破壊的ではなく、親の変換と合成可能です。. - 推奨
binaryMode = trueGLB 用に::単一の.glbファイルは、分割されたものより配布やブラウザでの読み込み、ゲームエンジンへのインポートが容易です.gltf+.binフォーマット。. - 経由で走査
for...of上でchildNodes: 数値インデックスは避け、将来の互換性のためにイテラブルを直接使用してください。.
一般的な問題
| 症状 | 考えられる原因 | 修正 |
|---|---|---|
child.entity = mesh エクスポートに影響しません | エンティティが誤ったノードレベルに割り当てられています | 割り当て entity リーフノードに割り当て、グループノードには割り当てないでください |
node.entity は常に null | チェックのみ rootNode それ自体 | 再帰的に入る node.childNodes; rootNode 通常はエンティティがありません |
| 変換がGLBビューアに反映されていません | globalTransform 更新されていません | globalTransform 保存時に計算されます; 設定 transform.translation 呼び出す前に scene.save() |
GLBは別個の .bin サイドカー | binaryMode デフォルトは false | 設定 saveOpts.binaryMode = true |
関連項目
- 機能と機能性: すべての機能領域の完全な API リファレンス。.
- フォーマットサポート: サポートされている 3D フォーマット、読み書き機能、フォーマットオプション。.
- プログラムで3D Meshを構築する方法