关于 lighting-environment
面向 Decentraland SDK7 场景开发者的灯光与环境技能,说明如何配置真实光源、天空时间和自发光材质,并强调光照限制及 Creator Hub Smart Items 的优先用法。
主要功能
- 01通过 Smart Items 添加灯光
- 02配置点光源与聚光灯
- 03设置阴影与光罩纹理
- 04控制天空盒时间
- 05区分自发光与环境照明
适用场景
- 01在场景中布置可开关的灯具
- 02调试未显示的场景光源
- 03创建昼夜变化环境
MCP 相关
说明在 Creator Hub MCP 可用时,应先搜索灯光 Smart Items 并使用 place_smart_item;未提供 Creator Hub MCP 时可改用手动 LightSource 配置。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ decentraland/ sdk-skills --skill lighting-environment安装后在 Claude Code 中输入/lighting-environment确认已加载。
详细介绍
Decentraland 中的照明与环境
规则:Creator Hub MCP 可用时,灯光应使用 Smart Items
当用户要求添加灯光,且 Creator Hub MCP 工具可用(mcp__creator-hub__*)时,始终先使用 search_catalog,再手动创建带有 LightSource 的实体。Creator Hub 目录中包含现成的灯光 Smart Items:
- Spotlight(
87c829b3-8e8d-4fcb-9f43-85d3aa9084f6,类别为lights)——包含真实的 GLB 模型(assets/asset-packs/spotlight/spotlight.glb)、预配置的core::LightSource、内置的 Turn On / Turn Off / Toggle 操作,以及适用于 Creator Hub UI 的inspector::Config。 - Point Light(类别为
lights)——采用相同模式:GLB 占位模型、预配置的 Point 类型core::LightSource,以及内置操作。 - 还有一个装饰性的“Spotlight”(类别为
decorations),它只是视觉装饰模型,不带LightSource——用户需要实际照明时,请务必从lights类别中选择。
使用 place_smart_item,并提供 assetId 和 position。它会处理所有事务:下载 GLB 文件、解析资源路径,以及设置 asset-packs::Placeholder、asset-packs::Script、asset-packs::Actions 和 inspector::Config 组件。该实体可立即在编辑器中使用,且已连接好操作触发器。
仅在以下情况回退到手动使用 create_entity + set_component 配置 core::LightSource:
- 没有可用的 Creator Hub MCP 工具(纯代码工作流)。
- 用户需要不带视觉模型的灯光(不可见光源)。
- 用户需要 Smart Item 未提供的非标准灯光参数。
下文介绍的手动 LightSource 组件 API 仍是两种方式的权威参考——Smart Items 使用相同的底层组件。
规则:3D 模型中的灯具不会发光
GLB 模型中看似灯具的几何体(灯具网格、灯泡形状、发光灯丝)纯粹是视觉效果——它不会在 Decentraland 中投射实际的动态光照。渲染器会将其视为普通几何体(可能使用自发光材质产生辉光效果,但不会照亮周围物体)。若要让灯具模型产生实际动态光照,请在同一实体上附加 LightSource 组件,或将其附加到放置在光源位置的子实体上。如果用户的场景模型中包含内置灯具,请主动说明:“模型中的灯具只是装饰性几何体——我需要添加 LightSource 组件才能产生实际照明。”
点光源
从某个位置向所有方向发光:
import { engine, Transform, LightSource } from '@dcl/sdk/ecs'
import { Vector3, Color3 } from '@dcl/sdk/math'
const light = engine.addEntity()
Transform.create(light, { position: Vector3.create(8, 3, 8) })
LightSource.create(light, {
type: LightSource.Type.Point({}),
color: Color3.White(),
intensity: 16000 // candela
})
彩色点光源
LightSource.create(light, {
type: LightSource.Type.Point({}),
color: Color3.create(1, 0.5, 0), // Warm orange
intensity: 16000,
range: 15 // Maximum distance in meters
})
默认值(来自协议):active 为 true,color 为白色,intensity 为 16000 坎德拉,range 为 -1(自动),shadow 为 false。color 是 Color3(RGB,各分量为 0–1)。
聚光灯
沿指定方向发射锥形光束:
import { Quaternion } from '@dcl/sdk/math'
const spotlight = engine.addEntity()
Transform.create(spotlight, {
position: Vector3.create(8, 4, 8),
rotation: Quaternion.fromEulerDegrees(90, 0, 0) // Point straight down — +90, not -90 (see below)
})
LightSource.create(spotlight, {
type: LightSource.Type.Spot({ innerAngle: 25, outerAngle: 45 }),
color: Color3.White(),
intensity: 16000
})
innerAngle— 全亮锥角(度)。默认值为21.8。最小值为0,最大值为179。outerAngle— 外层渐隐角(度)。默认值为30。最大值为179。innerAngle不能大于outerAngle;如果大于,引擎会将两者限制为相同值。- 锥形光束沿实体的局部 +Z(即实体的前方)照射:Explorer 会将 Unity 的
Light作为实体变换的子对象,并设置为单位局部姿态(LightSourceLifecycleSystem.cs,unity-explorer main 2026-10)。绕 X 轴旋转+90度会使光束垂直向下;旋转-90度则会使光束指向天空——使用@dcl/ecs-math计算可得,Quaternion.fromEulerDegrees(90, 0, 0)会将Vector3.Forward()旋转为(0, -1, 0),而-90会将其旋转为(0, 1, 0)(2026-10-22)。SDK 文档中的聚光灯示例和此技能的早期版本都将“向下”写成了-90,所以看似没有效果的天花板聚光灯可能是在照亮屋顶。尚未在世界中重新确认——请在“光照限制”下使用健全性测试检查一次光锥。 type是一个带判别值的联合类型。要在运行时读取或修改聚光灯参数,请先缩窄类型:if (comp.type?.$case === 'spot') { comp.type.spot.innerAngle = 30 }
阴影
为点光源或聚光灯启用阴影:
LightSource.create(spotlight, {
type: LightSource.Type.Spot({ innerAngle: 25, outerAngle: 45 }),
shadow: true,
intensity: 800
})
注意:只有聚光灯会渲染阴影,点光源不会。shadow 是组件的顶层布尔值(不在 Spot/Point 内)。
阴影遮罩纹理(Gobo)
通过光线投射图案:
const maskedLight = LightSource.getMutable(spotlight)
maskedLight.shadowMaskTexture = Material.Texture.Common({
src: 'assets/Images/lightmask1.png'
})
- 将
shadowMaskTexture = undefined设置为移除遮罩。 - 遮罩会投射光线形状(例如窗户图案),以模拟焦散或柔和阴影。用于聚光灯。
切换灯光
// Toggle on/off
const lightData = LightSource.getMutable(light)
lightData.active = !lightData.active
光照限制
- 场景可以创建许多灯光(引擎测试场景会在 2 个地块中生成约 9 个);渲染器决定实际渲染多少个。
- 桌面端质量预设会限制场景灯光数量:Low = 0(完全禁用场景灯光)、Medium = 6、High = 10(
QualityPresetLow/Medium/High.asset,unity-explorer main 2026-10;Settings 滑块还可以进一步调低预设上限)。如果场景中的灯光超过上限,则只渲染距离玩家最近的灯光。 - 排查“我的灯光不显示”时,先检查玩家当前启用的预设——在 Low 下,正确编写的
LightSource也不会渲染;无论如何调节强度、范围、材质或附着偏移都不会改变这一点。应说明受支持的最低档位是 Medium,而不是要求使用 High。可见的自发光火焰并不能证明蜡烛照亮了房间:应分别检查发光网格和照射到周围环境的光线。 - 同时最多渲染约 3 个投射阴影的灯光。
- 渲染器会根据质量设置和距离自动剔除灯光。
- 强度单位为坎德拉(1 米处的流明/平方米,即流明/4π)。默认值为
16000。 range的默认值为-1→ 根据intensity^0.25(四次方根,单位为米)自动计算。设置明确的range即可覆盖此值——这也会限制灯光的影响范围并节省性能。- 分散布置灯光,避免玩家附近同时有太多灯光(只会渲染距离最近的灯光)。
- **即使完全没有场景灯光,也要确保场景清晰可读。**桌面端 Low 和移动端 Very Low 都不会渲染任何场景灯光;在一次桌面端所有者测试中(2026-10-09),一个点光源可见,而同一房间内的两个聚光灯保持黑暗(原因尚未确定)。任何对游戏进程至关重要的内容——路径、可交互物体、“灯光变暖”的剧情节点——都必须依靠自发光材质、纹理和天空盒呈现;
LightSource只是点缀。这也适用于 Platform Support 下的移动端规则。 - **开始调参前,先做一分钟的基本检查:**使用默认
intensity: 16000,在地面上方 2.5 m 放置一个点光源和一个高度相同、朝向+90(垂直向下)的聚光灯,并在旁边放置一个自发光平面作为参照。点光源可见、聚光灯暗 → 检查朝向或预设,而不是强度。两者都不可见 → 预设为 Low。之后再调参。2026-10-08,在那次得出答案的测试之前,代码中记录了 8 轮 8–60 cd 的猜测;目录中的 Point Light / Spotlight Smart Items 默认从 16000 开始是有原因的。
SkyboxTime(昼夜循环)
使用 SkyboxTime 营造氛围——夜景搭配点光源可以营造戏剧化的环境。
在 scene.json 中设置固定时间
无需代码即可设置固定的时间。有效位置有两处:
// Genesis City scene — top-level
{ "skyboxConfig": { "fixedTime": 43200 } }
// World — inside worldConfiguration
{ "worldConfiguration": { "name": "my-name.dcl.eth", "skyboxConfig": { "fixedTime": 36000 } } }
时间值(从午夜起算的秒数,全天 = 86400):0 = 午夜,21600 = 上午 6 点,43200 = 中午,64800 = 下午 6 点(黄昏),86400 = 全天。
优先级(已通过引擎测试场景验证):worldConfiguration.skyboxConfig.fixedTime 的优先级高于顶层的 skyboxConfig.fixedTime;而运行时,engine.RootEntity 上的 SkyboxTime 组件会覆盖上述任一 JSON 值。
读取当前世界时间
import { getWorldTime } from '~system/Runtime'
executeTask(async () => {
const time = await getWorldTime({})
console.log('Seconds since midnight:', time.seconds)
})
动态更改时间
import { engine, SkyboxTime, TransitionMode } from '@dcl/sdk/ecs'
// Set time of day (must target the root entity)
SkyboxTime.create(engine.RootEntity, { fixedTime: 43200 }) // Noon
// Change with transition direction
SkyboxTime.createOrReplace(engine.RootEntity, {
fixedTime: 64800, // Dusk (6 PM)
transitionMode: TransitionMode.TM_BACKWARD // TM_FORWARD (0, default) or TM_BACKWARD (1)
})
// Remove the component to hand control back to global/world time
SkyboxTime.deleteFrom(engine.RootEntity)
transitionMode(可选)用于设置时间变化时的动画方向。默认值为TM_FORWARD。- 此组件必须位于
engine.RootEntity上。删除它后,时间会恢复为 scene.json/世界时间(或全局昼夜循环)。
昼夜循环系统
let currentTime = 43200
const CYCLE_SPEED = 100 // Time units per second
function dayNightCycle(dt: number) {
currentTime = (currentTime + CYCLE_SPEED * dt) % 86400
SkyboxTime.createOrReplace(engine.RootEntity, {
fixedTime: currentTime
})
}
engine.addSystem(dayNightCycle)
Realm 信息
检测玩家连接到哪个 Realm(服务器):
import { getRealm } from '~system/Runtime'
executeTask(async () => {
const realm = await getRealm({})
console.log('Realm:', realm.realmInfo?.realmName)
console.log('Network:', realm.realmInfo?.networkId)
console.log('Base URL:', realm.realmInfo?.baseUrl)
})
自发光材质(发光效果)
如需视觉发光而不照亮周围环境:
import { engine, Material } from '@dcl/sdk/ecs'
import { Color4, Color3 } from '@dcl/sdk/math'
// Self-illuminated 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 和 LightSource
如需让物体在视觉上发光并投射光线:
// Visual glow on the mesh
Material.setPbrMaterial(bulb, {
emissiveColor: Color3.create(1, 0.9, 0.7),
emissiveIntensity: 1.5
})
// Actual light emission
LightSource.create(bulb, {
type: LightSource.Type.Point({}),
color: Color3.create(1, 0.9, 0.7),
intensity: 200,
range: 10
})
阴影质量
shadow 是 LightSource 组件上的顶层可选布尔值(默认值为 false)。没有阴影类型枚举——质量会根据距离自动调整。Spot({...}) 只接受 innerAngle? 和 outerAngle?。
import { LightSource } from '@dcl/sdk/ecs'
// Spot light with shadows enabled
LightSource.create(spotEntity, {
type: LightSource.Type.Spot({ innerAngle: 25, outerAngle: 45 }),
shadow: true, // top-level boolean
intensity: 800
})
限制:
- 只有聚光灯支持阴影;点光源不会投射阴影。
- 同一时间最多渲染 3 个投射阴影的灯光——对于不需要阴影的灯光,请禁用
shadow。带阴影的聚光灯适合用于手电筒等戏剧性效果。 - 阴影质量和剔除会根据灯光与玩家的距离自动调整。具体距离因灯光类型和玩家的质量设置而异;一般规则如下:
| 与玩家的距离 | 结果 |
|---|---|
| < 10 m | 柔和阴影(高质量) |
| 10–20 m | 硬阴影(低质量) |
| > 20 m | 不渲染阴影 |
- 灯光本身仍会在更远的距离照亮场景——只有当玩家距离灯光超过 **160 m(10 个地块)**时,灯光才会禁用。因此,LightSource 适合用于大型场景,例如现场活动的舞台灯光,此时大多数观众都离灯具较远。
- 只有玩家站在场景内部时才会渲染灯光;在场景外部时不会渲染。
需要高级材质效果? 有关金属度、粗糙度、透明度、纹理贴图、纹理补间和纹理模式,请参阅 advanced-rendering 技能。
平台支持
- 桌面端(Unity explorer): 完全支持(点光源、聚光灯、阴影)。一次所有者测试(2026-10-09,默认强度下使用一个点光源和两个聚光灯)只显示了点光源;该问题未能复现,而且聚光灯可能朝上倾斜(参见「聚光灯」)——在认定为客户端缺陷之前,请运行「灯光限制」中的健全性测试。
- 移动端(Godot explorer): 自 v1.13.0 起支持
LightSource(场景动态灯光)——不再存在功能对等性差距。运行时会应用预算限制,详见下文。 - Bevy explorer: 完全支持(点光源、聚光灯、阴影)。
已根据文档提交 b4d4c88(移动端功能对等性跟踪)和 8139a7f(移动端限制)进行核实,时间为 2026 年 10 月。
移动端灯光预算
移动端对创作的灯光实施固定场景限制:8 个软限制/16 个硬限制的灯光源,2 个软限制/4 个硬限制的投射阴影灯光。软限制 = 移动端性能面板中显示警告;硬限制 = 场景无法加载。
除此之外,每个移动端图形配置文件只会启用一定预算范围内、距离最近的灯光源——Very Low 下为 0 个,High 下最多为 8 个——较低配置文件还可能完全禁用阴影。因此:
- 即使最多只有 8 个灯光会发光,创作 20 个灯光仍会占用完整的场景预算。请将创作数量控制在 8 个,不要依赖运行时预算。
- 切勿让游戏玩法所需的关键可见性依赖特定灯光是否启用:在 Very Low 下,没有场景灯光会启用。请使用环境光/自发光材质和天空盒保持基本可读性,并将
LightSource视为点缀。 - 不保证一定会有阴影。不要只依靠投射阴影来判断物体的位置。
完整的移动端限制表:optimize-scene → 移动端场景限制。
注意事项
range未设置(-1)时,会根据强度自动计算为intensity^0.25——强度较小时,范围会短得出乎意料。显式设置range,以获得可预测的衰减效果。shadow仅影响聚光灯;将其设为点光源的属性不会产生任何效果。- 为灯光方向添加动画:在灯光实体上添加
Tween/TweenSequence(Rotate 模式)——光束会跟随实体的前向量。 RootEntity上的SkyboxTime会覆盖任何 scene.jsonfixedTime;deleteFrom会恢复为该值。- 烘焙的灯光几何体不会发光。 带有灯或灯泡网格的 GLB 模型不会发出光线——请添加
LightSource组件以实现真实照明。参见上方规则。 - Smart Item
Placeholder需要解析后的文件路径,而不是模板变量。在asset-packs::Placeholder中将{assetPath}/spotlight.glb设为src,会导致辅助图标不可见或损坏。place_smart_item会自动将其解析为assets/asset-packs/spotlight/spotlight.glb等路径。如果必须通过set_component手动设置Placeholder,请使用磁盘上的实际路径。
示例场景
引擎团队测试场景(使用真实 API,并经过引擎测试):
- https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/0,4-dynamic-lights — 点光源和聚光灯 LightSource:运行时切换启用状态、颜色、范围、强度、聚光灯内外角度、阴影遮罩(gobo),以及通过补间动画旋转灯光。
- https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/2,0-skybox-scene-json — 通过顶层
skyboxConfig.fixedTime设置固定天空盒时间;使用getSceneInformation读取该值。 - https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/3,0-skybox-world-json — 通过
worldConfiguration.skyboxConfig.fixedTime设置固定天空盒时间(World 变体);演示worldConfiguration优先级更高。 - https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/2,1-skybox-sdk-scene-a 和 https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/3,1-skybox-sdk-scene-b — 在
RootEntity上运行时设置SkyboxTime,使用TransitionMode,并通过deleteFrom恢复为全局时间。