mcpField
L
lighting-environment

lighting-environment

github.com/decentraland创意与媒体4279 次安装今天更新
代码仓库

关于 lighting-environment

面向 Decentraland SDK7 场景开发者的灯光与环境技能,说明如何配置真实光源、天空时间和自发光材质,并强调光照限制及 Creator Hub Smart Items 的优先用法。

主要功能

  1. 01通过 Smart Items 添加灯光
  2. 02配置点光源与聚光灯
  3. 03设置阴影与光罩纹理
  4. 04控制天空盒时间
  5. 05区分自发光与环境照明

适用场景

  1. 01在场景中布置可开关的灯具
  2. 02调试未显示的场景光源
  3. 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.json fixedTime;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,并经过引擎测试):

评论

支持 Markdown