Loads and manages 3D assets via the Resources system. Use when adding models, textures, or fonts; declare in sources.js and access via core:ready event.
所有资源(模型、纹理、字体等)通过 Resources 类统一加载。资源在 sources.js 中声明,加载完成后通过 this.experience.resources.items 访问。
核心原则:在 sources.js 声明,通过 items 访问,在 core:ready 事件后使用。
所有资源在 src/js/sources.js 中统一声明:
// src/js/sources.js
export default [
{
name: 'playerModel', // 资源名称(用于访问)
type: 'gltfModel', // 资源类型
path: 'models/character/player.glb', // 相对于 public/ 的路径
},
{
name: 'grass_block_top_texture',
type: 'texture',
path: 'textures/blocks/grass_block_top.png',
},
// ...
]
| type | 加载器 | 用途 | 示例路径 |
|------|--------|------|----------|
| gltfModel | GLTFLoader | GLB/GLTF 模型 | models/xxx.glb |
| fbxModel | FBXLoader | FBX 模型 | models/xxx.fbx |
| objModel | OBJLoader | OBJ 模型 | models/xxx.obj |
| texture | TextureLoader | 普通纹理 | textures/xxx.png |
| hdrTexture | RGBELoader | HDR 环境贴图 | textures/xxx.hdr |
| exrTexture | EXRLoader | EXR 高动态范围 | textures/xxx.exr |
| ktx2Texture | KTX2Loader | KTX2 压缩纹理 | textures/xxx.ktx2 |
| cubeTexture | CubeTextureLoader | 立方体贴图 | ['px.jpg', 'nx.jpg', ...] |
| font | FontLoader | 字体文件 | fonts/xxx.json |
| audio | AudioLoader | 音频文件 | audio/xxx.mp3 |
| svg | SVGLoader | SVG 文件 | images/xxx.svg |
| video | VideoTexture | 视频纹理 | videos/xxx.mp4 |
// 在组件中访问资源
constructor() {
this.experience = new Experience()
this.resources = this.experience.resources
}
// 通过 items[name] 访问
const texture = this.resources.items['grass_block_top_texture']
const model = this.resources.items['playerModel']
const gltf = this.resources.items['playerModel']
// 完整 GLTF 对象
gltf.scene // THREE.Group - 场景根节点
gltf.animations // AnimationClip[] - 动画列表
gltf.cameras // Camera[] - 相机(如有)
gltf.asset // 元数据
// 添加到场景
this.scene.add(gltf.scene)
// 克隆模型(多实例)
const clone = gltf.scene.clone()
const texture = this.resources.items['grass_block_top_texture']
// 常见纹理配置
texture.colorSpace = THREE.SRGBColorSpace // 颜色空间
texture.wrapS = THREE.RepeatWrapping // 水平重复
texture.wrapT = THREE.RepeatWrapping // 垂直重复
texture.minFilter = THREE.NearestFilter // 像素风格
texture.magFilter = THREE.NearestFilter
texture.generateMipmaps = false // 像素风格关闭 mipmap
资源全部加载完成后触发 core:ready 事件:
import emitter from './utils/event-bus.js'
// 在需要等待资源的地方
emitter.on('core:ready', () => {
// 此时所有资源已加载完成
this.initWithResources()
})
// src/js/world/world.js
export default class World {
constructor() {
this.experience = new Experience()
this.resources = this.experience.resources
// 等待资源加载完成
emitter.on('core:ready', () => {
// 初始化需要资源的组件
this.player = new Player()
this.environment = new Environment()
this.chunkManager = new ChunkManager()
})
}
}
public/
├── models/
│ └── character/
│ └── my-model.glb ← 新模型
├── textures/
│ └── blocks/
│ └── my-texture.png ← 新纹理
// src/js/sources.js
export default [
// ... 现有资源
// 添加新资源
{
name: 'myModel',
type: 'gltfModel',
path: 'models/character/my-model.glb',
},
{
name: 'myTexture',
type: 'texture',
path: 'textures/blocks/my-texture.png',
},
]
// 在组件中(确保在 core:ready 后)
const model = this.resources.items['myModel']
const texture = this.resources.items['myTexture']
| 类型 | 命名模式 | 示例 |
|------|----------|------|
| 模型 | xxxModel | playerModel, steveModel |
| 纹理 | xxx_texture 或描述性 | grass_block_top_texture, dirt |
| HDR | xxxHDRTexture | environmentMapHDRTexture |
| 天空盒 | sky_xxxTexture | sky_sunriseTexture |
| 植物 | xxx_plant_Texture | dandelion_plant_Texture |
| 破坏阶段 | destroy_stage_N | destroy_stage_0 ~ destroy_stage_9 |
// Resources 提供加载进度
this.resources.loadProgress // 0.0 ~ 1.0
this.resources.isLoaded // boolean
this.resources.loaded // 已加载数量
this.resources.toLoad // 总数量
// BAD: 构造函数中直接访问(资源可能未加载)
constructor() {
this.model = this.resources.items['playerModel'] // ❌ 可能是 undefined
}
// GOOD: 在 core:ready 回调中访问
constructor() {
emitter.on('core:ready', () => {
this.model = this.resources.items['playerModel'] // ✅
})
}
// BAD: 直接使用加载器(绕过资源系统)
const loader = new GLTFLoader()
loader.load('models/xxx.glb', (gltf) => { ... })
// GOOD: 在 sources.js 声明
// sources.js
{ name: 'xxx', type: 'gltfModel', path: 'models/xxx.glb' }
// 组件中
const gltf = this.resources.items['xxx']
// BAD: 名称不匹配
// sources.js 中是 'playerModel'
const model = this.resources.items['player_model'] // ❌ undefined
// GOOD: 名称完全一致
const model = this.resources.items['playerModel'] // ✅
// BAD: 使用绝对路径或 src/ 路径
{ path: '/public/models/xxx.glb' } // ❌
{ path: 'src/assets/models/xxx.glb' } // ❌
// GOOD: 相对于 public/ 目录
{ path: 'models/xxx.glb' } // ✅
// BAD: 模糊的像素纹理(Minecraft 风格需要锐利边缘)
const texture = this.resources.items['grass']
// 使用默认 filter,导致模糊
// GOOD: 配置 NearestFilter
const texture = this.resources.items['grass']
texture.minFilter = THREE.NearestFilter
texture.magFilter = THREE.NearestFilter
texture.generateMipmaps = false
| 操作 | 代码 |
|------|------|
| 声明资源 | sources.js: { name, type, path } |
| 访问资源 | this.resources.items['name'] |
| 等待加载 | emitter.on('core:ready', () => {}) |
| 检查进度 | this.resources.loadProgress |
| GLTF 场景 | gltf.scene |
| GLTF 动画 | gltf.animations |
| 资源类型 | type 值 |
|----------|---------|
| GLB/GLTF | gltfModel |
| 普通纹理 | texture |
| HDR | hdrTexture |
| 字体 | font |
| 音频 | audio |
npx skills add hexianWeb/vtj-resource-management下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer