メインコンテンツまでスキップ

<pc-model>

<pc-model>タグは、GLBファイルから3Dモデルをインスタンス化するエンティティを定義するために使用されます。

エクスポート、圧縮メッシュ、ファイルの中身の調査、そしてその調整といったワークフロー全体の解説は、モデルの読み込みを参照してください。

使用法
  • <pc-scene>または<pc-entity>の直接の子である必要があります。
  • 0からn個の<pc-node>の子を持つことができます。それぞれがインスタンス化された階層内のノードにバインドし、そのノードをオーバーライドしたり、コンポーネントを追加したり、その下に新しいコンテンツをアタッチします。

属性

<pc-entity>のすべての属性も利用可能です。

属性タイプデフォルト説明
assetString-コンテナアセットID (container型のアセットを参照する必要があります)

イベント

これらのイベントは、addEventListener()を使用するか、このインターフェースのoneventnameプロパティにイベントリスナーを割り当てることでリッスンできます。

イベント説明
loadコンテナアセットのインスタンス化が完了するたびに発生します。assetの変更後の再インスタンス化も含みます。
errorコンテナアセットの読み込みが失敗したときに発生するErrorEventで、エンジンのエラーがmessageに入ります。

どちらのイベントもバブリングしないため、要素自身でリッスンしてください。あるいは、ページ上のすべてのモデルを監視するには、祖先要素でキャプチャフェーズのリスナーを使用します。

要素は階層がインスタンス化されてシーンに追加された時点でreadyになるため、readyな<pc-model>は常に有効なワールドトランスフォームを持つ非nullのentityを持ちます。読み込みが失敗した場合もreadyは確定し、entitynullのままになります。readyであることは読み込みが決着したことを意味し、成功したことを意味しません。両者を区別するにはerrorをリッスンする(またはentityを確認する)必要があります。

アニメーション

コンテナのアニメーションは、モデルの内側に<pc-anim>をネストすると再生されます。ファイルに入っていたものを得るには空のタグ1つで十分です。コンテナ内のすべてのアニメーションが、それぞれのトラック名を名前としてクリップになり、最初のものが再生を始めます。

<pc-entity name="robot">
<pc-model asset="robot">
<pc-anim></pc-anim>
</pc-model>
</pc-entity>

<pc-entity>のラッパーは飾りではありません。コンポーネントはインスタンス化されたルートではなく、最も近い外側のエンティティに取り付けられます。そのため、<pc-scene>の直下に置かれた<pc-model>にはコンポーネントの置き場所がなく、代わりに警告が出ます。クリップに自分で名前を付ける、クリップごとの速度やループを設定する、他のファイルからクリップを取得する、といった場合は<pc-anim-clip>を子として追加してください。

ファイルのアニメーションがエクスポートを通過したかを確認するには、コンポーネントに尋ねます。

import { whenReady } from '@playcanvas/web-components';

const anim = await whenReady('pc-anim');
console.log(anim.clips); // ['Walk', 'Idle']

パッケージ名でインポートするには、ページのimport mapに@playcanvas/web-componentsが必要です。プログラムによるアクセスを参照してください。アニメーションを含まないコンテナはモデル名を含む警告をログに出力するため、コードを書かずにコンソールで同じことを確認できます。

モデルの内側にネストした<pc-anim>が再生する、スケルタルアニメーション付きのGLBです。ドラッグで軌道回転できます:

ライブサンプル
<pc-app>
<pc-asset src="https://cdn.jsdelivr.net/npm/playcanvas@2.21.4/scripts/esm/camera-controls.mjs"></pc-asset>
<pc-asset src="https://developer.playcanvas.com/assets/t-rex.glb" id="t-rex"></pc-asset>
<pc-material id="floor" diffuse="#3a3f4b"></pc-material>
<pc-scene>
<pc-entity name="camera" position="2.5 1.5 3.5">
<pc-camera clear-color="#2a2d36"></pc-camera>
<pc-scripts>
<pc-script name="cameraControls" focus-point="0 1.2 0" pitch-range="-90 0" zoom-range="1.5 10"></pc-script>
</pc-scripts>
</pc-entity>
<pc-entity name="light" rotation="45 30 0">
<pc-light cast-shadows shadow-distance="20" intensity="1.5"></pc-light>
</pc-entity>
<pc-entity name="ground" scale="30 30 30">
<pc-render type="plane" material="floor"></pc-render>
</pc-entity>
<pc-entity name="t-rex" scale="1.5 1.5 1.5">
<pc-model asset="t-rex">
<pc-anim></pc-anim>
</pc-model>
</pc-entity>
</pc-scene>
</pc-app>

読み込まれた階層の内部に手を入れるには、変更したいノードごとに<pc-node>をネストします。

<pc-model asset="car">
<!-- GLBに含まれていた地面プレーンを非表示にします -->
<pc-node name="Plane" enabled="false"></pc-node>
</pc-model>

JavaScriptインターフェース

ModelElement APIを使用して、<pc-model>要素をプログラムで作成および操作できます。

階層の調査

hierarchy()メソッドは、インスタンス化されたツリーを実際に存在するとおりに報告します。これが<pc-node>が解決に用いる語彙であり、ソースアセットのノード名から想像されるものとは必ずしも一致しません。モデルの読み込みが実例で解説しています。こちらはリファレンスです。出力は1行で済みます。

import { whenReady } from '@playcanvas/web-components';

const model = await whenReady('pc-model');
console.log(String(model.hierarchy()));
Car
├─ FrontAxle
│ └─ Wheel [0] (render) {defaultGlbMaterial}
├─ RearAxle
│ └─ Wheel [1] (render) {defaultGlbMaterial}
├─ Wing
└─ Wing1

各行が1つのノードです。名前、その名前を他のノードと共有している場合は[index]、括弧内に持っているコンポーネントのタイプ、そして波括弧内にrenderコンポーネントのマテリアルが並びます。したがって上の2つのホイールには<pc-node name="Wheel" index="0"><pc-node name="Wheel" index="1">で到達でき、Wing1はエンジンが階層を構築する際に2つ目のWing兄弟をリネームして区別したものです。

hierarchy()はプレーンなデータツリーのルートノードを返します。インスタンス化されたものが何もない間 — コンテナアセットの読み込み前、読み込みが失敗した後、要素がドキュメントから外れた後 — はnullを返します。各ノードは次を持ちます。

プロパティタイプ説明
nameStringインスタンス化された時点でのノード名で、<pc-node>が検索する名前です。ソースアセット内の名前と異なる場合があります。エンジンは名前のないノードにnode_<index>という名前を合成し、同名の兄弟をリネームして区別するためです
pathStringモデルルート以下のノードの/区切りのパスで、そのノードにバインドした<pc-node>が報告するpathです。ルートのパスはそれ自身の名前です
indexNumber同じ名前を共有するノードの中でのこのノードの位置。モデル全体を深さ優先順で数えたもので、<pc-node>indexが選択する一致項目そのものです
componentsString[]ノードにアタッチされているコンポーネントのタイプ(renderなど)。ソート済みです
materialsObject[]ノードのrenderコンポーネントのメッシュインスタンス1つごとに{ index, name }エントリが1つ、コンポーネント順に並びます。renderコンポーネントを持たないノードでは空です
childrenObject[]ノードの子ノード
toString()Functionこのノードをルートとするサブツリーを上記の印字可能なツリーとして描画します。String(node)でどの枝でも出力できます

マテリアルのname値はそのまま読み取られる実行時のラベルであり、便利な手掛かりではあるものの一意ではありません。名前のないglTFマテリアルはUntitledと呼ばれ、マテリアルなしでオーサリングされたプリミティブはエンジンが共有するdefaultGlbMaterialを持ち、重複はそのまま重複し、スクリプトが割り当てを解除した場合は名前はnullになります。一意なのはindexです。どちらも<pc-node>material-overridesが選択に用いるもので、差し替えた<pc-material>name属性の内容をそのまま報告します。ここで識別したいマテリアルには設定しておく価値があります。

このツリーはスナップショットであり、呼び出しごとに新しく計算されます。その後の階層の変更を追跡することはなく、変更を加えても何も起こりません。プレーンなデータであるためJSON.stringifyを通過でき、ログ出力・差分比較・テストでの検証が容易です。