@meimu/mutracer 0.1.5 → 0.2.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 (526) hide show
  1. package/LICENSES/Classroom-CC0.txt +121 -0
  2. package/README.md +7 -7
  3. package/THIRD_PARTY_NOTICES.md +13 -8
  4. package/dist/assets/bvh.worker.js +1 -1
  5. package/dist/mutracer.umd.js +10407 -8353
  6. package/docs/api.md +200 -10
  7. package/docs/denoising.md +30 -15
  8. package/docs/materials.md +1 -1
  9. package/docs/performance.md +5 -2
  10. package/docs/progressive-rendering.md +32 -1
  11. package/docs/threejs.md +14 -5
  12. package/docs/updates.md +44 -2
  13. package/docs/viewer.md +11 -6
  14. package/lib/Display.d.ts +13 -2
  15. package/lib/Display.js +27 -6
  16. package/lib/Display.js.map +1 -1
  17. package/lib/Engine.d.ts +2 -0
  18. package/lib/Engine.js +52 -25
  19. package/lib/Engine.js.map +1 -1
  20. package/lib/Render.d.ts +44 -9
  21. package/lib/Render.js +115 -17
  22. package/lib/Render.js.map +1 -1
  23. package/lib/RenderLoop.d.ts +7 -1
  24. package/lib/RenderLoop.js +94 -13
  25. package/lib/RenderLoop.js.map +1 -1
  26. package/lib/main.d.ts +6 -3
  27. package/lib/main.js +1 -0
  28. package/lib/main.js.map +1 -1
  29. package/lib/math/access.d.ts +4 -0
  30. package/lib/math/access.js +10 -0
  31. package/lib/math/access.js.map +1 -0
  32. package/lib/math/mat3.d.ts +4 -0
  33. package/lib/math/mat3.js +54 -0
  34. package/lib/math/mat3.js.map +1 -0
  35. package/lib/math/mat4.d.ts +19 -0
  36. package/lib/math/mat4.js +413 -0
  37. package/lib/math/mat4.js.map +1 -0
  38. package/lib/math/storage.d.ts +6 -0
  39. package/lib/math/storage.js +22 -0
  40. package/lib/math/storage.js.map +1 -0
  41. package/lib/math/types.d.ts +3 -0
  42. package/lib/math/types.js +2 -0
  43. package/lib/math/types.js.map +1 -0
  44. package/lib/math/vec2.d.ts +13 -0
  45. package/lib/math/vec2.js +52 -0
  46. package/lib/math/vec2.js.map +1 -0
  47. package/lib/math/vec3.d.ts +23 -0
  48. package/lib/math/vec3.js +139 -0
  49. package/lib/math/vec3.js.map +1 -0
  50. package/lib/math.d.ts +5 -17
  51. package/lib/math.js +5 -55
  52. package/lib/math.js.map +1 -1
  53. package/lib/oidn.d.ts +1 -1
  54. package/lib/oidn.js +4 -2
  55. package/lib/oidn.js.map +1 -1
  56. package/lib/oidnBundledWeights.cdn.d.ts +2 -2
  57. package/lib/renderer/AovPrimitiveCache.d.ts +10 -0
  58. package/lib/renderer/AovPrimitiveCache.js +48 -0
  59. package/lib/renderer/AovPrimitiveCache.js.map +1 -0
  60. package/lib/renderer/Box3.d.ts +5 -0
  61. package/lib/renderer/Box3.js +9 -0
  62. package/lib/renderer/Box3.js.map +1 -0
  63. package/lib/renderer/GPUTraceQueue.d.ts +10 -0
  64. package/lib/renderer/GPUTraceQueue.js +31 -0
  65. package/lib/renderer/GPUTraceQueue.js.map +1 -0
  66. package/lib/renderer/MaterialData.d.ts +15 -0
  67. package/lib/renderer/MaterialData.js +61 -0
  68. package/lib/renderer/MaterialData.js.map +1 -0
  69. package/lib/renderer/MaterialTable.d.ts +11 -98
  70. package/lib/renderer/MaterialTable.js +34 -412
  71. package/lib/renderer/MaterialTable.js.map +1 -1
  72. package/lib/renderer/RenderingPipeline.d.ts +32 -13
  73. package/lib/renderer/RenderingPipeline.js +1 -17
  74. package/lib/renderer/RenderingPipeline.js.map +1 -1
  75. package/lib/renderer/TileRender.d.ts +0 -1
  76. package/lib/renderer/TileRender.js +14 -1
  77. package/lib/renderer/TileRender.js.map +1 -1
  78. package/lib/renderer/WGPUAov.d.ts +39 -0
  79. package/lib/renderer/WGPUAov.js +239 -0
  80. package/lib/renderer/WGPUAov.js.map +1 -0
  81. package/lib/renderer/WGPUBindlessMaterialData.d.ts +17 -0
  82. package/lib/renderer/WGPUBindlessMaterialData.js +48 -0
  83. package/lib/renderer/WGPUBindlessMaterialData.js.map +1 -0
  84. package/lib/renderer/WGPUBindlessTextures.d.ts +47 -0
  85. package/lib/renderer/WGPUBindlessTextures.js +180 -0
  86. package/lib/renderer/WGPUBindlessTextures.js.map +1 -0
  87. package/lib/renderer/WGPUBloomPass.js +17 -97
  88. package/lib/renderer/WGPUBloomPass.js.map +1 -1
  89. package/lib/renderer/WGPUComputePass.d.ts +1 -1
  90. package/lib/renderer/WGPUComputePass.js.map +1 -1
  91. package/lib/renderer/WGPUEnvMapDistribution.d.ts +12 -0
  92. package/lib/renderer/WGPUEnvMapDistribution.js +150 -0
  93. package/lib/renderer/WGPUEnvMapDistribution.js.map +1 -0
  94. package/lib/renderer/WGPUFullQuadPass.js +10 -9
  95. package/lib/renderer/WGPUFullQuadPass.js.map +1 -1
  96. package/lib/renderer/WGPUJNLMDenoiser.d.ts +1 -20
  97. package/lib/renderer/WGPUJNLMDenoiser.js +4 -267
  98. package/lib/renderer/WGPUJNLMDenoiser.js.map +1 -1
  99. package/lib/renderer/WGPURayTraceOutput.js +26 -17
  100. package/lib/renderer/WGPURayTraceOutput.js.map +1 -1
  101. package/lib/renderer/WGPURayTracePass.d.ts +36 -40
  102. package/lib/renderer/WGPURayTracePass.js +399 -550
  103. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  104. package/lib/renderer/WGPURenderingPipeline.d.ts +5 -3
  105. package/lib/renderer/WGPURenderingPipeline.js +239 -60
  106. package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
  107. package/lib/renderer/WGPUShaderCache.d.ts +2 -2
  108. package/lib/renderer/WGPUShaderCache.js +10 -5
  109. package/lib/renderer/WGPUShaderCache.js.map +1 -1
  110. package/lib/renderer/WGPUShaderCapabilities.d.ts +10 -0
  111. package/lib/renderer/WGPUShaderCapabilities.js +54 -0
  112. package/lib/renderer/WGPUShaderCapabilities.js.map +1 -0
  113. package/lib/renderer/WGPUSkyBaker.d.ts +13 -0
  114. package/lib/renderer/WGPUSkyBaker.js +85 -0
  115. package/lib/renderer/WGPUSkyBaker.js.map +1 -0
  116. package/lib/renderer/WebGLAov.d.ts +41 -0
  117. package/lib/renderer/WebGLAov.js +106 -0
  118. package/lib/renderer/WebGLAov.js.map +1 -0
  119. package/lib/renderer/WebGLFullQuadPass.d.ts +5 -3
  120. package/lib/renderer/WebGLFullQuadPass.js +18 -2
  121. package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
  122. package/lib/renderer/WebGLJNLMDenoiser.d.ts +1 -1
  123. package/lib/renderer/WebGLJNLMDenoiser.js +83 -74
  124. package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -1
  125. package/lib/renderer/WebGLRayTraceOutputPass.js +7 -4
  126. package/lib/renderer/WebGLRayTraceOutputPass.js.map +1 -1
  127. package/lib/renderer/WebGLRayTracePass.d.ts +12 -2
  128. package/lib/renderer/WebGLRayTracePass.js +82 -7
  129. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  130. package/lib/renderer/WebGLRenderingPipeline.js +116 -8
  131. package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
  132. package/lib/renderer/WebGLSkyBaker.d.ts +39 -0
  133. package/lib/renderer/WebGLSkyBaker.js +422 -0
  134. package/lib/renderer/WebGLSkyBaker.js.map +1 -0
  135. package/lib/renderer/WebGLSkySource.d.ts +9 -0
  136. package/lib/renderer/WebGLSkySource.js +28 -0
  137. package/lib/renderer/WebGLSkySource.js.map +1 -0
  138. package/lib/renderer/accumulationTarget.d.ts +5 -0
  139. package/lib/renderer/accumulationTarget.js.map +1 -1
  140. package/lib/renderer/aov.d.ts +42 -0
  141. package/lib/renderer/aov.js +50 -0
  142. package/lib/renderer/aov.js.map +1 -0
  143. package/lib/renderer/aovDisplay.d.ts +14 -0
  144. package/lib/renderer/aovDisplay.js +32 -0
  145. package/lib/renderer/aovDisplay.js.map +1 -0
  146. package/lib/renderer/aovScene.d.ts +21 -0
  147. package/lib/renderer/aovScene.js +139 -0
  148. package/lib/renderer/aovScene.js.map +1 -0
  149. package/lib/renderer/binnedSahBvh.js +2 -1
  150. package/lib/renderer/binnedSahBvh.js.map +1 -1
  151. package/lib/renderer/bvhAccel.d.ts +20 -10
  152. package/lib/renderer/bvhAccel.js +168 -58
  153. package/lib/renderer/bvhAccel.js.map +1 -1
  154. package/lib/renderer/bvhWorkerBuild.d.ts +1 -0
  155. package/lib/renderer/cameraSnapshot.js +2 -1
  156. package/lib/renderer/cameraSnapshot.js.map +1 -1
  157. package/lib/renderer/cameraUniform.d.ts +2 -0
  158. package/lib/renderer/cameraUniform.js +12 -0
  159. package/lib/renderer/cameraUniform.js.map +1 -0
  160. package/lib/renderer/committedScene.js +4 -0
  161. package/lib/renderer/committedScene.js.map +1 -1
  162. package/lib/renderer/denoiser.d.ts +3 -11
  163. package/lib/renderer/denoiser.js.map +1 -1
  164. package/lib/renderer/depthQuery.js +4 -1
  165. package/lib/renderer/depthQuery.js.map +1 -1
  166. package/lib/renderer/displacementPreparation.d.ts +11 -0
  167. package/lib/renderer/displacementPreparation.js +351 -0
  168. package/lib/renderer/displacementPreparation.js.map +1 -0
  169. package/lib/renderer/displacementRange.d.ts +1 -0
  170. package/lib/renderer/displacementRange.js +9 -0
  171. package/lib/renderer/displacementRange.js.map +1 -0
  172. package/lib/renderer/displayParityDiagnostics.d.ts +11 -0
  173. package/lib/renderer/displayParityDiagnostics.js +2 -0
  174. package/lib/renderer/displayParityDiagnostics.js.map +1 -0
  175. package/lib/renderer/envMapCreation.d.ts +9 -8
  176. package/lib/renderer/envMapCreation.js +36 -12
  177. package/lib/renderer/envMapCreation.js.map +1 -1
  178. package/lib/renderer/envMapDistribution.d.ts +12 -2
  179. package/lib/renderer/envMapDistribution.js +43 -34
  180. package/lib/renderer/envMapDistribution.js.map +1 -1
  181. package/lib/renderer/geometryBvhBounds.d.ts +4 -0
  182. package/lib/renderer/geometryBvhBounds.js +82 -0
  183. package/lib/renderer/geometryBvhBounds.js.map +1 -0
  184. package/lib/renderer/geometryUpdateState.d.ts +32 -0
  185. package/lib/renderer/geometryUpdateState.js +2 -0
  186. package/lib/renderer/geometryUpdateState.js.map +1 -0
  187. package/lib/renderer/geometryUpdates.d.ts +17 -9
  188. package/lib/renderer/geometryUpdates.js +92 -33
  189. package/lib/renderer/geometryUpdates.js.map +1 -1
  190. package/lib/renderer/glsl/aovDisplay.frag.d.ts +3 -0
  191. package/lib/renderer/glsl/aovDisplay.frag.js +54 -0
  192. package/lib/renderer/glsl/aovDisplay.frag.js.map +1 -0
  193. package/lib/renderer/glsl/aovReflectance.glsl.d.ts +2 -0
  194. package/lib/renderer/glsl/aovReflectance.glsl.js +87 -0
  195. package/lib/renderer/glsl/aovReflectance.glsl.js.map +1 -0
  196. package/lib/renderer/glsl/aovReflectanceSamples.glsl.d.ts +2 -0
  197. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +135 -0
  198. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js.map +1 -0
  199. package/lib/renderer/glsl/aovTrace.frag.d.ts +2 -0
  200. package/lib/renderer/glsl/aovTrace.frag.js +121 -0
  201. package/lib/renderer/glsl/aovTrace.frag.js.map +1 -0
  202. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +12 -12
  203. package/lib/renderer/glsl/chunks/envMap.glsl.js +80 -74
  204. package/lib/renderer/glsl/chunks/envMap.glsl.js.map +1 -1
  205. package/lib/renderer/glsl/chunks/intersect.glsl.js +429 -429
  206. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +144 -144
  207. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
  208. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +801 -801
  209. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  210. package/lib/renderer/glsl/chunks/random.glsl.js +6 -6
  211. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +49 -49
  212. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  213. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +80 -80
  214. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +102 -102
  215. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +20 -17
  216. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js.map +1 -1
  217. package/lib/renderer/glsl/chunks/sampling.glsl.js +93 -93
  218. package/lib/renderer/glsl/chunks/sobol.glsl.js +79 -79
  219. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  220. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +12 -12
  221. package/lib/renderer/glsl/chunks/uvProjection.glsl.js.map +1 -1
  222. package/lib/renderer/glsl/depthQuery.frag.js +7 -7
  223. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +17 -9
  224. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js.map +1 -1
  225. package/lib/renderer/glsl/rayTrace.frag.js +191 -191
  226. package/lib/renderer/glsl/shadowCatcher.frag.js +25 -20
  227. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  228. package/lib/renderer/glsl/webglPipeline.frag.js +65 -60
  229. package/lib/renderer/glsl/webglPipeline.frag.js.map +1 -1
  230. package/lib/renderer/lightConstants.d.ts +10 -0
  231. package/lib/renderer/lightConstants.js +11 -0
  232. package/lib/renderer/lightConstants.js.map +1 -0
  233. package/lib/renderer/lightCore.d.ts +12 -0
  234. package/lib/renderer/lightCore.js +13 -0
  235. package/lib/renderer/lightCore.js.map +1 -0
  236. package/lib/renderer/lightSampling.d.ts +20 -17
  237. package/lib/renderer/lightSampling.js +123 -56
  238. package/lib/renderer/lightSampling.js.map +1 -1
  239. package/lib/renderer/lightsData.d.ts +21 -0
  240. package/lib/renderer/lightsData.js +192 -0
  241. package/lib/renderer/lightsData.js.map +1 -0
  242. package/lib/renderer/lightsUtil.d.ts +3 -26
  243. package/lib/renderer/lightsUtil.js +3 -153
  244. package/lib/renderer/lightsUtil.js.map +1 -1
  245. package/lib/renderer/materialBufferData.d.ts +70 -0
  246. package/lib/renderer/materialBufferData.js +2 -0
  247. package/lib/renderer/materialBufferData.js.map +1 -0
  248. package/lib/renderer/materialConstants.d.ts +11 -0
  249. package/lib/renderer/materialConstants.js +11 -0
  250. package/lib/renderer/materialConstants.js.map +1 -1
  251. package/lib/renderer/materialCore.d.ts +8 -0
  252. package/lib/renderer/materialCore.js +9 -0
  253. package/lib/renderer/materialCore.js.map +1 -0
  254. package/lib/renderer/materialEmission.d.ts +2 -2
  255. package/lib/renderer/materialEmission.js +3 -3
  256. package/lib/renderer/materialEmission.js.map +1 -1
  257. package/lib/renderer/materialLayout.d.ts +2 -101
  258. package/lib/renderer/materialLayout.js +110 -172
  259. package/lib/renderer/materialLayout.js.map +1 -1
  260. package/lib/renderer/materialLayoutSchema.d.ts +26 -0
  261. package/lib/renderer/materialLayoutSchema.js +172 -0
  262. package/lib/renderer/materialLayoutSchema.js.map +1 -0
  263. package/lib/renderer/materialParams.d.ts +69 -0
  264. package/lib/renderer/materialParams.js +272 -0
  265. package/lib/renderer/materialParams.js.map +1 -0
  266. package/lib/renderer/materialTextureSlots.d.ts +14 -324
  267. package/lib/renderer/materialTextureSlots.js +21 -8
  268. package/lib/renderer/materialTextureSlots.js.map +1 -1
  269. package/lib/renderer/materialTextures.d.ts +6 -0
  270. package/lib/renderer/{texturesFromMaterials.js → materialTextures.js} +1 -2
  271. package/lib/renderer/materialTextures.js.map +1 -0
  272. package/lib/renderer/mergeMeshesToGeometry.js +6 -147
  273. package/lib/renderer/mergeMeshesToGeometry.js.map +1 -1
  274. package/lib/renderer/meshInstances.d.ts +4 -21
  275. package/lib/renderer/meshInstances.js +10 -56
  276. package/lib/renderer/meshInstances.js.map +1 -1
  277. package/lib/renderer/oidnNetwork.d.ts +2 -2
  278. package/lib/renderer/oidnNetwork.js +1 -1
  279. package/lib/renderer/oidnNetwork.js.map +1 -1
  280. package/lib/renderer/openPbrEnergyLut.js +850 -846
  281. package/lib/renderer/openPbrEnergyLut.js.map +1 -1
  282. package/lib/renderer/ownedDenoiser.d.ts +9 -0
  283. package/lib/renderer/ownedDenoiser.js +2 -0
  284. package/lib/renderer/ownedDenoiser.js.map +1 -0
  285. package/lib/renderer/packedMeshInstances.d.ts +23 -0
  286. package/lib/renderer/packedMeshInstances.js +80 -0
  287. package/lib/renderer/packedMeshInstances.js.map +1 -0
  288. package/lib/renderer/prepareMeshBVH.d.ts +12 -47
  289. package/lib/renderer/prepareMeshBVH.js +21 -642
  290. package/lib/renderer/prepareMeshBVH.js.map +1 -1
  291. package/lib/renderer/proceduralEnvironmentPower.d.ts +3 -0
  292. package/lib/renderer/proceduralEnvironmentPower.js +8 -0
  293. package/lib/renderer/proceduralEnvironmentPower.js.map +1 -0
  294. package/lib/renderer/progressiveScheduler.d.ts +1 -0
  295. package/lib/renderer/progressiveScheduler.js +3 -0
  296. package/lib/renderer/progressiveScheduler.js.map +1 -1
  297. package/lib/renderer/renderPipeline.d.ts +3 -1
  298. package/lib/renderer/renderPipeline.js.map +1 -1
  299. package/lib/renderer/renderingLimits.d.ts +9 -0
  300. package/lib/renderer/renderingLimits.js +18 -0
  301. package/lib/renderer/renderingLimits.js.map +1 -0
  302. package/lib/renderer/sceneAssembly.d.ts +73 -0
  303. package/lib/renderer/sceneAssembly.js +109 -0
  304. package/lib/renderer/sceneAssembly.js.map +1 -0
  305. package/lib/renderer/sceneChangeCore.d.ts +39 -0
  306. package/lib/renderer/sceneChangeCore.js +307 -0
  307. package/lib/renderer/sceneChangeCore.js.map +1 -0
  308. package/lib/renderer/sceneChangeDetector.d.ts +3 -6
  309. package/lib/renderer/sceneChangeDetector.js +24 -150
  310. package/lib/renderer/sceneChangeDetector.js.map +1 -1
  311. package/lib/renderer/sceneLayoutSchema.d.ts +118 -0
  312. package/lib/renderer/sceneLayoutSchema.js +111 -0
  313. package/lib/renderer/sceneLayoutSchema.js.map +1 -0
  314. package/lib/renderer/sceneLightChanges.d.ts +3 -3
  315. package/lib/renderer/sceneLightChanges.js.map +1 -1
  316. package/lib/renderer/scenePreparation.d.ts +55 -0
  317. package/lib/renderer/scenePreparation.js +360 -0
  318. package/lib/renderer/scenePreparation.js.map +1 -0
  319. package/lib/renderer/scratchSampling.js +18 -18
  320. package/lib/renderer/scratchSampling.js.map +1 -1
  321. package/lib/renderer/shader.d.ts +2 -0
  322. package/lib/renderer/shader.js +2 -0
  323. package/lib/renderer/shader.js.map +1 -1
  324. package/lib/renderer/shaderCapabilities.d.ts +23 -0
  325. package/lib/renderer/shaderCapabilities.js +55 -0
  326. package/lib/renderer/shaderCapabilities.js.map +1 -0
  327. package/lib/renderer/shaderCapacity.d.ts +2 -0
  328. package/lib/renderer/shaderCapacity.js +5 -0
  329. package/lib/renderer/shaderCapacity.js.map +1 -0
  330. package/lib/renderer/skyModel.d.ts +9 -0
  331. package/lib/renderer/skyModel.js +10 -0
  332. package/lib/renderer/skyModel.js.map +1 -0
  333. package/lib/renderer/textureAtlas.d.ts +60 -0
  334. package/lib/renderer/textureAtlas.js +145 -0
  335. package/lib/renderer/textureAtlas.js.map +1 -0
  336. package/lib/renderer/textureAtlasPixels.d.ts +7 -0
  337. package/lib/renderer/textureAtlasPixels.js +68 -0
  338. package/lib/renderer/textureAtlasPixels.js.map +1 -0
  339. package/lib/renderer/util.d.ts +1 -1
  340. package/lib/renderer/util.js.map +1 -1
  341. package/lib/renderer/webgl.d.ts +9 -2
  342. package/lib/renderer/webgl.js +54 -9
  343. package/lib/renderer/webgl.js.map +1 -1
  344. package/lib/renderer/wgpuBindless.d.ts +26 -0
  345. package/lib/renderer/wgpuBindless.js +95 -0
  346. package/lib/renderer/wgpuBindless.js.map +1 -0
  347. package/lib/renderer/wgpuBindlessSource.d.ts +2 -0
  348. package/lib/renderer/wgpuBindlessSource.js +51 -0
  349. package/lib/renderer/wgpuBindlessSource.js.map +1 -0
  350. package/lib/renderer/wgpuMaterialConstants.d.ts +4 -0
  351. package/lib/renderer/wgpuMaterialConstants.js +52 -0
  352. package/lib/renderer/wgpuMaterialConstants.js.map +1 -0
  353. package/lib/renderer/wgpuSceneUniform.d.ts +42 -0
  354. package/lib/renderer/wgpuSceneUniform.js +125 -0
  355. package/lib/renderer/wgpuSceneUniform.js.map +1 -0
  356. package/lib/renderer/wgpuShaderSource.d.ts +15 -0
  357. package/lib/renderer/wgpuShaderSource.js +31 -0
  358. package/lib/renderer/wgpuShaderSource.js.map +1 -0
  359. package/lib/renderer/wgsl/aovDisplay.wgsl.d.ts +1 -0
  360. package/lib/renderer/wgsl/aovDisplay.wgsl.js +70 -0
  361. package/lib/renderer/wgsl/aovDisplay.wgsl.js.map +1 -0
  362. package/lib/renderer/wgsl/aovReflectance.wgsl.d.ts +2 -0
  363. package/lib/renderer/wgsl/aovReflectance.wgsl.js +98 -0
  364. package/lib/renderer/wgsl/aovReflectance.wgsl.js.map +1 -0
  365. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.d.ts +2 -0
  366. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +135 -0
  367. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js.map +1 -0
  368. package/lib/renderer/wgsl/aovResolve.wgsl.d.ts +5 -0
  369. package/lib/renderer/wgsl/aovResolve.wgsl.js +38 -0
  370. package/lib/renderer/wgsl/aovResolve.wgsl.js.map +1 -0
  371. package/lib/renderer/wgsl/aovSnapshot.wgsl.d.ts +4 -0
  372. package/lib/renderer/wgsl/aovSnapshot.wgsl.js +21 -0
  373. package/lib/renderer/wgsl/aovSnapshot.wgsl.js.map +1 -0
  374. package/lib/renderer/wgsl/aovTrace.wgsl.d.ts +2 -0
  375. package/lib/renderer/wgsl/aovTrace.wgsl.js +115 -0
  376. package/lib/renderer/wgsl/aovTrace.wgsl.js.map +1 -0
  377. package/lib/renderer/wgsl/bloom.wgsl.d.ts +13 -0
  378. package/lib/renderer/wgsl/bloom.wgsl.js +92 -0
  379. package/lib/renderer/wgsl/bloom.wgsl.js.map +1 -0
  380. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  381. package/lib/renderer/wgsl/chunks/envMap.wgsl.d.ts +1 -1
  382. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +43 -37
  383. package/lib/renderer/wgsl/chunks/envMap.wgsl.js.map +1 -1
  384. package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +13 -1
  385. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +742 -705
  386. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  387. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +16 -16
  388. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -1
  389. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +3 -1
  390. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +84 -82
  391. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  392. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +855 -857
  393. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js.map +1 -1
  394. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +139 -139
  395. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  396. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +2 -1
  397. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +42 -32
  398. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  399. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +1 -1
  400. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +152 -148
  401. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -1
  402. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +239 -232
  403. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
  404. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +1 -1
  405. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +26 -13
  406. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -1
  407. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +91 -91
  408. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.d.ts +1 -1
  409. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js +1 -0
  410. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js.map +1 -1
  411. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +83 -83
  412. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +12 -12
  413. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js.map +1 -1
  414. package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +8 -3
  415. package/lib/renderer/wgsl/compose.frag.wgsl.js +143 -118
  416. package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -1
  417. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  418. package/lib/renderer/wgsl/depthQuery.wgsl.js +7 -7
  419. package/lib/renderer/wgsl/jnlm.compute.d.ts +25 -0
  420. package/lib/renderer/wgsl/jnlm.compute.js +315 -0
  421. package/lib/renderer/wgsl/jnlm.compute.js.map +1 -0
  422. package/lib/renderer/wgsl/offlineAdaptive.compute.js +28 -28
  423. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.d.ts +1 -0
  424. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +17 -0
  425. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js.map +1 -0
  426. package/lib/renderer/wgsl/proceduralSky.compute.d.ts +1 -0
  427. package/lib/renderer/wgsl/proceduralSky.compute.js +198 -0
  428. package/lib/renderer/wgsl/proceduralSky.compute.js.map +1 -0
  429. package/lib/renderer/wgsl/rayTrace.compute.d.ts +17 -1
  430. package/lib/renderer/wgsl/rayTrace.compute.js +612 -393
  431. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  432. package/lib/scene/Camera.js +7 -3
  433. package/lib/scene/Camera.js.map +1 -1
  434. package/lib/scene/EnvironmentLight.d.ts +5 -9
  435. package/lib/scene/EnvironmentLight.js +4 -14
  436. package/lib/scene/EnvironmentLight.js.map +1 -1
  437. package/lib/scene/EnvironmentLightState.d.ts +18 -0
  438. package/lib/scene/EnvironmentLightState.js +19 -0
  439. package/lib/scene/EnvironmentLightState.js.map +1 -0
  440. package/lib/scene/Geometry.d.ts +12 -6
  441. package/lib/scene/Geometry.js +37 -13
  442. package/lib/scene/Geometry.js.map +1 -1
  443. package/lib/scene/InstanceState.d.ts +39 -0
  444. package/lib/scene/InstanceState.js +77 -0
  445. package/lib/scene/InstanceState.js.map +1 -0
  446. package/lib/scene/InstancedMesh.d.ts +1 -1
  447. package/lib/scene/InstancedMesh.js +3 -0
  448. package/lib/scene/InstancedMesh.js.map +1 -1
  449. package/lib/scene/MaterialState.d.ts +209 -0
  450. package/lib/scene/MaterialState.js +231 -0
  451. package/lib/scene/MaterialState.js.map +1 -0
  452. package/lib/scene/Mesh.d.ts +4 -6
  453. package/lib/scene/Mesh.js +3 -11
  454. package/lib/scene/Mesh.js.map +1 -1
  455. package/lib/scene/MeshState.d.ts +20 -0
  456. package/lib/scene/MeshState.js +35 -0
  457. package/lib/scene/MeshState.js.map +1 -0
  458. package/lib/scene/OpenPBRMaterial.d.ts +6 -168
  459. package/lib/scene/OpenPBRMaterial.js +5 -223
  460. package/lib/scene/OpenPBRMaterial.js.map +1 -1
  461. package/lib/scene/PixelTexture.d.ts +6 -0
  462. package/lib/scene/PixelTexture.js +10 -0
  463. package/lib/scene/PixelTexture.js.map +1 -0
  464. package/lib/scene/ProceduralSky.d.ts +24 -0
  465. package/lib/scene/ProceduralSky.js +40 -0
  466. package/lib/scene/ProceduralSky.js.map +1 -0
  467. package/lib/scene/RectLight.d.ts +2 -13
  468. package/lib/scene/RectLight.js +3 -21
  469. package/lib/scene/RectLight.js.map +1 -1
  470. package/lib/scene/RectLightState.d.ts +31 -0
  471. package/lib/scene/RectLightState.js +26 -0
  472. package/lib/scene/RectLightState.js.map +1 -0
  473. package/lib/scene/Scene.d.ts +15 -4
  474. package/lib/scene/Scene.js.map +1 -1
  475. package/lib/scene/SceneNode.js +7 -6
  476. package/lib/scene/SceneNode.js.map +1 -1
  477. package/lib/scene/Texture.d.ts +10 -41
  478. package/lib/scene/Texture.js +4 -33
  479. package/lib/scene/Texture.js.map +1 -1
  480. package/lib/scene/TextureState.d.ts +35 -0
  481. package/lib/scene/TextureState.js +35 -0
  482. package/lib/scene/TextureState.js.map +1 -0
  483. package/lib/scene/attributeData.d.ts +4 -0
  484. package/lib/scene/attributeData.js +10 -0
  485. package/lib/scene/attributeData.js.map +1 -0
  486. package/lib/scene/lightState.d.ts +8 -0
  487. package/lib/scene/lightState.js +2 -0
  488. package/lib/scene/lightState.js.map +1 -0
  489. package/lib/scene/openPbrSchema.d.ts +7 -12
  490. package/lib/scene/openPbrSchema.js +273 -28
  491. package/lib/scene/openPbrSchema.js.map +1 -1
  492. package/lib/scene/skyParameters.d.ts +20 -0
  493. package/lib/scene/skyParameters.js +28 -0
  494. package/lib/scene/skyParameters.js.map +1 -0
  495. package/lib/scene/textureData.d.ts +9 -0
  496. package/lib/scene/textureData.js +2 -0
  497. package/lib/scene/textureData.js.map +1 -0
  498. package/lib/scene/texturePixels.d.ts +6 -0
  499. package/lib/scene/texturePixels.js +10 -0
  500. package/lib/scene/texturePixels.js.map +1 -0
  501. package/lib/settings/display.d.ts +33 -0
  502. package/lib/settings/display.js +7 -0
  503. package/lib/settings/display.js.map +1 -1
  504. package/lib/settings/render.d.ts +25 -3
  505. package/lib/settings/render.js +3 -1
  506. package/lib/settings/render.js.map +1 -1
  507. package/lib/tinybvh/tinybvh.wasm +0 -0
  508. package/lib/util/commonGeometry.js +7 -7
  509. package/lib/util/commonGeometry.js.map +1 -1
  510. package/lib/util/fromTHREE.d.ts +4 -1
  511. package/lib/util/fromTHREE.js +18 -5
  512. package/lib/util/fromTHREE.js.map +1 -1
  513. package/lib/util/geometry.js +42 -29
  514. package/lib/util/geometry.js.map +1 -1
  515. package/lib/util/loadRGBE.js +3 -4
  516. package/lib/util/loadRGBE.js.map +1 -1
  517. package/lib/util/studioLighting.d.ts +18 -0
  518. package/lib/util/studioLighting.js +36 -0
  519. package/lib/util/studioLighting.js.map +1 -0
  520. package/lib/version.d.ts +1 -1
  521. package/lib/version.js +1 -1
  522. package/lib/version.js.map +1 -1
  523. package/llms.txt +4 -0
  524. package/package.json +31 -5
  525. package/lib/renderer/texturesFromMaterials.d.ts +0 -6
  526. package/lib/renderer/texturesFromMaterials.js.map +0 -1
@@ -1,7 +1,20 @@
1
+ import { AovPrimitiveCache } from './AovPrimitiveCache.js';
2
+ import { packAovScene } from './aovScene.js';
3
+ import { aovMask } from './aov.js';
4
+ import { proceduralEnvironmentPower } from './proceduralEnvironmentPower.js';
5
+ import { WGPUSkyBaker } from './WGPUSkyBaker.js';
6
+ import { initialSceneConstants, sceneAttributeLayout, sceneTraversalConstants, prepareSceneLightSampling, writeTraceLighting, packSceneAnalyticLights, writeTraceQuality, traceSampling, writeTraceSampling } from './sceneAssembly.js';
7
+ import { rayTraceBindGroupLayouts } from './sceneLayoutSchema.js';
8
+ import { WGPUBindlessMaterialData } from './WGPUBindlessMaterialData.js';
9
+ import { WGPUBindlessTextures } from './WGPUBindlessTextures.js';
10
+ import { bindlessBindGroupLayouts, bindlessShaderSource } from './wgpuBindlessSource.js';
11
+ import { bindlessLimitReason, resourceTableLayout, setResourceTable } from './wgpuBindless.js';
12
+ import { wgpuMaterialConstants } from './wgpuMaterialConstants.js';
13
+ import { wgpuShaderSource, wgpuPipelineConstantKeys, WGPU_SHADER_DEFINE_KEYS } from './wgpuShaderSource.js';
14
+ import { makeRayTraceUniform, WGPU_SCENE_BUFFER_MIN_BYTES } from './wgpuSceneUniform.js';
1
15
  import { constants } from './webgl.js';
2
- import { MATERIAL_FLOAT_COUNT } from './materialLayout.js';
16
+ import { MATERIAL_FLOAT_COUNT } from './materialLayoutSchema.js';
3
17
  import { normalizeBounces } from './pathLimits.js';
4
- import { MATERIAL_TEXTURE_DEFINES, materialTextureFeatures } from './materialTextureSlots.js';
5
18
  import { updateMeshInstanceColors } from './prepareMeshBVH.js';
6
19
  import { updateTLASInstanceColors } from './bvhAccel.js';
7
20
  import { getMaterialHashKey } from '../scene/openPbrSchema.js';
@@ -9,31 +22,31 @@ import { sameInstanceMembership } from './meshInstances.js';
9
22
  import InstancedMesh from '../scene/InstancedMesh.js';
10
23
  import { dirtyMeshInstanceIndices } from './prepareMeshBVH.js';
11
24
  import { cameraApertureRadius } from './cameraLens.js';
12
- import { getRectLightUOrV, getRectLightArea, getSphereLightArea, getSpotLightArea, getSpotLightRadiance, getLightDirection, getRigidLightFrame, validateSceneLights } from './lightsUtil.js';
13
25
  import { getGeometryBvh, setGeometryBvh } from './geometryBvh.js';
26
+ import { packCameraUniform } from './cameraUniform.js';
14
27
  import { SHADOW_CATCHER_ACCUMULATION_BYTES } from './wgsl/chunks/shadowCatcherAccumulation.wgsl.js';
15
- import { samplingPatternCode, zSobolLog2SPP } from './sampling.js';
16
28
  import { DEPTH_SAMPLE_COUNT, packDepthSampleArea, unpackDepthSamples } from './depthQuery.js';
17
29
  import { MeshMembershipCache } from './meshMembership.js';
18
30
  import { mergeRefitRanges } from './bvhAccel.js';
19
31
  import { updatePreparedGeometries, canUpdateGeometries, geometryTopologyChanged, packVertexAttributes } from './geometryUpdates.js';
20
32
  import { SceneEnvironmentCache, RectLightTextureTracker } from './sceneLightChanges.js';
21
33
  import { MaterialChangeTracker, materialIsEmissive } from './materialChanges.js';
34
+ import { WGPUEnvMapDistribution } from './WGPUEnvMapDistribution.js';
22
35
  import { WGPUShaderCache, retainedShaderCapacity } from './WGPUShaderCache.js';
23
- import { WGPU_SCENE_FEATURE_BITS, wgpuSceneFeatureFlags } from './WGPUSceneFeatures.js';
36
+ import { WGPUShaderCapabilities } from './WGPUShaderCapabilities.js';
37
+ import { wgpuSceneFeatureFlags } from './WGPUSceneFeatures.js';
38
+ import { lightShaderCapabilities, retainedShaderCapabilities } from './shaderCapabilities.js';
24
39
  import { mat4 } from '../math.js';
25
- import MaterialTable, { DEFAULT_MAX_TEXTURE_ARRAY_BYTES, materialUsesMedium } from './MaterialTable.js';
40
+ import MaterialTable, { DEFAULT_MAX_TEXTURE_ARRAY_BYTES } from './MaterialTable.js';
26
41
  import { numberArraysEqual } from './util.js';
27
- import { generateBackgroundMapFromSceneBackground, environmentRotation, backgroundMapTransform } from './envMapCreation.js';
28
- import rayTraceCompute, { WORKGROUP_SIZE } from './wgsl/rayTrace.compute.js';
29
- import { CONSTANT_DIRECTIONAL_LIGHT, CONSTANT_RECT_LIGHT, CONSTANT_SPHERE_LIGHT, CONSTANT_SPOT_LIGHT } from './lightsUtil.js';
42
+ import { generateBackgroundMapFromSceneBackground, environmentRotation, backgroundMapTransform, backgroundMapRotation } from './envMapCreation.js';
43
+ import { WORKGROUP_SIZE } from './wgsl/rayTrace.compute.js';
30
44
  import { envMapDistribution, environmentMapSourcesMatch } from './envMapDistribution.js';
31
45
  import { updateMeshInstances, updateMeshInstanceTransforms } from './prepareMeshBVH.js';
32
46
  import { buildTLAS, concatBLASBuffers, getTraversalStackSizes, refitBLAS, refitTLAS } from './bvhAccel.js';
33
47
  import { isTextureDataSource } from '../scene/Texture.js';
34
- import { resolveMaterialAlphaMode } from '../scene/OpenPBRMaterial.js';
35
48
  import { DEFAULT_BEVEL_SAMPLES, DEFAULT_DIRECT_LIGHT_CANDIDATES, normalizeBevelSamples, normalizeDirectLightCandidates } from './RenderingPipeline.js';
36
- import { buildLightAliasTable, EmissiveTriangleCache, LightChoiceBuffer, estimateAnalyticLightPower, estimateEnvironmentPower, LIGHT_CHOICE_ANALYTIC, LIGHT_CHOICE_EMISSIVE_TRIANGLE, LIGHT_CHOICE_ENVIRONMENT, LIGHT_DOMAIN_ENVIRONMENT, LIGHT_DOMAIN_INFINITE, LIGHT_DOMAIN_LOCAL_AND_EMISSIVE, packEmissiveTriangles, packIESProfiles } from './lightSampling.js';
49
+ import { EmissiveTriangleCache, LightChoiceBuffer, estimateEnvironmentPower, } from './lightSampling.js';
37
50
  import { getOpenPbrEnergyLutData, OPENPBR_ENERGY_LUT_HEIGHT, OPENPBR_ENERGY_LUT_WIDTH } from './openPbrEnergyLut.js';
38
51
  import { offlineAdaptiveCompute } from './wgsl/offlineAdaptive.compute.js';
39
52
  import { normalizeOfflineAdaptiveSamplingOptions } from './OfflineAdaptiveSampling.js';
@@ -87,118 +100,13 @@ export function isWebGPUPipelineSpecializationFailure(...errors) {
87
100
  return errors.some((error) => /(?:compute )?library failed creation/i.test(getWebGPUErrorMessage(error)));
88
101
  }
89
102
  /** CPU-side views over the `RayTraceUniform` WGSL struct. */
90
- export function makeRayTraceUniform() {
91
- // Created from https://webgpufundamentals.org/webgpu/lessons/resources/wgsl-offset-computer.html
92
- const RayTraceUniformValues = new ArrayBuffer(256);
93
- const RayTraceUniformViews = {
94
- outputSize: new Float32Array(RayTraceUniformValues, 0, 2),
95
- sampleCount: new Float32Array(RayTraceUniformValues, 8, 1),
96
- scaleOffset: new Float32Array(RayTraceUniformValues, 16, 4),
97
- lightsCount: new Int32Array(RayTraceUniformValues, 32, 1),
98
- transmissiveOutputAlphaMin: new Float32Array(RayTraceUniformValues, 36, 1),
99
- jitter: new Float32Array(RayTraceUniformValues, 40, 2),
100
- backgroundColor: new Float32Array(RayTraceUniformValues, 48, 4),
101
- groundedBackgroundParams: new Float32Array(RayTraceUniformValues, 64, 4),
102
- groundedBackgroundCenter: new Float32Array(RayTraceUniformValues, 80, 2),
103
- blasOffset: new Int32Array(RayTraceUniformValues, 88, 1),
104
- isEmpty: new Int32Array(RayTraceUniformValues, 92, 1),
105
- bevel: new Int32Array(RayTraceUniformValues, 96, 1),
106
- dispersionWavelengths: new Int32Array(RayTraceUniformValues, 100, 1),
107
- envLightPmf: new Float32Array(RayTraceUniformValues, 104, 1),
108
- lightChoiceCount: new Int32Array(RayTraceUniformValues, 108, 1),
109
- lightWeightTotal: new Float32Array(RayTraceUniformValues, 112, 1),
110
- lightSamplingTextureWidth: new Int32Array(RayTraceUniformValues, 116, 1),
111
- lightChoiceTexelOffset: new Int32Array(RayTraceUniformValues, 120, 1),
112
- bounces: new Int32Array(RayTraceUniformValues, 124, 1),
113
- varianceMoments: new Int32Array(RayTraceUniformValues, 128, 1),
114
- adaptiveSampling: new Int32Array(RayTraceUniformValues, 132, 1),
115
- clamping: new Float32Array(RayTraceUniformValues, 136, 1),
116
- directLightCandidates: new Int32Array(RayTraceUniformValues, 140, 1),
117
- backgroundFlags: new Int32Array(RayTraceUniformValues, 144, 1),
118
- loopUnrollGuard: new Uint32Array(RayTraceUniformValues, 148, 1),
119
- sceneFeatureFlags: new Uint32Array(RayTraceUniformValues, 152, 1),
120
- sequenceSeed: new Uint32Array(RayTraceUniformValues, 156, 1),
121
- zSobolLogSPP: new Uint32Array(RayTraceUniformValues, 160, 1),
122
- sampleSequenceOffset: new Uint32Array(RayTraceUniformValues, 164, 1),
123
- environmentRotation: new Float32Array(RayTraceUniformValues, 176, 16),
124
- backgroundMapTransform: new Float32Array(RayTraceUniformValues, 240, 4)
125
- };
126
- // Fixed runtime trip bounds discourage thin-film loop unrolling. Keep 4 for
127
- // 2 polarizations/substrates and 3 channels, independent of BSDF budgets.
128
- RayTraceUniformViews.loopUnrollGuard[0] = 4;
129
- RayTraceUniformViews.environmentRotation.set(environmentRotation([]));
130
- RayTraceUniformViews.backgroundMapTransform.set(backgroundMapTransform());
131
- RayTraceUniformViews.bevel[0] = 1;
132
- RayTraceUniformViews.dispersionWavelengths[0] = 3;
133
- return {
134
- buffer: RayTraceUniformValues,
135
- views: RayTraceUniformViews
136
- };
137
- }
103
+ export { makeRayTraceUniform } from './wgpuSceneUniform.js';
138
104
  export function packAnalyticsLightsToBuffer(lights, texturesIndices, selectionPmfs, iesProfileTexelOffsets = []) {
139
- validateSceneLights(lights);
140
- const numLights = lights.length;
141
- if (numLights > FIXED_LIGHT_COUNT) {
142
- console.warn(`Too many lights, only the first ${FIXED_LIGHT_COUNT} lights will be used.`);
143
- }
144
- const data = new Float32Array(numLights * PIXELS_PER_LIGHT * 4);
145
- function packVec3(idx, v) {
146
- for (let i = 0; i < 3; i++) {
147
- data[i + idx * 4] = v[i];
148
- }
149
- }
150
- const lightTypeConstants = {
151
- DirectionalLight: CONSTANT_DIRECTIONAL_LIGHT,
152
- SphereLight: CONSTANT_SPHERE_LIGHT,
153
- RectLight: CONSTANT_RECT_LIGHT,
154
- SpotLight: CONSTANT_SPOT_LIGHT
155
- };
156
- for (let i = 0; i < numLights; i++) {
157
- const light = lights[i];
158
- const color = light.color;
159
- const intensity = light.intensity;
160
- const off = i * PIXELS_PER_LIGHT;
161
- packVec3(off, light.position);
162
- data[off * 4 + 3] = lightTypeConstants[light.type];
163
- // emission
164
- const emissionScale = light.type === 'SpotLight' ? getSpotLightRadiance(light) : intensity;
165
- packVec3(off + 1, [
166
- color[0] * emissionScale,
167
- color[1] * emissionScale,
168
- color[2] * emissionScale
169
- ]);
170
- if (light.type === 'RectLight') {
171
- data[(off + 1) * 4 + 3] = getRectLightArea(light);
172
- packVec3(off + 2, getRectLightUOrV(light, 0));
173
- data[(off + 2) * 4 + 3] = light.spread;
174
- packVec3(off + 3, getRectLightUOrV(light, 1));
175
- }
176
- else if (light.type === 'SphereLight') {
177
- data[(off + 1) * 4 + 3] = getSphereLightArea(light);
178
- data[(off + 2) * 4 + 3] = light.radius;
179
- }
180
- else if (light.type === 'SpotLight') {
181
- data[(off + 1) * 4 + 3] = getSpotLightArea(light);
182
- packVec3(off + 2, getLightDirection(light));
183
- data[(off + 2) * 4 + 3] = light.radius;
184
- packVec3(off + 3, [
185
- Math.cos((light.outerAngle * Math.PI) / 180),
186
- Math.cos((Math.min(light.innerAngle, light.outerAngle) * Math.PI) / 180),
187
- 0
188
- ]);
189
- }
190
- else if (light.type === 'DirectionalLight') {
191
- packVec3(off + 2, getLightDirection(light));
192
- }
193
- data[(off + 3) * 4 + 3] = light.type === 'SpotLight'
194
- ? iesProfileTexelOffsets[i] ?? -1
195
- : texturesIndices[i] ?? -1;
196
- data[(off + 4) * 4] = selectionPmfs[i] ?? 0;
197
- packVec3(off + 5, getRigidLightFrame(light).x);
198
- }
199
- return data;
105
+ return packSceneAnalyticLights(lights, texturesIndices, selectionPmfs, i => iesProfileTexelOffsets[i]);
200
106
  }
201
107
  class WGPURayTracePass {
108
+ _textureSelection;
109
+ _aovPrimitiveCache = new AovPrimitiveCache();
202
110
  _device;
203
111
  _rayTracePipeline;
204
112
  _targetAspect = 1;
@@ -212,6 +120,9 @@ class WGPURayTracePass {
212
120
  _materialChanges = new MaterialChangeTracker();
213
121
  _pendingMaterialUpdate;
214
122
  _materialData;
123
+ _bindless;
124
+ _retiredBindless = new Set();
125
+ _disposed = false;
215
126
  _maxTextureArrayBytes = DEFAULT_MAX_TEXTURE_ARRAY_BYTES;
216
127
  _pendingGeometryUpdates = new Set();
217
128
  _needsUpdateMeshData = true;
@@ -251,7 +162,7 @@ class WGPURayTracePass {
251
162
  const output = this._targetOutputs.get(target);
252
163
  [this._outColorBuffer, this._outNormalBuffer, this._outAlbedoBuffer, this._outShadowCatcherBuffer] = output?.buffers ?? [];
253
164
  if (output?.bindGroup && output.pipeline === this._rayTracePipeline && this._rayTraceBindGroups) {
254
- this._rayTraceBindGroups[3] = output.bindGroup;
165
+ this._rayTraceBindGroups[this._bindless ? 2 : 3] = output.bindGroup;
255
166
  }
256
167
  else {
257
168
  this._needsUpdateBindGroups = true;
@@ -281,6 +192,7 @@ class WGPURayTracePass {
281
192
  _instancesBuffer;
282
193
  _emissiveCache = new EmissiveTriangleCache();
283
194
  _lightChoices = new LightChoiceBuffer();
195
+ _shadowCatcherLightChoices = new LightChoiceBuffer();
284
196
  _lightSamplingData;
285
197
  _lightSamplingScratch;
286
198
  _lightSamplingTriangleCount = -1;
@@ -296,6 +208,8 @@ class WGPURayTracePass {
296
208
  _envImageSource;
297
209
  _envTex;
298
210
  _envDistributionTex;
211
+ _envDistribution;
212
+ _skyBaker;
299
213
  _backgroundImageSource;
300
214
  _backgroundTex;
301
215
  _rayTracePipelineLayout;
@@ -307,15 +221,13 @@ class WGPURayTracePass {
307
221
  _compiledHasAlpha = true;
308
222
  _compiledSceneHasAlpha = true;
309
223
  _alphaBlendStrategy = 'stochastic';
310
- _constants = {
311
- USE_BACKGROUND: false,
312
- USE_BACKGROUND_MAP: false,
313
- USE_GROUNDED_BACKGROUND: false,
314
- SAMPLING_PATTERN: 0,
315
- BEVEL_SAMPLES: DEFAULT_BEVEL_SAMPLES
316
- };
224
+ _constants = initialSceneConstants();
225
+ _retainedShaderCapabilities;
226
+ _retainedShaderStructure;
227
+ _shaderCapabilities = new WGPUShaderCapabilities();
317
228
  _prevPipelineConstants = {};
318
229
  _prevDefinesCode = '';
230
+ _prevPipelineInputs;
319
231
  _hasTransmission = false;
320
232
  _hasShadowCatcher = false;
321
233
  _hasDisplacement = false;
@@ -331,6 +243,7 @@ class WGPURayTracePass {
331
243
  _focusDistance = 10;
332
244
  _needsUpdateBindGroups = true;
333
245
  _computeShaderModule;
246
+ _aovPipelines = new WeakMap();
334
247
  _depthCompute;
335
248
  _depthTracePipeline;
336
249
  _depthPipeline;
@@ -342,9 +255,12 @@ class WGPURayTracePass {
342
255
  // Fold scene invariants before backend inlining; runtime edits use uniforms.
343
256
  _bakePipelineConstants = true;
344
257
  _failedPipelineSignature;
345
- constructor(device) {
258
+ constructor(device, _textureSelection = { requested: 'atlas' }) {
259
+ this._textureSelection = _textureSelection;
346
260
  this._device = device;
347
261
  this._shaderCache = new WGPUShaderCache(device);
262
+ if (_textureSelection.support)
263
+ this._bindless = new WGPUBindlessTextures(device);
348
264
  this._uniforms = {
349
265
  cameraUniform: this._uniformBuffer(36 * 4),
350
266
  rtUniform: this._uniformBuffer(this._rtUniform.buffer.byteLength),
@@ -579,129 +495,13 @@ class WGPURayTracePass {
579
495
  }
580
496
  }
581
497
  _createPipelineLayout() {
582
- //Bind group layouts
583
- const commonBufferLayoutEntries = Array.from({ length: 4 }, (_, i) => ({
584
- binding: i,
585
- visibility: GPUShaderStage.COMPUTE,
586
- buffer: {
587
- type: 'read-only-storage'
588
- }
589
- }));
590
- const buffersBindGroupLayout = this._shaderCache.createBindGroupLayout({
591
- label: 'Buffers',
592
- entries: commonBufferLayoutEntries
593
- });
594
- const textureLayoutEntries = [
595
- {
596
- binding: 0,
597
- visibility: GPUShaderStage.COMPUTE,
598
- sampler: {}
599
- },
600
- {
601
- binding: 1,
602
- visibility: GPUShaderStage.COMPUTE,
603
- texture: {
604
- viewDimension: '2d-array'
605
- }
606
- },
607
- // Map size
608
- {
609
- binding: 3,
610
- visibility: GPUShaderStage.COMPUTE,
611
- buffer: {
612
- type: 'uniform'
613
- }
614
- },
615
- // Env map
616
- {
617
- binding: 4,
618
- visibility: GPUShaderStage.COMPUTE,
619
- texture: {
620
- viewDimension: '2d',
621
- sampleType: 'unfilterable-float'
622
- }
623
- },
624
- // Env map distribution
625
- {
626
- binding: 5,
627
- visibility: GPUShaderStage.COMPUTE,
628
- texture: {
629
- viewDimension: '2d',
630
- sampleType: 'unfilterable-float'
631
- }
632
- },
633
- // Background map
634
- {
635
- binding: 6,
636
- visibility: GPUShaderStage.COMPUTE,
637
- texture: {
638
- viewDimension: '2d',
639
- sampleType: 'unfilterable-float'
640
- }
641
- },
642
- {
643
- binding: 8,
644
- visibility: GPUShaderStage.COMPUTE,
645
- texture: {
646
- viewDimension: '2d',
647
- sampleType: 'unfilterable-float'
648
- }
649
- },
650
- {
651
- binding: 9,
652
- visibility: GPUShaderStage.COMPUTE,
653
- texture: {
654
- viewDimension: '2d',
655
- sampleType: 'unfilterable-float'
656
- }
657
- },
658
- {
659
- binding: 10,
660
- visibility: GPUShaderStage.COMPUTE,
661
- texture: {
662
- viewDimension: '2d',
663
- sampleType: 'unfilterable-float'
664
- }
665
- }
666
- ];
667
- const texturesBindGroupLayout = this._shaderCache.createBindGroupLayout({
668
- label: 'Textures', entries: textureLayoutEntries
669
- });
670
- const uniformsBindGroupLayout = this._shaderCache.createBindGroupLayout({
671
- label: 'Uniforms',
672
- entries: [
673
- ...Array.from({ length: Object.keys(this._uniforms).length }, (_, i) => ({
674
- binding: i,
675
- visibility: GPUShaderStage.COMPUTE,
676
- buffer: {
677
- type: 'uniform'
678
- }
679
- })),
680
- ...([])
681
- ]
682
- });
683
- const rayTraceOutBuffersBindGroupLayout = this._shaderCache.createBindGroupLayout({
684
- label: 'Ray Trace Out Buffers',
685
- entries: [
686
- ...Array.from({ length: 4 }, (_, i) => ({
687
- binding: i,
688
- visibility: GPUShaderStage.COMPUTE,
689
- buffer: { type: 'storage' }
690
- })),
691
- ...([])
692
- ]
693
- });
694
- this._rayTracePipelineLayout = this._shaderCache.createPipelineLayout({
498
+ const descriptor = {
695
499
  label: 'Ray Trace Pipeline Layout',
696
- bindGroupLayouts: [
697
- buffersBindGroupLayout,
698
- texturesBindGroupLayout,
699
- uniformsBindGroupLayout,
700
- rayTraceOutBuffersBindGroupLayout
701
- ]
702
- });
500
+ bindGroupLayouts: (this._bindless ? bindlessBindGroupLayouts() : rayTraceBindGroupLayouts()).map(layout => this._shaderCache.createBindGroupLayout(layout))
501
+ };
502
+ this._rayTracePipelineLayout = this._shaderCache.createPipelineLayout(this._bindless ? resourceTableLayout(descriptor) : descriptor);
703
503
  }
704
- _updateGPUBuffer(label, gpuBuffer, data, minSize = 200) {
504
+ _updateGPUBuffer(label, gpuBuffer, data, minSize = WGPU_SCENE_BUFFER_MIN_BYTES) {
705
505
  const device = this._device;
706
506
  const size = Math.max(data.byteLength, minSize);
707
507
  if (gpuBuffer == null || gpuBuffer.size < size) {
@@ -739,6 +539,10 @@ class WGPURayTracePass {
739
539
  let compilationStartedAt;
740
540
  let pipelineCompilationStartedAt;
741
541
  try {
542
+ if (this._bindless?.retirement)
543
+ await this._bindless.retirement;
544
+ if (this._disposed)
545
+ return;
742
546
  if (this._needsUpdateMeshData) {
743
547
  this._updateMeshData();
744
548
  }
@@ -757,15 +561,24 @@ class WGPURayTracePass {
757
561
  this._updateLightSamplingData();
758
562
  }
759
563
  const device = this._device;
760
- const constants = this._constants;
761
- this._rtUniform.views.sceneFeatureFlags[0] = wgpuSceneFeatureFlags(constants);
564
+ const pipelineInputs = JSON.stringify([this._constants, this._hasDisplacement,
565
+ this._alphaBlendStrategy, this._blasLayoutMask, this._bakePipelineConstants]);
566
+ // Steady rendering must not repeat capability selection and cache-key
567
+ // preparation. Dirty resources still take the normal bind-group path.
568
+ if (pipelineInputs === this._prevPipelineInputs && this._rayTracePipeline &&
569
+ this._rayTraceBindGroups && !this._needsUpdateBindGroups)
570
+ return;
571
+ this._rtUniform.views.sceneFeatureFlags[0] = wgpuSceneFeatureFlags(this._constants);
572
+ const requiredCapabilities = retainedShaderCapabilities(this._constants);
573
+ const constants = { ...this._constants, ...requiredCapabilities };
762
574
  const hasAlpha = Boolean(constants.HAS_ALPHA_BLEND) &&
763
575
  this._alphaBlendStrategy === 'deterministic-source-over';
764
576
  const hasSceneAlpha = Boolean(constants.HAS_ALPHA);
765
- const pipelineSignature = JSON.stringify({
766
- constants: Object.keys(constants)
767
- .sort()
768
- .map((key) => [key, constants[key]]),
577
+ const pipelineConstantsKeys = wgpuPipelineConstantKeys(constants);
578
+ const defineCode = WGPU_SHADER_DEFINE_KEYS
579
+ .map((key) => `const ${key} = ${constants[key]};`)
580
+ .join('\n');
581
+ const structure = {
769
582
  hasDisplacement: this._hasDisplacement,
770
583
  hasAlpha,
771
584
  hasSceneAlpha,
@@ -773,45 +586,29 @@ class WGPURayTracePass {
773
586
  hasCoatNormals: Boolean(constants.USE_COAT_NORMAL_FRAMES),
774
587
  blasLayoutMask: this._blasLayoutMask,
775
588
  bakePipelineConstants: this._bakePipelineConstants
589
+ };
590
+ const structureKey = JSON.stringify({
591
+ ...structure, defineCode,
592
+ constants: pipelineConstantsKeys
593
+ .filter(key => !(key in requiredCapabilities))
594
+ .map(key => [key, constants[key]])
595
+ });
596
+ // Prefer an existing compatible pipeline, including an earlier lean
597
+ // variant. Only grow the current variant when it cannot cover an edit;
598
+ // do not carry unused capabilities across different transport/layouts.
599
+ const capabilities = this._shaderCapabilities.find(structureKey, requiredCapabilities) ??
600
+ retainedShaderCapabilities(this._constants, structureKey === this._retainedShaderStructure ? this._retainedShaderCapabilities : undefined);
601
+ Object.assign(constants, capabilities);
602
+ const pipelineSignature = JSON.stringify({
603
+ ...structure,
604
+ constants: Object.keys(constants).sort().map(key => [key, constants[key]])
776
605
  });
777
606
  attemptedPipelineSignature = pipelineSignature;
778
607
  if (pipelineSignature === this._failedPipelineSignature) {
779
608
  return;
780
609
  }
781
610
  this._pipelineError = undefined;
782
- // TODO hardcoded defines that will be replaced in the code.
783
- const definesKeys = [
784
- 'NUM_MAPS',
785
- 'TLAS_STACK_SIZE',
786
- 'BLAS_STACK_SIZE',
787
- 'NUM_UNIFORM_LIGHTS'
788
- ];
789
- // Scene feature flags and background selection are runtime uniforms so
790
- // interactive edits do not recompile the path tracer.
791
- const constantsNotUsed = [
792
- ...Object.keys(WGPU_SCENE_FEATURE_BITS),
793
- 'USE_BACKGROUND',
794
- 'USE_BACKGROUND_MAP',
795
- 'USE_GROUNDED_BACKGROUND',
796
- ...MATERIAL_TEXTURE_DEFINES,
797
- 'USE_ANISOTROPY_DIRECTIONS',
798
- 'USE_COAT_NORMAL_FRAMES',
799
- 'HAS_ALPHA_BLEND',
800
- 'HAS_ALPHA_MASK'
801
- ];
802
- const defines = definesKeys.reduce((obj, key) => {
803
- obj[key] = constants[key];
804
- return obj;
805
- }, {});
806
- const pipelineConstantsKeys = Object.keys(constants)
807
- .sort()
808
- .filter((key) => !definesKeys.includes(key) && !constantsNotUsed.includes(key));
809
- const defineCode = definesKeys
810
- .map((key) => `const ${key} = ${defines[key]};`)
811
- .join('\n');
812
- const previousPipelineConstantsKeys = Object.keys(this._prevPipelineConstants)
813
- .filter((key) => !definesKeys.includes(key) && !constantsNotUsed.includes(key))
814
- .sort();
611
+ const previousPipelineConstantsKeys = wgpuPipelineConstantKeys(this._prevPipelineConstants);
815
612
  const needsCreateShaderModule = !this._rayTracePipelineLayout ||
816
613
  !this._computeShaderModule ||
817
614
  pipelineConstantsKeys.join(',') !==
@@ -836,20 +633,15 @@ class WGPURayTracePass {
836
633
  let sourceFingerprint = this._shaderCompilationDiagnostics?.modules[0]?.sourceFingerprint ?? '';
837
634
  if (needsCreateShaderModule) {
838
635
  const sourceGenerationStartedAt = shaderCompilationNow();
839
- const constantsCode = pipelineConstantsKeys
840
- .map((key) => `${this._bakePipelineConstants ? 'const' : 'override'} ${key} = ${constants[key].toString()};`)
841
- .join('\n');
842
- const rayTraceShaderCode = /* wgsl */ `
843
- ${defineCode}
844
- ${constantsCode}
845
- ${rayTraceCompute({
846
- hasDisplacement: this._hasDisplacement,
847
- hasAlpha,
848
- hasSceneAlpha,
636
+ let rayTraceShaderCode = wgpuShaderSource(constants, {
637
+ hasDisplacement: this._hasDisplacement, hasAlpha, hasSceneAlpha,
849
638
  hasAnisotropyDirections: Boolean(constants.USE_ANISOTROPY_DIRECTIONS),
850
639
  hasCoatNormals: Boolean(constants.USE_COAT_NORMAL_FRAMES),
851
- blasLayoutMask: this._blasLayoutMask
852
- })}`;
640
+ blasLayoutMask: this._blasLayoutMask,
641
+ dynamicEnvironment: true
642
+ }, this._bakePipelineConstants);
643
+ if (this._bindless)
644
+ rayTraceShaderCode = bindlessShaderSource(rayTraceShaderCode, this._textureSelection.support.enable);
853
645
  sourceBytes = rayTraceShaderCode.length;
854
646
  sourceLines = shaderSourceLineCount(rayTraceShaderCode);
855
647
  sourceFingerprint = shaderSourceFingerprint(rayTraceShaderCode);
@@ -891,7 +683,7 @@ ${rayTraceCompute({
891
683
  // NOTE must before creating pipeline.
892
684
  // Because createComputePipelineAsync is async.
893
685
  // The constants may be changed after the pipeline is created(in setMesh).
894
- this._prevPipelineConstants = { ...this._constants };
686
+ this._prevPipelineConstants = { ...constants };
895
687
  this._prevDefinesCode = defineCode;
896
688
  this._needsUpdateBindGroups = true;
897
689
  device.pushErrorScope('validation');
@@ -899,7 +691,7 @@ ${rayTraceCompute({
899
691
  try {
900
692
  const pipelineConstants = !this._bakePipelineConstants
901
693
  ? pipelineConstantsKeys.reduce((obj, key) => {
902
- obj[key] = +this._constants[key];
694
+ obj[key] = +constants[key];
903
695
  return obj;
904
696
  }, {})
905
697
  : undefined;
@@ -1020,14 +812,24 @@ ${rayTraceCompute({
1020
812
  throw new Error(detail);
1021
813
  }
1022
814
  }
815
+ // Compilation can complete after Engine disposal/device loss has released
816
+ // the material table and its textures. Never bind that retired generation.
817
+ if (this._disposed)
818
+ return;
1023
819
  // TODO rebind when lights, materials, bvh changed.
1024
820
  if (this._needsUpdateBindGroups) {
1025
821
  this._needsUpdateBindGroups = false;
1026
822
  this._updateBindGroups();
1027
823
  }
824
+ this._retainedShaderCapabilities = capabilities;
825
+ this._retainedShaderStructure = structureKey;
826
+ this._shaderCapabilities.remember(structureKey, capabilities);
827
+ this._prevPipelineInputs = pipelineInputs;
1028
828
  this._failedPipelineSignature = undefined;
1029
829
  }
1030
830
  catch (error) {
831
+ if (this._disposed)
832
+ return;
1031
833
  this._pipelineError = error;
1032
834
  const failedAt = shaderCompilationNow();
1033
835
  if (this._shaderCompilationDiagnostics?.status === 'compiling') {
@@ -1057,9 +859,106 @@ ${rayTraceCompute({
1057
859
  this._isCompilingShader = false;
1058
860
  }
1059
861
  }
862
+ _prepareAovPipelines(kinds) {
863
+ const trace = this._rayTracePipeline;
864
+ if (!trace || !this._depthCompute)
865
+ return;
866
+ const reflectance = (aovMask(kinds) & 24) !== 0;
867
+ let variants = this._aovPipelines.get(trace);
868
+ if (!variants) {
869
+ variants = new Map();
870
+ this._aovPipelines.set(trace, variants);
871
+ }
872
+ let pipelines = variants.get(reflectance);
873
+ if (!pipelines) {
874
+ pipelines = {};
875
+ variants.set(reflectance, pipelines);
876
+ const pending = pipelines;
877
+ const textures = this._bindless, groupIndex = textures ? 2 : 3;
878
+ const output = this._device.createBindGroupLayout({ entries: [
879
+ { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'storage' } },
880
+ { binding: 6, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'storage' } },
881
+ { binding: 7, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'read-only-storage' } },
882
+ { binding: 8, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'uniform' } },
883
+ { binding: 9, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'read-only-storage' } }
884
+ ] });
885
+ const descriptor = { bindGroupLayouts: Array.from({ length: groupIndex }, (_, i) => trace.getBindGroupLayout(i)).concat(output) };
886
+ const layout = this._device.createPipelineLayout(textures ? resourceTableLayout(descriptor) : descriptor);
887
+ const compute = { ...this._depthCompute, constants: { ...this._depthCompute.constants, DEPTH_QUERY_MODE: 1, AOV_REFLECTANCE: reflectance ? 1 : 0 } };
888
+ // Keep the UI responsive during first use, and reuse both variants across
889
+ // preview/final target changes rather than recreating synchronous pipelines.
890
+ void Promise.all([
891
+ this._shaderCache.createComputePipelineAsync({ label: 'AOV accumulation', layout, compute: { ...compute, entryPoint: 'aovTrace' } }),
892
+ this._shaderCache.createComputePipelineAsync({ label: 'AOV center', layout, compute: { ...compute, entryPoint: 'aovTraceCenter' } })
893
+ ]).then(([accumulation, center]) => { pending.accumulation = accumulation; pending.center = center; }, error => { pending.error = error; });
894
+ }
895
+ if (pipelines.error)
896
+ throw pipelines.error;
897
+ return pipelines;
898
+ }
899
+ prepareAovs(kinds) {
900
+ const pipelines = this._prepareAovPipelines(kinds);
901
+ return !!pipelines?.accumulation && !!pipelines.center;
902
+ }
903
+ renderAovs(state, camera, samples, cap, kinds) {
904
+ const groups = this._rayTraceBindGroups;
905
+ if (!groups || !this._tlas || !this._preparedMeshData || !kinds.length)
906
+ return false;
907
+ const pipelines = this._prepareAovPipelines(kinds);
908
+ if (!pipelines?.accumulation || !pipelines.center)
909
+ return false;
910
+ state.resize(this._width, this._height);
911
+ const textures = this._bindless, groupIndex = textures ? 2 : 3;
912
+ const target = Math.min(samples, cap);
913
+ if (state.centerReady && state.samples >= target)
914
+ return true;
915
+ if (!state.frame) {
916
+ const primitiveIds = this._aovPrimitiveCache.get(this._preparedMeshData, this._tlas);
917
+ const packed = packAovScene(this._preparedMeshData, this._tlas, camera, this._width, this._height, state.history, primitiveIds, false);
918
+ state.frame = packed.frame;
919
+ state.setScene(packed.words, primitiveIds);
920
+ }
921
+ this._device.queue.writeBuffer(this._uniforms.rtUniform, 0, this._rtUniform.buffer);
922
+ this._device.queue.writeBuffer(this._uniforms.cameraUniform, 0, packCameraUniform(this._viewProjInv, this._cameraWorld, this._apertureRadius, this._focusDistance));
923
+ const device = this._device;
924
+ const run = (pipeline, sample) => {
925
+ // A fresh uniform for each queued dispatch keeps batch samples independent.
926
+ const parameters = device.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });
927
+ new Uint32Array(parameters.getMappedRange()).set([state.width, state.height, sample, aovMask(kinds)]);
928
+ parameters.unmap();
929
+ const output = device.createBindGroup({ layout: pipeline.getBindGroupLayout(groupIndex), entries: [
930
+ { binding: 5, resource: { buffer: state.accumulation } }, { binding: 6, resource: { buffer: state.center } },
931
+ { binding: 7, resource: { buffer: state.scene } }, { binding: 8, resource: { buffer: parameters } }, { binding: 9, resource: { buffer: state.previousCenter } }
932
+ ] });
933
+ const encoder = device.createCommandEncoder({ label: 'AOV' }), pass = encoder.beginComputePass();
934
+ if (textures?.table)
935
+ setResourceTable(pass, textures.table);
936
+ pass.setPipeline(pipeline);
937
+ for (let i = 0; i < groupIndex; i++)
938
+ pass.setBindGroup(i, groups[i]);
939
+ pass.setBindGroup(groupIndex, output);
940
+ pass.dispatchWorkgroups(Math.ceil(state.width / 8), Math.ceil(state.height / 8));
941
+ pass.end();
942
+ device.queue.submit([encoder.finish()]);
943
+ parameters.destroy();
944
+ };
945
+ if (!state.centerReady) {
946
+ run(pipelines.center, 0);
947
+ state.centerReady = true;
948
+ state.history.accept(state.frame);
949
+ }
950
+ if ((aovMask(kinds) & 31) === 0)
951
+ state.samples = target;
952
+ while (state.samples < target) {
953
+ run(pipelines.accumulation, state.samples);
954
+ state.samples++;
955
+ }
956
+ return true;
957
+ }
1060
958
  async readDepthSamples(area, aspect) {
1061
959
  const tracePipeline = this._rayTracePipeline;
1062
960
  const groups = this._rayTraceBindGroups;
961
+ const textures = this._bindless, textureRevision = textures?.revision;
1063
962
  if (!tracePipeline || !groups || !this._depthCompute || this._isCompilingShader)
1064
963
  return;
1065
964
  const packed = packDepthSampleArea(area, aspect ?? this._width / this._height);
@@ -1071,10 +970,11 @@ ${rayTraceCompute({
1071
970
  { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'uniform' } }
1072
971
  ]
1073
972
  });
1074
- const layout = this._shaderCache.createPipelineLayout({
973
+ const descriptor = {
1075
974
  label: 'Depth query layout',
1076
- bindGroupLayouts: [0, 1, 2].map(i => tracePipeline.getBindGroupLayout(i)).concat(outputLayout)
1077
- });
975
+ bindGroupLayouts: (textures ? [0, 1] : [0, 1, 2]).map(i => tracePipeline.getBindGroupLayout(i)).concat(outputLayout)
976
+ };
977
+ const layout = this._shaderCache.createPipelineLayout(textures ? resourceTableLayout(descriptor) : descriptor);
1078
978
  this._depthTracePipeline = tracePipeline;
1079
979
  this._depthPipeline = this._shaderCache.createComputePipelineAsync({
1080
980
  label: 'Depth query', layout,
@@ -1084,7 +984,7 @@ ${rayTraceCompute({
1084
984
  }
1085
985
  const pipeline = await this._depthPipeline;
1086
986
  // Scene uploads can replace the buffers while the small query compiles.
1087
- if (tracePipeline !== this._rayTracePipeline || groups !== this._rayTraceBindGroups)
987
+ if (tracePipeline !== this._rayTracePipeline || groups !== this._rayTraceBindGroups || textures !== this._bindless || textureRevision !== textures?.revision)
1088
988
  return;
1089
989
  const device = this._device;
1090
990
  const bytes = DEPTH_SAMPLE_COUNT * 16;
@@ -1096,16 +996,18 @@ ${rayTraceCompute({
1096
996
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
1097
997
  try {
1098
998
  device.queue.writeBuffer(params, 0, packed);
1099
- const outputGroup = device.createBindGroup({ layout: pipeline.getBindGroupLayout(3), entries: [
999
+ const outputGroup = device.createBindGroup({ layout: pipeline.getBindGroupLayout(textures ? 2 : 3), entries: [
1100
1000
  { binding: 0, resource: { buffer: output } },
1101
1001
  { binding: 4, resource: { buffer: params } }
1102
1002
  ] });
1103
1003
  const encoder = device.createCommandEncoder({ label: 'Depth query' });
1104
1004
  const pass = encoder.beginComputePass();
1005
+ if (textures?.table)
1006
+ setResourceTable(pass, textures.table);
1105
1007
  pass.setPipeline(pipeline);
1106
- for (let i = 0; i < 3; i++)
1008
+ for (let i = 0; i < (textures ? 2 : 3); i++)
1107
1009
  pass.setBindGroup(i, groups[i]);
1108
- pass.setBindGroup(3, outputGroup);
1010
+ pass.setBindGroup(textures ? 2 : 3, outputGroup);
1109
1011
  pass.dispatchWorkgroups(1);
1110
1012
  pass.end();
1111
1013
  encoder.copyBufferToBuffer(output, 0, readback, 0, bytes);
@@ -1140,50 +1042,49 @@ ${rayTraceCompute({
1140
1042
  if (!this._bvhBuffer || !this._instancesBuffer) {
1141
1043
  throw new Error('WebGPU BVH buffers are not ready.');
1142
1044
  }
1143
- const bufferBindGroup = _device.createBindGroup({
1144
- layout: bindGroupPipeline.getBindGroupLayout(0),
1145
- entries: [
1146
- this._bvhBuffer,
1147
- this._instancesBuffer,
1148
- this._attrBuffers,
1149
- this._materialsBuffer
1150
- ].map((buffer, i) => ({
1151
- binding: i,
1152
- resource: {
1153
- buffer: buffer
1154
- }
1155
- }))
1156
- });
1157
- const texturesBindGroup = _device.createBindGroup({
1158
- layout: bindGroupPipeline.getBindGroupLayout(1),
1159
- entries: [
1160
- {
1045
+ const bufferEntries = [
1046
+ this._bvhBuffer,
1047
+ this._instancesBuffer,
1048
+ this._attrBuffers,
1049
+ this._materialsBuffer
1050
+ ].map((buffer, i) => ({
1051
+ binding: i,
1052
+ resource: {
1053
+ buffer: buffer
1054
+ }
1055
+ }));
1056
+ const textureEntries = [
1057
+ ...(this._bindless ? [] : [{
1161
1058
  binding: 0,
1162
1059
  resource: this._mapsSampler
1163
1060
  },
1164
1061
  {
1165
1062
  binding: 1,
1166
1063
  resource: this._maps.createView()
1167
- },
1168
- {
1169
- binding: 3,
1170
- resource: {
1171
- buffer: this._mapInfoUniform
1172
- }
1173
- },
1174
- { binding: 4, resource: this._envTex.createView() },
1175
- { binding: 5, resource: this._envDistributionTex.createView() },
1176
- { binding: 6, resource: this._backgroundTex.createView() },
1177
- { binding: 8, resource: this._lightSamplingTexture.createView() },
1178
- { binding: 9, resource: this._openPbrEnergyLut.createView() },
1179
- {
1180
- binding: 10,
1181
- resource: this._adaptiveSamplingTexture.createView()
1064
+ }]),
1065
+ {
1066
+ binding: 3,
1067
+ resource: {
1068
+ buffer: this._bindless?.metadata ?? this._mapInfoUniform
1182
1069
  }
1183
- ]
1070
+ },
1071
+ { binding: 4, resource: this._envTex.createView() },
1072
+ { binding: 5, resource: this._envDistributionTex.createView() },
1073
+ { binding: 6, resource: this._backgroundTex.createView() },
1074
+ { binding: 8, resource: this._lightSamplingTexture.createView() },
1075
+ { binding: 9, resource: this._openPbrEnergyLut.createView() },
1076
+ {
1077
+ binding: 10,
1078
+ resource: this._adaptiveSamplingTexture.createView()
1079
+ }
1080
+ ];
1081
+ const bufferBindGroup = _device.createBindGroup({ layout: bindGroupPipeline.getBindGroupLayout(0),
1082
+ entries: this._bindless ? bufferEntries.concat(textureEntries.map(e => ({ ...e, binding: e.binding + 4 }))) : bufferEntries });
1083
+ const texturesBindGroup = this._bindless ? undefined : _device.createBindGroup({
1084
+ layout: bindGroupPipeline.getBindGroupLayout(1), entries: textureEntries
1184
1085
  });
1185
1086
  const uniformBindGroup = _device.createBindGroup({
1186
- layout: bindGroupPipeline.getBindGroupLayout(2),
1087
+ layout: bindGroupPipeline.getBindGroupLayout(this._bindless ? 1 : 2),
1187
1088
  entries: Object.keys(this._uniforms).map((key, i) => ({
1188
1089
  binding: i,
1189
1090
  resource: {
@@ -1193,7 +1094,7 @@ ${rayTraceCompute({
1193
1094
  });
1194
1095
  const target = this._targetOutputs.get(this._activeTarget);
1195
1096
  const outputBindGroup = target.pipeline === bindGroupPipeline && target.bindGroup || _device.createBindGroup({
1196
- layout: bindGroupPipeline.getBindGroupLayout(3),
1097
+ layout: bindGroupPipeline.getBindGroupLayout(this._bindless ? 2 : 3),
1197
1098
  entries: [
1198
1099
  this._outColorBuffer,
1199
1100
  this._outNormalBuffer,
@@ -1208,7 +1109,7 @@ ${rayTraceCompute({
1208
1109
  target.pipeline = bindGroupPipeline;
1209
1110
  this._rayTraceBindGroups = [
1210
1111
  bufferBindGroup,
1211
- texturesBindGroup,
1112
+ ...(texturesBindGroup ? [texturesBindGroup] : []),
1212
1113
  uniformBindGroup,
1213
1114
  outputBindGroup
1214
1115
  ];
@@ -1240,6 +1141,8 @@ ${rayTraceCompute({
1240
1141
  };
1241
1142
  }
1242
1143
  const pass = encoder.beginComputePass(descriptor);
1144
+ if (this._bindless?.table)
1145
+ setResourceTable(pass, this._bindless.table);
1243
1146
  if (!this._rayTracePipeline || !this._rayTraceBindGroups) {
1244
1147
  throw new Error('WebGPU ray tracing pass was submitted before it was ready.');
1245
1148
  }
@@ -1259,8 +1162,18 @@ ${rayTraceCompute({
1259
1162
  };
1260
1163
  }
1261
1164
  getDiagnostics() {
1165
+ const atlas = this._materialData instanceof MaterialTable ? this._materialData.textureAtlasStats : undefined;
1262
1166
  return {
1263
- textureAtlas: this._materialData?.textureAtlasStats,
1167
+ textureAtlas: atlas,
1168
+ materialTextures: {
1169
+ requested: this._textureSelection.requested,
1170
+ active: this._bindless ? 'bindless' : 'atlas',
1171
+ fallbackReason: this._textureSelection.fallbackReason,
1172
+ ...(this._bindless?.diagnostics ?? {
1173
+ textureCount: atlas?.textureCount ?? 0, estimatedBytes: atlas?.estimatedBytes ?? 0,
1174
+ scale: atlas?.scale ?? 1, metadataBytes: 0, resourceTableCapacity: 0, retiredBytes: 0
1175
+ })
1176
+ },
1264
1177
  shaderCompilation: this._shaderCompilationDiagnostics,
1265
1178
  lightSampling: {
1266
1179
  emissiveTriangles: this._emissiveTriangles.length,
@@ -1325,15 +1238,14 @@ ${rayTraceCompute({
1325
1238
  return changed;
1326
1239
  }
1327
1240
  setSamplingPattern(pattern, maxSamples, sequenceSeed = 0) {
1328
- const code = samplingPatternCode(pattern);
1329
- const logSPP = zSobolLog2SPP(code === 1 ? maxSamples - 1 : maxSamples);
1241
+ const sampling = traceSampling(pattern, maxSamples, sequenceSeed);
1242
+ const { code, logSPP } = sampling;
1330
1243
  const views = this._rtUniform.views;
1331
1244
  const changed = this._constants.SAMPLING_PATTERN !== code ||
1332
1245
  views.sequenceSeed[0] !== (sequenceSeed >>> 0) ||
1333
1246
  (code === 1 && views.zSobolLogSPP[0] !== logSPP);
1334
1247
  this._constants.SAMPLING_PATTERN = code;
1335
- views.sequenceSeed[0] = sequenceSeed;
1336
- views.zSobolLogSPP[0] = logSPP;
1248
+ writeTraceSampling(views, sampling);
1337
1249
  return changed;
1338
1250
  }
1339
1251
  setSampleSequenceOffset(offset) {
@@ -1354,10 +1266,7 @@ ${rayTraceCompute({
1354
1266
  this._device.queue.writeTexture({ texture: this._adaptiveSamplingTexture }, data, { bytesPerRow: width * Float32Array.BYTES_PER_ELEMENT }, [width, height]);
1355
1267
  }
1356
1268
  setQuality(options) {
1357
- this._rtUniform.views.bounces[0] = normalizeBounces(options.bounces);
1358
- this._rtUniform.views.bevel[0] = +options.bevel;
1359
- this._rtUniform.views.dispersionWavelengths[0] = options.dispersionWavelengths;
1360
- this._rtUniform.views.directLightCandidates[0] = normalizeDirectLightCandidates(options.directLightCandidates);
1269
+ writeTraceQuality(this._rtUniform.views, options);
1361
1270
  }
1362
1271
  _setEnvMap(envImage) {
1363
1272
  const device = this._device;
@@ -1365,53 +1274,74 @@ ${rayTraceCompute({
1365
1274
  if (!environmentMapSourcesMatch(envImage, this._envImageSource) ||
1366
1275
  !this._envTex) {
1367
1276
  this._envImageSource = envImage;
1368
- this._envTex?.destroy();
1369
- this._envDistributionTex?.destroy();
1370
- const distribution = envImage && envMapDistribution(envImage);
1371
- const usage = GPUTextureUsage.TEXTURE_BINDING |
1372
- GPUTextureUsage.COPY_DST |
1373
- GPUTextureUsage.RENDER_ATTACHMENT;
1374
- this._envTex = device.createTexture({
1375
- format: 'rgba32float',
1376
- usage,
1377
- label: 'Env',
1378
- size: {
1379
- width: envImage ? envImage.width : 1,
1380
- height: envImage ? envImage.height : 1,
1381
- depthOrArrayLayers: 1
1382
- }
1383
- });
1384
- this._envDistributionTex = device.createTexture({
1385
- format: 'rg32float',
1386
- usage,
1387
- label: 'Env Distribution',
1388
- size: {
1389
- width: distribution ? distribution.width : 1,
1390
- height: distribution ? distribution.height : 1,
1391
- depthOrArrayLayers: 1
1392
- }
1393
- });
1394
- if (envImage && distribution) {
1395
- device.queue.writeTexture({
1396
- texture: this._envTex
1397
- }, envImage.data.buffer, {
1398
- bytesPerRow: envImage.width * 4 * 4
1399
- }, {
1400
- width: envImage.width,
1401
- height: envImage.height,
1402
- depthOrArrayLayers: 1
1277
+ const sky = envImage && 'sky' in envImage ? envImage : undefined;
1278
+ if (sky && (sky.width + 2 > device.limits.maxTextureDimension2D || sky.height + 1 > device.limits.maxTextureDimension2D))
1279
+ throw new RangeError('ProceduralSky resolution exceeds the device texture size limit.');
1280
+ const gpuDistribution = envImage && (sky || envImage.width * envImage.height >= 65536) &&
1281
+ WGPUEnvMapDistribution.supported(device, envImage.width, envImage.height);
1282
+ if (sky && !gpuDistribution)
1283
+ throw new RangeError('ProceduralSky resolution exceeds the GPU sampling storage limit; reduce resolution.');
1284
+ const distribution = envImage && !('sky' in envImage) && !gpuDistribution ? envMapDistribution(envImage) : undefined;
1285
+ const distributionWidth = envImage ? envImage.width + 2 : 1;
1286
+ const distributionHeight = envImage ? envImage.height + 1 : 1;
1287
+ const width = envImage?.width ?? 1;
1288
+ const height = envImage?.height ?? 1;
1289
+ const resized = !this._envTex || this._envTex.width !== width || this._envTex.height !== height ||
1290
+ !this._envDistributionTex || this._envDistributionTex.width !== distributionWidth || this._envDistributionTex.height !== distributionHeight;
1291
+ if (resized) {
1292
+ this._envTex?.destroy();
1293
+ this._envDistributionTex?.destroy();
1294
+ const usage = GPUTextureUsage.TEXTURE_BINDING |
1295
+ GPUTextureUsage.COPY_DST |
1296
+ GPUTextureUsage.RENDER_ATTACHMENT;
1297
+ this._envTex = device.createTexture({
1298
+ format: 'rgba32float',
1299
+ usage: usage | GPUTextureUsage.STORAGE_BINDING,
1300
+ label: 'Env',
1301
+ size: {
1302
+ width,
1303
+ height,
1304
+ depthOrArrayLayers: 1
1305
+ }
1403
1306
  });
1404
- device.queue.writeTexture({
1405
- texture: this._envDistributionTex
1406
- }, distribution.data.buffer, {
1407
- bytesPerRow: distribution.width * 4 * 2
1408
- }, {
1409
- width: distribution.width,
1410
- height: distribution.height,
1411
- depthOrArrayLayers: 1
1307
+ this._envDistributionTex = device.createTexture({
1308
+ format: 'rg32float',
1309
+ usage: usage | GPUTextureUsage.STORAGE_BINDING,
1310
+ label: 'Env Distribution',
1311
+ size: {
1312
+ width: distributionWidth,
1313
+ height: distributionHeight,
1314
+ depthOrArrayLayers: 1
1315
+ }
1412
1316
  });
1413
1317
  }
1414
- this._needsUpdateBindGroups = true;
1318
+ if (envImage) {
1319
+ if ('sky' in envImage) {
1320
+ this._skyBaker ??= new WGPUSkyBaker(device);
1321
+ this._skyBaker.bake(envImage, this._envTex);
1322
+ }
1323
+ else
1324
+ device.queue.writeTexture({
1325
+ texture: this._envTex
1326
+ }, envImage.data.buffer, {
1327
+ bytesPerRow: envImage.width * 4 * 4
1328
+ }, {
1329
+ width: envImage.width,
1330
+ height: envImage.height,
1331
+ depthOrArrayLayers: 1
1332
+ });
1333
+ if (gpuDistribution) {
1334
+ this._envDistribution ??= new WGPUEnvMapDistribution(device);
1335
+ this._envDistribution.build(this._envTex, this._envDistributionTex);
1336
+ }
1337
+ else if (distribution) {
1338
+ this._envDistribution?.dispose();
1339
+ device.queue.writeTexture({ texture: this._envDistributionTex }, distribution.data.buffer, { bytesPerRow: distribution.width * 4 * 2 }, { width: distribution.width, height: distribution.height, depthOrArrayLayers: 1 });
1340
+ }
1341
+ }
1342
+ else
1343
+ this._envDistribution?.dispose();
1344
+ this._needsUpdateBindGroups ||= resized;
1415
1345
  }
1416
1346
  this._constants.USE_ENVMAP = !!envImage;
1417
1347
  }
@@ -1624,6 +1554,7 @@ ${rayTraceCompute({
1624
1554
  }
1625
1555
  setBackground(background) {
1626
1556
  this._rtUniform.views.backgroundMapTransform.set(backgroundMapTransform(background));
1557
+ this._rtUniform.views.backgroundMapRotation.set(backgroundMapRotation(background));
1627
1558
  this._constants.USE_BACKGROUND = !!background;
1628
1559
  const backgroundImage = background && !Array.isArray(background)
1629
1560
  ? generateBackgroundMapFromSceneBackground(background)
@@ -1658,73 +1589,45 @@ ${rayTraceCompute({
1658
1589
  return;
1659
1590
  }
1660
1591
  this._backgroundImageSource = backgroundImage;
1661
- this._backgroundTex?.destroy();
1662
1592
  const width = backgroundImage?.width ?? 1;
1663
1593
  const height = backgroundImage?.height ?? 1;
1664
- this._backgroundTex = this._device.createTexture({
1665
- format: 'rgba32float',
1666
- usage: GPUTextureUsage.TEXTURE_BINDING |
1667
- GPUTextureUsage.COPY_DST |
1668
- GPUTextureUsage.RENDER_ATTACHMENT,
1669
- label: 'Background',
1670
- size: { width, height, depthOrArrayLayers: 1 }
1671
- });
1672
- if (backgroundImage) {
1594
+ if (backgroundImage && 'sky' in backgroundImage && (width > this._device.limits.maxTextureDimension2D || height > this._device.limits.maxTextureDimension2D))
1595
+ throw new RangeError('ProceduralSky resolution exceeds the device texture size limit.');
1596
+ const resized = !this._backgroundTex || this._backgroundTex.width !== width || this._backgroundTex.height !== height;
1597
+ if (resized) {
1598
+ this._backgroundTex?.destroy();
1599
+ this._backgroundTex = this._device.createTexture({
1600
+ format: 'rgba32float',
1601
+ usage: GPUTextureUsage.TEXTURE_BINDING |
1602
+ GPUTextureUsage.COPY_DST |
1603
+ GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.STORAGE_BINDING,
1604
+ label: 'Background',
1605
+ size: { width, height, depthOrArrayLayers: 1 }
1606
+ });
1607
+ }
1608
+ if (backgroundImage && 'sky' in backgroundImage) {
1609
+ this._skyBaker ??= new WGPUSkyBaker(this._device);
1610
+ this._skyBaker.bake(backgroundImage, this._backgroundTex);
1611
+ }
1612
+ else if (backgroundImage) {
1673
1613
  const source = backgroundImage.data;
1674
1614
  const data = source instanceof Float32Array
1675
1615
  ? source
1676
- : Float32Array.from(source, (value) => (source instanceof Uint8Array || source instanceof Uint8ClampedArray) ? value / 255 : value);
1616
+ : source instanceof Uint8Array || source instanceof Uint8ClampedArray
1617
+ ? Float32Array.from(source, value => value / 255)
1618
+ : Float32Array.from(source);
1677
1619
  this._device.queue.writeTexture({ texture: this._backgroundTex }, data.buffer, { bytesPerRow: width * 4 * 4 }, { width, height, depthOrArrayLayers: 1 });
1678
1620
  }
1679
- this._needsUpdateBindGroups = true;
1621
+ this._needsUpdateBindGroups ||= resized;
1680
1622
  }
1681
1623
  _updateLightSamplingData() {
1682
- const choices = this._lightChoices;
1683
- choices.reserve(1 + this._analyticLights.length + this._emissiveTriangles.length);
1684
- choices.push(LIGHT_CHOICE_ENVIRONMENT, 0, estimateEnvironmentPower(this._envImageSource));
1685
- this._analyticLights.forEach((light, i) => choices.push(LIGHT_CHOICE_ANALYTIC, i, estimateAnalyticLightPower(light)));
1686
- this._emissiveTriangles.forEach((triangle, i) => choices.push(LIGHT_CHOICE_EMISSIVE_TRIANGLE, i, triangle.area * triangle.samplingLuminance));
1687
- const distribution = buildLightAliasTable(choices);
1688
- const domainDiagnostics = {
1689
- environment: { count: 0, weight: 0, pmf: 0 },
1690
- infinite: { count: 0, weight: 0, pmf: 0 },
1691
- localAndEmissive: { count: 0, weight: 0, pmf: 0 }
1692
- };
1693
- this._analyticLightSelectionPmfs = new Array(this._analyticLights.length).fill(0);
1694
- this._rtUniform.views.envLightPmf[0] = 0;
1695
- const domains = [domainDiagnostics.environment, domainDiagnostics.infinite, domainDiagnostics.localAndEmissive];
1696
- for (let i = 0; i < choices.count; i++) {
1697
- const type = choices.sourceTypes[i], source = choices.sourceIndices[i];
1698
- const pmf = distribution.pmfs[i];
1699
- const domainIndex = type === LIGHT_CHOICE_ENVIRONMENT ? LIGHT_DOMAIN_ENVIRONMENT :
1700
- type === LIGHT_CHOICE_ANALYTIC && this._analyticLights[source]?.type === 'DirectionalLight' ?
1701
- LIGHT_DOMAIN_INFINITE : LIGHT_DOMAIN_LOCAL_AND_EMISSIVE;
1702
- const domain = domains[domainIndex];
1703
- domain.count++;
1704
- domain.weight += choices.weights[i];
1705
- domain.pmf += pmf;
1706
- if (type === LIGHT_CHOICE_ENVIRONMENT)
1707
- this._rtUniform.views.envLightPmf[0] = pmf;
1708
- else if (type === LIGHT_CHOICE_ANALYTIC)
1709
- this._analyticLightSelectionPmfs[source] = pmf;
1710
- else
1711
- this._emissiveTriangles[source].selectionPmf = pmf;
1712
- }
1713
- this._lightDomainDiagnostics = domainDiagnostics;
1714
- this._rtUniform.views.lightChoiceCount[0] = choices.count;
1715
- this._rtUniform.views.lightWeightTotal[0] = distribution.totalWeight;
1716
- const emissiveTexels = this._emissiveTriangles.length * 6;
1717
- const choiceTexels = Math.max(choices.count, 1);
1718
- const profileStartTexel = emissiveTexels + choiceTexels;
1719
- const packedIES = packIESProfiles(this._analyticLights, profileStartTexel);
1720
- this._iesProfileTexelOffsets = packedIES.offsets;
1721
- const totalTexels = Math.max(profileStartTexel + packedIES.texelCount, 1);
1722
- const maxDimension = this._device.limits.maxTextureDimension2D;
1723
- const width = Math.min(maxDimension, Math.max(16, Math.ceil(Math.sqrt(totalTexels) / 16) * 16));
1724
- const height = Math.ceil(totalTexels / width);
1725
- if (height > maxDimension) {
1726
- throw new Error('Too many emissive triangles for the light sampling texture.');
1727
- }
1624
+ this._constants.LIGHT_CAPABILITIES = lightShaderCapabilities(this._analyticLights.map(light => light.type), this._emissiveTriangles.length);
1625
+ const lighting = prepareSceneLightSampling(this._analyticLights, this._emissiveTriangles, this._envImageSource && 'sky' in this._envImageSource ? proceduralEnvironmentPower(this._envImageSource) : estimateEnvironmentPower(this._envImageSource), this._device.limits.maxTextureDimension2D, this._lightChoices, this._lightSamplingScratch, this._shadowCatcherLightChoices);
1626
+ this._analyticLightSelectionPmfs = lighting.analyticPmfs;
1627
+ this._iesProfileTexelOffsets = lighting.profiles.offsets;
1628
+ this._lightDomainDiagnostics = lighting.domains;
1629
+ const { lightWidth: width, lightHeight: height, lightData: textureData } = lighting;
1630
+ writeTraceLighting(this._rtUniform.views, lighting);
1728
1631
  const resized = !this._lightSamplingTexture || width !== this._lightSamplingTextureSize[0] || height !== this._lightSamplingTextureSize[1];
1729
1632
  if (!this._lightSamplingTexture ||
1730
1633
  width !== this._lightSamplingTextureSize[0] ||
@@ -1739,14 +1642,6 @@ ${rayTraceCompute({
1739
1642
  this._lightSamplingTextureSize = [width, height];
1740
1643
  this._needsUpdateBindGroups = true;
1741
1644
  }
1742
- const textureData = this._lightSamplingScratch?.length === width * height * 4
1743
- ? this._lightSamplingScratch : new Float32Array(width * height * 4);
1744
- textureData.fill(0);
1745
- if (this._emissiveTriangles.length) {
1746
- packEmissiveTriangles(this._emissiveTriangles, textureData);
1747
- }
1748
- new Uint32Array(textureData.buffer).set(distribution.choices, emissiveTexels * 4);
1749
- textureData.set(packedIES.data, profileStartTexel * 4);
1750
1645
  const previous = this._lightSamplingData;
1751
1646
  const full = resized || !previous || this._lightSamplingTriangleCount !== this._emissiveTriangles.length;
1752
1647
  const words = new Uint32Array(textureData.buffer);
@@ -1772,8 +1667,6 @@ ${rayTraceCompute({
1772
1667
  this._lightSamplingScratch = previous;
1773
1668
  this._lightSamplingData = textureData;
1774
1669
  this._lightSamplingTriangleCount = this._emissiveTriangles.length;
1775
- this._rtUniform.views.lightSamplingTextureWidth[0] = width;
1776
- this._rtUniform.views.lightChoiceTexelOffset[0] = emissiveTexels;
1777
1670
  this._needsUpdateAnalyticLightsBuffer = true;
1778
1671
  this._needsUpdateLightSamplingData = false;
1779
1672
  }
@@ -1823,33 +1716,15 @@ ${rayTraceCompute({
1823
1716
  const tlas = buildTLAS(res.instances, res.blases);
1824
1717
  this._tlas = tlas;
1825
1718
  this._uploadBVH(tlas, res.blases);
1826
- const materialData = (this._materialData = new MaterialTable(materials, this._analyticLights, {
1719
+ const materialData = (this._materialData = this._createMaterialData(materials, this._analyticLights, {
1827
1720
  maxTextureArrayBytes: this._maxTextureArrayBytes,
1828
1721
  maxTextureArrayLayers: this._device.limits.maxTextureArrayLayers,
1829
1722
  maxTextureDimension2D: this._device.limits.maxTextureDimension2D
1830
1723
  }));
1831
1724
  this._emissiveTriangles = this._emissiveCache.collect(res.emissiveBindings, materials);
1832
1725
  this._needsUpdateLightSamplingData = true;
1833
- const attrNames = [
1834
- 'position',
1835
- 'normal',
1836
- 'uv',
1837
- 'uv1',
1838
- 'color',
1839
- 'tangent',
1840
- 'materialIndex'
1841
- ];
1842
- const attributes = attrNames.map((a) => mergedGeometry[a]);
1843
- const fixedSize = 4;
1844
- let stride = 0;
1845
- const offsets = attrNames.map((attrName, idx) => {
1846
- const attr = attributes[idx];
1847
- const offset = stride;
1848
- if (attr) {
1849
- stride += fixedSize;
1850
- }
1851
- return offset;
1852
- });
1726
+ const attributeLayout = sceneAttributeLayout(mergedGeometry);
1727
+ const { stride, offsets } = attributeLayout;
1853
1728
  const attrBufferData = new F32(mergedGeometry.vertexCount * stride);
1854
1729
  packVertexAttributes(mergedGeometry, attrBufferData, stride, offsets, 0, mergedGeometry.vertexCount);
1855
1730
  this._attributeData = attrBufferData;
@@ -1869,17 +1744,7 @@ ${rayTraceCompute({
1869
1744
  cwbvh: 8
1870
1745
  };
1871
1746
  this._blasLayoutMask = res.blases.reduce((mask, blas) => mask | blasLayoutBits[blas.bvh.layout ?? 'bvh2'], 0);
1872
- Object.assign(this._constants, {
1873
- TLAS_STACK_SIZE: retainedShaderCapacity(traversalStackSizes.tlas, Number(this._constants.TLAS_STACK_SIZE ?? 0)),
1874
- BLAS_STACK_SIZE: retainedShaderCapacity(traversalStackSizes.blas, Number(this._constants.BLAS_STACK_SIZE ?? 0), 32),
1875
- USE_UV: mergedGeometry.uv != null,
1876
- USE_VERTEX_COLOR: mergedGeometry.color != null,
1877
- ATTR_STRIDE: stride / fixedSize,
1878
- ...offsets.reduce((obj, off, idx) => {
1879
- obj[attrNames[idx].toUpperCase() + '_OFF'] = off / fixedSize;
1880
- return obj;
1881
- }, {})
1882
- });
1747
+ Object.assign(this._constants, sceneTraversalConstants(traversalStackSizes.tlas, traversalStackSizes.blas, this._constants), attributeLayout.constants);
1883
1748
  this._updateMaterialConstants(materials, materialData, mergedGeometry);
1884
1749
  this._updateTextures(materialData);
1885
1750
  this._needsUpdateBindGroups = true;
@@ -1910,47 +1775,10 @@ ${rayTraceCompute({
1910
1775
  // Needs to recreate pipeline layout
1911
1776
  this._rayTracePipelineLayout = undefined;
1912
1777
  }
1913
- const HAS_BEVEL = materials.some((m) => m.bevelSize > 0);
1914
- const SPECTRAL = materials.some((m) => m.transmissionDispersionScale > 0);
1915
- const HAS_MEDIUM = materials.some(materialUsesMedium);
1916
- // Retain the atlas uniform capacity when a stage/material is removed.
1917
- // Shrinking the array would rebuild every pipeline again on the next edit.
1918
- const NUM_MAPS = Math.max(Math.ceil(+materialData.defines.NUM_MAPS / 10) * 10, Number(this._constants.NUM_MAPS ?? 0), 20);
1919
- // Either layer's map requires independent normals, including a smooth
1920
- // coat over a mapped base. Unmapped materials retain the shared path.
1921
- const USE_COAT_NORMAL_FRAMES = materials.some(m => m.coatWeight > 0 && (!!m.normalMap || !!m.coatNormalMap));
1922
- Object.assign(this._constants, {
1923
- // Match the atlas UV selector. Keep the second set when any texture
1924
- // needs it; material/texture edits already rebuild these constants.
1925
- USE_UV1: materialData.bufferData.mapUvChannel.some(channel => channel > 0.5),
1926
- // Isotropic OpenPBR constructs its own basis. Normal mapping uses
1927
- // triangle UV differentials rather than this vertex tangent.
1928
- USE_TANGENT: mergedGeometry.tangent != null &&
1929
- materials.some(material => material.specularAnisotropy > 0 || material.coatAnisotropy > 0 || (!!material.coatNormalMap && material.coatWeight > 0)),
1930
- USE_COAT_NORMAL_FRAMES,
1931
- USE_ANISOTROPY_DIRECTIONS: USE_COAT_NORMAL_FRAMES || materials.some(m => m.specularAnisotropy > 0 && (m.specularAnisotropyModel === 'gltf' || !!m.anisotropyMap || m.specularAnisotropyRotation !== 0) ||
1932
- m.coatAnisotropy > 0 && m.coatAnisotropyRotation !== 0),
1933
- HAS_MEDIUM,
1934
- HAS_SHADOW_CATCHER: this._hasShadowCatcher,
1935
- HAS_THIN_FILM: materials.some((material) => material.thinFilmWeight > 0),
1936
- HAS_COAT: materials.some((material) => material.coatWeight > 0),
1937
- HAS_FUZZ: materials.some((material) => material.fuzzWeight > 0),
1938
- HAS_SUBSURFACE: materials.some((material) => material.subsurfaceWeight > 0),
1939
- HAS_BEVEL,
1940
- HAS_ALPHA_MASK: materials.some((m) => resolveMaterialAlphaMode(m) === 'mask'),
1941
- HAS_ALPHA_BLEND: materials.some((m) => resolveMaterialAlphaMode(m) === 'blend'),
1942
- HAS_ALPHA: materials.some((m) => resolveMaterialAlphaMode(m) !== 'opaque'),
1943
- SPECTRAL,
1944
- BEVEL_SAMPLES: this._bevelSamples,
1945
- USE_RR: true,
1946
- // Match WebGL: defer roulette for multiple-scattering SSS paths.
1947
- RR_MAX: HAS_MEDIUM ? 12 : 2,
1948
- NUM_UNIFORM_LIGHTS: FIXED_LIGHT_COUNT,
1949
- ...materialData.defines,
1950
- NUM_MAPS,
1951
- ...materialTextureFeatures(materialData.defines),
1952
- USE_NORMAL_MAPS: +materialData.defines.NUM_NORMAL_MAPS > 0
1953
- });
1778
+ Object.assign(this._constants, wgpuMaterialConstants(materials, materialData, mergedGeometry, this._bevelSamples, Number(this._constants.NUM_MAPS ?? 0)));
1779
+ // Runtime storage metadata has no texture-count specialization.
1780
+ if (this._bindless)
1781
+ this._constants.NUM_MAPS = 20;
1954
1782
  }
1955
1783
  _updateGeometryData() {
1956
1784
  const res = this._preparedMeshData, tlas = this._tlas;
@@ -1996,7 +1824,7 @@ ${rayTraceCompute({
1996
1824
  const res = this._preparedMeshData;
1997
1825
  let materialData = this._materialData;
1998
1826
  if (update.level === 'textures') {
1999
- materialData = this._materialData = new MaterialTable(res.materials, this._analyticLights, {
1827
+ materialData = this._materialData = this._createMaterialData(res.materials, this._analyticLights, {
2000
1828
  maxTextureArrayBytes: this._maxTextureArrayBytes,
2001
1829
  maxTextureArrayLayers: this._device.limits.maxTextureArrayLayers,
2002
1830
  maxTextureDimension2D: this._device.limits.maxTextureDimension2D
@@ -2106,7 +1934,28 @@ ${rayTraceCompute({
2106
1934
  this._dirtyTransformMeshes.clear();
2107
1935
  this._needsRefitTLAS = false;
2108
1936
  }
1937
+ _createMaterialData(...args) {
1938
+ if (this._bindless) {
1939
+ const data = new WGPUBindlessMaterialData(args[0], args[1]);
1940
+ const reason = bindlessLimitReason(this._device, data.textures.length);
1941
+ if (!reason)
1942
+ return data;
1943
+ this._textureSelection.fallbackReason = reason;
1944
+ const retired = this._bindless;
1945
+ this._retiredBindless.add(retired);
1946
+ void this._device.queue.onSubmittedWorkDone().catch(() => { }).then(() => { retired.dispose(); this._retiredBindless.delete(retired); });
1947
+ this._bindless = undefined;
1948
+ this._computeShaderModule = undefined;
1949
+ this._rayTracePipelineLayout = undefined;
1950
+ }
1951
+ return new MaterialTable(...args);
1952
+ }
2109
1953
  _updateTextures(materialData) {
1954
+ if (materialData instanceof WGPUBindlessMaterialData) {
1955
+ this._bindless.update(materialData.textures, this._maxTextureArrayBytes);
1956
+ this._needsUpdateBindGroups = true;
1957
+ return;
1958
+ }
2110
1959
  // Textures
2111
1960
  // TODO Avoid zero length array.
2112
1961
  const mapInfo = materialData.bufferData.mapInfo ?? [0, 0, 0, 0];
@@ -2268,14 +2117,7 @@ ${rayTraceCompute({
2268
2117
  const arr = this._rtUniform.views.jitter;
2269
2118
  arr[0] = x;
2270
2119
  arr[1] = y;
2271
- this._device.queue.writeBuffer(this._uniforms.cameraUniform, 0, new F32([
2272
- ...this._viewProjInv,
2273
- ...this._cameraWorld,
2274
- this._apertureRadius,
2275
- this._focusDistance,
2276
- 0,
2277
- 0
2278
- ]));
2120
+ this._device.queue.writeBuffer(this._uniforms.cameraUniform, 0, packCameraUniform(this._viewProjInv, this._cameraWorld, this._apertureRadius, this._focusDistance));
2279
2121
  }
2280
2122
  setSampleTiles(columns, rows, tileX, tileY) {
2281
2123
  const arr = this._rtUniform.views.scaleOffset;
@@ -2301,7 +2143,14 @@ ${rayTraceCompute({
2301
2143
  return this._hasShadowCatcher;
2302
2144
  }
2303
2145
  dispose() {
2146
+ this._disposed = true;
2147
+ this._envDistribution?.dispose();
2148
+ this._skyBaker?.dispose();
2149
+ this._bindless?.dispose();
2150
+ this._retiredBindless.forEach(textures => textures.dispose());
2151
+ this._retiredBindless.clear();
2304
2152
  this._shaderCache.clear();
2153
+ this._shaderCapabilities.clear();
2305
2154
  const buffers = new Set([
2306
2155
  ...Array.from(this._targetOutputs.values()).flatMap(target => target.buffers),
2307
2156
  this._mapInfoUniform,