Loading...
Loading...
Compare original and translation side by side
| Need | Component | When |
|---|---|---|
| Entity faces the camera | | Name tags, signs, sprite-like objects |
| Text in the 3D world | | Labels, signs, floating text above entities |
| Custom material appearance | | Metallic, rough, transparent, emissive surfaces |
| Show/hide without removing | | LOD systems, toggling objects, conditional display |
| Modify GLTF model nodes | | Override materials or shadow casting on specific mesh nodes |
TextShapeBillboardMaterial.setPbrMaterialGltfNodeModifiersmodifiers| 需求 | 组件 | 使用场景 |
|---|---|---|
| 实体朝向摄像机 | | 名牌、标牌、精灵类对象 |
| 3D 世界中的文字 | | 标签、标牌、实体上方的浮动文字 |
| 自定义材质外观 | | 金属、粗糙、透明、自发光表面 |
| 无需移除即可显示或隐藏 | | LOD 系统、对象切换、条件显示 |
| 修改 GLTF 模型节点 | | 覆盖特定网格节点的材质或阴影投射 |
TextShapeBillboardMaterial.setPbrMaterialmodifiersGltfNodeModifiersimport { 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
})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
})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 rotationBM_YBM_ALLBM_ALLoppositeDirectionBillboardbillboardModeQuaternion.fromEulerDegrees(0, 180, 0)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 rotationBM_YBM_ALLBM_ALLoppositeDirectionBillboardbillboardModeQuaternion.fromEulerDegrees(0, 180, 0)targetEntitytargetEntityBillboardtargetEntity?: Entity// Face a specific entity instead of the camera
Billboard.create(card, { targetEntity: sphere })
// Yaw-only tracking of a target (BM_Y respected while targeting)
Billboard.create(card, { targetEntity: target, billboardMode: BillboardMode.BM_Y })
// Retarget at runtime
Billboard.getMutable(card).targetEntity = otherEntitytargetEntitytargetEntityengine.CameraEntity2billboardModeBM_YtargetEntitytargetEntitytargetEntityBillboardtargetEntity?: Entity// Face a specific entity instead of the camera
Billboard.create(card, { targetEntity: sphere })
// Yaw-only tracking of a target (BM_Y respected while targeting)
Billboard.create(card, { targetEntity: target, billboardMode: BillboardMode.BM_Y })
// Retarget at runtime
Billboard.getMutable(card).targetEntity = otherEntitytargetEntitytargetEntityengine.CameraEntity2billboardModetargetEntityBM_YtargetEntitytargetEntityimport { 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
})fontSizeoutlineColoroutlineWidthimport { 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
})fontSizeoutlineColoroutlineWidthTextAlignMode.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{baseDir}/references/rendering-patterns.mdTextAlignMode.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{baseDir}/references/rendering-patterns.mdimport { 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
})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/Images/cutout.png' }),
transparencyMode: MaterialTransparencyMode.MTM_ALPHA_TEST,
alphaTest: 0.5
})MTM_ALPHA_TESTMTM_ALPHA_BLEND// 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/Images/cutout.png' }),
transparencyMode: MaterialTransparencyMode.MTM_ALPHA_TEST,
alphaTest: 0.5
})MTM_ALPHA_TESTMTM_ALPHA_BLEND// 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/Images/diffuse.png' }),
emissiveTexture: Material.Texture.Common({ src: 'assets/Images/emissive.png' }),
emissiveIntensity: 1.0,
emissiveColor: Color3.White()
})emissiveColoralbedoColor// 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/Images/diffuse.png' }),
emissiveTexture: Material.Texture.Common({ src: 'assets/Images/emissive.png' }),
emissiveIntensity: 1.0,
emissiveColor: Color3.White()
})emissiveColoralbedoColorMaterial.setPbrMaterial(entity, {
texture: Material.Texture.Common({ src: 'assets/Images/diffuse.png' }),
bumpTexture: Material.Texture.Common({ src: 'assets/Images/normal.png' }),
emissiveTexture: Material.Texture.Common({ src: 'assets/Images/emissive.png' })
})Material.setPbrMaterial(entity, {
texture: Material.Texture.Common({ src: 'assets/Images/diffuse.png' }),
bumpTexture: Material.Texture.Common({ src: 'assets/Images/normal.png' }),
emissiveTexture: Material.Texture.Common({ src: 'assets/Images/emissive.png' })
})setPbrMaterialsetBasicMaterialcastShadows: booleantruefalseMaterial.setPbrMaterial(entity, { albedoColor: Color4.Green(), castShadows: false })GltfNodeModifierscastShadows: falsesetPbrMaterialsetBasicMaterialcastShadows: booleantruefalseMaterial.setPbrMaterial(entity, { albedoColor: Color4.Green(), castShadows: false })castShadows: falseGltfNodeModifiersimport { 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
})_colliderimport { 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
})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.visibleVisibilityComponent{baseDir}/references/rendering-patterns.mdimport { engine, VisibilityComponent } from '@dcl/sdk/ecs'
// Hide an entity
VisibilityComponent.create(entity, { visible: false })
// Toggle visibility
const visibility = VisibilityComponent.getMutable(entity)
visibility.visible = !visibility.visibleVisibilityComponent{baseDir}/references/rendering-patterns.mdpropagateToChildren: trueVisibilityComponentVisibilityComponent.create(parentEntity, { visible: false, propagateToChildren: true })1,0-visibility-comp-propagationVisibilityComponentpropagateToChildrenfalsevisibleVisibilityComponentpropagateToChildren: truevisible: truepropagateToChildren: trueVisibilityComponentTransform.parentVisibilityComponentpropagateToChildren: trueVisibilityComponent.create(parentEntity, { visible: false, propagateToChildren: true })1,0-visibility-comp-propagationVisibilityComponentpropagateToChildrenfalsevisibleVisibilityComponentpropagateToChildren: truevisible: truepropagateToChildren: trueVisibilityComponentTransform.parentimport { GltfNodeModifiers } from '@dcl/sdk/ecs'
GltfNodeModifiers.create(entity, {
modifiers: [
{
path: 'RootNode/Armor', // GLTF hierarchy path
castShadows: false // Disable shadow casting for this node
}
]
})path: ''material: { material: { $case: 'pbr' | 'unlit', ... } }{baseDir}/references/rendering-patterns.md74,-8-gltfnodemodifierpath/Scene_root/shark_skeleton/Sphere/Sphere.001path: ''material$case: 'pbr'albedoColoremissiveColoremissiveIntensity$case: 'unlit'diffuseColormodifierspbr: { texture: Material.Texture.Video({ videoPlayerEntity: someEntityWithVideoPlayer }) }castShadows: falsematerialmodifierspathpathGltfNodeModifiers.createOrReplace(entity, { modifiers: [...] })GltfNodeModifiers.deleteFrom(entity)import { GltfNodeModifiers } from '@dcl/sdk/ecs'
GltfNodeModifiers.create(entity, {
modifiers: [
{
path: 'RootNode/Armor', // GLTF hierarchy path
castShadows: false // Disable shadow casting for this node
}
]
})path: ''material: { material: { $case: 'pbr' | 'unlit', ... } }{baseDir}/references/rendering-patterns.md74,-8-gltfnodemodifierpath/Scene_root/shark_skeleton/Sphere/Sphere.001path: ''material$case: 'pbr'albedoColoremissiveColoremissiveIntensity$case: 'unlit'diffuseColormodifierspbr: { texture: Material.Texture.Video({ videoPlayerEntity: someEntityWithVideoPlayer }) }castShadows: falsematerialmodifierspathpathGltfNodeModifiers.createOrReplace(entity, { modifiers: [...] })GltfNodeModifiers.deleteFrom(entity)Material.setPbrMaterial(portraitFrame, {
texture: Material.Texture.Avatar({ userId: '0x...' })
})Material.setPbrMaterial(portraitFrame, {
texture: Material.Texture.Avatar({ userId: '0x...' })
})import { TextureFilterMode, TextureWrapMode } from '@dcl/sdk/ecs'
Material.setPbrMaterial(entity, {
texture: Material.Texture.Common({
src: 'assets/Images/pixel-art.png',
filterMode: TextureFilterMode.TFM_POINT, // crisp pixels (no smoothing)
wrapMode: TextureWrapMode.TWM_REPEAT // tile the texture
})
})TFM_POINTTFM_BILINEARTFM_TRILINEARTWM_REPEATTWM_CLAMPTWM_MIRRORimport { TextureFilterMode, TextureWrapMode } from '@dcl/sdk/ecs'
Material.setPbrMaterial(entity, {
texture: Material.Texture.Common({
src: 'assets/Images/pixel-art.png',
filterMode: TextureFilterMode.TFM_POINT, // crisp pixels (no smoothing)
wrapMode: TextureWrapMode.TWM_REPEAT // tile the texture
})
})TFM_POINTTFM_BILINEARTFM_TRILINEARTWM_REPEATTWM_CLAMPTWM_MIRRORTween.setTextureMoveContinuousTween.setTextureMoveTMT_OFFSETTMT_TILINGTweenSequencewrapMode: TWM_REPEAT{baseDir}/references/rendering-patterns.mdTween.setTextureMoveContinuousTween.setTextureMoveTMT_OFFSETTMT_TILINGTweenSequencewrapMode: TWM_REPEAT{baseDir}/references/rendering-patterns.mdMaterial| Method | Returns | Throws if no material? |
|---|---|---|
| Read-only | Yes |
| Read-only | No |
| Read/write | Yes |
| Read/write | No |
// Read a property safely
const src = Material.getFlatOrNull(entity)?.texture?.src
// Mutate a texture in-place without knowing PBR vs Basic
Material.getFlatMutableOrNull(entity)!.texture = Material.Texture.Common({ src: 'assets/Images/new.png' })Material| 方法 | 返回值 | 没有材质时是否抛出异常? |
|---|---|---|
| 只读 | 是 |
| 只读 | 否 |
| 可读写 | 是 |
| 可读写 | 否 |
// Read a property safely
const src = Material.getFlatOrNull(entity)?.texture?.src
// Mutate a texture in-place without knowing PBR vs Basic
Material.getFlatMutableOrNull(entity)!.texture = Material.Texture.Common({ src: 'assets/Images/new.png' })GltfNodeModifierscastShadowscreateOrReplacedeleteFromVisibilityComponentpropagateToChildrenTween.setTextureMoveTextureMovementType.TMT_OFFSETTMT_TILINGTweenSequenceBillboardTextShapeGltfContainerGltfNodeModifierscastShadowscreateOrReplacedeleteFrompathVisibilityComponentpropagateToChildrenTween.setTextureMoveTextureMovementType.TMT_OFFSETTMT_TILINGTweenSequenceBillboardTextShapeGltfContainer