返回 Skill 列表
extension
分类: 开发与工程无需 API Key

add-3d-models

使用GltfContainer将3D模型(.glb/.gltf)添加到Decentraland场景中。涵盖加载模型、定位、缩放、碰撞器设置,以及浏览开源的3D资产目录以寻找免费的CC0模型。当用户想要添加模型、导入GLB文件或寻找免费的3D资源时使用。

person作者: jakexiaohubgithub

Adding 3D Models to Decentraland Scenes

Loading a 3D Model

Use GltfContainer to load .glb or .gltf files:

import { engine, Transform, GltfContainer, ColliderLayer } from '@dcl/sdk/ecs'
import { Vector3, Quaternion } from '@dcl/sdk/math'

const model = engine.addEntity()
Transform.create(model, {
  position: Vector3.create(8, 0, 8),
  rotation: Quaternion.fromEulerDegrees(0, 0, 0),
  scale: Vector3.create(1, 1, 1)
})
GltfContainer.create(model, {
  src: 'models/myModel.glb',
  visibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS | ColliderLayer.CL_POINTER
})

Always set visibleMeshesCollisionMask when loading models. Catalog models don't include separate collider meshes — using the visible mesh as the collider ensures the model is solid and clickable.

File Organization

Place model files in a models/ directory at the project root:

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

Colliders

Using Model's Built-in Colliders

Models exported with collision meshes work automatically. Set the collision mask:

GltfContainer.create(model, {
  src: 'models/building.glb',
  visibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS | ColliderLayer.CL_POINTER,
  invisibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS
})

Adding Simple Colliders

For basic shapes, add MeshCollider:

import { MeshCollider } from '@dcl/sdk/ecs'
MeshCollider.setBox(model) // Box collider
MeshCollider.setSphere(model) // Sphere collider

Common Model Operations

Scaling

Transform.create(model, {
  position: Vector3.create(8, 0, 8),
  scale: Vector3.create(2, 2, 2) // 2x size
})

Rotation

Transform.create(model, {
  position: Vector3.create(8, 0, 8),
  rotation: Quaternion.fromEulerDegrees(0, 90, 0) // Rotate 90° on Y axis
})

Parenting (Attach to Another Entity)

const parent = engine.addEntity()
Transform.create(parent, { position: Vector3.create(8, 0, 8) })

const child = engine.addEntity()
Transform.create(child, {
  position: Vector3.create(0, 2, 0), // 2m above parent
  parent: parent
})
GltfContainer.create(child, { src: 'models/hat.glb' })

Free 3D Models — OpenDCL Catalog (5,700+ models)

The catalog file is at {baseDir}/references/model-catalog.md. Each line has this format:

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

How to search

Search with one keyword at a time — try the most specific word first:

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

If no results, try synonyms, broader terms, or related words:

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

Browse all categories to discover what's available:

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

Search within a specific category:

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

How to use models

  1. Search the catalog with different keywords until you find matching models
  2. Review the results — check dimensions, triangle count, animations, and description
  3. Download the model with the curl command into models/
  4. Reference in code with GltfContainer.create(entity, { src: 'models/{slug}.glb' })
  5. If the model has animations (listed in [anim: ...]), use the Animator component to play them
  6. After placing the model, you can fetch its preview thumbnail (preview: URL) to see what it looks like

Example workflow

# 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..."
// Use in code with animations
import { engine, Transform, GltfContainer, Animator } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const zombie = engine.addEntity()
Transform.create(zombie, { position: Vector3.create(8, 0, 8) })
GltfContainer.create(zombie, { src: 'models/zombie-purple.glb' })
Animator.create(zombie, {
  states: [
    { clip: 'ZombieWalk', playing: true, loop: true },
    { clip: 'ZombieAttack', playing: false, loop: false }
  ]
})

Important: GltfContainer only works with local files. Never use external URLs for the model src field. Always download models into models/ first. Never cd into the models directory. Always run curl from the project root with curl -o models/slug.glb "URL". Do NOT use cd models && curl -o slug.glb.

Checking Model Load State

Use GltfContainerLoadingState to check if a model has finished loading:

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

engine.addSystem(() => {
  const state = GltfContainerLoadingState.getOrNull(modelEntity)
  if (state && state.currentState === LoadingState.FINISHED) {
    console.log('Model loaded successfully')
  } else if (state && state.currentState === LoadingState.FINISHED_WITH_ERROR) {
    console.log('Model failed to load')
  }
})

Troubleshooting

| Problem | Cause | Solution | |---------|-------|----------| | Model not visible | Wrong file path | Verify the file exists at the exact path relative to project root (e.g., models/myModel.glb) | | Model not visible | Position outside scene boundaries | Check Transform position is within 0-16 per parcel. Center of 1-parcel scene is (8, 0, 8) | | Model not visible | Scale is 0 or very small | Check Transform.scale — default is (1,1,1). Try larger values if model was exported very small | | Model not visible | Behind the camera | Move the avatar or rotate to look in the model's direction | | Model loads but looks wrong | Y-up vs Z-up mismatch | Decentraland uses Y-up. Re-export from Blender with "Y Up" checked | | "FINISHED_WITH_ERROR" load state | Corrupted or unsupported .glb | Re-export the model. Use .glb (binary GLTF) format. Ensure no unsupported extensions | | Clicking model does nothing | Missing collider | Add visibleMeshesCollisionMask: ColliderLayer.CL_POINTER to GltfContainer or add MeshCollider |

Need to optimize models for scene limits? See the optimize-scene skill for triangle budgets and LOD patterns. Need animations from your model? See the animations-tweens skill for playing GLTF animation clips with Animator.

Model Best Practices

  • Keep models under 50MB per file for good loading times
  • Use .glb format (binary GLTF) — smaller than .gltf
  • Optimize triangle count: aim for under 1,500 triangles per model for small props
  • Use texture atlases when possible to reduce draw calls
  • Models with embedded animations can be played with the Animator component
  • Test model orientation — Decentraland uses Y-up coordinate system
  • Materials in models should use PBR (physically-based rendering) for best results