@meimu/mutracer 0.1.5 → 0.3.0

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 (590) hide show
  1. package/LICENSES/Classroom-CC0.txt +121 -0
  2. package/README.md +10 -7
  3. package/THIRD_PARTY_NOTICES.md +13 -8
  4. package/dist/assets/bvh.worker.js +1 -1
  5. package/dist/mutracer.umd.js +12316 -9228
  6. package/docs/api.md +232 -21
  7. package/docs/caustics.md +80 -0
  8. package/docs/denoising.md +30 -15
  9. package/docs/materials.md +6 -5
  10. package/docs/performance.md +5 -2
  11. package/docs/progressive-rendering.md +73 -1
  12. package/docs/technical/continuous-spectrum.md +93 -0
  13. package/docs/threejs.md +14 -5
  14. package/docs/updates.md +46 -2
  15. package/docs/viewer-checklist.md +65 -0
  16. package/docs/viewer.md +15 -8
  17. package/lib/Display.d.ts +13 -2
  18. package/lib/Display.js +28 -7
  19. package/lib/Display.js.map +1 -1
  20. package/lib/Engine.d.ts +4 -0
  21. package/lib/Engine.js +99 -37
  22. package/lib/Engine.js.map +1 -1
  23. package/lib/Render.d.ts +98 -15
  24. package/lib/Render.js +275 -27
  25. package/lib/Render.js.map +1 -1
  26. package/lib/RenderLoop.d.ts +11 -1
  27. package/lib/RenderLoop.js +120 -15
  28. package/lib/RenderLoop.js.map +1 -1
  29. package/lib/main.d.ts +6 -3
  30. package/lib/main.js +1 -0
  31. package/lib/main.js.map +1 -1
  32. package/lib/math/access.d.ts +4 -0
  33. package/lib/math/access.js +10 -0
  34. package/lib/math/access.js.map +1 -0
  35. package/lib/math/mat3.d.ts +4 -0
  36. package/lib/math/mat3.js +54 -0
  37. package/lib/math/mat3.js.map +1 -0
  38. package/lib/math/mat4.d.ts +19 -0
  39. package/lib/math/mat4.js +413 -0
  40. package/lib/math/mat4.js.map +1 -0
  41. package/lib/math/storage.d.ts +6 -0
  42. package/lib/math/storage.js +22 -0
  43. package/lib/math/storage.js.map +1 -0
  44. package/lib/math/types.d.ts +3 -0
  45. package/lib/math/types.js +2 -0
  46. package/lib/math/types.js.map +1 -0
  47. package/lib/math/vec2.d.ts +13 -0
  48. package/lib/math/vec2.js +52 -0
  49. package/lib/math/vec2.js.map +1 -0
  50. package/lib/math/vec3.d.ts +23 -0
  51. package/lib/math/vec3.js +139 -0
  52. package/lib/math/vec3.js.map +1 -0
  53. package/lib/math.d.ts +5 -17
  54. package/lib/math.js +5 -55
  55. package/lib/math.js.map +1 -1
  56. package/lib/oidn.d.ts +1 -1
  57. package/lib/oidn.js +4 -2
  58. package/lib/oidn.js.map +1 -1
  59. package/lib/oidnBundledWeights.cdn.d.ts +2 -2
  60. package/lib/renderer/AovPrimitiveCache.d.ts +10 -0
  61. package/lib/renderer/AovPrimitiveCache.js +48 -0
  62. package/lib/renderer/AovPrimitiveCache.js.map +1 -0
  63. package/lib/renderer/Box3.d.ts +5 -0
  64. package/lib/renderer/Box3.js +9 -0
  65. package/lib/renderer/Box3.js.map +1 -0
  66. package/lib/renderer/GPUTraceQueue.d.ts +11 -0
  67. package/lib/renderer/GPUTraceQueue.js +33 -0
  68. package/lib/renderer/GPUTraceQueue.js.map +1 -0
  69. package/lib/renderer/MaterialData.d.ts +15 -0
  70. package/lib/renderer/MaterialData.js +61 -0
  71. package/lib/renderer/MaterialData.js.map +1 -0
  72. package/lib/renderer/MaterialTable.d.ts +11 -98
  73. package/lib/renderer/MaterialTable.js +34 -412
  74. package/lib/renderer/MaterialTable.js.map +1 -1
  75. package/lib/renderer/RenderingPipeline.d.ts +36 -13
  76. package/lib/renderer/RenderingPipeline.js +1 -17
  77. package/lib/renderer/RenderingPipeline.js.map +1 -1
  78. package/lib/renderer/TileRender.d.ts +0 -1
  79. package/lib/renderer/TileRender.js +14 -1
  80. package/lib/renderer/TileRender.js.map +1 -1
  81. package/lib/renderer/WGPUAov.d.ts +39 -0
  82. package/lib/renderer/WGPUAov.js +239 -0
  83. package/lib/renderer/WGPUAov.js.map +1 -0
  84. package/lib/renderer/WGPUBindlessMaterialData.d.ts +17 -0
  85. package/lib/renderer/WGPUBindlessMaterialData.js +48 -0
  86. package/lib/renderer/WGPUBindlessMaterialData.js.map +1 -0
  87. package/lib/renderer/WGPUBindlessTextures.d.ts +47 -0
  88. package/lib/renderer/WGPUBindlessTextures.js +180 -0
  89. package/lib/renderer/WGPUBindlessTextures.js.map +1 -0
  90. package/lib/renderer/WGPUBloomPass.js +17 -97
  91. package/lib/renderer/WGPUBloomPass.js.map +1 -1
  92. package/lib/renderer/WGPUCausticLightPass.d.ts +48 -0
  93. package/lib/renderer/WGPUCausticLightPass.js +217 -0
  94. package/lib/renderer/WGPUCausticLightPass.js.map +1 -0
  95. package/lib/renderer/WGPUComputePass.d.ts +1 -1
  96. package/lib/renderer/WGPUComputePass.js.map +1 -1
  97. package/lib/renderer/WGPUEnvMapDistribution.d.ts +12 -0
  98. package/lib/renderer/WGPUEnvMapDistribution.js +150 -0
  99. package/lib/renderer/WGPUEnvMapDistribution.js.map +1 -0
  100. package/lib/renderer/WGPUFullQuadPass.js +10 -9
  101. package/lib/renderer/WGPUFullQuadPass.js.map +1 -1
  102. package/lib/renderer/WGPUJNLMDenoiser.d.ts +1 -20
  103. package/lib/renderer/WGPUJNLMDenoiser.js +4 -267
  104. package/lib/renderer/WGPUJNLMDenoiser.js.map +1 -1
  105. package/lib/renderer/WGPUPhotonMap.d.ts +37 -0
  106. package/lib/renderer/WGPUPhotonMap.js +191 -0
  107. package/lib/renderer/WGPUPhotonMap.js.map +1 -0
  108. package/lib/renderer/WGPURayTraceOutput.d.ts +13 -1
  109. package/lib/renderer/WGPURayTraceOutput.js +132 -29
  110. package/lib/renderer/WGPURayTraceOutput.js.map +1 -1
  111. package/lib/renderer/WGPURayTracePass.d.ts +83 -56
  112. package/lib/renderer/WGPURayTracePass.js +884 -837
  113. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  114. package/lib/renderer/WGPURenderingPipeline.d.ts +5 -3
  115. package/lib/renderer/WGPURenderingPipeline.js +297 -82
  116. package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
  117. package/lib/renderer/WGPUShaderCache.d.ts +2 -2
  118. package/lib/renderer/WGPUShaderCache.js +10 -5
  119. package/lib/renderer/WGPUShaderCache.js.map +1 -1
  120. package/lib/renderer/WGPUShaderCapabilities.d.ts +10 -0
  121. package/lib/renderer/WGPUShaderCapabilities.js +54 -0
  122. package/lib/renderer/WGPUShaderCapabilities.js.map +1 -0
  123. package/lib/renderer/WGPUSkyBaker.d.ts +13 -0
  124. package/lib/renderer/WGPUSkyBaker.js +85 -0
  125. package/lib/renderer/WGPUSkyBaker.js.map +1 -0
  126. package/lib/renderer/WebGLAov.d.ts +41 -0
  127. package/lib/renderer/WebGLAov.js +106 -0
  128. package/lib/renderer/WebGLAov.js.map +1 -0
  129. package/lib/renderer/WebGLFullQuadPass.d.ts +7 -4
  130. package/lib/renderer/WebGLFullQuadPass.js +22 -2
  131. package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
  132. package/lib/renderer/WebGLJNLMDenoiser.d.ts +1 -1
  133. package/lib/renderer/WebGLJNLMDenoiser.js +83 -74
  134. package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -1
  135. package/lib/renderer/WebGLRayTraceOutputPass.js +7 -4
  136. package/lib/renderer/WebGLRayTraceOutputPass.js.map +1 -1
  137. package/lib/renderer/WebGLRayTracePass.d.ts +18 -3
  138. package/lib/renderer/WebGLRayTracePass.js +121 -9
  139. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  140. package/lib/renderer/WebGLRenderingPipeline.js +126 -22
  141. package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
  142. package/lib/renderer/WebGLSkyBaker.d.ts +39 -0
  143. package/lib/renderer/WebGLSkyBaker.js +422 -0
  144. package/lib/renderer/WebGLSkyBaker.js.map +1 -0
  145. package/lib/renderer/WebGLSkySource.d.ts +9 -0
  146. package/lib/renderer/WebGLSkySource.js +28 -0
  147. package/lib/renderer/WebGLSkySource.js.map +1 -0
  148. package/lib/renderer/accumulationTarget.d.ts +6 -0
  149. package/lib/renderer/accumulationTarget.js.map +1 -1
  150. package/lib/renderer/aov.d.ts +42 -0
  151. package/lib/renderer/aov.js +50 -0
  152. package/lib/renderer/aov.js.map +1 -0
  153. package/lib/renderer/aovDisplay.d.ts +14 -0
  154. package/lib/renderer/aovDisplay.js +32 -0
  155. package/lib/renderer/aovDisplay.js.map +1 -0
  156. package/lib/renderer/aovScene.d.ts +21 -0
  157. package/lib/renderer/aovScene.js +139 -0
  158. package/lib/renderer/aovScene.js.map +1 -0
  159. package/lib/renderer/binnedSahBvh.js +2 -1
  160. package/lib/renderer/binnedSahBvh.js.map +1 -1
  161. package/lib/renderer/bvhAccel.d.ts +20 -10
  162. package/lib/renderer/bvhAccel.js +168 -58
  163. package/lib/renderer/bvhAccel.js.map +1 -1
  164. package/lib/renderer/bvhWorkerBuild.d.ts +1 -0
  165. package/lib/renderer/cameraSnapshot.js +2 -1
  166. package/lib/renderer/cameraSnapshot.js.map +1 -1
  167. package/lib/renderer/cameraUniform.d.ts +2 -0
  168. package/lib/renderer/cameraUniform.js +12 -0
  169. package/lib/renderer/cameraUniform.js.map +1 -0
  170. package/lib/renderer/causticDiagnostics.d.ts +31 -0
  171. package/lib/renderer/causticDiagnostics.js +5 -0
  172. package/lib/renderer/causticDiagnostics.js.map +1 -0
  173. package/lib/renderer/causticEmission.d.ts +10 -0
  174. package/lib/renderer/causticEmission.js +40 -0
  175. package/lib/renderer/causticEmission.js.map +1 -0
  176. package/lib/renderer/causticUniform.d.ts +12 -0
  177. package/lib/renderer/causticUniform.js +22 -0
  178. package/lib/renderer/causticUniform.js.map +1 -0
  179. package/lib/renderer/caustics.d.ts +16 -0
  180. package/lib/renderer/caustics.js +93 -0
  181. package/lib/renderer/caustics.js.map +1 -0
  182. package/lib/renderer/committedScene.js +4 -0
  183. package/lib/renderer/committedScene.js.map +1 -1
  184. package/lib/renderer/denoiser.d.ts +3 -11
  185. package/lib/renderer/denoiser.js.map +1 -1
  186. package/lib/renderer/depthQuery.js +4 -1
  187. package/lib/renderer/depthQuery.js.map +1 -1
  188. package/lib/renderer/displacementPreparation.d.ts +11 -0
  189. package/lib/renderer/displacementPreparation.js +351 -0
  190. package/lib/renderer/displacementPreparation.js.map +1 -0
  191. package/lib/renderer/displacementRange.d.ts +1 -0
  192. package/lib/renderer/displacementRange.js +9 -0
  193. package/lib/renderer/displacementRange.js.map +1 -0
  194. package/lib/renderer/displayParityDiagnostics.d.ts +11 -0
  195. package/lib/renderer/displayParityDiagnostics.js +2 -0
  196. package/lib/renderer/displayParityDiagnostics.js.map +1 -0
  197. package/lib/renderer/envMapCreation.d.ts +9 -8
  198. package/lib/renderer/envMapCreation.js +36 -12
  199. package/lib/renderer/envMapCreation.js.map +1 -1
  200. package/lib/renderer/envMapDistribution.d.ts +12 -2
  201. package/lib/renderer/envMapDistribution.js +43 -34
  202. package/lib/renderer/envMapDistribution.js.map +1 -1
  203. package/lib/renderer/geometryBvhBounds.d.ts +4 -0
  204. package/lib/renderer/geometryBvhBounds.js +82 -0
  205. package/lib/renderer/geometryBvhBounds.js.map +1 -0
  206. package/lib/renderer/geometryUpdateState.d.ts +32 -0
  207. package/lib/renderer/geometryUpdateState.js +2 -0
  208. package/lib/renderer/geometryUpdateState.js.map +1 -0
  209. package/lib/renderer/geometryUpdates.d.ts +17 -9
  210. package/lib/renderer/geometryUpdates.js +92 -33
  211. package/lib/renderer/geometryUpdates.js.map +1 -1
  212. package/lib/renderer/glsl/aovDisplay.frag.d.ts +3 -0
  213. package/lib/renderer/glsl/aovDisplay.frag.js +54 -0
  214. package/lib/renderer/glsl/aovDisplay.frag.js.map +1 -0
  215. package/lib/renderer/glsl/aovReflectance.glsl.d.ts +2 -0
  216. package/lib/renderer/glsl/aovReflectance.glsl.js +87 -0
  217. package/lib/renderer/glsl/aovReflectance.glsl.js.map +1 -0
  218. package/lib/renderer/glsl/aovReflectanceSamples.glsl.d.ts +2 -0
  219. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +135 -0
  220. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js.map +1 -0
  221. package/lib/renderer/glsl/aovTrace.frag.d.ts +2 -0
  222. package/lib/renderer/glsl/aovTrace.frag.js +121 -0
  223. package/lib/renderer/glsl/aovTrace.frag.js.map +1 -0
  224. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +12 -12
  225. package/lib/renderer/glsl/chunks/emissiveLight.glsl.d.ts +2 -0
  226. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +35 -0
  227. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js.map +1 -0
  228. package/lib/renderer/glsl/chunks/envMap.glsl.js +73 -67
  229. package/lib/renderer/glsl/chunks/envMap.glsl.js.map +1 -1
  230. package/lib/renderer/glsl/chunks/intersect.glsl.js +432 -434
  231. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
  232. package/lib/renderer/glsl/chunks/materialBuffer.glsl.d.ts +1 -0
  233. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +160 -157
  234. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
  235. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +802 -802
  236. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  237. package/lib/renderer/glsl/chunks/random.glsl.js +6 -6
  238. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.d.ts +1 -0
  239. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +72 -67
  240. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  241. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +94 -76
  242. package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
  243. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -0
  244. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +143 -120
  245. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
  246. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +21 -18
  247. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js.map +1 -1
  248. package/lib/renderer/glsl/chunks/sampling.glsl.js +91 -94
  249. package/lib/renderer/glsl/chunks/sampling.glsl.js.map +1 -1
  250. package/lib/renderer/glsl/chunks/sobol.glsl.js +79 -79
  251. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  252. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +12 -12
  253. package/lib/renderer/glsl/chunks/uvProjection.glsl.js.map +1 -1
  254. package/lib/renderer/glsl/depthQuery.frag.js +7 -7
  255. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +17 -9
  256. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js.map +1 -1
  257. package/lib/renderer/glsl/rayTrace.frag.d.ts +1 -1
  258. package/lib/renderer/glsl/rayTrace.frag.js +271 -248
  259. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
  260. package/lib/renderer/glsl/shadowCatcher.frag.js +37 -32
  261. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  262. package/lib/renderer/glsl/webglPipeline.frag.js +65 -60
  263. package/lib/renderer/glsl/webglPipeline.frag.js.map +1 -1
  264. package/lib/renderer/lightConstants.d.ts +10 -0
  265. package/lib/renderer/lightConstants.js +11 -0
  266. package/lib/renderer/lightConstants.js.map +1 -0
  267. package/lib/renderer/lightCore.d.ts +12 -0
  268. package/lib/renderer/lightCore.js +13 -0
  269. package/lib/renderer/lightCore.js.map +1 -0
  270. package/lib/renderer/lightSampling.d.ts +22 -18
  271. package/lib/renderer/lightSampling.js +135 -62
  272. package/lib/renderer/lightSampling.js.map +1 -1
  273. package/lib/renderer/lightsData.d.ts +21 -0
  274. package/lib/renderer/lightsData.js +192 -0
  275. package/lib/renderer/lightsData.js.map +1 -0
  276. package/lib/renderer/lightsUtil.d.ts +3 -26
  277. package/lib/renderer/lightsUtil.js +3 -153
  278. package/lib/renderer/lightsUtil.js.map +1 -1
  279. package/lib/renderer/materialBufferData.d.ts +70 -0
  280. package/lib/renderer/materialBufferData.js +2 -0
  281. package/lib/renderer/materialBufferData.js.map +1 -0
  282. package/lib/renderer/materialConstants.d.ts +11 -0
  283. package/lib/renderer/materialConstants.js +11 -0
  284. package/lib/renderer/materialConstants.js.map +1 -1
  285. package/lib/renderer/materialCore.d.ts +8 -0
  286. package/lib/renderer/materialCore.js +9 -0
  287. package/lib/renderer/materialCore.js.map +1 -0
  288. package/lib/renderer/materialEmission.d.ts +2 -2
  289. package/lib/renderer/materialEmission.js +3 -3
  290. package/lib/renderer/materialEmission.js.map +1 -1
  291. package/lib/renderer/materialLayout.d.ts +2 -101
  292. package/lib/renderer/materialLayout.js +110 -172
  293. package/lib/renderer/materialLayout.js.map +1 -1
  294. package/lib/renderer/materialLayoutSchema.d.ts +26 -0
  295. package/lib/renderer/materialLayoutSchema.js +172 -0
  296. package/lib/renderer/materialLayoutSchema.js.map +1 -0
  297. package/lib/renderer/materialParams.d.ts +69 -0
  298. package/lib/renderer/materialParams.js +272 -0
  299. package/lib/renderer/materialParams.js.map +1 -0
  300. package/lib/renderer/materialTextureSlots.d.ts +14 -324
  301. package/lib/renderer/materialTextureSlots.js +21 -8
  302. package/lib/renderer/materialTextureSlots.js.map +1 -1
  303. package/lib/renderer/materialTextures.d.ts +6 -0
  304. package/lib/renderer/{texturesFromMaterials.js → materialTextures.js} +1 -2
  305. package/lib/renderer/materialTextures.js.map +1 -0
  306. package/lib/renderer/mergeMeshesToGeometry.js +6 -147
  307. package/lib/renderer/mergeMeshesToGeometry.js.map +1 -1
  308. package/lib/renderer/meshInstances.d.ts +4 -21
  309. package/lib/renderer/meshInstances.js +10 -56
  310. package/lib/renderer/meshInstances.js.map +1 -1
  311. package/lib/renderer/oidnNetwork.d.ts +2 -2
  312. package/lib/renderer/oidnNetwork.js +1 -1
  313. package/lib/renderer/oidnNetwork.js.map +1 -1
  314. package/lib/renderer/openPbrEnergyLut.js +850 -846
  315. package/lib/renderer/openPbrEnergyLut.js.map +1 -1
  316. package/lib/renderer/ownedDenoiser.d.ts +9 -0
  317. package/lib/renderer/ownedDenoiser.js +2 -0
  318. package/lib/renderer/ownedDenoiser.js.map +1 -0
  319. package/lib/renderer/packedMeshInstances.d.ts +23 -0
  320. package/lib/renderer/packedMeshInstances.js +80 -0
  321. package/lib/renderer/packedMeshInstances.js.map +1 -0
  322. package/lib/renderer/prepareMeshBVH.d.ts +12 -47
  323. package/lib/renderer/prepareMeshBVH.js +21 -642
  324. package/lib/renderer/prepareMeshBVH.js.map +1 -1
  325. package/lib/renderer/proceduralEnvironmentPower.d.ts +3 -0
  326. package/lib/renderer/proceduralEnvironmentPower.js +8 -0
  327. package/lib/renderer/proceduralEnvironmentPower.js.map +1 -0
  328. package/lib/renderer/progressiveScheduler.d.ts +1 -0
  329. package/lib/renderer/progressiveScheduler.js +7 -3
  330. package/lib/renderer/progressiveScheduler.js.map +1 -1
  331. package/lib/renderer/renderPipeline.d.ts +4 -1
  332. package/lib/renderer/renderPipeline.js.map +1 -1
  333. package/lib/renderer/renderingLimits.d.ts +9 -0
  334. package/lib/renderer/renderingLimits.js +18 -0
  335. package/lib/renderer/renderingLimits.js.map +1 -0
  336. package/lib/renderer/researchTransport.d.ts +31 -0
  337. package/lib/renderer/researchTransport.js +5 -0
  338. package/lib/renderer/researchTransport.js.map +1 -0
  339. package/lib/renderer/sceneAssembly.d.ts +73 -0
  340. package/lib/renderer/sceneAssembly.js +109 -0
  341. package/lib/renderer/sceneAssembly.js.map +1 -0
  342. package/lib/renderer/sceneChangeCore.d.ts +39 -0
  343. package/lib/renderer/sceneChangeCore.js +307 -0
  344. package/lib/renderer/sceneChangeCore.js.map +1 -0
  345. package/lib/renderer/sceneChangeDetector.d.ts +3 -6
  346. package/lib/renderer/sceneChangeDetector.js +24 -150
  347. package/lib/renderer/sceneChangeDetector.js.map +1 -1
  348. package/lib/renderer/sceneLayoutSchema.d.ts +119 -0
  349. package/lib/renderer/sceneLayoutSchema.js +111 -0
  350. package/lib/renderer/sceneLayoutSchema.js.map +1 -0
  351. package/lib/renderer/sceneLightChanges.d.ts +3 -3
  352. package/lib/renderer/sceneLightChanges.js.map +1 -1
  353. package/lib/renderer/scenePreparation.d.ts +55 -0
  354. package/lib/renderer/scenePreparation.js +360 -0
  355. package/lib/renderer/scenePreparation.js.map +1 -0
  356. package/lib/renderer/scratchSampling.js +18 -18
  357. package/lib/renderer/scratchSampling.js.map +1 -1
  358. package/lib/renderer/shader.d.ts +2 -0
  359. package/lib/renderer/shader.js +2 -0
  360. package/lib/renderer/shader.js.map +1 -1
  361. package/lib/renderer/shaderCapabilities.d.ts +23 -0
  362. package/lib/renderer/shaderCapabilities.js +55 -0
  363. package/lib/renderer/shaderCapabilities.js.map +1 -0
  364. package/lib/renderer/shaderCapacity.d.ts +2 -0
  365. package/lib/renderer/shaderCapacity.js +5 -0
  366. package/lib/renderer/shaderCapacity.js.map +1 -0
  367. package/lib/renderer/skyModel.d.ts +9 -0
  368. package/lib/renderer/skyModel.js +10 -0
  369. package/lib/renderer/skyModel.js.map +1 -0
  370. package/lib/renderer/spectrum.d.ts +21 -0
  371. package/lib/renderer/spectrum.js +154 -0
  372. package/lib/renderer/spectrum.js.map +1 -0
  373. package/lib/renderer/textureAtlas.d.ts +60 -0
  374. package/lib/renderer/textureAtlas.js +145 -0
  375. package/lib/renderer/textureAtlas.js.map +1 -0
  376. package/lib/renderer/textureAtlasPixels.d.ts +7 -0
  377. package/lib/renderer/textureAtlasPixels.js +68 -0
  378. package/lib/renderer/textureAtlasPixels.js.map +1 -0
  379. package/lib/renderer/util.d.ts +1 -1
  380. package/lib/renderer/util.js.map +1 -1
  381. package/lib/renderer/webgl.d.ts +9 -2
  382. package/lib/renderer/webgl.js +54 -9
  383. package/lib/renderer/webgl.js.map +1 -1
  384. package/lib/renderer/webglLightSampling.d.ts +39 -0
  385. package/lib/renderer/webglLightSampling.js +15 -0
  386. package/lib/renderer/webglLightSampling.js.map +1 -0
  387. package/lib/renderer/wgpuBindless.d.ts +26 -0
  388. package/lib/renderer/wgpuBindless.js +95 -0
  389. package/lib/renderer/wgpuBindless.js.map +1 -0
  390. package/lib/renderer/wgpuBindlessSource.d.ts +2 -0
  391. package/lib/renderer/wgpuBindlessSource.js +51 -0
  392. package/lib/renderer/wgpuBindlessSource.js.map +1 -0
  393. package/lib/renderer/wgpuMaterialConstants.d.ts +4 -0
  394. package/lib/renderer/wgpuMaterialConstants.js +52 -0
  395. package/lib/renderer/wgpuMaterialConstants.js.map +1 -0
  396. package/lib/renderer/wgpuSceneUniform.d.ts +42 -0
  397. package/lib/renderer/wgpuSceneUniform.js +125 -0
  398. package/lib/renderer/wgpuSceneUniform.js.map +1 -0
  399. package/lib/renderer/wgpuShaderSource.d.ts +22 -0
  400. package/lib/renderer/wgpuShaderSource.js +33 -0
  401. package/lib/renderer/wgpuShaderSource.js.map +1 -0
  402. package/lib/renderer/wgsl/aovDisplay.wgsl.d.ts +1 -0
  403. package/lib/renderer/wgsl/aovDisplay.wgsl.js +70 -0
  404. package/lib/renderer/wgsl/aovDisplay.wgsl.js.map +1 -0
  405. package/lib/renderer/wgsl/aovReflectance.wgsl.d.ts +2 -0
  406. package/lib/renderer/wgsl/aovReflectance.wgsl.js +98 -0
  407. package/lib/renderer/wgsl/aovReflectance.wgsl.js.map +1 -0
  408. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.d.ts +2 -0
  409. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +135 -0
  410. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js.map +1 -0
  411. package/lib/renderer/wgsl/aovResolve.wgsl.d.ts +5 -0
  412. package/lib/renderer/wgsl/aovResolve.wgsl.js +38 -0
  413. package/lib/renderer/wgsl/aovResolve.wgsl.js.map +1 -0
  414. package/lib/renderer/wgsl/aovSnapshot.wgsl.d.ts +4 -0
  415. package/lib/renderer/wgsl/aovSnapshot.wgsl.js +21 -0
  416. package/lib/renderer/wgsl/aovSnapshot.wgsl.js.map +1 -0
  417. package/lib/renderer/wgsl/aovTrace.wgsl.d.ts +2 -0
  418. package/lib/renderer/wgsl/aovTrace.wgsl.js +115 -0
  419. package/lib/renderer/wgsl/aovTrace.wgsl.js.map +1 -0
  420. package/lib/renderer/wgsl/bloom.wgsl.d.ts +13 -0
  421. package/lib/renderer/wgsl/bloom.wgsl.js +92 -0
  422. package/lib/renderer/wgsl/bloom.wgsl.js.map +1 -0
  423. package/lib/renderer/wgsl/causticLight.compute.d.ts +6 -0
  424. package/lib/renderer/wgsl/causticLight.compute.js +537 -0
  425. package/lib/renderer/wgsl/causticLight.compute.js.map +1 -0
  426. package/lib/renderer/wgsl/chunks/background.wgsl.d.ts +2 -0
  427. package/lib/renderer/wgsl/chunks/background.wgsl.js +102 -0
  428. package/lib/renderer/wgsl/chunks/background.wgsl.js.map +1 -0
  429. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.d.ts +2 -0
  430. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +12 -0
  431. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js.map +1 -0
  432. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.d.ts +2 -0
  433. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +16 -0
  434. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js.map +1 -0
  435. package/lib/renderer/wgsl/chunks/caustics.wgsl.d.ts +1 -0
  436. package/lib/renderer/wgsl/chunks/caustics.wgsl.js +62 -0
  437. package/lib/renderer/wgsl/chunks/caustics.wgsl.js.map +1 -0
  438. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  439. package/lib/renderer/wgsl/chunks/envMap.wgsl.d.ts +1 -1
  440. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +41 -35
  441. package/lib/renderer/wgsl/chunks/envMap.wgsl.js.map +1 -1
  442. package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +13 -1
  443. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +747 -704
  444. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  445. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +16 -16
  446. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -1
  447. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +4 -1
  448. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +83 -79
  449. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  450. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +855 -857
  451. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js.map +1 -1
  452. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +137 -137
  453. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  454. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +3 -1
  455. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +52 -32
  456. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  457. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +1 -1
  458. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +152 -144
  459. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -1
  460. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
  461. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +269 -245
  462. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
  463. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +1 -1
  464. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +27 -14
  465. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -1
  466. package/lib/renderer/wgsl/chunks/sampling.wgsl.d.ts +1 -1
  467. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +91 -95
  468. package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -1
  469. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.d.ts +1 -1
  470. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js +1 -0
  471. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js.map +1 -1
  472. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +83 -83
  473. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +12 -12
  474. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js.map +1 -1
  475. package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +8 -3
  476. package/lib/renderer/wgsl/compose.frag.wgsl.js +143 -118
  477. package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -1
  478. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  479. package/lib/renderer/wgsl/depthQuery.wgsl.js +7 -7
  480. package/lib/renderer/wgsl/jnlm.compute.d.ts +25 -0
  481. package/lib/renderer/wgsl/jnlm.compute.js +315 -0
  482. package/lib/renderer/wgsl/jnlm.compute.js.map +1 -0
  483. package/lib/renderer/wgsl/offlineAdaptive.compute.js +28 -28
  484. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.d.ts +1 -0
  485. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +17 -0
  486. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js.map +1 -0
  487. package/lib/renderer/wgsl/photonMap.compute.d.ts +29 -0
  488. package/lib/renderer/wgsl/photonMap.compute.js +352 -0
  489. package/lib/renderer/wgsl/photonMap.compute.js.map +1 -0
  490. package/lib/renderer/wgsl/proceduralSky.compute.d.ts +1 -0
  491. package/lib/renderer/wgsl/proceduralSky.compute.js +198 -0
  492. package/lib/renderer/wgsl/proceduralSky.compute.js.map +1 -0
  493. package/lib/renderer/wgsl/rayTrace.compute.d.ts +25 -1
  494. package/lib/renderer/wgsl/rayTrace.compute.js +645 -500
  495. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  496. package/lib/scene/Camera.js +7 -3
  497. package/lib/scene/Camera.js.map +1 -1
  498. package/lib/scene/EnvironmentLight.d.ts +5 -9
  499. package/lib/scene/EnvironmentLight.js +4 -14
  500. package/lib/scene/EnvironmentLight.js.map +1 -1
  501. package/lib/scene/EnvironmentLightState.d.ts +18 -0
  502. package/lib/scene/EnvironmentLightState.js +19 -0
  503. package/lib/scene/EnvironmentLightState.js.map +1 -0
  504. package/lib/scene/Geometry.d.ts +12 -6
  505. package/lib/scene/Geometry.js +37 -13
  506. package/lib/scene/Geometry.js.map +1 -1
  507. package/lib/scene/InstanceState.d.ts +39 -0
  508. package/lib/scene/InstanceState.js +77 -0
  509. package/lib/scene/InstanceState.js.map +1 -0
  510. package/lib/scene/InstancedMesh.d.ts +1 -1
  511. package/lib/scene/InstancedMesh.js +3 -0
  512. package/lib/scene/InstancedMesh.js.map +1 -1
  513. package/lib/scene/MaterialState.d.ts +209 -0
  514. package/lib/scene/MaterialState.js +231 -0
  515. package/lib/scene/MaterialState.js.map +1 -0
  516. package/lib/scene/Mesh.d.ts +4 -6
  517. package/lib/scene/Mesh.js +3 -11
  518. package/lib/scene/Mesh.js.map +1 -1
  519. package/lib/scene/MeshState.d.ts +20 -0
  520. package/lib/scene/MeshState.js +35 -0
  521. package/lib/scene/MeshState.js.map +1 -0
  522. package/lib/scene/OpenPBRMaterial.d.ts +6 -168
  523. package/lib/scene/OpenPBRMaterial.js +5 -223
  524. package/lib/scene/OpenPBRMaterial.js.map +1 -1
  525. package/lib/scene/PixelTexture.d.ts +6 -0
  526. package/lib/scene/PixelTexture.js +10 -0
  527. package/lib/scene/PixelTexture.js.map +1 -0
  528. package/lib/scene/ProceduralSky.d.ts +24 -0
  529. package/lib/scene/ProceduralSky.js +40 -0
  530. package/lib/scene/ProceduralSky.js.map +1 -0
  531. package/lib/scene/RectLight.d.ts +2 -13
  532. package/lib/scene/RectLight.js +3 -21
  533. package/lib/scene/RectLight.js.map +1 -1
  534. package/lib/scene/RectLightState.d.ts +31 -0
  535. package/lib/scene/RectLightState.js +26 -0
  536. package/lib/scene/RectLightState.js.map +1 -0
  537. package/lib/scene/Scene.d.ts +15 -4
  538. package/lib/scene/Scene.js.map +1 -1
  539. package/lib/scene/SceneNode.js +7 -6
  540. package/lib/scene/SceneNode.js.map +1 -1
  541. package/lib/scene/Texture.d.ts +10 -41
  542. package/lib/scene/Texture.js +4 -33
  543. package/lib/scene/Texture.js.map +1 -1
  544. package/lib/scene/TextureState.d.ts +35 -0
  545. package/lib/scene/TextureState.js +35 -0
  546. package/lib/scene/TextureState.js.map +1 -0
  547. package/lib/scene/attributeData.d.ts +4 -0
  548. package/lib/scene/attributeData.js +10 -0
  549. package/lib/scene/attributeData.js.map +1 -0
  550. package/lib/scene/lightState.d.ts +8 -0
  551. package/lib/scene/lightState.js +2 -0
  552. package/lib/scene/lightState.js.map +1 -0
  553. package/lib/scene/openPbrSchema.d.ts +7 -12
  554. package/lib/scene/openPbrSchema.js +273 -28
  555. package/lib/scene/openPbrSchema.js.map +1 -1
  556. package/lib/scene/skyParameters.d.ts +20 -0
  557. package/lib/scene/skyParameters.js +28 -0
  558. package/lib/scene/skyParameters.js.map +1 -0
  559. package/lib/scene/textureData.d.ts +9 -0
  560. package/lib/scene/textureData.js +2 -0
  561. package/lib/scene/textureData.js.map +1 -0
  562. package/lib/scene/texturePixels.d.ts +6 -0
  563. package/lib/scene/texturePixels.js +10 -0
  564. package/lib/scene/texturePixels.js.map +1 -0
  565. package/lib/settings/display.d.ts +33 -0
  566. package/lib/settings/display.js +7 -0
  567. package/lib/settings/display.js.map +1 -1
  568. package/lib/settings/render.d.ts +36 -3
  569. package/lib/settings/render.js +4 -1
  570. package/lib/settings/render.js.map +1 -1
  571. package/lib/tinybvh/tinybvh.wasm +0 -0
  572. package/lib/util/commonGeometry.js +7 -7
  573. package/lib/util/commonGeometry.js.map +1 -1
  574. package/lib/util/fromTHREE.d.ts +4 -1
  575. package/lib/util/fromTHREE.js +20 -7
  576. package/lib/util/fromTHREE.js.map +1 -1
  577. package/lib/util/geometry.js +42 -29
  578. package/lib/util/geometry.js.map +1 -1
  579. package/lib/util/loadRGBE.js +3 -4
  580. package/lib/util/loadRGBE.js.map +1 -1
  581. package/lib/util/studioLighting.d.ts +18 -0
  582. package/lib/util/studioLighting.js +36 -0
  583. package/lib/util/studioLighting.js.map +1 -0
  584. package/lib/version.d.ts +1 -1
  585. package/lib/version.js +1 -1
  586. package/lib/version.js.map +1 -1
  587. package/llms.txt +5 -0
  588. package/package.json +33 -7
  589. package/lib/renderer/texturesFromMaterials.d.ts +0 -6
  590. package/lib/renderer/texturesFromMaterials.js.map +0 -1
@@ -0,0 +1,23 @@
1
+ export declare const MATERIAL_SHADER_CAPABILITIES: {
2
+ readonly transmission: 1;
3
+ readonly metal: 2;
4
+ };
5
+ export declare const LIGHT_SHADER_CAPABILITIES: {
6
+ readonly SphereLight: 1;
7
+ readonly RectLight: 2;
8
+ readonly SpotLight: 4;
9
+ readonly DirectionalLight: 8;
10
+ readonly emissive: 16;
11
+ };
12
+ export declare const ALL_MATERIAL_SHADER_CAPABILITIES = 3;
13
+ export declare const ALL_LIGHT_SHADER_CAPABILITIES = 31;
14
+ export declare function lightShaderCapabilities(types: readonly string[], emissiveCount: number): number;
15
+ export declare function updateSceneShaderCapabilities(constants: Record<string, boolean | number>): void;
16
+ export interface ShaderCapabilities {
17
+ SCENE_CAPABILITIES: number;
18
+ MATERIAL_CAPABILITIES: number;
19
+ LIGHT_CAPABILITIES: number;
20
+ }
21
+ export declare function shaderCapabilitiesInclude(supported: ShaderCapabilities, required: ShaderCapabilities): boolean;
22
+ /** Retain support, not the scene's active flags. Commit only after compilation succeeds. */
23
+ export declare function retainedShaderCapabilities(constants: Record<string, boolean | number>, previous?: ShaderCapabilities): ShaderCapabilities;
@@ -0,0 +1,55 @@
1
+ import { wgpuSceneFeatureFlags, WGPU_SCENE_FEATURE_BITS } from './WGPUSceneFeatures.js';
2
+ export const MATERIAL_SHADER_CAPABILITIES = { transmission: 1, metal: 2 };
3
+ export const LIGHT_SHADER_CAPABILITIES = {
4
+ SphereLight: 1, RectLight: 2, SpotLight: 4, DirectionalLight: 8, emissive: 16
5
+ };
6
+ export const ALL_MATERIAL_SHADER_CAPABILITIES = 3;
7
+ export const ALL_LIGHT_SHADER_CAPABILITIES = 31;
8
+ export function lightShaderCapabilities(types, emissiveCount) {
9
+ let mask = emissiveCount > 0 ? LIGHT_SHADER_CAPABILITIES.emissive : 0;
10
+ for (const type of types) {
11
+ switch (type) {
12
+ case 'SphereLight':
13
+ mask |= LIGHT_SHADER_CAPABILITIES.SphereLight;
14
+ break;
15
+ case 'RectLight':
16
+ mask |= LIGHT_SHADER_CAPABILITIES.RectLight;
17
+ break;
18
+ case 'SpotLight':
19
+ mask |= LIGHT_SHADER_CAPABILITIES.SpotLight;
20
+ break;
21
+ case 'DirectionalLight':
22
+ mask |= LIGHT_SHADER_CAPABILITIES.DirectionalLight;
23
+ break;
24
+ }
25
+ }
26
+ return mask;
27
+ }
28
+ export function updateSceneShaderCapabilities(constants) {
29
+ constants.SCENE_CAPABILITIES = wgpuSceneFeatureFlags(constants);
30
+ }
31
+ export function shaderCapabilitiesInclude(supported, required) {
32
+ return (supported.SCENE_CAPABILITIES & required.SCENE_CAPABILITIES) === required.SCENE_CAPABILITIES &&
33
+ (supported.MATERIAL_CAPABILITIES & required.MATERIAL_CAPABILITIES) === required.MATERIAL_CAPABILITIES &&
34
+ (supported.LIGHT_CAPABILITIES & required.LIGHT_CAPABILITIES) === required.LIGHT_CAPABILITIES;
35
+ }
36
+ /** Retain support, not the scene's active flags. Commit only after compilation succeeds. */
37
+ export function retainedShaderCapabilities(constants, previous) {
38
+ let scene = wgpuSceneFeatureFlags(constants) | (previous?.SCENE_CAPABILITIES ?? 0);
39
+ // Metalness is a continuous base-material edit, including the first change
40
+ // from a dielectric to a metal. Keep that support in every base variant.
41
+ const material = MATERIAL_SHADER_CAPABILITIES.metal |
42
+ Number(constants.MATERIAL_CAPABILITIES ?? 0) | (previous?.MATERIAL_CAPABILITIES ?? 0);
43
+ const commonSurface = WGPU_SCENE_FEATURE_BITS.HAS_COAT | WGPU_SCENE_FEATURE_BITS.HAS_FUZZ;
44
+ // Activate this small group on first use, keeping a plain scene's initial
45
+ // pipeline lean. Thin film, media, dispersion and alpha remain independent.
46
+ if ((scene & commonSurface) !== 0) {
47
+ scene |= commonSurface;
48
+ }
49
+ return {
50
+ SCENE_CAPABILITIES: scene,
51
+ MATERIAL_CAPABILITIES: material,
52
+ LIGHT_CAPABILITIES: Number(constants.LIGHT_CAPABILITIES ?? 0) | (previous?.LIGHT_CAPABILITIES ?? 0)
53
+ };
54
+ }
55
+ //# sourceMappingURL=shaderCapabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shaderCapabilities.js","sourceRoot":"","sources":["../../src/renderer/shaderCapabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,qBAAqB,EAAE,uBAAuB,EAAC,MAAM,wBAAwB,CAAC;AAEtF,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAC,YAAY,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAU,CAAC;AACjF,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE;CACrE,CAAC;AACX,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,CAAC;AAClD,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,CAAC;AAEhD,MAAM,UAAU,uBAAuB,CAAC,KAAwB,EAAE,aAAqB;IACrF,IAAI,IAAI,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACtE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,aAAa;gBAAE,IAAI,IAAI,yBAAyB,CAAC,WAAW,CAAC;gBAAC,MAAM;YACzE,KAAK,WAAW;gBAAE,IAAI,IAAI,yBAAyB,CAAC,SAAS,CAAC;gBAAC,MAAM;YACrE,KAAK,WAAW;gBAAE,IAAI,IAAI,yBAAyB,CAAC,SAAS,CAAC;gBAAC,MAAM;YACrE,KAAK,kBAAkB;gBAAE,IAAI,IAAI,yBAAyB,CAAC,gBAAgB,CAAC;gBAAC,MAAM;QACrF,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,SAA2C;IACvF,SAAS,CAAC,kBAAkB,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;AAClE,CAAC;AAQD,MAAM,UAAU,yBAAyB,CAAC,SAA6B,EAAE,QAA4B;IACnG,OAAO,CAAC,SAAS,CAAC,kBAAkB,GAAG,QAAQ,CAAC,kBAAkB,CAAC,KAAK,QAAQ,CAAC,kBAAkB;QACjG,CAAC,SAAS,CAAC,qBAAqB,GAAG,QAAQ,CAAC,qBAAqB,CAAC,KAAK,QAAQ,CAAC,qBAAqB;QACrG,CAAC,SAAS,CAAC,kBAAkB,GAAG,QAAQ,CAAC,kBAAkB,CAAC,KAAK,QAAQ,CAAC,kBAAkB,CAAC;AACjG,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,0BAA0B,CAAC,SAA2C,EAAE,QAA6B;IACnH,IAAI,KAAK,GAAG,qBAAqB,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,kBAAkB,IAAI,CAAC,CAAC,CAAC;IACnF,2EAA2E;IAC3E,yEAAyE;IACzE,MAAM,QAAQ,GAAG,4BAA4B,CAAC,KAAK;QACjD,MAAM,CAAC,SAAS,CAAC,qBAAqB,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,qBAAqB,IAAI,CAAC,CAAC,CAAC;IACxF,MAAM,aAAa,GAAG,uBAAuB,CAAC,QAAQ,GAAG,uBAAuB,CAAC,QAAQ,CAAC;IAC1F,0EAA0E;IAC1E,4EAA4E;IAC5E,IAAI,CAAC,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,KAAK,IAAI,aAAa,CAAC;IACzB,CAAC;IACD,OAAO;QACL,kBAAkB,EAAE,KAAK;QACzB,qBAAqB,EAAE,QAAQ;QAC/B,kBAAkB,EAAE,MAAM,CAAC,SAAS,CAAC,kBAAkB,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,kBAAkB,IAAI,CAAC,CAAC;KACpG,CAAC;AACJ,CAAC","sourcesContent":["import {wgpuSceneFeatureFlags, WGPU_SCENE_FEATURE_BITS} from './WGPUSceneFeatures.js';\n\nexport const MATERIAL_SHADER_CAPABILITIES = {transmission: 1, metal: 2} as const;\nexport const LIGHT_SHADER_CAPABILITIES = {\n SphereLight: 1, RectLight: 2, SpotLight: 4, DirectionalLight: 8, emissive: 16\n} as const;\nexport const ALL_MATERIAL_SHADER_CAPABILITIES = 3;\nexport const ALL_LIGHT_SHADER_CAPABILITIES = 31;\n\nexport function lightShaderCapabilities(types: readonly string[], emissiveCount: number) {\n let mask = emissiveCount > 0 ? LIGHT_SHADER_CAPABILITIES.emissive : 0;\n for (const type of types) {\n switch (type) {\n case 'SphereLight': mask |= LIGHT_SHADER_CAPABILITIES.SphereLight; break;\n case 'RectLight': mask |= LIGHT_SHADER_CAPABILITIES.RectLight; break;\n case 'SpotLight': mask |= LIGHT_SHADER_CAPABILITIES.SpotLight; break;\n case 'DirectionalLight': mask |= LIGHT_SHADER_CAPABILITIES.DirectionalLight; break;\n }\n }\n return mask;\n}\n\nexport function updateSceneShaderCapabilities(constants: Record<string, boolean | number>) {\n constants.SCENE_CAPABILITIES = wgpuSceneFeatureFlags(constants);\n}\n\nexport interface ShaderCapabilities {\n SCENE_CAPABILITIES: number;\n MATERIAL_CAPABILITIES: number;\n LIGHT_CAPABILITIES: number;\n}\n\nexport function shaderCapabilitiesInclude(supported: ShaderCapabilities, required: ShaderCapabilities) {\n return (supported.SCENE_CAPABILITIES & required.SCENE_CAPABILITIES) === required.SCENE_CAPABILITIES &&\n (supported.MATERIAL_CAPABILITIES & required.MATERIAL_CAPABILITIES) === required.MATERIAL_CAPABILITIES &&\n (supported.LIGHT_CAPABILITIES & required.LIGHT_CAPABILITIES) === required.LIGHT_CAPABILITIES;\n}\n\n/** Retain support, not the scene's active flags. Commit only after compilation succeeds. */\nexport function retainedShaderCapabilities(constants: Record<string, boolean | number>, previous?: ShaderCapabilities): ShaderCapabilities {\n let scene = wgpuSceneFeatureFlags(constants) | (previous?.SCENE_CAPABILITIES ?? 0);\n // Metalness is a continuous base-material edit, including the first change\n // from a dielectric to a metal. Keep that support in every base variant.\n const material = MATERIAL_SHADER_CAPABILITIES.metal |\n Number(constants.MATERIAL_CAPABILITIES ?? 0) | (previous?.MATERIAL_CAPABILITIES ?? 0);\n const commonSurface = WGPU_SCENE_FEATURE_BITS.HAS_COAT | WGPU_SCENE_FEATURE_BITS.HAS_FUZZ;\n // Activate this small group on first use, keeping a plain scene's initial\n // pipeline lean. Thin film, media, dispersion and alpha remain independent.\n if ((scene & commonSurface) !== 0) {\n scene |= commonSurface;\n }\n return {\n SCENE_CAPABILITIES: scene,\n MATERIAL_CAPABILITIES: material,\n LIGHT_CAPABILITIES: Number(constants.LIGHT_CAPABILITIES ?? 0) | (previous?.LIGHT_CAPABILITIES ?? 0)\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ /** Grow in coarse buckets; scene edits must not shrink a compiled stack. */
2
+ export declare function retainedShaderCapacity(required: number, previous?: number, minimum?: number): number;
@@ -0,0 +1,5 @@
1
+ /** Grow in coarse buckets; scene edits must not shrink a compiled stack. */
2
+ export function retainedShaderCapacity(required, previous = 0, minimum = 8) {
3
+ return Math.max(previous, minimum, 2 ** Math.ceil(Math.log2(Math.max(1, required))));
4
+ }
5
+ //# sourceMappingURL=shaderCapacity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shaderCapacity.js","sourceRoot":"","sources":["../../src/renderer/shaderCapacity.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,UAAU,sBAAsB,CAAC,QAAgB,EAAE,QAAQ,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC;IAChF,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACvF,CAAC","sourcesContent":["/** Grow in coarse buckets; scene edits must not shrink a compiled stack. */\nexport function retainedShaderCapacity(required: number, previous = 0, minimum = 8) {\n return Math.max(previous, minimum, 2 ** Math.ceil(Math.log2(Math.max(1, required))));\n}\n\n"]}
@@ -0,0 +1,9 @@
1
+ /** Apparent sun radius in degrees; larger than the real 0.27° so the disk reads at map resolution. */
2
+ export declare const SUN_RADIUS = 0.4;
3
+ /** Aerosol density relative to a very clean atmosphere (optical depth about 0.005). */
4
+ export declare const TURBIDITY = 5;
5
+ export declare const GROUND_ALBEDO: number[];
6
+ /** Sun plus sky irradiance on a horizontal plane with the sun at 33°. */
7
+ export declare const ILLUMINANCE: number;
8
+ /** Horizontal illuminance of this atmosphere for unit solar irradiance and a 33° sun. */
9
+ export declare const REFERENCE_ILLUMINANCE = 0.488;
@@ -0,0 +1,10 @@
1
+ /** Apparent sun radius in degrees; larger than the real 0.27° so the disk reads at map resolution. */
2
+ export const SUN_RADIUS = 0.4;
3
+ /** Aerosol density relative to a very clean atmosphere (optical depth about 0.005). */
4
+ export const TURBIDITY = 5;
5
+ export const GROUND_ALBEDO = [0.2, 0.18, 0.15];
6
+ /** Sun plus sky irradiance on a horizontal plane with the sun at 33°. */
7
+ export const ILLUMINANCE = Math.PI;
8
+ /** Horizontal illuminance of this atmosphere for unit solar irradiance and a 33° sun. */
9
+ export const REFERENCE_ILLUMINANCE = 0.488;
10
+ //# sourceMappingURL=skyModel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skyModel.js","sourceRoot":"","sources":["../../src/renderer/skyModel.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,CAAC;AAC9B,uFAAuF;AACvF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC;AAC3B,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC/C,yEAAyE;AACzE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC;AACnC,yFAAyF;AACzF,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC","sourcesContent":["/** Apparent sun radius in degrees; larger than the real 0.27° so the disk reads at map resolution. */\nexport const SUN_RADIUS = 0.4;\n/** Aerosol density relative to a very clean atmosphere (optical depth about 0.005). */\nexport const TURBIDITY = 5;\nexport const GROUND_ALBEDO = [0.2, 0.18, 0.15];\n/** Sun plus sky irradiance on a horizontal plane with the sun at 33°. */\nexport const ILLUMINANCE = Math.PI;\n/** Horizontal illuminance of this atmosphere for unit solar irradiance and a 33° sun. */\nexport const REFERENCE_ILLUMINANCE = 0.488;\n\n"]}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Continuous wavelength sampling shared by camera paths and caustic photons.
3
+ *
4
+ * CIE 1931 matching functions use the multi-lobe fit from Wyman, Sloan and
5
+ * Shirley, "Simple Analytic Approximations to the CIE XYZ Color Matching
6
+ * Functions", JCGT 2(2), 2013. Only the published formula and coefficients are
7
+ * used. Out-of-gamut negatives clamp to zero, and each channel is normalized so
8
+ * that a uniform wavelength keeps white light white.
9
+ */
10
+ export declare const SPECTRUM_WAVELENGTH_MIN = 400;
11
+ export declare const SPECTRUM_WAVELENGTH_RANGE = 300;
12
+ export declare function spectrumRgb(wavelength: number): number[];
13
+ export declare const SPECTRUM_PHOTON_DISTRIBUTION = 3;
14
+ /** Maps a unit random number to a wavelength and its probability density. */
15
+ export declare function spectrumSample(distribution: number, u: number): {
16
+ wavelength: number;
17
+ pdf: number;
18
+ };
19
+ export declare function spectrumIorWavelength(wavelength: number): number;
20
+ export declare const spectrumWgsl: string;
21
+ export declare const spectrumGlsl: string;
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Continuous wavelength sampling shared by camera paths and caustic photons.
3
+ *
4
+ * CIE 1931 matching functions use the multi-lobe fit from Wyman, Sloan and
5
+ * Shirley, "Simple Analytic Approximations to the CIE XYZ Color Matching
6
+ * Functions", JCGT 2(2), 2013. Only the published formula and coefficients are
7
+ * used. Out-of-gamut negatives clamp to zero, and each channel is normalized so
8
+ * that a uniform wavelength keeps white light white.
9
+ */
10
+ export const SPECTRUM_WAVELENGTH_MIN = 400;
11
+ export const SPECTRUM_WAVELENGTH_RANGE = 300;
12
+ // Amplitude, mean, sigma below the mean and sigma above it.
13
+ const XYZ_LOBES = [
14
+ [[1.056, 599.8, 37.9, 31.0], [0.362, 442.0, 16.0, 26.7], [-0.065, 501.1, 20.4, 26.2]],
15
+ [[0.821, 568.8, 46.9, 40.5], [0.286, 530.9, 16.3, 31.1]],
16
+ [[1.217, 437.0, 11.8, 36.0], [0.681, 459.0, 26.0, 13.8]]
17
+ ];
18
+ // Linear sRGB primaries, D65.
19
+ const XYZ_TO_RGB = [
20
+ [3.2406, -1.5372, -0.4986],
21
+ [-0.9689, 1.8758, 0.0415],
22
+ [0.0557, -0.204, 1.057]
23
+ ];
24
+ function unnormalizedRgb(wavelength) {
25
+ const xyz = XYZ_LOBES.map((lobes) => {
26
+ let sum = 0;
27
+ for (const lobe of lobes) {
28
+ const t = (wavelength - lobe[1]) / (wavelength < lobe[1] ? lobe[2] : lobe[3]);
29
+ sum += lobe[0] * Math.exp(-0.5 * t * t);
30
+ }
31
+ return sum;
32
+ });
33
+ return XYZ_TO_RGB.map((row) => Math.max(0, row[0] * xyz[0] + row[1] * xyz[1] + row[2] * xyz[2]));
34
+ }
35
+ function channelScale() {
36
+ const steps = 3000;
37
+ const sum = [0, 0, 0];
38
+ for (let i = 0; i < steps; i++) {
39
+ const rgb = unnormalizedRgb(SPECTRUM_WAVELENGTH_MIN + (SPECTRUM_WAVELENGTH_RANGE * (i + 0.5)) / steps);
40
+ for (let c = 0; c < 3; c++)
41
+ sum[c] += rgb[c] / steps;
42
+ }
43
+ // Rounded so JavaScript and native builds generate identical shader text.
44
+ return sum.map((mean) => Number((1 / mean).toFixed(6)));
45
+ }
46
+ const SCALE = channelScale();
47
+ export function spectrumRgb(wavelength) {
48
+ return unnormalizedRgb(wavelength).map((value, c) => value * SCALE[c]);
49
+ }
50
+ // Inverse CDFs in 5 nm bins: one per RGB channel for camera paths, and r+g+b for
51
+ // photons. Narrow bins keep each sampled response close to the fit.
52
+ const SAMPLE_BINS = 60;
53
+ const SAMPLE_BIN_WIDTH = SPECTRUM_WAVELENGTH_RANGE / SAMPLE_BINS;
54
+ export const SPECTRUM_PHOTON_DISTRIBUTION = 3;
55
+ function sampleCdfs() {
56
+ const substeps = 20;
57
+ const cdfs = [];
58
+ for (let distribution = 0; distribution <= SPECTRUM_PHOTON_DISTRIBUTION; distribution++) {
59
+ const cdf = [0];
60
+ for (let bin = 0; bin < SAMPLE_BINS; bin++) {
61
+ let mass = 0;
62
+ for (let i = 0; i < substeps; i++) {
63
+ const rgb = spectrumRgb(SPECTRUM_WAVELENGTH_MIN + (bin + (i + 0.5) / substeps) * SAMPLE_BIN_WIDTH);
64
+ mass += distribution === SPECTRUM_PHOTON_DISTRIBUTION ? rgb[0] + rgb[1] + rgb[2] : rgb[distribution];
65
+ }
66
+ cdf.push(cdf[bin] + mass);
67
+ }
68
+ for (const value of cdf)
69
+ cdfs.push(Number((value / cdf[SAMPLE_BINS]).toFixed(7)));
70
+ }
71
+ return cdfs;
72
+ }
73
+ const SAMPLE_CDFS = sampleCdfs();
74
+ /** Maps a unit random number to a wavelength and its probability density. */
75
+ export function spectrumSample(distribution, u) {
76
+ const first = distribution * (SAMPLE_BINS + 1);
77
+ let low = 0;
78
+ let high = SAMPLE_BINS;
79
+ while (high - low > 1) {
80
+ const middle = (low + high) >> 1;
81
+ if (SAMPLE_CDFS[first + middle] <= u)
82
+ low = middle;
83
+ else
84
+ high = middle;
85
+ }
86
+ const mass = SAMPLE_CDFS[first + low + 1] - SAMPLE_CDFS[first + low];
87
+ return {
88
+ wavelength: SPECTRUM_WAVELENGTH_MIN + SAMPLE_BIN_WIDTH * (low + (u - SAMPLE_CDFS[first + low]) / mass),
89
+ pdf: mass / SAMPLE_BIN_WIDTH
90
+ };
91
+ }
92
+ // Cauchy IOR grows quickly at short wavelengths and strong dispersion scales turn
93
+ // violet light into total internal reflection. Below 500 nm the refracting
94
+ // wavelength eases toward 475 nm, while color still follows the sampled wavelength.
95
+ const IOR_KNEE = 500;
96
+ const IOR_KNEE_WIDTH = 25;
97
+ export function spectrumIorWavelength(wavelength) {
98
+ if (wavelength >= IOR_KNEE)
99
+ return wavelength;
100
+ return IOR_KNEE - IOR_KNEE_WIDTH * (1 - Math.exp((wavelength - IOR_KNEE) / IOR_KNEE_WIDTH));
101
+ }
102
+ const CDF_LITERALS = SAMPLE_CDFS.map((value) => value.toFixed(7)).join(',');
103
+ const lobeSum = (lobes) => lobes.map((lobe) => `${lobe[0]}f*spectrumLobe(wavelength,${lobe[1]}f,${lobe[2]}f,${lobe[3]}f)`).join('+');
104
+ export const spectrumWgsl = /* wgsl */ `
105
+ fn spectrumLobe(wavelength:f32,mean:f32,below:f32,above:f32)->f32 {
106
+ let t=(wavelength-mean)/select(above,below,wavelength<mean);
107
+ return exp(-0.5*t*t);
108
+ }
109
+ fn spectrumRgb(wavelength:f32)->vec3f {
110
+ let xyz=vec3f(${XYZ_LOBES.map(lobeSum).join(',')});
111
+ let rgb=mat3x3f(${[0, 1, 2].map((c) => XYZ_TO_RGB.map((row) => `${row[c]}f`).join(',')).join(',')})*xyz;
112
+ return max(rgb,vec3f(0.0))*vec3f(${SCALE.map((s) => `${s}f`).join(',')});
113
+ }
114
+ fn spectrumIorWavelength(wavelength:f32)->f32 {
115
+ if(wavelength>=${IOR_KNEE}.0) { return wavelength; }
116
+ return ${IOR_KNEE}.0-${IOR_KNEE_WIDTH}.0*(1.0-exp((wavelength-${IOR_KNEE}.0)/${IOR_KNEE_WIDTH}.0));
117
+ }
118
+ const SPECTRUM_CDF=array<f32,${(SAMPLE_BINS + 1) * 4}>(${CDF_LITERALS});
119
+ fn spectrumSample(distribution:u32,u:f32,pdf:ptr<function,f32>)->f32 {
120
+ let first=distribution*${SAMPLE_BINS + 1}u;
121
+ var low=0u;
122
+ var high=${SAMPLE_BINS}u;
123
+ while(high-low>1u) {
124
+ let middle=(low+high)/2u;
125
+ if(SPECTRUM_CDF[first+middle]<=u) { low=middle; } else { high=middle; }
126
+ }
127
+ let mass=SPECTRUM_CDF[first+low+1u]-SPECTRUM_CDF[first+low];
128
+ *pdf=mass/${SAMPLE_BIN_WIDTH}.0;
129
+ return ${SPECTRUM_WAVELENGTH_MIN}.0+${SAMPLE_BIN_WIDTH}.0*(f32(low)+(u-SPECTRUM_CDF[first+low])/mass);
130
+ }
131
+
132
+ fn cU(channel:u32,u:f32)->f32 {
133
+ var pdf=0.0;
134
+ return spectrumIorWavelength(spectrumSample(channel,u,&pdf));
135
+ }
136
+ `;
137
+ export const spectrumGlsl = /* glsl */ `
138
+ const float SPECTRUM_CDF[${(SAMPLE_BINS + 1) * 4}]=float[${(SAMPLE_BINS + 1) * 4}](${CDF_LITERALS});
139
+
140
+ float cU(int channel,float u) {
141
+ int first=channel*${SAMPLE_BINS + 1};
142
+ int low=0;
143
+ int high=${SAMPLE_BINS};
144
+ while(high-low>1) {
145
+ int middle=(low+high)/2;
146
+ if(SPECTRUM_CDF[first+middle]<=u) { low=middle; } else { high=middle; }
147
+ }
148
+ float start=SPECTRUM_CDF[first+low];
149
+ float wavelength=${SPECTRUM_WAVELENGTH_MIN}.0+${SAMPLE_BIN_WIDTH}.0*(float(low)+(u-start)/(SPECTRUM_CDF[first+low+1]-start));
150
+ if(wavelength>=${IOR_KNEE}.0) { return wavelength; }
151
+ return ${IOR_KNEE}.0-${IOR_KNEE_WIDTH}.0*(1.0-exp((wavelength-${IOR_KNEE}.0)/${IOR_KNEE_WIDTH}.0));
152
+ }
153
+ `;
154
+ //# sourceMappingURL=spectrum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spectrum.js","sourceRoot":"","sources":["../../src/renderer/spectrum.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Continuous wavelength sampling shared by camera paths and caustic photons.\n *\n * CIE 1931 matching functions use the multi-lobe fit from Wyman, Sloan and\n * Shirley, \"Simple Analytic Approximations to the CIE XYZ Color Matching\n * Functions\", JCGT 2(2), 2013. Only the published formula and coefficients are\n * used. Out-of-gamut negatives clamp to zero, and each channel is normalized so\n * that a uniform wavelength keeps white light white.\n */\nexport const SPECTRUM_WAVELENGTH_MIN = 400;\nexport const SPECTRUM_WAVELENGTH_RANGE = 300;\n\n// Amplitude, mean, sigma below the mean and sigma above it.\nconst XYZ_LOBES: number[][][] = [\n [[1.056, 599.8, 37.9, 31.0], [0.362, 442.0, 16.0, 26.7], [-0.065, 501.1, 20.4, 26.2]],\n [[0.821, 568.8, 46.9, 40.5], [0.286, 530.9, 16.3, 31.1]],\n [[1.217, 437.0, 11.8, 36.0], [0.681, 459.0, 26.0, 13.8]]\n];\n// Linear sRGB primaries, D65.\nconst XYZ_TO_RGB: number[][] = [\n [3.2406, -1.5372, -0.4986],\n [-0.9689, 1.8758, 0.0415],\n [0.0557, -0.204, 1.057]\n];\n\nfunction unnormalizedRgb(wavelength: number): number[] {\n const xyz = XYZ_LOBES.map((lobes) => {\n let sum = 0;\n for (const lobe of lobes) {\n const t = (wavelength - lobe[1]) / (wavelength < lobe[1] ? lobe[2] : lobe[3]);\n sum += lobe[0] * Math.exp(-0.5 * t * t);\n }\n return sum;\n });\n return XYZ_TO_RGB.map((row) => Math.max(0, row[0] * xyz[0] + row[1] * xyz[1] + row[2] * xyz[2]));\n}\n\nfunction channelScale(): number[] {\n const steps = 3000;\n const sum = [0, 0, 0];\n for (let i = 0; i < steps; i++) {\n const rgb = unnormalizedRgb(SPECTRUM_WAVELENGTH_MIN + (SPECTRUM_WAVELENGTH_RANGE * (i + 0.5)) / steps);\n for (let c = 0; c < 3; c++) sum[c] += rgb[c] / steps;\n }\n // Rounded so JavaScript and native builds generate identical shader text.\n return sum.map((mean) => Number((1 / mean).toFixed(6)));\n}\nconst SCALE = channelScale();\n\nexport function spectrumRgb(wavelength: number): number[] {\n return unnormalizedRgb(wavelength).map((value, c) => value * SCALE[c]);\n}\n\n// Inverse CDFs in 5 nm bins: one per RGB channel for camera paths, and r+g+b for\n// photons. Narrow bins keep each sampled response close to the fit.\nconst SAMPLE_BINS = 60;\nconst SAMPLE_BIN_WIDTH = SPECTRUM_WAVELENGTH_RANGE / SAMPLE_BINS;\nexport const SPECTRUM_PHOTON_DISTRIBUTION = 3;\nfunction sampleCdfs(): number[] {\n const substeps = 20;\n const cdfs: number[] = [];\n for (let distribution = 0; distribution <= SPECTRUM_PHOTON_DISTRIBUTION; distribution++) {\n const cdf = [0];\n for (let bin = 0; bin < SAMPLE_BINS; bin++) {\n let mass = 0;\n for (let i = 0; i < substeps; i++) {\n const rgb = spectrumRgb(SPECTRUM_WAVELENGTH_MIN + (bin + (i + 0.5) / substeps) * SAMPLE_BIN_WIDTH);\n mass += distribution === SPECTRUM_PHOTON_DISTRIBUTION ? rgb[0] + rgb[1] + rgb[2] : rgb[distribution];\n }\n cdf.push(cdf[bin] + mass);\n }\n for (const value of cdf) cdfs.push(Number((value / cdf[SAMPLE_BINS]).toFixed(7)));\n }\n return cdfs;\n}\nconst SAMPLE_CDFS = sampleCdfs();\n\n/** Maps a unit random number to a wavelength and its probability density. */\nexport function spectrumSample(distribution: number, u: number) {\n const first = distribution * (SAMPLE_BINS + 1);\n let low = 0;\n let high = SAMPLE_BINS;\n while (high - low > 1) {\n const middle = (low + high) >> 1;\n if (SAMPLE_CDFS[first + middle] <= u) low = middle;\n else high = middle;\n }\n const mass = SAMPLE_CDFS[first + low + 1] - SAMPLE_CDFS[first + low];\n return {\n wavelength: SPECTRUM_WAVELENGTH_MIN + SAMPLE_BIN_WIDTH * (low + (u - SAMPLE_CDFS[first + low]) / mass),\n pdf: mass / SAMPLE_BIN_WIDTH\n };\n}\n\n// Cauchy IOR grows quickly at short wavelengths and strong dispersion scales turn\n// violet light into total internal reflection. Below 500 nm the refracting\n// wavelength eases toward 475 nm, while color still follows the sampled wavelength.\nconst IOR_KNEE = 500;\nconst IOR_KNEE_WIDTH = 25;\n\nexport function spectrumIorWavelength(wavelength: number) {\n if (wavelength >= IOR_KNEE) return wavelength;\n return IOR_KNEE - IOR_KNEE_WIDTH * (1 - Math.exp((wavelength - IOR_KNEE) / IOR_KNEE_WIDTH));\n}\n\nconst CDF_LITERALS = SAMPLE_CDFS.map((value) => value.toFixed(7)).join(',');\nconst lobeSum = (lobes: number[][]) =>\n lobes.map((lobe) => `${lobe[0]}f*spectrumLobe(wavelength,${lobe[1]}f,${lobe[2]}f,${lobe[3]}f)`).join('+');\n\nexport const spectrumWgsl = /* wgsl */ `\nfn spectrumLobe(wavelength:f32,mean:f32,below:f32,above:f32)->f32 {\n let t=(wavelength-mean)/select(above,below,wavelength<mean);\n return exp(-0.5*t*t);\n}\nfn spectrumRgb(wavelength:f32)->vec3f {\n let xyz=vec3f(${XYZ_LOBES.map(lobeSum).join(',')});\n let rgb=mat3x3f(${[0, 1, 2].map((c) => XYZ_TO_RGB.map((row) => `${row[c]}f`).join(',')).join(',')})*xyz;\n return max(rgb,vec3f(0.0))*vec3f(${SCALE.map((s) => `${s}f`).join(',')});\n}\nfn spectrumIorWavelength(wavelength:f32)->f32 {\n if(wavelength>=${IOR_KNEE}.0) { return wavelength; }\n return ${IOR_KNEE}.0-${IOR_KNEE_WIDTH}.0*(1.0-exp((wavelength-${IOR_KNEE}.0)/${IOR_KNEE_WIDTH}.0));\n}\nconst SPECTRUM_CDF=array<f32,${(SAMPLE_BINS + 1) * 4}>(${CDF_LITERALS});\nfn spectrumSample(distribution:u32,u:f32,pdf:ptr<function,f32>)->f32 {\n let first=distribution*${SAMPLE_BINS + 1}u;\n var low=0u;\n var high=${SAMPLE_BINS}u;\n while(high-low>1u) {\n let middle=(low+high)/2u;\n if(SPECTRUM_CDF[first+middle]<=u) { low=middle; } else { high=middle; }\n }\n let mass=SPECTRUM_CDF[first+low+1u]-SPECTRUM_CDF[first+low];\n *pdf=mass/${SAMPLE_BIN_WIDTH}.0;\n return ${SPECTRUM_WAVELENGTH_MIN}.0+${SAMPLE_BIN_WIDTH}.0*(f32(low)+(u-SPECTRUM_CDF[first+low])/mass);\n}\n// Refracting wavelength of a camera path that carries one RGB channel.\nfn spectrumCameraWavelength(channel:u32,u:f32)->f32 {\n var pdf=0.0;\n return spectrumIorWavelength(spectrumSample(channel,u,&pdf));\n}\n`;\n\nexport const spectrumGlsl = /* glsl */ `\nconst float SPECTRUM_CDF[${(SAMPLE_BINS + 1) * 4}]=float[${(SAMPLE_BINS + 1) * 4}](${CDF_LITERALS});\n// Refracting wavelength of a camera path that carries one RGB channel.\nfloat spectrumCameraWavelength(int channel,float u) {\n int first=channel*${SAMPLE_BINS + 1};\n int low=0;\n int high=${SAMPLE_BINS};\n while(high-low>1) {\n int middle=(low+high)/2;\n if(SPECTRUM_CDF[first+middle]<=u) { low=middle; } else { high=middle; }\n }\n float start=SPECTRUM_CDF[first+low];\n float wavelength=${SPECTRUM_WAVELENGTH_MIN}.0+${SAMPLE_BIN_WIDTH}.0*(float(low)+(u-start)/(SPECTRUM_CDF[first+low+1]-start));\n if(wavelength>=${IOR_KNEE}.0) { return wavelength; }\n return ${IOR_KNEE}.0-${IOR_KNEE_WIDTH}.0*(1.0-exp((wavelength-${IOR_KNEE}.0)/${IOR_KNEE_WIDTH}.0));\n}\n`;\n"]}
@@ -0,0 +1,60 @@
1
+ import type TextureState from '../scene/TextureState.js';
2
+ export declare const DEFAULT_MAX_TEXTURE_ARRAY_BYTES: number;
3
+ export interface MaterialTableOptions {
4
+ maxTextureArrayBytes?: number;
5
+ maxTextureArrayLayers?: number;
6
+ maxTextureDimension2D?: number;
7
+ }
8
+ export interface TextureAtlasStats {
9
+ estimatedBytes: number;
10
+ height: number;
11
+ layers: number;
12
+ packTimeMs: number;
13
+ scale: number;
14
+ sourcePixels: number;
15
+ textureCount: number;
16
+ width: number;
17
+ }
18
+ export interface AtlasPlacement {
19
+ height: number;
20
+ index: number;
21
+ layer: number;
22
+ width: number;
23
+ x: number;
24
+ y: number;
25
+ }
26
+ interface AtlasShelf {
27
+ height: number;
28
+ x: number;
29
+ y: number;
30
+ }
31
+ interface AtlasPage {
32
+ nextY: number;
33
+ placements: AtlasPlacement[];
34
+ shelves: AtlasShelf[];
35
+ }
36
+ export declare function planTextureAtlas(textures: TextureState[], mapColorLinear: number[], options?: MaterialTableOptions, floatStorage?: boolean): {
37
+ pages: AtlasPage[];
38
+ placements: AtlasPlacement[];
39
+ width: number;
40
+ height: number;
41
+ floatStorage: boolean;
42
+ bytesPerPixel: number;
43
+ mapInfo: number[];
44
+ mapTransform: number[];
45
+ mapWrap: number[];
46
+ mapUvChannel: number[];
47
+ mapColorLinear: number[];
48
+ stats: {
49
+ estimatedBytes: number;
50
+ height: number;
51
+ layers: number;
52
+ packTimeMs: number;
53
+ scale: number;
54
+ sourcePixels: number;
55
+ textureCount: number;
56
+ width: number;
57
+ };
58
+ };
59
+ export type TextureAtlasPlan = ReturnType<typeof planTextureAtlas>;
60
+ export {};
@@ -0,0 +1,145 @@
1
+ import { textureWrapIndex } from '../scene/TextureState.js';
2
+ export const DEFAULT_MAX_TEXTURE_ARRAY_BYTES = 384 * 1024 * 1024;
3
+ /**
4
+ * Packs material textures into a small 2D-array atlas.
5
+ *
6
+ * The input rectangles are sorted from tallest/largest to smallest, then
7
+ * placed with a shelf allocator. Each atlas layer contains horizontal shelves;
8
+ * a texture is inserted into the first shelf with enough remaining width, or a
9
+ * new shelf is opened below the existing ones. A new array layer is allocated
10
+ * only when none of the current layers has enough room.
11
+ *
12
+ * `makeTextureArray` first tries this packing at full resolution. If the result
13
+ * exceeds the adapter layer limit or the configured memory budget, it performs
14
+ * a binary search for the largest uniform scale that fits. This preserves full
15
+ * resolution whenever packing alone is sufficient and degrades predictably on
16
+ * constrained hardware.
17
+ *
18
+ * The returned placements keep the original logical texture indices. Shaders
19
+ * use per-texture atlas metadata instead of treating the logical index as the
20
+ * physical array layer.
21
+ */
22
+ function packTextureAtlas(textures, pageSize, scale) {
23
+ const pages = [];
24
+ const placements = new Array(textures.length);
25
+ const items = textures
26
+ .map((texture, index) => ({
27
+ height: Math.max(1, Math.floor(texture.image.height * scale)),
28
+ index,
29
+ width: Math.max(1, Math.floor(texture.image.width * scale))
30
+ }))
31
+ .sort((a, b) => b.height - a.height || b.width - a.width);
32
+ for (const item of items) {
33
+ let placement;
34
+ for (let layer = 0; layer < pages.length && !placement; layer++) {
35
+ const page = pages[layer];
36
+ for (const shelf of page.shelves) {
37
+ if (item.height <= shelf.height &&
38
+ shelf.x + item.width <= pageSize) {
39
+ placement = {
40
+ height: item.height, index: item.index, width: item.width,
41
+ layer,
42
+ x: shelf.x,
43
+ y: shelf.y
44
+ };
45
+ shelf.x += item.width;
46
+ break;
47
+ }
48
+ }
49
+ if (!placement && page.nextY + item.height <= pageSize) {
50
+ placement = {
51
+ height: item.height, index: item.index, width: item.width,
52
+ layer,
53
+ x: 0,
54
+ y: page.nextY
55
+ };
56
+ page.shelves.push({
57
+ height: item.height,
58
+ x: item.width,
59
+ y: page.nextY
60
+ });
61
+ page.nextY += item.height;
62
+ }
63
+ }
64
+ if (!placement) {
65
+ const layer = pages.length;
66
+ placement = { height: item.height, index: item.index, width: item.width, layer, x: 0, y: 0 };
67
+ pages.push({
68
+ nextY: item.height,
69
+ placements: [],
70
+ shelves: [{ height: item.height, x: item.width, y: 0 }]
71
+ });
72
+ }
73
+ pages[placement.layer].placements.push(placement);
74
+ placements[item.index] = placement;
75
+ }
76
+ return { pages, placements };
77
+ }
78
+ export function planTextureAtlas(textures, mapColorLinear, options = {}, floatStorage = mapColorLinear.some(value => !!value)) {
79
+ const bytesPerPixel = floatStorage ? 8 : 4;
80
+ if (!textures.length)
81
+ return { pages: [], placements: [],
82
+ width: 1, height: 1, floatStorage, bytesPerPixel, mapInfo: [],
83
+ mapTransform: [], mapWrap: [], mapUvChannel: [], mapColorLinear,
84
+ stats: { estimatedBytes: 0, height: 1, layers: 0, packTimeMs: 0, scale: 1,
85
+ sourcePixels: 0, textureCount: 0, width: 1 } };
86
+ const maxTextureArrayLayers = options.maxTextureArrayLayers ?? Infinity;
87
+ const maxTextureDimension2D = options.maxTextureDimension2D ?? Infinity;
88
+ const maxTextureArrayBytes = options.maxTextureArrayBytes ?? DEFAULT_MAX_TEXTURE_ARRAY_BYTES;
89
+ const sourcePixels = textures.reduce((sum, texture) => sum + texture.image.width * texture.image.height, 0);
90
+ const maxSourceDimension = textures.reduce((max, texture) => Math.max(max, texture.image.width, texture.image.height), 1);
91
+ const maxPageSizeFromBudget = Math.max(1, Math.floor(Math.sqrt(maxTextureArrayBytes / bytesPerPixel)));
92
+ const pageSize = Math.max(1, Math.floor(Math.min(maxSourceDimension, maxTextureDimension2D, maxPageSizeFromBudget)));
93
+ const pageBytes = pageSize * pageSize * bytesPerPixel;
94
+ const maxPageCount = Math.max(1, Math.min(maxTextureArrayLayers, Math.floor(maxTextureArrayBytes / pageBytes)));
95
+ const maxScale = Math.min(1, pageSize / maxSourceDimension);
96
+ let packed = packTextureAtlas(textures, pageSize, maxScale);
97
+ let scale = maxScale;
98
+ if (packed.pages.length > maxPageCount) {
99
+ let low = 0;
100
+ let high = maxScale;
101
+ let bestPacked;
102
+ let bestScale = 0;
103
+ for (let i = 0; i < 14; i++) {
104
+ const candidateScale = (low + high) / 2;
105
+ const candidate = packTextureAtlas(textures, pageSize, candidateScale);
106
+ if (candidate.pages.length <= maxPageCount) {
107
+ low = candidateScale;
108
+ bestScale = candidateScale;
109
+ bestPacked = candidate;
110
+ }
111
+ else {
112
+ high = candidateScale;
113
+ }
114
+ }
115
+ if (!bestPacked) {
116
+ throw new Error(`Unable to fit ${textures.length} textures into ${maxPageCount} atlas layers.`);
117
+ }
118
+ packed = bestPacked;
119
+ scale = bestScale;
120
+ }
121
+ const atlasWidth = packed.placements.reduce((max, placement) => Math.max(max, placement.x + placement.width), 1);
122
+ const atlasHeight = packed.placements.reduce((max, placement) => Math.max(max, placement.y + placement.height), 1);
123
+ // mapInfo = [uvScale.x, uvScale.y, layer + uvOffset.x, uvOffset.y].
124
+ // Packing layer and X offset into one float keeps the shader metadata to one
125
+ // vec4 per logical texture; floor(z) restores the layer and fract(z) the X.
126
+ const mapInfo = packed.placements.flatMap((placement) => {
127
+ const offsetX = (placement.x + 0.5) / atlasWidth;
128
+ const offsetY = (placement.y + 0.5) / atlasHeight;
129
+ return [
130
+ Math.max(placement.width - 1, 0) / atlasWidth,
131
+ Math.max(placement.height - 1, 0) / atlasHeight,
132
+ placement.layer + offsetX,
133
+ offsetY
134
+ ];
135
+ });
136
+ return { pages: packed.pages, placements: packed.placements, width: atlasWidth, height: atlasHeight,
137
+ floatStorage, bytesPerPixel, mapInfo,
138
+ mapTransform: textures.flatMap(texture => [texture.uvScale[0], texture.uvScale[1], texture.uvOffset[0], texture.uvOffset[1]]),
139
+ mapWrap: textures.flatMap(texture => [textureWrapIndex(texture.wrapS), textureWrapIndex(texture.wrapT)]),
140
+ mapUvChannel: textures.map(texture => texture.uvChannel), mapColorLinear,
141
+ stats: { estimatedBytes: atlasWidth * atlasHeight * packed.pages.length * bytesPerPixel,
142
+ height: atlasHeight, layers: packed.pages.length, packTimeMs: 0, scale, sourcePixels,
143
+ textureCount: textures.length, width: atlasWidth } };
144
+ }
145
+ //# sourceMappingURL=textureAtlas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textureAtlas.js","sourceRoot":"","sources":["../../src/renderer/textureAtlas.ts"],"names":[],"mappings":"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","sourcesContent":["import type TextureState from '../scene/TextureState.js';\nimport { textureWrapIndex } from '../scene/TextureState.js';\n\nexport const DEFAULT_MAX_TEXTURE_ARRAY_BYTES = 384 * 1024 * 1024;\n\nexport interface MaterialTableOptions {\n maxTextureArrayBytes?: number;\n maxTextureArrayLayers?: number;\n maxTextureDimension2D?: number;\n}\n\nexport interface TextureAtlasStats {\n estimatedBytes: number;\n height: number;\n layers: number;\n packTimeMs: number;\n scale: number;\n sourcePixels: number;\n textureCount: number;\n width: number;\n}\n\nexport interface AtlasPlacement {\n height: number;\n index: number;\n layer: number;\n width: number;\n x: number;\n y: number;\n}\n\ninterface AtlasShelf {\n height: number;\n x: number;\n y: number;\n}\n\ninterface AtlasPage {\n nextY: number;\n placements: AtlasPlacement[];\n shelves: AtlasShelf[];\n}\n\n/**\n * Packs material textures into a small 2D-array atlas.\n *\n * The input rectangles are sorted from tallest/largest to smallest, then\n * placed with a shelf allocator. Each atlas layer contains horizontal shelves;\n * a texture is inserted into the first shelf with enough remaining width, or a\n * new shelf is opened below the existing ones. A new array layer is allocated\n * only when none of the current layers has enough room.\n *\n * `makeTextureArray` first tries this packing at full resolution. If the result\n * exceeds the adapter layer limit or the configured memory budget, it performs\n * a binary search for the largest uniform scale that fits. This preserves full\n * resolution whenever packing alone is sufficient and degrades predictably on\n * constrained hardware.\n *\n * The returned placements keep the original logical texture indices. Shaders\n * use per-texture atlas metadata instead of treating the logical index as the\n * physical array layer.\n */\nfunction packTextureAtlas(\n textures: TextureState[],\n pageSize: number,\n scale: number\n) {\n const pages: AtlasPage[] = [];\n const placements = new Array<AtlasPlacement>(textures.length);\n const items = textures\n .map((texture, index) => ({\n height: Math.max(1, Math.floor(texture.image.height * scale)),\n index,\n width: Math.max(1, Math.floor(texture.image.width * scale))\n }))\n .sort((a, b) => b.height - a.height || b.width - a.width);\n\n for (const item of items) {\n let placement: AtlasPlacement | undefined;\n for (let layer = 0; layer < pages.length && !placement; layer++) {\n const page = pages[layer];\n for (const shelf of page.shelves) {\n if (\n item.height <= shelf.height &&\n shelf.x + item.width <= pageSize\n ) {\n placement = {\n height: item.height, index: item.index, width: item.width,\n layer,\n x: shelf.x,\n y: shelf.y\n };\n shelf.x += item.width;\n break;\n }\n }\n if (!placement && page.nextY + item.height <= pageSize) {\n placement = {\n height: item.height, index: item.index, width: item.width,\n layer,\n x: 0,\n y: page.nextY\n };\n page.shelves.push({\n height: item.height,\n x: item.width,\n y: page.nextY\n });\n page.nextY += item.height;\n }\n }\n\n if (!placement) {\n const layer = pages.length;\n placement = { height: item.height, index: item.index, width: item.width, layer, x: 0, y: 0 };\n pages.push({\n nextY: item.height,\n placements: [],\n shelves: [{ height: item.height, x: item.width, y: 0 }]\n });\n }\n pages[placement.layer].placements.push(placement);\n placements[item.index] = placement;\n }\n\n return { pages, placements };\n}\n\n\nexport function planTextureAtlas(textures: TextureState[], mapColorLinear: number[], options: MaterialTableOptions = {},\n floatStorage = mapColorLinear.some(value => !!value)) {\n const bytesPerPixel = floatStorage ? 8 : 4;\n if (!textures.length) return { pages: [] as AtlasPage[], placements: [] as AtlasPlacement[],\n width: 1, height: 1, floatStorage, bytesPerPixel, mapInfo: [] as number[],\n mapTransform: [] as number[], mapWrap: [] as number[], mapUvChannel: [] as number[], mapColorLinear,\n stats: {estimatedBytes: 0, height: 1, layers: 0, packTimeMs: 0, scale: 1,\n sourcePixels: 0, textureCount: 0, width: 1} };\n const maxTextureArrayLayers = options.maxTextureArrayLayers ?? Infinity;\n const maxTextureDimension2D = options.maxTextureDimension2D ?? Infinity;\n const maxTextureArrayBytes =\n options.maxTextureArrayBytes ?? DEFAULT_MAX_TEXTURE_ARRAY_BYTES;\n const sourcePixels = textures.reduce(\n (sum, texture) => sum + texture.image.width * texture.image.height,\n 0\n );\n const maxSourceDimension = textures.reduce(\n (max, texture) =>\n Math.max(max, texture.image.width, texture.image.height),\n 1\n );\n const maxPageSizeFromBudget = Math.max(\n 1,\n Math.floor(Math.sqrt(maxTextureArrayBytes / bytesPerPixel))\n );\n const pageSize = Math.max(\n 1,\n Math.floor(\n Math.min(\n maxSourceDimension,\n maxTextureDimension2D,\n maxPageSizeFromBudget\n )\n )\n );\n const pageBytes = pageSize * pageSize * bytesPerPixel;\n const maxPageCount = Math.max(\n 1,\n Math.min(\n maxTextureArrayLayers,\n Math.floor(maxTextureArrayBytes / pageBytes)\n )\n );\n const maxScale = Math.min(1, pageSize / maxSourceDimension);\n let packed = packTextureAtlas(textures, pageSize, maxScale);\n let scale = maxScale;\n\n if (packed.pages.length > maxPageCount) {\n let low = 0;\n let high = maxScale;\n let bestPacked: ReturnType<typeof packTextureAtlas> | undefined;\n let bestScale = 0;\n for (let i = 0; i < 14; i++) {\n const candidateScale = (low + high) / 2;\n const candidate = packTextureAtlas(\n textures,\n pageSize,\n candidateScale\n );\n if (candidate.pages.length <= maxPageCount) {\n low = candidateScale;\n bestScale = candidateScale;\n bestPacked = candidate;\n } else {\n high = candidateScale;\n }\n }\n if (!bestPacked) {\n throw new Error(\n `Unable to fit ${textures.length} textures into ${maxPageCount} atlas layers.`\n );\n }\n packed = bestPacked;\n scale = bestScale;\n }\n\n const atlasWidth = packed.placements.reduce((max, placement) => Math.max(max, placement.x + placement.width), 1);\n const atlasHeight = packed.placements.reduce((max, placement) => Math.max(max, placement.y + placement.height), 1);\n // mapInfo = [uvScale.x, uvScale.y, layer + uvOffset.x, uvOffset.y].\n // Packing layer and X offset into one float keeps the shader metadata to one\n // vec4 per logical texture; floor(z) restores the layer and fract(z) the X.\n const mapInfo = packed.placements.flatMap((placement) => {\n const offsetX = (placement.x + 0.5) / atlasWidth;\n const offsetY = (placement.y + 0.5) / atlasHeight;\n return [\n Math.max(placement.width - 1, 0) / atlasWidth,\n Math.max(placement.height - 1, 0) / atlasHeight,\n placement.layer + offsetX,\n offsetY\n ];\n });\n\n return { pages: packed.pages, placements: packed.placements, width: atlasWidth, height: atlasHeight,\n floatStorage, bytesPerPixel, mapInfo,\n mapTransform: textures.flatMap(texture => [texture.uvScale[0], texture.uvScale[1], texture.uvOffset[0], texture.uvOffset[1]]),\n mapWrap: textures.flatMap(texture => [textureWrapIndex(texture.wrapS), textureWrapIndex(texture.wrapT)]),\n mapUvChannel: textures.map(texture => texture.uvChannel), mapColorLinear,\n stats: { estimatedBytes: atlasWidth * atlasHeight * packed.pages.length * bytesPerPixel,\n height: atlasHeight, layers: packed.pages.length, packTimeMs: 0, scale, sourcePixels,\n textureCount: textures.length, width: atlasWidth } };\n}\nexport type TextureAtlasPlan = ReturnType<typeof planTextureAtlas>;\n"]}
@@ -0,0 +1,7 @@
1
+ import type { TextureDataSource } from '../scene/textureData.js';
2
+ import type { AtlasPlacement } from './textureAtlas.js';
3
+ export declare function writeAtlasPixel(data: Uint16Array | Uint8Array, index: number, value: number): void;
4
+ export declare function writeRawAtlasPlacement(data: Uint16Array | Uint8Array, width: number, placement: AtlasPlacement, texture: {
5
+ image: TextureDataSource;
6
+ flipY: boolean;
7
+ }, floatStorage: boolean): void;