Skip to content

示例指南

u-spaceexamples/ 目录中包含了大量演示引擎功能的示例。以下是几个关键示例及其所展示的系统特性。

运行方式与版本

示例统一通过 examples/importmap.js 注入 Import Map。本地通过 localhost127.0.0.10.0.0.0192.168.x.x 访问时会加载仓库里的 ../dist/ 构建产物;在线部署或非本地域名访问时会从 jsDelivr 加载当前发布版本 u-space@0.0.32。Vercel 文档部署会继续把 __VERSION__ 占位符替换为 package.json 中的版本号,源码里的 0.0.32 作为直接托管 examples/ 时的 fallback。

插件示例可以在页面加载 importmap.js 前通过 window.__IMPORTS__ 声明额外依赖。将 u-space/plugins/<name> 的值设为 true 时,importmap.js 会自动在本地和 CDN 路径之间切换。

1. demo01.html:基础配置与交互

该示例演示了通过 WebGPU 渲染 3D 场景所需的最少配置,与 快速上手 指南中的内容一致。

核心要点:

  • Viewer 注入 DOM 元素。
  • 使用 WebGPU Color 设置场景背景。
  • 添加基础几何体(如 BoxGeometry)。
  • 通过 viewer.interactionManager.pointerMoveEventsEnabled 启用全局交互。
  • 像操作 DOM 元素一样,为 3D 网格原生绑定事件监听(clickpointerenterpointerleave)。

2. test_loader.html:模型缓存机制

该示例深入解析了 u-space 的模型加载管线,阐明运行时缓存与浏览器持久化缓存之间的区别。

核心要点:

  • 使用全局 Model 类通过 Model.prototype.loadAsync() 异步加载 .glb 文件。
  • 理解 cache: true(将模型节点保留在内存中,可实现即时克隆/实例化)。
  • 理解 persistent: true(使用 Service Worker / Cache Storage API 对实际网络请求数据进行持久化缓存)。
  • 演示如何将这些异步加载的资源安全地注册到 viewer.objectManager
  • 提供通过 Model.clearMemoryCache()Model.clearPersistentCache() 手动清除缓存的示例。

3. load_tiles.html:GIS 与地球渲染

该示例使用外部对等依赖 3d-tiles-renderer,通过 u-space 插件安全封装后,渲染大规模 LOD GIS 地球。

核心要点:

  • 动态实例化复杂插件(ArcgisTilesRenderer),并传入核心 viewer 引用。
  • 由于瓦片是异步流式加载并持续更新视口的,需使用 viewer.frameloop = 'always'
  • 通过插件的 invalidate(lon, lat, alt) 方法定位到指定的经纬高位置。
  • 使用 lonLatHeightToPosition() / positionToLonLatHeight() 在 WGS84 经纬高和场景世界坐标之间互转。

4. test_umanager.html:场景组合与解析器

该综合示例融合了多种工具,展示如何构建完整的应用程序,而不仅仅是放置单个模型。

核心要点:

  • 同时初始化多个插件(minimap、tracking、keyboard-controls),并通过 .enable() / .disable() 切换其状态。
  • 流式传输结构化场景布局,解析场景描述(SceneLoaderTopologiesLoader)。
  • 使用相机动画(VisionsLoaderVisionsParser)在场景中编排预定义的飞行路径。
  • 获取复杂的节点材质,并自定义 WebGPU 专属的 TSL(Three Shading Language)节点,如 TSLEffects.fluid()

5. test_umanager_loader.html:UManagerLoader 一体化加载

在线演示

该示例演示通过 UManagerLoader 在同一个路径下同时加载语义楼层、Facilities 和非语义场景树内容。加载结果会返回一个 UManagerSceneGroup,其中 semanticGroup 指向 SemanticGroupsceneGroup 指向非语义场景组。

核心要点:

  • 使用 UManagerLoader.setPath() 配置场景根目录,并通过一次 loadAsync() 完成 SemanticLoader + SceneLoader 组合加载。
  • SceneLoader 会自动跳过语义文件中已存在的 id,避免建筑、楼层或设备重复加载。
  • 通过 root.semanticGroup.getDefaultFacilityLayer()root.sceneGroup.getDefaultSceneLayer() 直接获取默认设备合批层和场景模型合批层。
  • 通过 viewer.objectManager 获取 SceneInstanceObjectFacilityInstanceObject,再直接使用 viewer.controls.flyToObject() 飞向单个实例。
  • 使用 setInstanceHighlight()setInstanceVisible()setInstanceOpacity() 等统一 API 控制实例,不需要关心底层是合并几何、InstancedMesh 还是 fallback Model
  • 示例把 viewerloaderrootsemanticGroupsceneGroupfacilityLayersceneLayersceneInstancesfacilities 暴露到 window.uManagerExample,方便在控制台调试。

6. test_umanager_dynamic_instances.html:运行时动态实例

在线演示

该示例把运行时实例新增、删除、恢复和按 ID 查询拆到独立场景中,避免和 UManagerLoader 的一体化加载流程混在一起。

核心要点:

  • 创建 SceneInstancedLayer 并调用 reserveBatch(url, template, capacity) 预分配容量。
  • 通过 SceneInstanceObject.setInstanceIdentity({ id, kind, name }) 设置实例独立身份字段,不依赖 userData 参与 layer 内部索引。
  • 同一个 layer 内 instanceId 必须唯一;重复 ID 的新增会返回 false,加入后修改身份字段会在下一次按 ID 查询时刷新索引。
  • 使用 addInstances() 批量新增实例,使用 removeInstance(id) / removeInstances(id) 按完整 instanceId 删除实例。
  • 使用 getInstanceById(id) 快速获取实例,返回对象可直接用于 setInstanceHighlight()viewer.controls.flyToObject()
  • 示例把 viewerlayertemplateallInstancesremovedInstances 暴露到 window.dynamicInstanceExample

7. test_umanager2.html:大型场景可编辑静态合批

该性能目标场景同时加载语义对象和完整场景树,并通过 SceneLoader.setEditableBatching() 把兼容的普通 Mesh 烘焙合并到 SceneEditableBatchLayer。它适合 draw calls 和可渲染 Mesh 数量成为主要 CPU/GPU 提交瓶颈、但业务仍需要按对象 ID 显隐、高亮或偶尔移动对象的场景。

核心要点:

  • 使用 setEditableBatching({ maxVerticesPerBatch, maxIndicesPerBatch, freezeAnimations }) 显式开启;默认 SceneLoader 行为不变。
  • 兼容的不透明 Mesh 按材质、Geometry attribute 布局、阴影状态和 renderOrder 合并;透明、蒙皮、morph、自定义 shader 和不兼容 Geometry 保留 fallback。
  • 合批对象仍保留 SceneInstanceObject,显隐、颜色和不透明高亮通过 TSL 状态纹理更新;transform 或半透明修改只 materialize 当前对象。
  • 页面使用 pixelRatio: 1 控制高 DPI drawing buffer 成本,并关闭不需要的交互 raycast。
  • 首帧前通过 renderer.compileAsync() 预热 WebGPU material pipeline,避免把编译中的中间画面展示给用户。
  • 使用 ?editableBatching=false 可关闭该路径,与默认 path-based SceneInstancedLayer/普通模型加载结果做性能和画面对比。
  • sceneGroup.userData.editableBatch 提供 sourceMeshesbatchesdrawCallsSavedverticesindices 和 fallback 原因统计。

该模式通过展开重复顶点换取更少 draw calls;高重复、大 Geometry 的同模板对象可能仍更适合 SceneInstancedLayer。详见 u-manager setEditableBatching() API

8. test_umanager2_offscreen.html:OffscreenCanvas Worker + editable batching

该示例是 test_umanager2.html 的 Worker 版本。完整 Viewer、Three.js 对象重建、editable batch 构建、相机控制和 WebGPU 渲染运行在 dedicated render Worker;主线程只持有可见 canvas、转发输入/resize,并显示 Worker 返回的状态与统计。静态 SBMX/glTF 的 fetch、字节/JSON/base64 解析和图片解码继续拆到 render Worker 创建的第二个 decode Worker,因此加载新模型时已有 3D 场景仍可响应输入。

通过专用 Vite 配置启动:

bash
pnpm example:offscreen

然后访问 http://127.0.0.1:5510/offscreen/test_umanager2_offscreen.html。该示例的 HTML、主线程入口、Worker 入口和专用 Vite 配置集中在 examples/offscreen/ 目录。可用 pnpm build:example:offscreen 验证生产构建。

在线演示由一键发布流程单独打包:HTML 加载生成的 JavaScript,Worker 保持 ES module 格式,Draco/Basis WASM 等资源写入 /examples/assets/。线上页面不直接执行源码 .ts,HDR 则复用 /examples/textures/puresky_1k.hdr

核心要点:

  • 主线程使用 OffscreenViewerHost 调用 transferControlToOffscreen(),以 structured-clone 消息转发 pointer、wheel、resize 和业务 command。
  • Worker 在模块顶层通过 const worker = await createWorkerViewer() 创建真正的 Viewer,随后以顺序式代码加载 HDR、SemanticLoaderSceneLoader,无需把整个入口包进 setup callback。
  • render Worker 通过 ModelLoaderManager.setDecodeWorker() 启用 test_umanager2_offscreen.decode.worker.ts,并把返回的实例绑定 disposer 注册到 runtime 清理;decode Worker 从 u-space/worker/model-decoder 调用 installModelDecodeWorker(),以 transferable ArrayBuffer / ImageBitmap 返回静态 glTF 数据,Three.js/GPU 对象仍只在 render Worker 创建。外部 buffer/贴图继续经过 render Worker 的 LoadingManager URL modifier 与加载统计,跨域依赖不会继承模型请求的敏感 headers/credentials。
  • 解码队列一次只允许一个待确认数据包;render Worker 重建后发送 ACK 再取下一项,防止 1GB 级场景同时堆积多个模型副本。相同图片通过有界 LRU 内容指纹复用 bitmap 身份,避免把原本 25 个 editable material batches 拆成大量重复批次,同时不永久持有所有历史贴图。
  • animation、skin、morph、camera、sparse accessor、glTF extension/压缩扩展和非 triangle primitive 不进入快速路径,会自动使用现有 loader。访问 ?modelDecodeWorker=off 可关闭嵌套 Worker,与原始 loader 做画面、批次和加载响应 A/B 对比;默认开启。
  • Worker runtime 同时接管 Three.js ImageLoaderImageBitmapLoader:JPEG/PNG/GIF/WebP 任一边超过 WebGPU 默认 8192 上限时,会在第一次 createImageBitmap() 解码时等比缩小,保留 loader options/cache/abort 语义且不修改源文件,避免 Texture size 引发的 WebGPU validation 级联错误。
  • await host.init() / initialized 只表示 Worker 内 viewer.init() 完成;HDR、模型、editable batch、pipeline 预热和业务首帧完成后,Worker 才显式调用一次 worker.ready(detail)。主线程应先注册 ready 监听,再执行 host.init(),并在 ready 后调用业务 command。
  • SceneLoader.setEditableBatching() 在 Worker 中完成 Geometry 克隆、变换烘焙、合并和 TSL 状态纹理创建;透明、蒙皮、morph、自定义 shader 等不支持子集保持 fallback。
  • 首帧前关闭 controls invalidation 并等待 renderer.compileAsync(),预热 WebGPU 合批管线后再显示完整画面。
  • HUD 显示实际 drawCalls、三角形、static scene matrices 状态,以及 1 秒滚动窗口的 FPS、平均/p95/最大帧间隔、超过 25ms 的占比和样本数;demand 模式恢复时的空闲间隔不会被误算成渲染帧。
  • 示例调用 semanticGroup.showAllFloors().showAllFacilities() 并保持 SemanticGroup.visible = true,楼层、墙体、空间、门窗和设备等所有语义对象均保留且默认显示。HUD 的设备调试区通过 Worker command 选择、飞向、高亮或清除当前 Facility;这些操作都不修改任何语义对象或建筑场景的显隐状态,“清除调试”只撤销高亮。
  • SemanticLoader 的压平语义 Geometry 属于分析叠加层,本示例按调试需求默认显示完整语义模型,因此其半透明颜色会与建筑楼壳叠加;业务项目可以按自身展示策略单独控制该层。
  • 标准 RenderPipeline scene pass 保持启用,editable batch 只接收源模型中的不透明 Mesh;透明子 Mesh 保留标准 fallback,以兼顾透明合成正确性和不降低 pixel ratio 的运镜帧率。
  • 相机拖拽继续由主线程事件桥接到 Worker;业务对象不能跨线程传输,按 ID 显隐、变色、transform 或 materialize() 应包装成 Worker command,通过 host.request() 调用。
  • 相机定位后先调用 Three.js 原生 viewer.scene.updateMatrixWorld(true),再设置 viewer.scene.matrixWorldAutoUpdate = false 跳过每帧整树矩阵遍历;新增场景层级后用 scene.updateWorldMatrix(true, true) 只提交新增子树。Worker command 修改单个普通 Mesh 或 InstanceObject 时调用 object.updateWorldMatrix(true, false),修改 Group 时调用 group.updateWorldMatrix(true, true),最后调用 viewer.invalidate()InstanceObject 的原生方法覆盖会继续触发 instance buffer dirty 或 editable-batch materialize。
  • ready() 前的加载或管线预编译异常会触发 error、逆序资源清理和 Worker 关闭;初始化期间销毁 Host、canvas 转移/初始消息失败或 Worker 主动关闭会 reject 尚未完成的 host.init() / request() 并清理 DOM、resize 和待发送 pointer move。Host dispose 后会忽略队列中迟到的业务事件与 response。
  • Offscreen 负责释放主线程,editable batching 负责减少 draw submission;两者都不会自动减少三角形或透明 overdraw。

浏览器必须同时支持 transferControlToOffscreen() 和 Worker WebGPU。CSS2D/CSS3D、Info 等真实 DOM 叠加层仍应保留在主线程。完整接口和边界见 Viewer OffscreenCanvas Worker API

9. test_model_animation.html:模型内置动画

在线演示

该示例演示了如何加载含内置动画的 glTF 模型,并通过 Model 类的动画 API 控制播放。

核心要点:

  • 使用 Model.loadAsync() 加载带动画的 .glb 文件,动画片段自动初始化。
  • 使用 viewer.frameloop = 'always' 开启持续渲染以驱动动画。
  • 监听 beforeRender 事件,通过 model.updateAnimation(e.delta) 推进动画时间。
  • 使用 model.playAnimation(name) 按名称播放单个动画,model.playAllAnimations() 播放全部。
  • 使用 model.stopAnimation() 停止动画播放。

10. test_css_renderer.html:CSS2D / CSS2.5D / CSS3D 渲染器

该示例演示了如何在 3D 场景中叠加渲染 HTML 元素,展示三种 CSS 渲染模式的效果差异。

核心要点:

  • 使用 viewer.cssRenderer.createCSS2DObject() 创建始终面向相机、固定屏幕尺寸的 2D 标签。
  • 使用 viewer.cssRenderer.createCSS25DObject() 创建面向相机但随距离缩放的 2.5D 精灵。
  • 使用 viewer.cssRenderer.createCSS3DObject() 创建具有完整 3D 变换的面板。
  • CSS2.5D 和 CSS3D 对象需要设置 scale(通常 0.01),因为 HTML 元素的像素尺寸远大于 3D 世界单位。
  • 渲染器采用懒加载,仅在首次创建对应类型对象时初始化。

11. test_postprocessing.html:后处理效果

该示例演示了 RenderPipeline 的内置后处理功能,包括 Bloom、SSGI、TRAA 以及自定义后处理组合器。

核心要点:

  • 使用 viewer.renderPipeline.enableBloom() / disableBloom() 运行时切换 Bloom 效果。
  • 使用 viewer.renderPipeline.updateBloom() 实时调整 strength、radius、threshold 参数。
  • 使用 viewer.renderPipeline.enableSSGI() / disableSSGI() 切换屏幕空间全局光照。
  • 使用 viewer.renderPipeline.updateSSGI() 实时调整 SSGI 参数(直接修改 uniform,无需重建节点图)。
  • 使用 viewer.renderPipeline.enableTRAA() / disableTRAA() 切换时间抗锯齿。
  • 使用 viewer.renderPipeline.setOutputComposer() 自定义后处理链(示例中实现了灰度滤镜)。
  • 使用 setOutputComposer(null) 恢复默认渲染管线。

12. test_viewer_utils.html:Viewer 工具方法

该示例演示了 Viewer 新增的便捷方法:截图导出、背景切换、雾效控制和阴影开关。

核心要点:

  • 使用 viewer.screenshot() 导出当前渲染画面为 PNG 文件。
  • 使用 viewer.setBackground(color) 快速切换场景背景颜色。
  • 使用 viewer.enableFog() / viewer.disableFog() 控制雾效。
  • 使用 viewer.enableShadow() / viewer.disableShadow() 控制阴影渲染。
  • 使用 viewer.resize(width, height) 手动触发尺寸更新。

13. test_camera_controls.html:CameraControls 增强方法

该示例演示了 CameraControls 的飞行定位、视角存取、锁定和二三维切换功能。

核心要点:

  • 使用 viewer.controls.flyTo(position, target) 将相机飞行到指定坐标。
  • 使用 viewer.controls.getCameraViewpoint() 获取当前视角数据。
  • 使用 viewer.controls.setCameraViewpoint(data) 恢复保存的视角。
  • 使用 viewer.controls.lock() / unlock() 锁定或解锁相机控制。
  • 使用 viewer.controls.setViewMode('2d') / setViewMode('3d') 在二三维视图间切换。

14. test_object_manager.html:ObjectManager 增强方法

该示例演示了 ObjectManager 的显隐控制、孤立显示、透明度设置、包围盒查询和过滤功能。

核心要点:

  • 使用 viewer.objectManager.show(id) / hide(id) 控制对象可见性。
  • 使用 viewer.objectManager.isolate(ids) 孤立显示指定对象。
  • 使用 viewer.objectManager.setOpacity(id, value) 设置材质透明度。
  • 使用 viewer.objectManager.getBoundingBox() 查询所有对象的包围盒。
  • 使用 viewer.objectManager.filter(predicate) 按条件过滤对象。

15. test_material_effects.html:MaterialEffects 增强效果

该示例演示了材质效果系统的线框、半透明、X 光和淡入淡出功能。

核心要点:

  • 使用 MaterialEffects.wireframe(object) 开启线框渲染模式。
  • 使用 MaterialEffects.highlightColor(object, { opacity }) 设置半透明效果。
  • 使用 MaterialEffects.highlightColor(object, { color, opacity, overwrite: true, depthWrite: false }) 实现 X 光透视效果。
  • 使用 MaterialEffects.fadeOut(object) / fadeIn(object) 执行淡入淡出动画。
  • 使用 MaterialEffects.removeHighlightColor(object) 恢复原始材质状态。

16. test_outline.html:TSLEffects Outline 描边

在线演示

该示例演示 TSLEffects.outline() 作为 RenderPipeline output effect 对普通 Mesh、Group 和核心 InstanceObject 进行屏幕空间描边。

核心要点:

  • 使用 viewer.renderPipeline.addOutputEffect(outline) 叠加 Outline,不修改原始材质,也不占用业务侧 setOutputComposer()
  • 使用 outline.setSelectedObjects() 在 Box、Sphere、InstanceObject、全部对象和空选择之间切换。
  • 使用 outline.update() 实时调整强度、厚度、Glow 和 instanceBoundsPadding
  • InstanceObject 有实际渲染对象时直接描边;没有可渲染子树时可通过 getInstanceBoundingBox() 自动生成不可见 bounds proxy。
  • 销毁时先调用 removeOutputEffect(outline),再调用 outline.dispose() 释放 OutlineNode 与代理资源。

17. test_selection.html:Selection 选择系统

该示例演示了对象选择系统的单选和框选功能。

核心要点:

  • 创建 Selection 实例并监听 selectdeselectchange 事件。
  • 使用 selection.select() / deselect() / toggle() / clear() 进行程序化选择操作。
  • 使用 selection.enableBoxSelection() 开启鼠标框选模式。
  • 框选模式下可配合 viewer.controls.lock() 避免框选与相机旋转冲突。

18. test_measure.html:MeasureTool 测量工具

该示例演示了 3D 场景中的距离、面积和角度测量。

核心要点:

  • 使用 measureTool.measureDistance(pointA, pointB) 测量两点距离。
  • 使用 measureTool.measureArea(points) 测量多边形面积。
  • 使用 measureTool.measureAngle(pointA, vertex, pointC) 测量夹角。
  • 测量结果以可视化线条渲染到场景中,返回的 MeasureResult 包含数值和单位。

19. test_annotation.html:AnnotationManager 标注管理

该示例演示了 3D 标注的创建、更新和管理,配合 CSSRenderer 实现 HTML 浮动标签。

核心要点:

  • 创建 AnnotationManager 实例并通过 setCSSObjectFactory() 绑定 CSSRenderer
  • 使用 annotationManager.add(id, options) 添加带引线和自定义样式的标注。
  • 使用 annotationManager.addText(text, position) 快捷添加纯文本标注。
  • 使用 updateContent() 动态更新标注内容,updatePosition() 移动标注位置。
  • 使用 hideAll() / showAll() 批量控制标注显隐。

20. test_clipping.html:ClippingTool 剖切工具

该示例演示了剖切面的创建和实时调整。

核心要点:

  • 创建 ClippingTool 实例并调用 attach() 将场景物体移入 ClippingGroup。
  • 使用 clippingTool.addPlane(id, options) 添加剖切面。
  • 使用滑块通过 clippingTool.setPlaneConstant() 实时调整剖切位置。
  • 使用 showHelper() / hideHelper() 切换剖切面可视化辅助。

21. test_lights.html:LightManager 灯光管理

该示例演示了灯光管理器的灯光预设和 Helper 可视化功能。

核心要点:

  • 创建 LightManager 实例并使用 applyPreset() 一键应用灯光预设。
  • 支持 4 种预设:indoor(室内)、outdoor(室外)、studio(摄影棚)、warehouse(仓库)。
  • 使用 showAllHelpers() / hideAllHelpers() 显示或隐藏灯光辅助可视化。
  • 每种预设会自动清除旧灯光并创建新的灯光组合。

22. test_fire.html:WebGPU 体积火焰

该示例演示了 u-space/plugins/fireFireEffect 插件,封装 Three.js 官方体积火焰示例,在独立 volumetric pass 中模拟火焰和烟雾后叠加到主场景。

核心要点:

  • 使用 FireEffect 创建 WebGPU 体积火焰、烟雾、扰动、动态点光源和体积阴影。
  • 通过 positionsize 设置体积盒底部中心和烟雾扩散约束范围。
  • 默认使用 TeapotGeometry(0.8, 28) 作为 emitter;也可以传入业务 Object3D 和自定义 emitterGeometry
  • 通过 fire.update() 实时调整 fireIntensitysmokeLifespanemitterRadius 等参数。
  • 插件使用 RenderPipeline output effect 接入,不占用业务侧的 setOutputComposer()

23. test_ssr.html:SSR 时空降噪

在线演示

该示例使用程序化室内场景演示完整的屏幕空间反射链路:Stochastic SSR、Temporal Reproject 和 Recurrent Denoise。

核心要点:

  • 使用 viewer.renderPipeline.enableSSR() / disableSSR() 开关完整 SSR 后处理链。
  • 使用 viewer.renderPipeline.updateSSR() 实时调整 ray marching、历史帧数和降噪参数。
  • SSR 自动写入打包的法线/粗糙度、漫反射/金属度及 velocity MRT 通道。
  • 默认 Viewer 的 reversed depth 可直接使用;RenderPipeline 会在三个内部 pass 中正确跳过背景,同时保持原始深度用于位置与历史重建。
  • 使用 viewer.frameloop = 'always' 为时域重投影和循环降噪提供连续帧。
  • 场景包含移动发光球体,可直接观察运动向量重投影与残影收敛效果。
  • 示例通过 pixelRatio: 1 使用 1× drawing buffer,避免 Retina 屏幕把 Temporal Reproject 和 Recurrent Denoise 放大到 2.25 倍像素量。
  • maxDistance 从默认值 0.4 开始,保留滑块用于观察追踪距离对质量和性能的影响。
  • 移动物体继续生成 velocity,但不投射动态阴影;2048² 方向光阴影只更新一次。

24. test_ao.html:环境光遮蔽

在线演示

该示例使用程序化墙角与紧密摆放的几何体,独立展示 RenderPipeline 的 SSGI AO 分量。页面默认开启 AO,并固定 giIntensity: 0,因此画面只保留 scene.rgb × AO 遮蔽效果。

核心要点:

  • 使用 viewer.renderPipeline.enableSSGI() 开启 AO,并通过 giIntensity: 0 关闭间接漫反射。
  • 使用 disableSSGI() 对比无 AO 画面,再使用当前参数重新开启。
  • 使用 updateSSGI() 实时调整 aoIntensityradiusthickness
  • 使用 pixelRatio: 1 控制全屏 SSGI 在高 DPI 屏幕上的成本。
  • 场景不加载外部资源,墙角、堆叠物体和窄缝可以直接观察接触遮蔽。

u-space docs