性能优化
优化你的场景,使其加载更快并为所有玩家流畅运行。
你可以在场景中优化多个方面,以确保为访问它们的玩家带来尽可能好的体验。本文档介绍了一些最佳实践,它们能显著影响场景的加载速度,以及对玩家在场景内或相邻场景中时的运行流畅度。
请记住,许多玩家访问 Decentraland 时,可能使用的是非游戏硬件、通过浏览器访问,或者在 移动应用中 手机上——这些都会限制可用于你的场景的处理能力。访问你的场景时,所有人都应该获得流畅的体验。
查看 实用资源 可使用一些有帮助的工具,例如 Decentraland Scene Optimizer,它会从你的场景 3D 模型中提取、去重并压缩纹理。
Decentraland 浏览器在引擎层面强制执行了许多优化。这些优化效果显著,但要在浏览器中同时渲染多个用户生成的体验,挑战仍然很大。我们需要你的帮助,让一切顺畅运行。
时机
视频播放
播放视频是引擎最耗资源的任务之一。如果你的场景包含视频,请确保同一时间只有 一个 VideoTexture 在同时使用。多个平面可以共享同一个 VideoTexture,而不会对性能造成明显影响,但一旦添加第二个 VideoTexture,其对帧率的影响就会非常明显。
你还应避免让视频在无法被看到的区域播放。例如,如果你在室内有一个屏幕,可以根据玩家进出时触发区域来切换视频。
延迟加载
如果你的场景很大,或者包含并非始终可见的室内区域,你可以选择不从一开始就加载整套实体。相反,随着玩家访问场景的不同区域,再按区域加载内容。这可以显著减少场景的加载时间,也能减少引擎在每一帧需要处理的纹理和 3D 内容数量。
例如,博物馆的主建筑可以从一开始就加载,但每层的画作则只会在玩家到达该层时才加载。
参见 这个示例场景 ,看看它可能如何实现。
为了尽量避免卡顿,最好通过切换实体形状的 可见的 属性为 false 来隐藏实体。采用这种方式时,你在创建它们时就把它们加入引擎,但只是让它们的模型不可见。
另一种方法是,直到需要时才把实体添加到引擎中。这可能会在实体第一次出现时造成一些卡顿,而且它们也可能需要几秒钟才能变得可见。这种方法的好处在于,它是绕过 场景限制。请记住,场景限制计数针对的是任一时刻在场景中被渲染的内容,而不是可能被渲染的全部内容。通过加载和卸载场景的一部分,你应该能够绕开这些限制。
你也可以对距离较远或被遮挡的实体切换动画开关。例如,对于播放非常细微待机动画的 NPC,你可以让它只在玩家距离小于 20 米时播放该动画。围绕 NPC 使用触发区域,并据此开启或关闭其动画。
异步块
……的代码块 异步代码 在等待时不会阻塞其他所有内容的进度:场景会继续运行,而异步块会在其等待的响应到达后继续执行。请注意,场景在单线程上运行,因此这不是并行处理;它只是避免在等待外部响应时让场景停顿。
任何依赖异步服务响应的过程,例如 getPlayerData() 或 getRealm() 都应始终运行在异步块中,否则它们会在等待响应时阻塞场景其余部分的加载。对任何第三方服务器调用也同样适用。
请注意,场景会在所有非异步内容完成后被视为完全加载。玩家进入场景时,异步进程可能仍在运行。避免出现这样的情况:某个异步进程会加载一个实体,而该实体可能会让玩家卡在其几何体内部。
依赖事件
尽量让场景逻辑依赖于监听 事件 ,而不是每帧都运行检查。
该 update() 函数的数据存储在一个 系统 会在每一帧运行,理想情况下每秒 30 次。如果可以通过订阅事件来替代,尽量不要做反复检查。
例如,与其不断检查玩家的穿戴物品,不如订阅 onProfileChanged 事件,并且只在穿戴物品发生变化时检查玩家的穿戴物品。
如果你必须使用系统,也不要在每一帧都进行检查或调整。你可以在 update 函数中加入一个计时器,只在每隔整整一秒,或按其他合适的周期时执行一次检查。
优化 3D 模型
你的 3D 模型可以通过多种方式优化得更轻量。
在使用该功能时 Creator Hub,你可以查看场景中 3D 模型所使用资源的统计信息,以及它们是否超过了任何 场景限制.

你可以展开此菜单以查看详情。

以下是一些改进这些指标的提示:
在可能的情况下,在多个 3D 模型之间共享纹理。一个好做法是使用单张纹理作为图集贴图,并在场景中的所有模型之间共享。与其使用多张小纹理,不如使用一张 1024x1024 像素的大共享纹理。
注意:不要让同一个图像文件同时作为材质的 albedo 纹理、normal map 或 emissive map。即使内容相同,也请使用不同文件。将同一个图像文件分配给不同类型的纹理属性,在压缩为资源包时可能会引入不希望出现的视觉瑕疵。
.glb 是一种压缩格式,因此它的体积总会比一个 .gltf。另一方面,在 .gltf 通过将纹理导出为单独文件,很容易共享纹理图像。你可以通过使用 以下工作流程,从而同时拥有 .glb 带外部纹理文件的模型。
避免使用混合透明。混合透明必须绕过不少渲染优化。如果可能,优先使用不透明或 alpha 测试几何体。
避免使用蒙皮网格。它们会显著拖慢性能。
在 Blender 中抢救一个沉重的模型
当统计数据指向某一个特定模型时,通常修复模型比在代码中绕开它更快。在 Blender 或任何类似工具中,最有用的编辑包括:
减少三角形数量 使用 Decimate 修改器。这是一个用于处理你已拥有模型的抢救工具。新模型最好从一开始就直接建模为低多边形。
调整纹理大小 为 2 的幂次大小,1024x1024 或更小,并将它们重新打包进 .glb.
删除玩家永远看不到的面,比如道具的底部和背面。开启 背面剔除 ,而不是把几何体加倍。
合并材质 为一个,使用单张图集纹理,而不是每个部分一张纹理。
从
_collider网格中移除灯光、摄像机和材质。 引擎会忽略它们,因此它们纯属负担。
在导出回同一文件之前,检查修改前后的三角形数量和材质数量。如果预览正在运行,它会随你的更改重新加载。
多次重复使用同一个模型
场景里常常充满重复内容:街道上的路灯、房间里的椅子、公园里的树木。构建这些内容的最佳方式其实最简单—— 给每个副本分配各自的实体,并让它们都指向同一个 .glb 文件。
引擎会识别出这些实体共享同一个来源。该文件只会下载一次,只会转换为资源包一次,而且其网格和纹理只会在内存中保留一份——第 20 个路灯除了它在世界中的位置之外,几乎不会带来额外成本。这在不同场景之间也同样适用:如果相邻场景使用同一个文件,它已经在内存中了。导出二十个几乎相同的 .glb 文件,则意味着二十次下载和内存中的二十份副本。
这 不会 节省的是 draw call。无论 20 个路灯来自 20 个实体还是来自一个包含 20 个路灯建模在一起的 .glb 模型,20 个路灯都意味着 20 个需要绘制的对象。减少该数量的唯一办法,是在建模工具中把网格合并起来;这确实是个权衡——参见 实例化 vs 复制 vs 合并 ,了解在什么情况下这样做值得。
还有几个相关提示:
按簇分组,而不是做成一个巨大的模型。 如果你有很多零散的道具,一个不错的折中方案是每组一个 .glb ——比如一段街区或一个房间的一套家具——而不是每个道具一个模型,或者整个场景一个模型。这样既减少了对象数量,又能让每个簇保持足够小,从而让剔除仍然能发挥作用。
一次生成很多副本? 先用
AssetLoad组件预先加载模型。随后这些副本会基于已经在内存中的模型创建,而不是每个都在等待同一次下载。构建每个副本仍然需要工作,所以一次性大量生成无论如何都可能拖慢一帧——预加载消除了等待文件的时间,而不是创建副本的成本。一个非常大的模型比许多小模型更让引擎吃力。 引擎会把构建场景的工作分摊到多帧,以避免卡顿,但它无法拆分一个单独的超大模型——它会落在同一帧里。许多较小的部分会平滑加载;一个庞大的整体块更容易造成可见的卡顿。
重复一个模型不会引入新的纹理或几何体。 由一个模型构建的 20 个路灯会共享该模型的网格和纹理,而不是为集合增加新的内容——第 20 个在纹理内存上几乎没有成本。材质是个例外:引擎会为每个被渲染的对象创建一个材质实例,以应用你场景的边界裁剪,因此材质数量取决于你渲染的对象数量,而不是你使用的模型数量。这些实例仍然共享相同的纹理和着色器变体,所以它们消耗的是少量内存,而不是帧时间。会把场景推向纹理 限制 的原因之一,是拥有许多 不同的 模型,每个模型都有自己专属的一套内容——因此围绕更少的可复用模型库来整合场景会有所帮助。
背面剔除
为了进行性能优化,Backface Culling 将被设置为 开启 位于 所有 模型材质在引擎中渲染后,无论其设置如何都如此。
如果你预计会看到模型的背面或内部,请复制这些面并反转法线。
故障排除
要验证场景是否存在材质 Backface Culling 问题,请按以下步骤操作:
打开
调试面板。
如果场景已发布,请在聊天中输入
/debug命令。如果你处于场景的预览模式,请点击错误图标(

调试图标 ),它位于屏幕右上角。
调试面板将出现在屏幕右下角。
在 当前场景,点击 背面调试器 按钮。

切换 强制背面剔除:它会显示启用了 Backface Culling 的材质。这是优化在生产环境中启用后的实际渲染效果。切换开关可找出需要修复的材质。
切换 背面调试器 ,即可轻松找出关闭 Backface Culling 的材质。它会高亮显示:
红色:未将 Backface Culling 设置为 开启.
绿色:启用 Backface Culling 的材质 开启.
Backface Culling 关闭的材质(左)与开启的材质(右)
资源包转换
每次发布场景时,Decentraland 内容服务器都会将其中的每个 .gltf 和 .glb 模型压缩为资源包格式。该格式 显著 更轻,因此场景的加载速度更快、运行也更流畅。转换会在每次部署后立即开始。通常只需几秒钟,但对于非常大的场景,或服务器繁忙时,则可能需要更久,因为转换会针对每个平台单独运行,并且可能排在其他场景后面。你可以 直接检查转换状态 。
在开发场景时也在本地运行同样的转换。这会让预览更流畅,并让你在发布前检查压缩模型是否存在问题。参见 使用优化后的资源预览.
连接性
如果你的场景连接到任何第三方服务器,或使用 messagebus 在玩家之间发送消息,也有一些事项需要注意。
你的场景同一时间应只保持一个活动的 WebSockets 连接。
HTTP 调用会由引擎汇聚处理,因此同一时间只会处理一个。任何额外请求都会在内部排队,并必须等到其他请求完成后才能继续。这个排队过程由系统自动处理,你无需做任何事情。
当使用 messagebus 在玩家之间发送消息时,请注意所有消息都会发送给服务器岛内的所有其他玩家。避免出现“接收到一条消息就直接发送另一条消息”的情况,因为当场景里人多时,消息数量会迅速呈指数增长。
场景 UI
当场景 UI 由许多个独立元素组成时,渲染成本会变得很高。请记住,每个 UI 元素都需要引擎单独执行一次 drawcall。
避免在每一帧都调整 UI,这样尤其耗性能,而且可能会被排队处理。例如,如果你的 UI 中有一个应随时间缩小的生命值条,玩家可能分辨不出它以 10 FPS 更新还是以 30 FPS(每帧)更新有什么区别。更新这条条形的系统可以使用一个计时 100 毫秒的短计时器,只有当计时器归零时才影响 UI。
避免存在大量隐藏的 UI 元素,即使它们未被渲染,也会对性能产生影响。在可能的情况下,尽量按需创建 UI 组件。
World 中的地形
发布到 Decentraland World 会被自动生成的草地、树木和海景所环绕。渲染这些地形会消耗玩家的一部分渲染预算。如果你的场景不需要它,可以 禁用地形 在你的 scene.json 中禁用,以便把这些资源留给你场景自己的内容。
监控性能
衡量场景性能最好的指标是 FPS(每秒帧数)。在预览中,你可以在调试面板里看到当前场景的 FPS。你的目标应始终保持 30 FPS 或更高。
在已部署的场景中,你可以通过输入 /showfps 来切换显示这些指标的面板。
场景统计面板
在桌面客户端的预览中运行场景时,你可以打开一个面板,显示场景内容的实时统计数据。点击屏幕右上角、控制台和调试图标旁边的统计图标。

该面板会将场景的三角形、实体、刚体和纹理与它们的限制值进行对照,显示各项预算的使用百分比。某项达到其限制的 80% 后,数值会变为橙色。它还会显示材质、几何体、碰撞体以及外部视频或音频的纯计数。将鼠标悬停在每项指标旁边的信息图标上,可查看其统计内容及重要性的说明。
随着内容的加载和卸载,这些数字会实时更新,因此该面板非常适合用来检查诸如 延迟加载 之类的策略如何影响引擎在任一时刻实际处理的内容。参见 场景限制 了解每项限制的详细信息。请记住,这些都是软限制:超过其中一项不会阻止你的场景,但会降低玩家的性能体验。
场景与引擎之间的消息
场景性能的主要瓶颈之一,通常是场景代码与引擎之间发送消息。
在预览中运行场景时,请注意右上角会显示“Y = Toggle Panel”。按下键盘上的 Y 即可打开一个面板,其中包含一些实时更新的有用信息。
当你与涉及 SDK 和引擎之间消息的内容交互时,你会注意到“Processed Messages”的数字在增长。你需要密切关注“Pending on Queue”的数字,它应始终为 0 或接近 0。这表示有多少消息尚未被处理,而是被推入了队列。如果“Pending on Queue”的数值开始增长,那么你已经进入危险区域,应考虑对场景进行更多优化。
请记住,你在预览中体验到的性能可能与生产环境中的不同:
周围相邻场景可能会产生负面影响
将场景的 3D 模型压缩为资源包可能会带来正面影响
访问你场景的一些玩家可能正在使用性能较弱的硬件
先尝试将场景部署到 Decentraland World ,再进行更全面的测试,这始终是个好做法。
始终向玩家征求反馈。不要想当然地认为你体验场景的方式与其他所有人都一样。
使用 AI 优化
AI 代理可以为你处理本页所述的大部分测量和修复工作。Decentraland 提供 AI 技能 ,这些内容会教会编码代理(如 Claude Code 或 Cursor)如何优化场景,而桌面客户端还包含一个 MCP 服务器 ,让代理能够直接检查并测量你正在运行的场景。
借助 optimize-scene 和 unity-explorer-mcp 已安装的技能和已连接的 MCP 服务器,代理可以:
根据内容预算检查场景:它会读取与场景统计面板相同的实时数据,并将其与 场景限制进行比较,从而告诉你是哪一项预算接近上限。
找出责任资产:它会根据场景中每个 3D 模型贡献的三角形数量、材质数量和 draw call 数量进行排序,其中包括从特定视角可见的内容,因此它能准确知道应先优化哪些模型。
测量真实帧率:它会将玩家定位到场景中的任意位置,并采样玩家在该处实际体验到的 FPS,包括瞬时卡顿。
验证自己的工作:每次更改后它都可以重新测量,因此其建议和修复都有真实数据支撑,而不是猜测。
这让优化变成了你可以直接提出的需求:
“检查我的场景是否在限制范围内,找出在出生点附近拖慢帧率的任何因素,修复它,并向我展示修复前后的数据。”
结合 Blender MCP 服务器使用
Decentraland 工具会告诉代理哪些模型最重,但它们不会直接编辑模型本身。若想更进一步,你可以尝试将它们与 Blender MCP 服务器结合起来,它会让代理获得访问 Blender 编辑工具的能力。这使代理能够在 Blender 中打开一个重量较大的模型,减少其三角形数量、合并其材质或缩小其纹理,然后将结果作为一个 .glb 文件导出回场景中,随后再在世界内重新测量帧率。
请记住,自动化的网格编辑可能会明显改变模型外观,因此务必检查结果并保留原始文件的备份。
最后更新于