mcpField
A
add-3d-models

add-3d-models

github.com/dcl-regenesislabsクリエイティブ・メディア1742 回インストール21 週間前に更新
リポジトリ

add-3d-models について

Decentralandのシーン制作者向けに、3Dモデルの配置と設定を案内するスキルです。静的・実行時エンティティ、コライダー、モデルカタログ検索、読み込み時の問題を扱います。

主な機能

  1. 01main-entities.tsへの静的モデル配置
  2. 02GLTFとメッシュコライダーの設定
  3. 03カタログモデルの検索とダウンロード
  4. 04モデルの変換と親エンティティの設定
  5. 05読み込みや表示の問題の診断

活用シーン

  1. 01Decentralandシーンへの静的な小道具の追加
  2. 02実行時のモデル生成
  3. 03シーン用モデルの検索
  4. 04モデルが見えない・クリックできない問題の診断

インストール

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

$npx skills add https://github.com/dcl-regenesislabs/opendcl --skill add-3d-models

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

詳細

Decentraland シーンへの 3D モデルの追加

モデルの配置先:main-entities.ts

作成時に配置する 3D モデルは、静的な表示エンティティです。src/index.ts で engine.addEntity() を使うのではなく、main-entities.ts で宣言してください。ビルド時に main-entities.ts は main.crdt にコンパイルされ、エンジンは main() の実行前にこれをプリロードするため、エディターでモデルをドラッグしたり、回転させたりできます。

// main-entities.ts
import type { Scene } from '@dcl/sdk/scene-types'

export const scene = {
  my_model: {
    components: {
      Transform: { position: { x: 8, y: 0, z: 8 } },
      GltfContainer: {
        src: 'models/myModel.glb',
        visibleMeshesCollisionMask: 3 // CL_PHYSICS | CL_POINTER
      }
    }
  }
} satisfies Scene

GltfContainer では、必ず visibleMeshesCollisionMask を設定してください。カタログのモデルには個別のコライダーメッシュが含まれていません。表示メッシュをコライダーとして使うことで、モデルが実体を持ち、クリックできるようになります。リテラル内では列挙型を使用できないため、main-entities.ts では整数値(ColliderLayer.CL_PHYSICS = 1、CL_POINTER = 2、両方の場合は 3)を使ってください。

代わりに src/index.ts で engine.addEntity() を使う場合:モデルを動的に生成する場合(ループ内でプロシージャルに配置する、イベント時に出現させる、NFT の所有権を条件とするなど)のみにしてください。静的な小道具には、必ず main-entities.ts を使用してください。

ファイル構成

プロジェクトのルートにある models/ ディレクトリにモデルファイルを配置します。

project/
├── models/
│   ├── building.glb
│   ├── tree.glb
│   └── furniture/
│       ├── chair.glb
│       └── table.glb
├── src/
│   └── index.ts
└── scene.json

コライダー

モデルに組み込まれたコライダーの使用
// main-entities.ts — declared inline with GltfContainer
building: {
  components: {
    Transform: { position: { x: 8, y: 0, z: 8 } },
    GltfContainer: {
      src: 'models/building.glb',
      visibleMeshesCollisionMask: 3,    // CL_PHYSICS | CL_POINTER
      invisibleMeshesCollisionMask: 1   // CL_PHYSICS
    }
  }
}
シンプルなコライダーの追加

基本図形(GLTF なし)の場合は、MeshCollider を追加します。

// main-entities.ts
invisible_wall: {
  components: {
    Transform: { position: { x: 0, y: 1, z: 8 }, scale: { x: 0.1, y: 2, z: 16 } },
    MeshCollider: { mesh: { $case: 'box', box: { uvs: [] } } }
  }
}

その他の形状:{ $case: 'sphere', sphere: {} }、{ $case: 'plane', plane: { uvs: [] } }、{ $case: 'cylinder', cylinder: {} }。

⚠️ 重要:Transform フィールドに undefined を渡さないでください

Transform フィールド(position、rotation、scale)が存在するにもかかわらず undefined の場合、SDK のシリアライザーはクラッシュします。代わりに、キー自体を省略してください。これは main-entities.ts のリテラルと、実行時のヘルパーの両方に当てはまります。main-entities.ts では、フィールドを記述しなければよいので自然に対応できます。

モデルの一般的な操作

スケーリング
// main-entities.ts
big_statue: {
  components: {
    Transform: { position: { x: 8, y: 0, z: 8 }, scale: { x: 2, y: 2, z: 2 } },
    GltfContainer: { src: 'models/statue.glb' }
  }
}
回転(オイラー角を作成時にクォータニオンへ変換)

クォータニオンは { x, y, z, w } です。Quaternion.fromEulerDegrees(0, 90, 0) に相当するリテラルは { x: 0, y: 0.7071, z: 0, w: 0.7071 } です。正確な角度で回転させる必要があり、手計算を避けたい場合は、main-entities.ts で rotation を単位回転に設定し、src/index.ts で実行時に Transform.getMutable(entity).rotation = Quaternion.fromEulerDegrees(0, 90, 0) を使って回転させてください。

親子関係

親は名前(同じ scene オブジェクト内の文字列キー)で参照します。ビルドでは、2 回目の処理で名前がエンティティ ID に解決されます。

// main-entities.ts
character: {
  components: {
    Transform: { position: { x: 8, y: 0, z: 8 } },
    GltfContainer: { src: 'models/character.glb' }
  }
},
hat: {
  components: {
    Transform: {
      position: { x: 0, y: 2, z: 0 },  // 2m above parent's origin
      parent: 'character'
    },
    GltfContainer: { src: 'models/hat.glb' }
  }
}

無料の 3D モデル — OpenDCL カタログ(5,700 以上のモデル)

カタログファイルは {baseDir}/references/model-catalog.md にあります。各行の形式は次のとおりです。

slug | dims | tris | size | category/sub | description [tags] [anim: clips] | curl command | preview: thumbnail_url
検索方法

一度に 1 つのキーワードで検索してください。まず最も具体的な語を試します。

grep -i "zombie" {baseDir}/references/model-catalog.md

結果がない場合は、類義語、より広い用語、関連語を試してください。

  • "sofa" → "couch" → "seat" → "furniture"
  • "car" → "vehicle" → "truck" → "van"
  • "wall" → "fence" → "barrier" → "structure"

すべてのカテゴリを確認して、利用可能なものを探します。

grep "^##" {baseDir}/references/model-catalog.md

特定のカテゴリ内を検索します。

grep "^##\|chair" {baseDir}/references/model-catalog.md
モデルの使い方
  1. 条件に合うモデルが見つかるまで、カタログで異なるキーワードを検索します
  2. 検索結果を確認します。寸法、三角形の数、アニメーション、説明をチェックしてください
  3. curl コマンドを使ってモデルを models/ にダウンロードします
  4. GltfContainer.create(entity, { src: 'models/{slug}.glb' }) でコードから参照します
  5. モデルにアニメーション([anim: ...] に記載)がある場合は、Animator コンポーネントを使って再生します
  6. モデルを配置した後、プレビューサムネイル(preview: URL)を取得して、モデルの見た目を確認できます
ワークフローの例
# Search for zombie models
grep -i "zombie" {baseDir}/references/model-catalog.md

# Found: zombie-purple | 2.8×2.9×0.5m | 1472 tri | 271KB | character/zombie | ...
#   [anim: Tpose, ZombieAttack, ZombieUP, ZombieWalk]
#   preview: https://models.dclregenesislabs.xyz/blobs/bafkrei...

# Download the model
curl -o models/zombie-purple.glb "https://models.dclregenesislabs.xyz/blobs/bafybeiffc..."
// main-entities.ts — declare the entity with all its initial state
import type { Scene } from '@dcl/sdk/scene-types'

export const scene = {
  zombie: {
    components: {
      Transform: { position: { x: 8, y: 0, z: 8 } },
      GltfContainer: { src: 'models/zombie-purple.glb' },
      Animator: {
        states: [
          { clip: 'ZombieWalk', playing: true, loop: true },
          { clip: 'ZombieAttack', playing: false, loop: false }
        ]
      }
    }
  }
} satisfies Scene

実行時にアニメーションを切り替える場合(例:クリック時に攻撃を発動させる場合)は、src/index.ts を使用します。

import { engine, Animator } from '@dcl/sdk/ecs'

export function main() {
  const zombie = engine.getEntityOrNullByName('zombie')
  if (zombie) Animator.playSingleAnimation(zombie, 'ZombieAttack')
}

重要:GltfContainer が使用できるのはローカルファイルのみです。モデルの src フィールドに外部 URL を使わないでください。必ず先にモデルを models/ にダウンロードしてください。 models ディレクトリに cd しないでください。必ずプロジェクトのルートから curl -o models/slug.glb "URL" を実行します。cd models && curl -o slug.glb は使用しないでください。

モデルの読み込み状態の確認

読み込み状態のポーリングは実行時の動作です。src/index.ts に記述し、エンティティを名前で参照してください。

import { engine, GltfContainerLoadingState, LoadingState } from '@dcl/sdk/ecs'

export function main() {
  engine.addSystem(() => {
    const model = engine.getEntityOrNullByName('zombie')
    if (!model) return
    const state = GltfContainerLoadingState.getOrNull(model)
    if (state?.currentState === LoadingState.FINISHED) {
      console.log('Model loaded successfully')
    } else if (state?.currentState === LoadingState.FINISHED_WITH_ERROR) {
      console.log('Model failed to load')
    }
  })
}

トラブルシューティング

問題原因解決策
モデルが表示されないファイルパスが間違っているプロジェクトのルートからの相対パス(例:models/myModel.glb)にファイルが存在することを確認してください
モデルが表示されないシーンの境界外に配置されているTransform の位置が区画ごとに 0~16 の範囲内にあることを確認してください。1 区画のシーンの中心は (8, 0, 8) です
モデルが表示されないスケールが 0 または非常に小さいTransform.scale を確認してください。デフォルトは (1,1,1) です。モデルが非常に小さくエクスポートされている場合は、より大きな値を試してください
モデルが表示されないカメラの後ろにあるアバターを移動するか、モデルの方向を向くように回転させてください
モデルは読み込まれるが、見た目がおかしいY-up と Z-up の不一致Decentraland では Y-up を使用します。Blender から「Y Up」にチェックを入れて再エクスポートしてください
読み込み状態が「FINISHED_WITH_ERROR」.glb が破損しているか、サポートされていないモデルを再エクスポートしてください。.glb(バイナリ GLTF)形式を使用し、サポートされていない拡張機能がないことを確認してください
モデルをクリックしても何も起きないコライダーがないGltfContainer に visibleMeshesCollisionMask: ColliderLayer.CL_POINTER を追加するか、MeshCollider を追加してください

シーンの制限に合わせてモデルを最適化する必要がありますか? 三角形ポリゴンの予算と LOD パターンについては、optimize-scene スキルをご覧ください。 モデルにアニメーションを追加する必要がありますか? Animator を使用して GLTF アニメーションクリップを再生する方法については、animations-tweens スキルをご覧ください。

モデルのベストプラクティス

  • 読み込み時間を短縮するため、モデルはファイルごとに 50MB 未満にしてください
  • .glb 形式(バイナリ GLTF)を使用してください。.gltf よりサイズが小さくなります
  • 三角形ポリゴン数を最適化してください。小さな小道具では、モデルあたり 1,500 個未満を目指してください
  • 可能な場合はテクスチャアトラスを使用して、描画呼び出しを減らしてください
  • アニメーションが埋め込まれたモデルは、Animator コンポーネントで再生できます
  • モデルの向きをテストしてください。Decentraland では Y-up 座標系を使用します
  • 最良の結果を得るには、モデルのマテリアルに PBR(物理ベースレンダリング)を使用してください

コメント