@fps-games/editor 0.1.4-beta.5 → 0.1.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/dist/build-info.json +16 -16
  2. package/dist/local-editor-harness.d.ts +24 -5
  3. package/dist/local-editor-harness.d.ts.map +1 -1
  4. package/dist/local-editor-harness.js +456 -90
  5. package/dist/local-editor-harness.js.map +1 -1
  6. package/dist/local-editor-performance-stats.d.ts +12 -0
  7. package/dist/local-editor-performance-stats.d.ts.map +1 -0
  8. package/dist/local-editor-performance-stats.js +46 -0
  9. package/dist/local-editor-performance-stats.js.map +1 -0
  10. package/dist/playable-babylon-facade.d.ts +2 -2
  11. package/dist/playable-babylon-facade.d.ts.map +1 -1
  12. package/dist/playable-babylon-facade.js +1 -1
  13. package/dist/playable-babylon-facade.js.map +1 -1
  14. package/dist/playable-babylon-rendering.d.ts +57 -12
  15. package/dist/playable-babylon-rendering.d.ts.map +1 -1
  16. package/dist/playable-babylon-rendering.js +529 -20
  17. package/dist/playable-babylon-rendering.js.map +1 -1
  18. package/dist/playable-local-editor-host.d.ts +10 -9
  19. package/dist/playable-local-editor-host.d.ts.map +1 -1
  20. package/dist/playable-local-editor-host.js.map +1 -1
  21. package/dist/playable-sdk.d.ts +5 -3
  22. package/dist/playable-sdk.d.ts.map +1 -1
  23. package/dist/playable-sdk.js +3 -2
  24. package/dist/playable-sdk.js.map +1 -1
  25. package/dist/static-shadow-cpu-worker.d.ts +7 -0
  26. package/dist/static-shadow-cpu-worker.d.ts.map +1 -0
  27. package/dist/static-shadow-cpu-worker.js +221 -0
  28. package/dist/static-shadow-cpu-worker.js.map +1 -0
  29. package/node_modules/@fps-games/babylon-renderer/dist/index.d.ts +3 -1
  30. package/node_modules/@fps-games/babylon-renderer/dist/index.d.ts.map +1 -1
  31. package/node_modules/@fps-games/babylon-renderer/dist/index.js +3 -1
  32. package/node_modules/@fps-games/babylon-renderer/dist/index.js.map +1 -1
  33. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.d.ts +4 -0
  34. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.d.ts.map +1 -0
  35. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.js +584 -0
  36. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.js.map +1 -0
  37. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-atlas.d.ts +61 -0
  38. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-atlas.d.ts.map +1 -0
  39. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-atlas.js +382 -0
  40. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-atlas.js.map +1 -0
  41. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-bake.d.ts +47 -0
  42. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-bake.d.ts.map +1 -0
  43. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-bake.js +285 -0
  44. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-bake.js.map +1 -0
  45. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-baker.d.ts +88 -0
  46. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-baker.d.ts.map +1 -0
  47. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-baker.js +813 -0
  48. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-baker.js.map +1 -0
  49. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-rendering.d.ts +27 -0
  50. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-rendering.d.ts.map +1 -0
  51. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-rendering.js +220 -0
  52. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-rendering.js.map +1 -0
  53. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-system.d.ts +35 -3
  54. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-system.d.ts.map +1 -1
  55. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-system.js +65 -609
  56. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-system.js.map +1 -1
  57. package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.d.ts +169 -14
  58. package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.d.ts.map +1 -1
  59. package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.js +9 -3
  60. package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.js.map +1 -1
  61. package/node_modules/@fps-games/babylon-renderer/package.json +1 -1
  62. package/node_modules/@fps-games/editor-babylon/dist/index.d.ts +2 -0
  63. package/node_modules/@fps-games/editor-babylon/dist/index.d.ts.map +1 -1
  64. package/node_modules/@fps-games/editor-babylon/dist/index.js +2 -0
  65. package/node_modules/@fps-games/editor-babylon/dist/index.js.map +1 -1
  66. package/node_modules/@fps-games/editor-babylon/dist/performance-monitor.d.ts +34 -0
  67. package/node_modules/@fps-games/editor-babylon/dist/performance-monitor.d.ts.map +1 -0
  68. package/node_modules/@fps-games/editor-babylon/dist/performance-monitor.js +272 -0
  69. package/node_modules/@fps-games/editor-babylon/dist/performance-monitor.js.map +1 -0
  70. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts +6 -0
  71. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts.map +1 -1
  72. package/node_modules/@fps-games/editor-babylon/dist/projection.js +65 -1
  73. package/node_modules/@fps-games/editor-babylon/dist/projection.js.map +1 -1
  74. package/node_modules/@fps-games/editor-babylon/dist/rendering.d.ts +19 -0
  75. package/node_modules/@fps-games/editor-babylon/dist/rendering.d.ts.map +1 -0
  76. package/node_modules/@fps-games/editor-babylon/dist/rendering.js +66 -0
  77. package/node_modules/@fps-games/editor-babylon/dist/rendering.js.map +1 -0
  78. package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.d.ts +5 -2
  79. package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.d.ts.map +1 -1
  80. package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.js +65 -32
  81. package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.js.map +1 -1
  82. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.d.ts.map +1 -1
  83. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js +19 -2
  84. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js.map +1 -1
  85. package/node_modules/@fps-games/editor-babylon/package.json +5 -5
  86. package/node_modules/@fps-games/editor-browser/dist/index.d.ts +1 -1
  87. package/node_modules/@fps-games/editor-browser/dist/index.d.ts.map +1 -1
  88. package/node_modules/@fps-games/editor-browser/dist/index.js.map +1 -1
  89. package/node_modules/@fps-games/editor-browser/dist/local-editor-rendering-actions.d.ts +8 -0
  90. package/node_modules/@fps-games/editor-browser/dist/local-editor-rendering-actions.d.ts.map +1 -0
  91. package/node_modules/@fps-games/editor-browser/dist/local-editor-rendering-actions.js +14 -0
  92. package/node_modules/@fps-games/editor-browser/dist/local-editor-rendering-actions.js.map +1 -0
  93. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.d.ts.map +1 -1
  94. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.js +10 -2
  95. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.js.map +1 -1
  96. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts +1 -1
  97. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts.map +1 -1
  98. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js +17 -0
  99. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js.map +1 -1
  100. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts.map +1 -1
  101. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js +466 -42
  102. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js.map +1 -1
  103. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts +70 -5
  104. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts.map +1 -1
  105. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts +1 -1
  106. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts.map +1 -1
  107. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js +595 -5
  108. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js.map +1 -1
  109. package/node_modules/@fps-games/editor-browser/package.json +3 -3
  110. package/node_modules/@fps-games/editor-core/dist/editor-session.d.ts +14 -1
  111. package/node_modules/@fps-games/editor-core/dist/editor-session.d.ts.map +1 -1
  112. package/node_modules/@fps-games/editor-core/dist/editor-session.js +34 -10
  113. package/node_modules/@fps-games/editor-core/dist/editor-session.js.map +1 -1
  114. package/node_modules/@fps-games/editor-core/dist/inspector.d.ts +2 -1
  115. package/node_modules/@fps-games/editor-core/dist/inspector.d.ts.map +1 -1
  116. package/node_modules/@fps-games/editor-core/dist/inspector.js +11 -1
  117. package/node_modules/@fps-games/editor-core/dist/inspector.js.map +1 -1
  118. package/node_modules/@fps-games/editor-core/dist/serialized-object.d.ts +7 -0
  119. package/node_modules/@fps-games/editor-core/dist/serialized-object.d.ts.map +1 -1
  120. package/node_modules/@fps-games/editor-core/dist/serialized-object.js +1 -0
  121. package/node_modules/@fps-games/editor-core/dist/serialized-object.js.map +1 -1
  122. package/node_modules/@fps-games/editor-core/package.json +2 -2
  123. package/node_modules/@fps-games/editor-forge-play/package.json +2 -2
  124. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.d.ts.map +1 -1
  125. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.js +10 -5
  126. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.js.map +1 -1
  127. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/placement.d.ts.map +1 -1
  128. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/placement.js +3 -1
  129. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/placement.js.map +1 -1
  130. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.d.ts +4 -1
  131. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.d.ts.map +1 -1
  132. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js +29 -0
  133. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js.map +1 -1
  134. package/node_modules/@fps-games/editor-playable-sdk/dist/document/types.d.ts +10 -0
  135. package/node_modules/@fps-games/editor-playable-sdk/dist/document/types.d.ts.map +1 -1
  136. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.d.ts.map +1 -1
  137. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.js +3 -0
  138. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.js.map +1 -1
  139. package/node_modules/@fps-games/editor-playable-sdk/dist/index.d.ts +1 -0
  140. package/node_modules/@fps-games/editor-playable-sdk/dist/index.d.ts.map +1 -1
  141. package/node_modules/@fps-games/editor-playable-sdk/dist/index.js +1 -0
  142. package/node_modules/@fps-games/editor-playable-sdk/dist/index.js.map +1 -1
  143. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.d.ts +33 -2
  144. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.d.ts.map +1 -1
  145. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.js +232 -16
  146. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.js.map +1 -1
  147. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.d.ts +1 -1
  148. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.d.ts.map +1 -1
  149. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.js +1 -1
  150. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.js.map +1 -1
  151. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.d.ts +12 -1
  152. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.d.ts.map +1 -1
  153. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.js +153 -0
  154. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.js.map +1 -1
  155. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/index.d.ts +4 -2
  156. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/index.d.ts.map +1 -1
  157. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/index.js +2 -1
  158. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/index.js.map +1 -1
  159. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/reducer.d.ts.map +1 -1
  160. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/reducer.js +4 -1
  161. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/reducer.js.map +1 -1
  162. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/rendering-alpha-index.d.ts +19 -0
  163. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/rendering-alpha-index.d.ts.map +1 -0
  164. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/rendering-alpha-index.js +57 -0
  165. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/rendering-alpha-index.js.map +1 -0
  166. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/types.d.ts +7 -1
  167. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/types.d.ts.map +1 -1
  168. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.d.ts.map +1 -1
  169. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.js +620 -36
  170. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.js.map +1 -1
  171. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/profile.d.ts +8 -3
  172. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/profile.d.ts.map +1 -1
  173. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/profile.js +258 -10
  174. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/profile.js.map +1 -1
  175. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/types.d.ts +110 -3
  176. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/types.d.ts.map +1 -1
  177. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.d.ts.map +1 -1
  178. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.js +25 -0
  179. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.js.map +1 -1
  180. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/types.d.ts +2 -1
  181. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/types.d.ts.map +1 -1
  182. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/client.d.ts.map +1 -1
  183. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/client.js +4 -0
  184. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/client.js.map +1 -1
  185. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/companion-configs.d.ts +9 -1
  186. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/companion-configs.d.ts.map +1 -1
  187. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/companion-configs.js +12 -1
  188. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/companion-configs.js.map +1 -1
  189. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/types.d.ts +2 -0
  190. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/types.d.ts.map +1 -1
  191. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.d.ts +1 -0
  192. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.d.ts.map +1 -1
  193. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.js +75 -0
  194. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.js.map +1 -1
  195. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/index.d.ts +1 -0
  196. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/index.d.ts.map +1 -1
  197. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/index.js +1 -0
  198. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/index.js.map +1 -1
  199. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.d.ts +17 -0
  200. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.d.ts.map +1 -0
  201. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.js +262 -0
  202. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.js.map +1 -0
  203. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.d.ts.map +1 -1
  204. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.js +7 -3
  205. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.js.map +1 -1
  206. package/node_modules/@fps-games/editor-playable-sdk/dist/session/identity.d.ts +6 -0
  207. package/node_modules/@fps-games/editor-playable-sdk/dist/session/identity.d.ts.map +1 -1
  208. package/node_modules/@fps-games/editor-playable-sdk/dist/session/identity.js +31 -0
  209. package/node_modules/@fps-games/editor-playable-sdk/dist/session/identity.js.map +1 -1
  210. package/node_modules/@fps-games/editor-playable-sdk/dist/session/index.d.ts +2 -1
  211. package/node_modules/@fps-games/editor-playable-sdk/dist/session/index.d.ts.map +1 -1
  212. package/node_modules/@fps-games/editor-playable-sdk/dist/session/index.js +1 -1
  213. package/node_modules/@fps-games/editor-playable-sdk/dist/session/index.js.map +1 -1
  214. package/node_modules/@fps-games/editor-playable-sdk/dist/session/patches.d.ts.map +1 -1
  215. package/node_modules/@fps-games/editor-playable-sdk/dist/session/patches.js +21 -9
  216. package/node_modules/@fps-games/editor-playable-sdk/dist/session/patches.js.map +1 -1
  217. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.d.ts +151 -0
  218. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.d.ts.map +1 -0
  219. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.js +445 -0
  220. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.js.map +1 -0
  221. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/index.d.ts +2 -0
  222. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/index.d.ts.map +1 -0
  223. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/index.js +2 -0
  224. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/index.js.map +1 -0
  225. package/node_modules/@fps-games/editor-playable-sdk/package.json +3 -3
  226. package/node_modules/@fps-games/editor-protocol/package.json +1 -1
  227. package/package.json +8 -8
@@ -1,3 +1,23 @@
1
+ const SHADOW_RENDERING_GROUP_BLOB = {
2
+ id: 'shadow-group-moving-object',
3
+ label: 'Moving Object Shadows',
4
+ summary: 'Blob: lightweight for moving objects and project-default fallback.',
5
+ };
6
+ const SHADOW_RENDERING_GROUP_STATIC = {
7
+ id: 'shadow-group-static-scene',
8
+ label: 'Static Scene Shadows',
9
+ summary: 'Consumes baked artifacts; update during authoring/build, runtime only displays results.',
10
+ };
11
+ const SHADOW_RENDERING_GROUP_PLANAR = {
12
+ id: 'shadow-group-directional-planar',
13
+ label: 'Directional Planar Shadows',
14
+ summary: 'Real-time planar projection following the directional light.',
15
+ };
16
+ const SHADOW_RENDERING_GROUP_COMPAT = {
17
+ id: 'shadow-group-compatibility',
18
+ label: 'Compatibility Shadows',
19
+ summary: 'Legacy ShadowGenerator / CSM read-only compatibility paths.',
20
+ };
1
21
  export function createEditorSceneRenderingPanelState(profile, state = {}, options = {}) {
2
22
  const blob = profile.shadows.blob;
3
23
  const staticProjected = profile.shadows.staticProjected;
@@ -6,6 +26,10 @@ export function createEditorSceneRenderingPanelState(profile, state = {}, option
6
26
  const postProcess = profile.postProcess;
7
27
  const dirty = state.dirty === true;
8
28
  const lastError = state.lastError ?? null;
29
+ const language = options.language ?? 'en';
30
+ const staticShadowBake = resolveStaticShadowBakeLifecycleState(state.staticShadowBake, staticProjected.enabled);
31
+ const staticShadowStatus = formatStaticShadowBakeLifecycleStatus(staticShadowBake, language);
32
+ const staticShadowBakeInProgress = staticShadowBake.status === 'baking';
9
33
  const panel = {
10
34
  title: 'Rendering',
11
35
  summary: 'Project-level rendering settings shared by editor preview and runtime.',
@@ -21,7 +45,7 @@ export function createEditorSceneRenderingPanelState(profile, state = {}, option
21
45
  ? 'Revert rendering settings to the last saved rendering settings.'
22
46
  : 'Rendering settings already match the last saved rendering settings.',
23
47
  }],
24
- sections: [{
48
+ sections: [createRenderingGroupsSection(profile.renderingGroups.slots), {
25
49
  id: 'environment',
26
50
  title: 'Environment / IBL',
27
51
  summary: 'World environment texture and reflection lighting shared by editor preview and runtime.',
@@ -223,11 +247,13 @@ export function createEditorSceneRenderingPanelState(profile, state = {}, option
223
247
  title: 'Shadows',
224
248
  summary: 'Global shadow systems for editor preview and runtime.',
225
249
  layout: 'list',
250
+ systemsCollapsible: true,
226
251
  systems: [
227
252
  {
228
253
  id: 'blob-shadow',
229
254
  label: 'Blob Shadow',
230
255
  kind: 'blob-shadow',
256
+ group: { ...SHADOW_RENDERING_GROUP_BLOB },
231
257
  active: blob.enabled,
232
258
  summary: 'Default object shadow',
233
259
  properties: [
@@ -345,10 +371,25 @@ export function createEditorSceneRenderingPanelState(profile, state = {}, option
345
371
  },
346
372
  {
347
373
  id: 'static-projected-shadow',
348
- label: 'Static Shape Shadow',
374
+ label: 'Static Baked Shadow',
349
375
  kind: 'static-projected-shadow',
376
+ group: { ...SHADOW_RENDERING_GROUP_STATIC },
350
377
  active: staticProjected.enabled,
351
- summary: 'Baked object shape',
378
+ summary: staticShadowStatus.summary,
379
+ status: staticShadowStatus.status,
380
+ details: createStaticShadowBakeDetails(staticShadowBake, language),
381
+ progress: staticShadowStatus.progress,
382
+ actions: [{
383
+ id: 'bake-static-shadows',
384
+ label: 'Bake Static Shadows',
385
+ icon: 'save',
386
+ disabled: !staticProjected.enabled || staticShadowBakeInProgress,
387
+ tooltip: staticShadowBakeInProgress
388
+ ? 'Static shadow bake is already running.'
389
+ : staticProjected.enabled
390
+ ? 'Bake static shadow chunks for objects authored as Static Baked Shadow.'
391
+ : 'Enable Static Baked Shadow before baking.',
392
+ }],
352
393
  properties: [
353
394
  {
354
395
  path: 'shadows.staticProjected.enabled',
@@ -404,14 +445,47 @@ export function createEditorSceneRenderingPanelState(profile, state = {}, option
404
445
  commitMode: 'live',
405
446
  },
406
447
  {
407
- path: 'shadows.staticProjected.bake.resolution',
408
- label: 'Resolution',
448
+ path: 'shadows.staticProjected.bake.texelsPerMeter',
449
+ label: 'Texels per Meter',
409
450
  valueType: 'number',
410
451
  control: 'number',
411
- value: staticProjected.bake.resolution,
452
+ value: staticProjected.bake.texelsPerMeter,
453
+ min: 1,
454
+ step: 1,
455
+ tooltip: 'Target SDF atlas texel density for baked static shadows.',
456
+ commitMode: 'blur',
457
+ },
458
+ {
459
+ path: 'shadows.staticProjected.bake.atlasSize',
460
+ label: 'Atlas Size',
461
+ valueType: 'number',
462
+ control: 'number',
463
+ value: staticProjected.bake.atlasSize,
412
464
  min: 16,
413
465
  step: 1,
414
- tooltip: 'Silhouette bake texture resolution per caster.',
466
+ tooltip: 'Maximum width and height for each static shadow atlas page.',
467
+ commitMode: 'blur',
468
+ },
469
+ {
470
+ path: 'shadows.staticProjected.bake.maxAtlasPages',
471
+ label: 'Page Budget',
472
+ valueType: 'number',
473
+ control: 'number',
474
+ value: staticProjected.bake.maxAtlasPages,
475
+ min: 1,
476
+ step: 1,
477
+ tooltip: 'Maximum atlas pages allowed before bake lowers the effective texel density.',
478
+ commitMode: 'blur',
479
+ },
480
+ {
481
+ path: 'shadows.staticProjected.bake.sdfRadiusPx',
482
+ label: 'SDF Radius',
483
+ valueType: 'number',
484
+ control: 'number',
485
+ value: staticProjected.bake.sdfRadiusPx,
486
+ min: 0,
487
+ step: 1,
488
+ tooltip: 'Signed-distance radius in pixels used to preserve crisp controllable edges.',
415
489
  commitMode: 'blur',
416
490
  },
417
491
  {
@@ -437,23 +511,35 @@ export function createEditorSceneRenderingPanelState(profile, state = {}, option
437
511
  commitMode: 'live',
438
512
  },
439
513
  {
440
- path: 'shadows.staticProjected.bake.maxSize',
441
- label: 'Max Size',
514
+ path: 'shadows.staticProjected.bake.spatialChunkSize',
515
+ label: 'Spatial Chunk Size',
442
516
  valueType: 'number',
443
517
  control: 'number',
444
- value: staticProjected.bake.maxSize,
518
+ value: staticProjected.bake.spatialChunkSize,
445
519
  min: 0.01,
446
520
  step: 0.01,
447
521
  unit: 'm',
448
- tooltip: 'Maximum projected bounds size for static shadows.',
522
+ tooltip: 'World size of each spatial bake chunk before atlas packing.',
449
523
  commitMode: 'live',
450
524
  },
525
+ {
526
+ path: 'shadows.staticProjected.bake.targetChunkCount',
527
+ label: 'Target Chunks',
528
+ valueType: 'number',
529
+ control: 'number',
530
+ value: staticProjected.bake.targetChunkCount,
531
+ min: 1,
532
+ step: 1,
533
+ tooltip: 'Soft chunk-count budget. Large scenes automatically enlarge spatial chunks to stay near this target.',
534
+ commitMode: 'blur',
535
+ },
451
536
  ],
452
537
  },
453
538
  {
454
539
  id: 'planar-main',
455
540
  label: 'Planar Main',
456
541
  kind: 'planar-shadow',
542
+ group: { ...SHADOW_RENDERING_GROUP_PLANAR },
457
543
  active: planar.enabled,
458
544
  summary: 'Follow Directional Light',
459
545
  properties: [
@@ -584,6 +670,7 @@ export function createEditorSceneRenderingPanelState(profile, state = {}, option
584
670
  id: 'legacy-shadow',
585
671
  label: 'Legacy Shadow',
586
672
  kind: 'legacy-shadow',
673
+ group: { ...SHADOW_RENDERING_GROUP_COMPAT },
587
674
  active: profile.shadows.enabled && !planar.enabled,
588
675
  readOnly: true,
589
676
  summary: profile.shadows.enabled ? 'Compatibility path' : 'Disabled',
@@ -597,6 +684,7 @@ export function createEditorSceneRenderingPanelState(profile, state = {}, option
597
684
  id: 'csm-shadow',
598
685
  label: 'CSM',
599
686
  kind: 'csm-shadow',
687
+ group: { ...SHADOW_RENDERING_GROUP_COMPAT },
600
688
  active: profile.shadows.enabled && profile.shadows.useCsm && !planar.enabled,
601
689
  readOnly: true,
602
690
  summary: profile.shadows.useCsm ? 'Compatibility path' : 'Disabled',
@@ -609,7 +697,382 @@ export function createEditorSceneRenderingPanelState(profile, state = {}, option
609
697
  ],
610
698
  }],
611
699
  };
612
- return localizeRenderingPanelState(panel, options.language ?? 'en', dirty);
700
+ return localizeRenderingPanelState(panel, language, dirty);
701
+ }
702
+ function resolveStaticShadowBakeLifecycleState(state, enabled) {
703
+ if (!enabled) {
704
+ return {
705
+ status: 'disabled',
706
+ chunkCount: 0,
707
+ };
708
+ }
709
+ return state ?? {
710
+ status: 'missing',
711
+ chunkCount: 0,
712
+ };
713
+ }
714
+ function formatStaticShadowBakeLifecycleStatus(state, language) {
715
+ const chunkCount = Math.max(0, Math.trunc(state.chunkCount ?? 0));
716
+ const chunkText = language === 'zh'
717
+ ? `${chunkCount} 个分块`
718
+ : `${chunkCount} chunk${chunkCount === 1 ? '' : 's'}`;
719
+ if (state.status === 'baking') {
720
+ const progress = state.progress ?? {
721
+ label: language === 'zh' ? '正在烘焙静态阴影' : 'Baking static shadows',
722
+ indeterminate: true,
723
+ };
724
+ return {
725
+ summary: language === 'zh' ? '正在烘焙' : 'Baking',
726
+ status: language === 'zh'
727
+ ? formatChineseStaticShadowBakingStatus(state)
728
+ : state.reason ?? 'Baking static shadow artifact.',
729
+ progress: {
730
+ ...progress,
731
+ label: language === 'zh' ? formatChineseStaticShadowProgressLabel(state) : progress.label,
732
+ },
733
+ };
734
+ }
735
+ if (state.status === 'disabled') {
736
+ const fallback = 'Static Baked Shadow is disabled.';
737
+ return {
738
+ summary: language === 'zh' ? '已禁用' : 'Disabled',
739
+ status: resolveLocalizedStaticShadowStatusReason(state.reason, fallback, '静态烘焙阴影已禁用。', language),
740
+ };
741
+ }
742
+ if (state.status === 'missing') {
743
+ const fallback = 'No static shadow bake artifact is available.';
744
+ return {
745
+ summary: language === 'zh' ? '缺少烘焙' : 'Missing bake',
746
+ status: resolveLocalizedStaticShadowStatusReason(state.reason, fallback, '当前没有可用的静态阴影烘焙数据。', language),
747
+ };
748
+ }
749
+ if (state.status === 'preview-unsaved') {
750
+ const fallback = 'Static shadow preview has not been saved yet.';
751
+ return {
752
+ summary: language === 'zh' ? `预览未保存 · ${chunkText}` : `Preview unsaved · ${chunkText}`,
753
+ status: resolveLocalizedStaticShadowStatusReason(state.reason, fallback, '静态阴影预览尚未保存。', language),
754
+ };
755
+ }
756
+ if (state.status === 'out-of-date') {
757
+ const fallback = 'Static shadow bake is out of date.';
758
+ return {
759
+ summary: language === 'zh' ? `已过期 · ${chunkText}` : `Out of date · ${chunkText}`,
760
+ status: resolveLocalizedStaticShadowStatusReason(state.reason, fallback, '静态阴影烘焙已过期。', language),
761
+ };
762
+ }
763
+ if (state.status === 'invalid') {
764
+ const fallback = 'Static shadow bake artifact is invalid.';
765
+ return {
766
+ summary: language === 'zh' ? '烘焙无效' : 'Invalid bake',
767
+ status: resolveLocalizedStaticShadowStatusReason(state.reason, fallback, '静态阴影烘焙数据无效。', language),
768
+ };
769
+ }
770
+ const fallback = 'Static shadow bake artifact is up to date.';
771
+ if (chunkCount === 0) {
772
+ return {
773
+ summary: language === 'zh' ? '无静态投射物' : 'No static casters',
774
+ status: resolveLocalizedStaticShadowStatusReason(state.reason, fallback, '没有物体被显式设置为静态烘焙阴影。', language),
775
+ };
776
+ }
777
+ return {
778
+ summary: language === 'zh' ? `最新 · ${chunkText}` : `Up to date · ${chunkText}`,
779
+ status: resolveLocalizedStaticShadowStatusReason(state.reason, fallback, '静态阴影烘焙数据已是最新。', language),
780
+ };
781
+ }
782
+ function resolveLocalizedStaticShadowStatusReason(reason, englishFallback, localizedFallback, language) {
783
+ if (language !== 'zh')
784
+ return reason ?? englishFallback;
785
+ return !reason || reason === englishFallback ? localizedFallback : reason;
786
+ }
787
+ function formatChineseStaticShadowBakingStatus(state) {
788
+ const stats = state.stats ?? null;
789
+ const phase = stats?.phase;
790
+ const attempted = stats?.attemptedChunkCount ?? 0;
791
+ const completed = stats?.chunkCount ?? 0;
792
+ const atlasPages = stats?.pageCount ?? stats?.textureCount ?? 0;
793
+ const encodedPages = stats?.textureCount ?? 0;
794
+ if (phase === 'collect') {
795
+ if ((stats?.sourceRootCount ?? 0) > 0)
796
+ return `已收集 ${stats?.sourceRootCount ?? 0} 个静态投射物,正在准备空间分块。`;
797
+ return '正在收集静态阴影投射物。';
798
+ }
799
+ if (phase === 'sdf') {
800
+ if (attempted > 0)
801
+ return `正在生成静态阴影 SDF ${Math.min(completed + 1, attempted)} / ${attempted}。`;
802
+ return '正在生成静态阴影 SDF。';
803
+ }
804
+ if (phase === 'pack') {
805
+ return `正在将 ${completed} 个静态阴影分块打包到 ${atlasPages} 张 Atlas。`;
806
+ }
807
+ if (phase === 'encode') {
808
+ return `正在编码静态阴影 Atlas ${Math.min(encodedPages + 1, atlasPages || encodedPages + 1)} / ${atlasPages || encodedPages + 1}。`;
809
+ }
810
+ if (phase === 'complete')
811
+ return '正在写入静态阴影烘焙数据。';
812
+ if (attempted > 0)
813
+ return `正在烘焙静态阴影分块 ${Math.min(completed + 1, attempted)} / ${attempted}。`;
814
+ if ((stats?.sourceRootCount ?? 0) > 0)
815
+ return `已收集 ${stats?.sourceRootCount ?? 0} 个静态投射物,正在准备分块。`;
816
+ return '正在收集静态阴影投射物。';
817
+ }
818
+ function formatChineseStaticShadowProgressLabel(state) {
819
+ const stats = state.stats ?? null;
820
+ const phase = stats?.phase;
821
+ const attempted = stats?.attemptedChunkCount ?? 0;
822
+ const completed = stats?.chunkCount ?? 0;
823
+ if (phase === 'collect')
824
+ return '收集静态投射物';
825
+ if (phase === 'pack')
826
+ return '打包静态阴影 Atlas';
827
+ if (phase === 'encode') {
828
+ const atlasPages = stats?.pageCount ?? stats?.textureCount ?? 0;
829
+ const encodedPages = stats?.textureCount ?? 0;
830
+ return `静态阴影 Atlas ${Math.min(encodedPages, atlasPages)} / ${atlasPages}`;
831
+ }
832
+ return attempted > 0
833
+ ? `静态阴影烘焙 ${Math.min(completed, attempted)} / ${attempted}`
834
+ : '正在烘焙静态阴影';
835
+ }
836
+ function createStaticShadowBakeDetails(state, language) {
837
+ const stats = state.stats ?? null;
838
+ const details = [];
839
+ const add = (labelEn, labelZh, value, tone) => {
840
+ if (value == null || value === '')
841
+ return;
842
+ details.push({
843
+ label: language === 'zh' ? labelZh : labelEn,
844
+ value: String(value),
845
+ ...(tone ? { tone } : {}),
846
+ });
847
+ };
848
+ const chunkCount = stats?.chunkCount ?? state.chunkCount;
849
+ const performance = calculateStaticShadowPerformanceDetails(stats, chunkCount);
850
+ add('Static casters', '静态投射物', formatOptionalCount(stats?.sourceRootCount));
851
+ add('Bake meshes', '参与 Mesh', formatOptionalCount(stats?.sourceMeshCount));
852
+ add('Chunks', '分块', formatOptionalCount(chunkCount), chunkCount === 0 ? 'warning' : undefined);
853
+ add('Atlas pages', 'Atlas 页', formatOptionalCount(stats?.pageCount ?? stats?.textureCount ?? chunkCount));
854
+ add('Texture memory', '贴图显存', performance.textureMemoryText, performance.textureMemoryTone);
855
+ add('Texture pixels', '贴图像素', performance.atlasPixelsText);
856
+ add('Atlas occupancy', 'Atlas 利用率', performance.atlasOccupancyText, performance.atlasOccupancyTone);
857
+ add('Atlas used', 'Atlas 已用', performance.atlasUsedPixelsText);
858
+ add('Atlas allocated', 'Atlas 分配', performance.atlasAllocatedPixelsText);
859
+ add('Runtime draws', '运行时 Draw', performance.drawCallsText);
860
+ add('Shadow mesh', '阴影 Mesh', performance.meshText);
861
+ add('Triangles', '三角形', performance.triangleText);
862
+ add('Vertices', '顶点', performance.vertexText);
863
+ add('Effective texels / m', '实际每米像素', formatOptionalNumber(stats?.effectiveTexelsPerMeter ?? stats?.texelsPerMeter));
864
+ if (stats?.effectiveTexelsPerMeter != null
865
+ && stats?.texelsPerMeter != null
866
+ && Math.abs(stats.effectiveTexelsPerMeter - stats.texelsPerMeter) > 0.001) {
867
+ add('Target texels / m', '目标每米像素', formatOptionalNumber(stats.texelsPerMeter), 'warning');
868
+ }
869
+ add('Atlas size', 'Atlas 尺寸', stats?.atlasSize ? `${stats.atlasSize}px` : null);
870
+ add('Page budget', '页预算', formatOptionalCount(stats?.maxAtlasPages));
871
+ add('SDF radius', 'SDF 半径', stats?.sdfRadiusPx != null ? `${stats.sdfRadiusPx}px` : null);
872
+ add('Spatial chunk', '空间分块', stats?.spatialChunkSize ? formatMeters(stats.spatialChunkSize) : null);
873
+ if (stats?.effectiveSpatialChunkSize != null
874
+ && stats?.spatialChunkSize != null
875
+ && Math.abs(stats.effectiveSpatialChunkSize - stats.spatialChunkSize) > 0.001) {
876
+ add('Effective chunk', '实际分块', formatMeters(stats.effectiveSpatialChunkSize), 'warning');
877
+ }
878
+ add('Target chunks', '目标分块', formatOptionalCount(stats?.targetChunkCount));
879
+ add('Baked chunks', '重烘分块', formatOptionalCount(stats?.bakedChunkCount));
880
+ add('Reused chunks', '复用分块', formatOptionalCount(stats?.reusedChunkCount), stats?.reusedChunkCount ? 'success' : undefined);
881
+ add('Resolution', '贴图尺寸', stats?.resolution ? `${stats.resolution}px` : null);
882
+ add('Chunk size', '分块尺寸', stats?.chunkSize ? formatMeters(stats.chunkSize) : null);
883
+ add('Duration', '耗时', formatDurationMs(stats?.durationMs, language));
884
+ if (state.status === 'baking') {
885
+ add('Current chunk', '当前分块', stats?.currentChunkId);
886
+ const attempted = stats?.attemptedChunkCount;
887
+ const completed = stats?.chunkCount;
888
+ if (stats?.phase)
889
+ add('Stage', '阶段', formatStaticShadowBakePhase(stats.phase, language));
890
+ if (attempted != null && completed != null) {
891
+ add('Progress', '进度', language === 'zh' ? `${completed} / ${attempted} 个分块` : `${completed} / ${attempted} chunks`);
892
+ }
893
+ }
894
+ else {
895
+ add('Skipped chunks', '跳过分块', formatOptionalCount(stats?.skippedChunkCount), stats?.skippedChunkCount ? 'warning' : undefined);
896
+ }
897
+ return details;
898
+ }
899
+ function calculateStaticShadowPerformanceDetails(stats, fallbackChunkCount) {
900
+ if (!stats) {
901
+ return {
902
+ textureMemoryText: null,
903
+ atlasPixelsText: null,
904
+ atlasUsedPixelsText: null,
905
+ atlasAllocatedPixelsText: null,
906
+ atlasOccupancyText: null,
907
+ drawCallsText: null,
908
+ meshText: null,
909
+ triangleText: null,
910
+ vertexText: null,
911
+ };
912
+ }
913
+ const chunkCount = Math.max(0, Math.trunc(stats.chunkCount ?? fallbackChunkCount ?? 0));
914
+ const isAtlas = stats.pageCount != null || stats.atlasSize != null || stats.effectiveTexelsPerMeter != null;
915
+ const textureCount = Math.max(0, Math.trunc(isAtlas
916
+ ? stats.pageCount ?? stats.textureCount ?? 0
917
+ : stats.textureCount ?? chunkCount));
918
+ const textureSize = isAtlas ? stats.atlasSize : stats.resolution;
919
+ const fallbackTextureBytes = textureCount > 0 && textureSize != null && Number.isFinite(textureSize) && textureSize > 0
920
+ ? textureCount * textureSize * textureSize * 4
921
+ : null;
922
+ const allocatedPixels = isAtlas
923
+ ? stats.atlasAllocatedPixels ?? (fallbackTextureBytes != null ? fallbackTextureBytes / 4 : null)
924
+ : (fallbackTextureBytes != null ? fallbackTextureBytes / 4 : null);
925
+ const usedPixels = isAtlas ? stats.atlasUsedPixels ?? null : null;
926
+ const textureBytes = allocatedPixels != null ? allocatedPixels * 4 : null;
927
+ const occupancy = isAtlas
928
+ ? stats.atlasOccupancy ?? (allocatedPixels != null && allocatedPixels > 0 && usedPixels != null
929
+ ? usedPixels / allocatedPixels
930
+ : null)
931
+ : null;
932
+ const drawCalls = textureCount > 0 ? textureCount : null;
933
+ const renderMeshes = isAtlas ? drawCalls : chunkCount || null;
934
+ const triangles = chunkCount > 0 ? chunkCount * 2 : null;
935
+ const vertices = chunkCount > 0 ? chunkCount * 4 : null;
936
+ return {
937
+ textureMemoryText: formatBytes(textureBytes),
938
+ textureMemoryTone: textureBytes != null && textureBytes >= 256 * 1024 * 1024 ? 'warning' : undefined,
939
+ atlasPixelsText: formatPixelCount(allocatedPixels),
940
+ atlasUsedPixelsText: formatPixelCount(usedPixels),
941
+ atlasAllocatedPixelsText: formatPixelCount(allocatedPixels),
942
+ atlasOccupancyText: formatPercentage(occupancy),
943
+ atlasOccupancyTone: occupancy != null && occupancy < 0.35 ? 'warning' : undefined,
944
+ drawCallsText: formatOptionalCount(drawCalls),
945
+ meshText: formatOptionalCount(renderMeshes),
946
+ triangleText: formatOptionalCount(triangles),
947
+ vertexText: formatOptionalCount(vertices),
948
+ };
949
+ }
950
+ function formatStaticShadowBakePhase(phase, language) {
951
+ if (language !== 'zh')
952
+ return phase;
953
+ switch (phase) {
954
+ case 'collect': return '收集';
955
+ case 'reuse': return '复用已有分块';
956
+ case 'chunk': return '烘焙分块';
957
+ case 'sdf': return '生成 SDF';
958
+ case 'pack': return '打包 Atlas';
959
+ case 'encode': return '编码 Atlas';
960
+ case 'complete': return '写入结果';
961
+ default: return phase;
962
+ }
963
+ }
964
+ function formatOptionalCount(value) {
965
+ if (value == null || !Number.isFinite(value))
966
+ return null;
967
+ return String(Math.max(0, Math.trunc(value)));
968
+ }
969
+ function formatOptionalNumber(value) {
970
+ if (value == null || !Number.isFinite(value))
971
+ return null;
972
+ return Number.isInteger(value) ? String(value) : value.toFixed(2).replace(/\.?0+$/, '');
973
+ }
974
+ function formatPixelCount(value) {
975
+ if (value == null || !Number.isFinite(value))
976
+ return null;
977
+ const pixels = Math.max(0, value);
978
+ if (pixels >= 1000000)
979
+ return `${formatOptionalNumber(pixels / 1000000)} MP`;
980
+ if (pixels >= 1000)
981
+ return `${formatOptionalNumber(pixels / 1000)} KP`;
982
+ return formatOptionalCount(pixels);
983
+ }
984
+ function formatPercentage(value) {
985
+ if (value == null || !Number.isFinite(value))
986
+ return null;
987
+ return `${formatOptionalNumber(Math.max(0, Math.min(1, value)) * 100)}%`;
988
+ }
989
+ function formatBytes(value) {
990
+ if (value == null || !Number.isFinite(value))
991
+ return null;
992
+ const bytes = Math.max(0, value);
993
+ if (bytes >= 1024 * 1024 * 1024)
994
+ return `${formatOptionalNumber(bytes / (1024 * 1024 * 1024))} GiB`;
995
+ if (bytes >= 1024 * 1024)
996
+ return `${formatOptionalNumber(bytes / (1024 * 1024))} MiB`;
997
+ if (bytes >= 1024)
998
+ return `${formatOptionalNumber(bytes / 1024)} KiB`;
999
+ return `${formatOptionalCount(bytes)} B`;
1000
+ }
1001
+ function formatMeters(value) {
1002
+ const text = Number.isInteger(value) ? String(value) : value.toFixed(2).replace(/\.?0+$/, '');
1003
+ return `${text} m`;
1004
+ }
1005
+ function formatDurationMs(value, language) {
1006
+ if (value == null || !Number.isFinite(value))
1007
+ return null;
1008
+ const duration = Math.max(0, value);
1009
+ if (duration < 1000)
1010
+ return `${Math.round(duration)} ms`;
1011
+ const seconds = duration / 1000;
1012
+ const text = seconds < 10 ? seconds.toFixed(1) : String(Math.round(seconds));
1013
+ return language === 'zh' ? `${text} 秒` : `${text}s`;
1014
+ }
1015
+ function createRenderingGroupsSection(slots) {
1016
+ return {
1017
+ id: 'rendering-groups',
1018
+ title: 'Rendering Groups / Order Presets',
1019
+ summary: 'Named Babylon rendering groups and alphaIndex presets used by object Inspector dropdowns.',
1020
+ layout: 'list',
1021
+ systems: slots.map((slot) => ({
1022
+ id: `rendering-group-${slot.renderingGroupId}`,
1023
+ label: slot.name,
1024
+ kind: 'rendering-group',
1025
+ active: true,
1026
+ summary: `Babylon group ${slot.renderingGroupId}`,
1027
+ actions: [{
1028
+ id: 'rendering-alpha-preset.add',
1029
+ label: 'Add Order Preset',
1030
+ icon: 'plus',
1031
+ tooltip: 'Add a named alphaIndex preset for this rendering group.',
1032
+ params: { renderingGroupId: slot.renderingGroupId },
1033
+ }],
1034
+ properties: [
1035
+ createReadonlyRenderingProperty(`renderingGroups.slots.${slot.renderingGroupId}.renderingGroupId`, 'Group ID', slot.renderingGroupId),
1036
+ {
1037
+ path: `renderingGroups.slots.${slot.renderingGroupId}.name`,
1038
+ label: 'Group Name',
1039
+ valueType: 'string',
1040
+ control: 'string',
1041
+ value: slot.name,
1042
+ tooltip: 'Display name for this fixed Babylon rendering group id.',
1043
+ commitMode: 'blur',
1044
+ },
1045
+ ...slot.alphaIndexPresets.flatMap((preset, index) => [
1046
+ {
1047
+ path: `renderingGroups.slots.${slot.renderingGroupId}.alphaIndexPresets.${index}.name`,
1048
+ label: `Preset ${index + 1} Name`,
1049
+ valueType: 'string',
1050
+ control: 'string',
1051
+ value: preset.name,
1052
+ tooltip: 'User-facing name shown in object Inspector dropdowns.',
1053
+ commitMode: 'blur',
1054
+ actions: [{
1055
+ id: 'rendering-alpha-preset.delete',
1056
+ label: 'Delete',
1057
+ icon: 'trash',
1058
+ tooltip: 'Delete this alphaIndex preset. Existing objects keep their numeric alphaIndex.',
1059
+ params: { renderingGroupId: slot.renderingGroupId, presetIndex: index },
1060
+ }],
1061
+ },
1062
+ {
1063
+ path: `renderingGroups.slots.${slot.renderingGroupId}.alphaIndexPresets.${index}.alphaIndex`,
1064
+ label: `Preset ${index + 1} Value`,
1065
+ valueType: 'number',
1066
+ control: 'number',
1067
+ value: preset.alphaIndex,
1068
+ step: 1,
1069
+ tooltip: 'Babylon alphaIndex value stored on objects that use this preset.',
1070
+ commitMode: 'blur',
1071
+ },
1072
+ ]),
1073
+ ],
1074
+ })),
1075
+ };
613
1076
  }
614
1077
  function createReadonlyRenderingProperty(path, label, value) {
615
1078
  return {
@@ -668,15 +1131,15 @@ function createEnvironmentTexturePickerControlOptions(input) {
668
1131
  function createShadowDefaultModeOptions(language) {
669
1132
  return language === 'zh'
670
1133
  ? [
671
- { label: '静态形状阴影', value: 'static' },
672
- { label: 'Blob 阴影', value: 'blob' },
673
1134
  { label: '无阴影', value: 'none' },
1135
+ { label: 'Blob 阴影', value: 'blob' },
1136
+ { label: '静态烘焙阴影', value: 'static' },
674
1137
  { label: '主平面阴影', value: 'planar' },
675
1138
  ]
676
1139
  : [
677
- { label: 'Static Shape', value: 'static' },
678
- { label: 'Blob', value: 'blob' },
679
1140
  { label: 'None', value: 'none' },
1141
+ { label: 'Blob', value: 'blob' },
1142
+ { label: 'Static Baked', value: 'static' },
680
1143
  { label: 'Planar', value: 'planar' },
681
1144
  ];
682
1145
  }
@@ -708,7 +1171,15 @@ const RENDERING_PANEL_TEXT = {
708
1171
  revert: 'Revert',
709
1172
  revertDirty: 'Revert rendering settings to the last saved rendering settings.',
710
1173
  revertClean: 'Rendering settings already match the last saved rendering settings.',
1174
+ bakeStatic: 'Bake Static Shadows',
1175
+ bakeStaticReady: 'Bake static shadow chunks for objects authored as Static Baked Shadow.',
1176
+ bakeStaticDisabled: 'Enable Static Baked Shadow before baking.',
1177
+ bakeStaticRunning: 'Static shadow bake is already running.',
711
1178
  sections: {
1179
+ 'rendering-groups': {
1180
+ title: 'Rendering Groups / Order Presets',
1181
+ summary: 'Named Babylon rendering groups and alphaIndex presets used by object Inspector dropdowns.',
1182
+ },
712
1183
  environment: {
713
1184
  title: 'Environment / IBL',
714
1185
  summary: 'World environment texture and reflection lighting shared by editor preview and runtime.',
@@ -722,6 +1193,24 @@ const RENDERING_PANEL_TEXT = {
722
1193
  summary: 'Global shadow systems for editor preview and runtime.',
723
1194
  },
724
1195
  },
1196
+ groups: {
1197
+ 'shadow-group-moving-object': {
1198
+ label: 'Moving Object Shadows',
1199
+ summary: 'Blob: lightweight for moving objects and project-default fallback.',
1200
+ },
1201
+ 'shadow-group-static-scene': {
1202
+ label: 'Static Scene Shadows',
1203
+ summary: 'Consumes baked artifacts; update during authoring/build, runtime only displays results.',
1204
+ },
1205
+ 'shadow-group-directional-planar': {
1206
+ label: 'Directional Planar Shadows',
1207
+ summary: 'Real-time planar projection following the directional light.',
1208
+ },
1209
+ 'shadow-group-compatibility': {
1210
+ label: 'Compatibility Shadows',
1211
+ summary: 'Legacy ShadowGenerator / CSM read-only compatibility paths.',
1212
+ },
1213
+ },
725
1214
  systems: {
726
1215
  'environment-global': {
727
1216
  label: 'Environment Texture',
@@ -739,7 +1228,7 @@ const RENDERING_PANEL_TEXT = {
739
1228
  summary: 'Default object shadow',
740
1229
  },
741
1230
  'static-projected-shadow': {
742
- label: 'Static Shape Shadow',
1231
+ label: 'Static Baked Shadow',
743
1232
  summary: 'Baked object shape',
744
1233
  },
745
1234
  'legacy-shadow': {
@@ -827,8 +1316,8 @@ const RENDERING_PANEL_TEXT = {
827
1316
  tooltip: 'Vertical offset above the static shadow plane to reduce z-fighting.',
828
1317
  },
829
1318
  'shadows.staticProjected.bake.resolution': {
830
- label: 'Resolution',
831
- tooltip: 'Silhouette bake texture resolution per caster.',
1319
+ label: 'Legacy Resolution',
1320
+ tooltip: 'Legacy v1 mask resolution. v2 SDF atlas bake uses Texels per Meter and Atlas Size.',
832
1321
  },
833
1322
  'shadows.staticProjected.bake.padding': {
834
1323
  label: 'Padding',
@@ -839,8 +1328,32 @@ const RENDERING_PANEL_TEXT = {
839
1328
  tooltip: 'Reserved blur radius for static shadow bake softness.',
840
1329
  },
841
1330
  'shadows.staticProjected.bake.maxSize': {
842
- label: 'Max Size',
843
- tooltip: 'Maximum projected bounds size for static shadows.',
1331
+ label: 'Legacy Max Size',
1332
+ tooltip: 'Legacy alias for Spatial Chunk Size.',
1333
+ },
1334
+ 'shadows.staticProjected.bake.texelsPerMeter': {
1335
+ label: 'Texels per Meter',
1336
+ tooltip: 'Target SDF atlas texel density for baked static shadows.',
1337
+ },
1338
+ 'shadows.staticProjected.bake.atlasSize': {
1339
+ label: 'Atlas Size',
1340
+ tooltip: 'Maximum width and height for each static shadow atlas page.',
1341
+ },
1342
+ 'shadows.staticProjected.bake.maxAtlasPages': {
1343
+ label: 'Page Budget',
1344
+ tooltip: 'Maximum atlas pages before bake lowers the effective texel density.',
1345
+ },
1346
+ 'shadows.staticProjected.bake.sdfRadiusPx': {
1347
+ label: 'SDF Radius',
1348
+ tooltip: 'Signed-distance radius in pixels used for crisp controllable edges.',
1349
+ },
1350
+ 'shadows.staticProjected.bake.spatialChunkSize': {
1351
+ label: 'Spatial Chunk Size',
1352
+ tooltip: 'World size of each spatial bake chunk before atlas packing.',
1353
+ },
1354
+ 'shadows.staticProjected.bake.targetChunkCount': {
1355
+ label: 'Target Chunks',
1356
+ tooltip: 'Soft chunk-count budget. Large scenes automatically enlarge spatial chunks to stay near this target.',
844
1357
  },
845
1358
  },
846
1359
  },
@@ -851,7 +1364,15 @@ const RENDERING_PANEL_TEXT = {
851
1364
  revert: '还原',
852
1365
  revertDirty: '还原到上一次保存的渲染设置。',
853
1366
  revertClean: '当前渲染设置已经和上一次保存状态一致。',
1367
+ bakeStatic: '烘焙静态阴影',
1368
+ bakeStaticReady: '为标记为静态烘焙阴影的物体生成分块阴影。',
1369
+ bakeStaticDisabled: '请先启用静态烘焙阴影。',
1370
+ bakeStaticRunning: '静态阴影正在烘焙中。',
854
1371
  sections: {
1372
+ 'rendering-groups': {
1373
+ title: '渲染分组 / 顺序预设',
1374
+ summary: '项目级 Babylon rendering group 名称和 alphaIndex 预设,用于物体 Inspector 下拉选择。',
1375
+ },
855
1376
  environment: {
856
1377
  title: '环境 / IBL',
857
1378
  summary: '世界环境贴图与 PBR 环境反射,编辑器预览和运行时共用。',
@@ -865,6 +1386,24 @@ const RENDERING_PANEL_TEXT = {
865
1386
  summary: '项目级阴影系统,编辑器预览和运行时共用。',
866
1387
  },
867
1388
  },
1389
+ groups: {
1390
+ 'shadow-group-moving-object': {
1391
+ label: '移动物体阴影',
1392
+ summary: 'Blob:低成本,适合移动物体,也可作为项目默认阴影。',
1393
+ },
1394
+ 'shadow-group-static-scene': {
1395
+ label: '静态场景阴影',
1396
+ summary: '只显示已烘焙 artifact;编辑器/构建期更新,运行时消费结果。',
1397
+ },
1398
+ 'shadow-group-directional-planar': {
1399
+ label: '主平面实时阴影',
1400
+ summary: '跟随直射光动态投影,适合需要方向感的物体。',
1401
+ },
1402
+ 'shadow-group-compatibility': {
1403
+ label: '兼容阴影',
1404
+ summary: '旧 ShadowGenerator / CSM 只读兼容路径。',
1405
+ },
1406
+ },
868
1407
  systems: {
869
1408
  'environment-global': {
870
1409
  label: '环境贴图',
@@ -882,7 +1421,7 @@ const RENDERING_PANEL_TEXT = {
882
1421
  summary: '默认物体阴影',
883
1422
  },
884
1423
  'static-projected-shadow': {
885
- label: '静态形状阴影',
1424
+ label: '静态烘焙阴影',
886
1425
  summary: '烘焙物体轮廓',
887
1426
  },
888
1427
  'legacy-shadow': {
@@ -1004,27 +1543,27 @@ const RENDERING_PANEL_TEXT = {
1004
1543
  },
1005
1544
  'shadows.staticProjected.enabled': {
1006
1545
  label: '启用',
1007
- tooltip: '启用共用的静态形状阴影系统。',
1546
+ tooltip: '启用共用的静态烘焙阴影系统。',
1008
1547
  },
1009
1548
  'shadows.staticProjected.appearance.color': {
1010
1549
  label: '颜色',
1011
- tooltip: '静态形状阴影颜色。透明度单独编辑。',
1550
+ tooltip: '静态烘焙阴影颜色。透明度单独编辑。',
1012
1551
  },
1013
1552
  'shadows.staticProjected.appearance.color.a': {
1014
1553
  label: '不透明度',
1015
- tooltip: '静态形状阴影不透明度,范围 0 到 1。',
1554
+ tooltip: '静态烘焙阴影不透明度,范围 0 到 1。',
1016
1555
  },
1017
1556
  'shadows.staticProjected.plane.height': {
1018
1557
  label: '高度',
1019
- tooltip: '静态形状阴影所在的地面高度。',
1558
+ tooltip: '静态烘焙阴影所在的地面高度。',
1020
1559
  },
1021
1560
  'shadows.staticProjected.plane.yOffset': {
1022
1561
  label: 'Y 偏移',
1023
- tooltip: '静态形状阴影相对地面的垂直偏移,用于避免 z-fighting。',
1562
+ tooltip: '静态烘焙阴影相对地面的垂直偏移,用于避免 z-fighting。',
1024
1563
  },
1025
1564
  'shadows.staticProjected.bake.resolution': {
1026
- label: '贴图尺寸',
1027
- tooltip: '每个投射物烘焙轮廓贴图的分辨率。',
1565
+ label: '旧版贴图尺寸',
1566
+ tooltip: '旧版 v1 mask 分辨率。v2 SDF atlas 烘焙使用每米像素和 Atlas 尺寸。',
1028
1567
  },
1029
1568
  'shadows.staticProjected.bake.padding': {
1030
1569
  label: '留白',
@@ -1035,8 +1574,32 @@ const RENDERING_PANEL_TEXT = {
1035
1574
  tooltip: '静态阴影烘焙柔化预留半径。',
1036
1575
  },
1037
1576
  'shadows.staticProjected.bake.maxSize': {
1038
- label: '最大尺寸',
1039
- tooltip: '静态形状阴影使用的最大投影范围尺寸。',
1577
+ label: '旧版最大尺寸',
1578
+ tooltip: '旧版字段,作为空间分块尺寸的兼容别名。',
1579
+ },
1580
+ 'shadows.staticProjected.bake.texelsPerMeter': {
1581
+ label: '每米像素',
1582
+ tooltip: '静态阴影 SDF atlas 的目标像素密度。',
1583
+ },
1584
+ 'shadows.staticProjected.bake.atlasSize': {
1585
+ label: 'Atlas 尺寸',
1586
+ tooltip: '每张静态阴影 atlas 页的最大宽高。',
1587
+ },
1588
+ 'shadows.staticProjected.bake.maxAtlasPages': {
1589
+ label: '页预算',
1590
+ tooltip: '超过该 atlas 页数时,烘焙会降低实际每米像素以保护运行时成本。',
1591
+ },
1592
+ 'shadows.staticProjected.bake.sdfRadiusPx': {
1593
+ label: 'SDF 半径',
1594
+ tooltip: '用于重建清晰可控边缘的有符号距离半径,单位像素。',
1595
+ },
1596
+ 'shadows.staticProjected.bake.spatialChunkSize': {
1597
+ label: '空间分块尺寸',
1598
+ tooltip: '进入 atlas packing 前,每个空间烘焙分块覆盖的世界尺寸。',
1599
+ },
1600
+ 'shadows.staticProjected.bake.targetChunkCount': {
1601
+ label: '目标分块数',
1602
+ tooltip: '分块数量软预算。大场景会自动放大空间分块,尽量接近该数量。',
1040
1603
  },
1041
1604
  'shadows.planar.enabled': {
1042
1605
  label: '启用',
@@ -1124,10 +1687,7 @@ function localizeRenderingPanelState(panel, language, dirty) {
1124
1687
  if (panel.status === RENDERING_PANEL_TEXT.en.dirtyStatus)
1125
1688
  panel.status = text.dirtyStatus;
1126
1689
  for (const action of panel.actions ?? []) {
1127
- if (action.id !== 'revert-rendering')
1128
- continue;
1129
- action.label = text.revert;
1130
- action.tooltip = dirty ? text.revertDirty : text.revertClean;
1690
+ localizeRenderingAction(action, text, dirty);
1131
1691
  }
1132
1692
  for (const section of panel.sections) {
1133
1693
  const sectionText = text.sections[section.id];
@@ -1137,10 +1697,18 @@ function localizeRenderingPanelState(panel, language, dirty) {
1137
1697
  section.summary = sectionText.summary;
1138
1698
  for (const system of section.systems) {
1139
1699
  const systemText = text.systems[system.id];
1700
+ if (system.group) {
1701
+ const groupText = text.groups[system.group.id];
1702
+ if (groupText?.label)
1703
+ system.group.label = groupText.label;
1704
+ if (groupText?.summary)
1705
+ system.group.summary = groupText.summary;
1706
+ }
1140
1707
  if (systemText?.label)
1141
1708
  system.label = systemText.label;
1142
- if (systemText?.summary)
1709
+ if (systemText?.summary && !(system.id === 'static-projected-shadow' && system.status)) {
1143
1710
  system.summary = systemText.summary;
1711
+ }
1144
1712
  if (language === 'zh' && system.id === 'environment-global' && system.summary === 'No IBL texture') {
1145
1713
  system.summary = '未设置 IBL 贴图';
1146
1714
  }
@@ -1148,12 +1716,28 @@ function localizeRenderingPanelState(panel, language, dirty) {
1148
1716
  system.summary = systemText.disabled;
1149
1717
  if (systemText?.compatibility && system.summary === RENDERING_PANEL_TEXT.en.systems[system.id]?.compatibility)
1150
1718
  system.summary = systemText.compatibility;
1719
+ for (const action of system.actions ?? [])
1720
+ localizeRenderingAction(action, text, dirty);
1151
1721
  for (const property of system.properties)
1152
1722
  localizeRenderingProperty(property, text);
1153
1723
  }
1154
1724
  }
1155
1725
  return panel;
1156
1726
  }
1727
+ function localizeRenderingAction(action, text, dirty) {
1728
+ if (action.id === 'revert-rendering') {
1729
+ action.label = text.revert;
1730
+ action.tooltip = dirty ? text.revertDirty : text.revertClean;
1731
+ }
1732
+ if (action.id === 'bake-static-shadows') {
1733
+ action.label = text.bakeStatic;
1734
+ action.tooltip = action.disabled
1735
+ ? action.tooltip === RENDERING_PANEL_TEXT.en.bakeStaticRunning
1736
+ ? text.bakeStaticRunning
1737
+ : text.bakeStaticDisabled
1738
+ : text.bakeStaticReady;
1739
+ }
1740
+ }
1157
1741
  function localizeRenderingProperty(property, text) {
1158
1742
  const propertyText = text.properties[property.path];
1159
1743
  if (!propertyText)