mcpField
A
advanced-rendering

advanced-rendering

github.com/dcl-regenesislabs开发1738 次安装21 周前更新
代码仓库

关于 advanced-rendering

advanced-rendering 是面向 Decentraland 开发的技能,介绍如何用 SDK 渲染组件配置 3D 视觉效果。内容涵盖文字、面向摄像机的实体、材质、模型节点覆盖、可见性和纹理动画,并说明如何在 main-entities.ts 中编写实体。

主要功能

  1. 01用 Billboard 创建面向摄像机的实体
  2. 02用 TextShape 渲染 3D 文字
  3. 03配置 PBR 材质和纹理
  4. 04切换实体可见性
  5. 05覆盖 GLTF 节点材质
  6. 06动画化材质纹理移动

适用场景

  1. 01为物体添加浮动标签
  2. 02制作发光或透明表面
  3. 03按条件隐藏实体
  4. 04滚动水面或传送带纹理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dcl-regenesislabs/opendcl --skill advanced-rendering

安装后在 Claude Code 中输入/advanced-rendering确认已加载。

详细介绍

Decentraland 中的高级渲染

编写方式拆分

Billboard、TextShape、Material、MeshRenderer、GltfContainer、VisibilityComponent 和 GltfNodeModifiers 均支持在 main-entities.ts 中使用——在其中完整声明视觉实体(标牌、标签、公告板、发光道具、带有逐节点覆盖的模型)及其视觉组件。下面展示 engine.addEntity() 后接 Transform.create + MeshRenderer / Billboard / TextShape 的示例,采用的是 main-entities.ts 出现之前的写法——请将实体声明移至 main-entities.ts,并仅在 src/index.ts 中保留运行时修改(例如,VisibilityComponent.getMutable(entity).visible = false)。

// Example: floating label
// main-entities.ts
shop_label: {
  components: {
    Transform: { position: { x: 8, y: 3, z: 8 } },
    TextShape: { text: 'OPEN', fontSize: 4, textColor: { r: 1, g: 1, b: 1, a: 1 } },
    Billboard: { billboardMode: 7 }  // BM_ALL
  }
}

如何选择渲染功能

需求组件使用场景
实体面向摄像机Billboard名称标签、标牌、类似精灵的对象
3D 世界中的文本TextShape标签、标牌、实体上方的悬浮文本
自定义材质外观Material.setPbrMaterial金属、粗糙、透明、自发光表面
显示/隐藏但不移除VisibilityComponentLOD 系统、切换对象、条件显示
修改 GLTF 模型节点GltfNodeModifiers覆盖特定网格节点的材质或阴影投射

选择流程:

  1. 需要在屏幕上显示文本?→ 改用 build-ui(React-ECS Label)
  2. 需要在 3D 空间中显示文本?→ TextShape(+ Billboard 以面向摄像机)
  3. 需要发光/透明材质?→ 使用 Material.setPbrMaterial 设置自发光/透明度
  4. 需要覆盖模型节点上的材质?→ 使用带有 modifiers 数组的 GltfNodeModifiers

Billboard(面向摄像机)

让实体始终旋转并面向玩家的摄像机:

import { engine, Transform, Billboard, BillboardMode, MeshRenderer } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const sign = engine.addEntity()
Transform.create(sign, { position: Vector3.create(8, 2, 8) })
MeshRenderer.setPlane(sign)

// Rotate only on Y axis (most common — stays upright)
Billboard.create(sign, {
  billboardMode: BillboardMode.BM_Y
})
Billboard 模式
BillboardMode.BM_Y      // Rotate on Y axis only (stays upright) — most common
BillboardMode.BM_ALL    // Rotate on all axes (fully faces camera)
BillboardMode.BM_X      // Rotate on X axis only
BillboardMode.BM_Z      // Rotate on Z axis only
BillboardMode.BM_NONE   // No billboard rotation
  • 大多数情况下优先使用 BM_Y 而不是 BM_ALL——效果更自然,渲染成本也更低。
  • BM_ALL 适用于粒子或需要始终直接面向摄像机的特效。

TextShape(3D 文本)

直接在 3D 空间中渲染文本:

import { engine, Transform, TextShape, TextAlignMode } from '@dcl/sdk/ecs'
import { Vector3, Color4 } from '@dcl/sdk/math'

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

TextShape.create(label, {
  text: 'Hello World!',
  fontSize: 24,
  textColor: Color4.White(),
  outlineColor: Color4.Black(),
  outlineWidth: 0.1,
  textAlign: TextAlignMode.TAM_MIDDLE_CENTER
})
文本对齐选项
TextAlignMode.TAM_TOP_LEFT
TextAlignMode.TAM_TOP_CENTER
TextAlignMode.TAM_TOP_RIGHT
TextAlignMode.TAM_MIDDLE_LEFT
TextAlignMode.TAM_MIDDLE_CENTER
TextAlignMode.TAM_MIDDLE_RIGHT
TextAlignMode.TAM_BOTTOM_LEFT
TextAlignMode.TAM_BOTTOM_CENTER
TextAlignMode.TAM_BOTTOM_RIGHT
悬浮标签(Billboard + TextShape)

组合使用 Billboard 和 TextShape,创建始终面向玩家的标签:

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

TextShape.create(floatingLabel, {
  text: 'NPC Name',
  fontSize: 16,
  textColor: Color4.White(),
  outlineColor: Color4.Black(),
  outlineWidth: 0.08,
  textAlign: TextAlignMode.TAM_BOTTOM_CENTER
})

Billboard.create(floatingLabel, {
  billboardMode: BillboardMode.BM_Y
})

高级 PBR 材质

金属度和粗糙度
import { engine, Transform, MeshRenderer, Material, MaterialTransparencyMode } from '@dcl/sdk/ecs'
import { Color4, Color3 } from '@dcl/sdk/math'

// Shiny metal
Material.setPbrMaterial(entity, {
  albedoColor: Color4.create(0.8, 0.8, 0.9, 1),
  metallic: 1.0,
  roughness: 0.1
})

// Rough stone
Material.setPbrMaterial(entity, {
  albedoColor: Color4.create(0.5, 0.5, 0.5, 1),
  metallic: 0.0,
  roughness: 0.9
})
透明度
// Alpha blend — smooth transparency
Material.setPbrMaterial(entity, {
  albedoColor: Color4.create(1, 0, 0, 0.5), // 50% transparent red
  transparencyMode: MaterialTransparencyMode.MTM_ALPHA_BLEND
})

// Alpha test — cutout (binary visible/invisible based on threshold)
Material.setPbrMaterial(entity, {
  texture: Material.Texture.Common({ src: 'assets/cutout.png' }),
  transparencyMode: MaterialTransparencyMode.MTM_ALPHA_TEST,
  alphaTest: 0.5
})
自发光(发光效果)
// Glowing material (emissiveColor uses Color3, not Color4)
Material.setPbrMaterial(entity, {
  albedoColor: Color4.create(0, 0, 0, 1),
  emissiveColor: Color3.create(0, 1, 0),  // Green glow
  emissiveIntensity: 2.0
})

// Emissive with texture
Material.setPbrMaterial(entity, {
  texture: Material.Texture.Common({ src: 'assets/diffuse.png' }),
  emissiveTexture: Material.Texture.Common({ src: 'assets/emissive.png' }),
  emissiveIntensity: 1.0,
  emissiveColor: Color3.White()
})
纹理贴图
Material.setPbrMaterial(entity, {
  texture: Material.Texture.Common({ src: 'assets/diffuse.png' }),
  bumpTexture: Material.Texture.Common({ src: 'assets/normal.png' }),
  emissiveTexture: Material.Texture.Common({ src: 'assets/emissive.png' })
})

GltfContainer 可见性蒙版

使用碰撞蒙版控制 GLTF 模型中特定网格层的可见性和碰撞:

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

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

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

VisibilityComponent

显示或隐藏实体,而不将其移除:

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

// Hide an entity
VisibilityComponent.create(entity, { visible: false })

// Toggle visibility
const visibility = VisibilityComponent.getMutable(entity)
visibility.visible = !visibility.visible

// Useful for LOD (Level of Detail)
function lodSystem() {
  const playerPos = Transform.get(engine.PlayerEntity).position

  for (const [entity, transform] of engine.getEntitiesWith(Transform, MeshRenderer)) {
    const distance = Vector3.distance(playerPos, transform.position)

    if (distance > 30) {
      VisibilityComponent.createOrReplace(entity, { visible: false })
    } else {
      VisibilityComponent.createOrReplace(entity, { visible: true })
    }
  }
}

engine.addSystem(lodSystem)
逐节点修改器(GltfNodeModifiers)

覆盖 GLTF 模型中特定节点的材质或阴影投射。支持在 main-entities.ts 中使用:

// main-entities.ts
armored_knight: {
  components: {
    Transform: { position: { x: 8, y: 0, z: 8 } },
    GltfContainer: { src: 'models/knight.glb' },
    GltfNodeModifiers: {
      modifiers: [
        {
          path: 'RootNode/Armor',     // GLTF hierarchy path
          castShadows: false           // disable shadows for this node
        }
      ]
    }
  }
}

覆盖整个模型:传入 path: ''(空字符串),将修改器应用于模型中的每个节点。适用于通过一次材质替换为整个模型重新贴皮:

red_team_unit: {
  components: {
    Transform: { position: { x: 4, y: 0, z: 8 } },
    GltfContainer: { src: 'models/unit.glb' },
    GltfNodeModifiers: {
      modifiers: [
        {
          path: '',
          material: {
            material: {
              $case: 'pbr',
              pbr: { albedoColor: { r: 1, g: 0, b: 0, a: 1 } }
            }
          }
        }
      ]
    }
  }
}
纹理补间(为材质纹理添加动画)

随时间改变材质的纹理偏移/平铺——适用于水、熔岩、传送带、滚动背景。Tween 组件支持在 main-entities.ts 中使用:

// main-entities.ts — continuous texture scroll
conveyor: {
  components: {
    Transform: { position: { x: 8, y: 1, z: 8 } },
    MeshRenderer: { mesh: { $case: 'plane', plane: { uvs: [] } } },
    Material: { material: { $case: 'pbr', pbr: { texture: { tex: { $case: 'texture', texture: { src: 'images/belt.png' } } } } } },
    Tween: {
      duration: 2000,
      easingFunction: 0,  // EF_LINEAR
      mode: {
        $case: 'textureMoveContinuous',
        textureMoveContinuous: { direction: { x: 1, y: 0 }, speed: 0.5 }
        // movementType defaults to 0 = TMT_OFFSET; use 1 = TMT_TILING to scale instead
      }
    }
  }
}

要实现有限的纹理移动,可以使用 { $case: 'textureMove', textureMove: { start: { x: 0, y: 0 }, end: { x: 1, y: 0 }, movementType: 0 } },并设置 duration。

运行时辅助函数(位于 src/index.ts):Tween.setTextureMove(entity, from, to, durationMs) 和 Tween.setTextureMoveContinuous(entity, direction, speed)。

头像纹理

从玩家的头像生成纹理:

Material.setPbrMaterial(portraitFrame, {
  texture: Material.Texture.Avatar({ userId: '0x...' })
})
纹理模式

控制纹理的过滤和环绕方式:

import { TextureFilterMode, TextureWrapMode } from '@dcl/sdk/ecs'

Material.setPbrMaterial(entity, {
  texture: Material.Texture.Common({
    src: 'images/pixel-art.png',
    filterMode: TextureFilterMode.TFM_POINT,    // crisp pixels (no smoothing)
    wrapMode: TextureWrapMode.TWM_REPEAT        // tile the texture
  })
})

过滤模式:TFM_POINT(像素化)、TFM_BILINEAR(平滑)、TFM_TRILINEAR(最平滑)。 环绕模式:TWM_REPEAT(平铺)、TWM_CLAMP(拉伸边缘)、TWM_MIRROR(镜像平铺)。

最佳实践

  • 使用 BillboardMode.BM_Y 而不是 BM_ALL,效果更自然,渲染速度也更快
  • 保持 fontSize 清晰易读(世界内文字使用 16-32)
  • 为 TextShape 添加 outlineColor 和 outlineWidth,确保文字在任何背景下都清晰可辨
  • 将 emissiveColor 与较暗的 albedoColor 搭配使用,以获得最明显的发光效果
  • MTM_ALPHA_TEST 比 MTM_ALPHA_BLEND 更省资源;无需平滑透明效果时,请使用镂空模式
  • 组合使用 Billboard + TextShape,在 NPC 或物体上方显示浮动名称标签
  • 使用 VisibilityComponent 实现 LOD 系统,而不是移除后再重新添加实体

评论

支持 Markdown