@meimu/mutracer 0.1.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (590) hide show
  1. package/LICENSES/Classroom-CC0.txt +121 -0
  2. package/README.md +10 -7
  3. package/THIRD_PARTY_NOTICES.md +13 -8
  4. package/dist/assets/bvh.worker.js +1 -1
  5. package/dist/mutracer.umd.js +12316 -9228
  6. package/docs/api.md +232 -21
  7. package/docs/caustics.md +80 -0
  8. package/docs/denoising.md +30 -15
  9. package/docs/materials.md +6 -5
  10. package/docs/performance.md +5 -2
  11. package/docs/progressive-rendering.md +73 -1
  12. package/docs/technical/continuous-spectrum.md +93 -0
  13. package/docs/threejs.md +14 -5
  14. package/docs/updates.md +46 -2
  15. package/docs/viewer-checklist.md +65 -0
  16. package/docs/viewer.md +15 -8
  17. package/lib/Display.d.ts +13 -2
  18. package/lib/Display.js +28 -7
  19. package/lib/Display.js.map +1 -1
  20. package/lib/Engine.d.ts +4 -0
  21. package/lib/Engine.js +99 -37
  22. package/lib/Engine.js.map +1 -1
  23. package/lib/Render.d.ts +98 -15
  24. package/lib/Render.js +275 -27
  25. package/lib/Render.js.map +1 -1
  26. package/lib/RenderLoop.d.ts +11 -1
  27. package/lib/RenderLoop.js +120 -15
  28. package/lib/RenderLoop.js.map +1 -1
  29. package/lib/main.d.ts +6 -3
  30. package/lib/main.js +1 -0
  31. package/lib/main.js.map +1 -1
  32. package/lib/math/access.d.ts +4 -0
  33. package/lib/math/access.js +10 -0
  34. package/lib/math/access.js.map +1 -0
  35. package/lib/math/mat3.d.ts +4 -0
  36. package/lib/math/mat3.js +54 -0
  37. package/lib/math/mat3.js.map +1 -0
  38. package/lib/math/mat4.d.ts +19 -0
  39. package/lib/math/mat4.js +413 -0
  40. package/lib/math/mat4.js.map +1 -0
  41. package/lib/math/storage.d.ts +6 -0
  42. package/lib/math/storage.js +22 -0
  43. package/lib/math/storage.js.map +1 -0
  44. package/lib/math/types.d.ts +3 -0
  45. package/lib/math/types.js +2 -0
  46. package/lib/math/types.js.map +1 -0
  47. package/lib/math/vec2.d.ts +13 -0
  48. package/lib/math/vec2.js +52 -0
  49. package/lib/math/vec2.js.map +1 -0
  50. package/lib/math/vec3.d.ts +23 -0
  51. package/lib/math/vec3.js +139 -0
  52. package/lib/math/vec3.js.map +1 -0
  53. package/lib/math.d.ts +5 -17
  54. package/lib/math.js +5 -55
  55. package/lib/math.js.map +1 -1
  56. package/lib/oidn.d.ts +1 -1
  57. package/lib/oidn.js +4 -2
  58. package/lib/oidn.js.map +1 -1
  59. package/lib/oidnBundledWeights.cdn.d.ts +2 -2
  60. package/lib/renderer/AovPrimitiveCache.d.ts +10 -0
  61. package/lib/renderer/AovPrimitiveCache.js +48 -0
  62. package/lib/renderer/AovPrimitiveCache.js.map +1 -0
  63. package/lib/renderer/Box3.d.ts +5 -0
  64. package/lib/renderer/Box3.js +9 -0
  65. package/lib/renderer/Box3.js.map +1 -0
  66. package/lib/renderer/GPUTraceQueue.d.ts +11 -0
  67. package/lib/renderer/GPUTraceQueue.js +33 -0
  68. package/lib/renderer/GPUTraceQueue.js.map +1 -0
  69. package/lib/renderer/MaterialData.d.ts +15 -0
  70. package/lib/renderer/MaterialData.js +61 -0
  71. package/lib/renderer/MaterialData.js.map +1 -0
  72. package/lib/renderer/MaterialTable.d.ts +11 -98
  73. package/lib/renderer/MaterialTable.js +34 -412
  74. package/lib/renderer/MaterialTable.js.map +1 -1
  75. package/lib/renderer/RenderingPipeline.d.ts +36 -13
  76. package/lib/renderer/RenderingPipeline.js +1 -17
  77. package/lib/renderer/RenderingPipeline.js.map +1 -1
  78. package/lib/renderer/TileRender.d.ts +0 -1
  79. package/lib/renderer/TileRender.js +14 -1
  80. package/lib/renderer/TileRender.js.map +1 -1
  81. package/lib/renderer/WGPUAov.d.ts +39 -0
  82. package/lib/renderer/WGPUAov.js +239 -0
  83. package/lib/renderer/WGPUAov.js.map +1 -0
  84. package/lib/renderer/WGPUBindlessMaterialData.d.ts +17 -0
  85. package/lib/renderer/WGPUBindlessMaterialData.js +48 -0
  86. package/lib/renderer/WGPUBindlessMaterialData.js.map +1 -0
  87. package/lib/renderer/WGPUBindlessTextures.d.ts +47 -0
  88. package/lib/renderer/WGPUBindlessTextures.js +180 -0
  89. package/lib/renderer/WGPUBindlessTextures.js.map +1 -0
  90. package/lib/renderer/WGPUBloomPass.js +17 -97
  91. package/lib/renderer/WGPUBloomPass.js.map +1 -1
  92. package/lib/renderer/WGPUCausticLightPass.d.ts +48 -0
  93. package/lib/renderer/WGPUCausticLightPass.js +217 -0
  94. package/lib/renderer/WGPUCausticLightPass.js.map +1 -0
  95. package/lib/renderer/WGPUComputePass.d.ts +1 -1
  96. package/lib/renderer/WGPUComputePass.js.map +1 -1
  97. package/lib/renderer/WGPUEnvMapDistribution.d.ts +12 -0
  98. package/lib/renderer/WGPUEnvMapDistribution.js +150 -0
  99. package/lib/renderer/WGPUEnvMapDistribution.js.map +1 -0
  100. package/lib/renderer/WGPUFullQuadPass.js +10 -9
  101. package/lib/renderer/WGPUFullQuadPass.js.map +1 -1
  102. package/lib/renderer/WGPUJNLMDenoiser.d.ts +1 -20
  103. package/lib/renderer/WGPUJNLMDenoiser.js +4 -267
  104. package/lib/renderer/WGPUJNLMDenoiser.js.map +1 -1
  105. package/lib/renderer/WGPUPhotonMap.d.ts +37 -0
  106. package/lib/renderer/WGPUPhotonMap.js +191 -0
  107. package/lib/renderer/WGPUPhotonMap.js.map +1 -0
  108. package/lib/renderer/WGPURayTraceOutput.d.ts +13 -1
  109. package/lib/renderer/WGPURayTraceOutput.js +132 -29
  110. package/lib/renderer/WGPURayTraceOutput.js.map +1 -1
  111. package/lib/renderer/WGPURayTracePass.d.ts +83 -56
  112. package/lib/renderer/WGPURayTracePass.js +884 -837
  113. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  114. package/lib/renderer/WGPURenderingPipeline.d.ts +5 -3
  115. package/lib/renderer/WGPURenderingPipeline.js +297 -82
  116. package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
  117. package/lib/renderer/WGPUShaderCache.d.ts +2 -2
  118. package/lib/renderer/WGPUShaderCache.js +10 -5
  119. package/lib/renderer/WGPUShaderCache.js.map +1 -1
  120. package/lib/renderer/WGPUShaderCapabilities.d.ts +10 -0
  121. package/lib/renderer/WGPUShaderCapabilities.js +54 -0
  122. package/lib/renderer/WGPUShaderCapabilities.js.map +1 -0
  123. package/lib/renderer/WGPUSkyBaker.d.ts +13 -0
  124. package/lib/renderer/WGPUSkyBaker.js +85 -0
  125. package/lib/renderer/WGPUSkyBaker.js.map +1 -0
  126. package/lib/renderer/WebGLAov.d.ts +41 -0
  127. package/lib/renderer/WebGLAov.js +106 -0
  128. package/lib/renderer/WebGLAov.js.map +1 -0
  129. package/lib/renderer/WebGLFullQuadPass.d.ts +7 -4
  130. package/lib/renderer/WebGLFullQuadPass.js +22 -2
  131. package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
  132. package/lib/renderer/WebGLJNLMDenoiser.d.ts +1 -1
  133. package/lib/renderer/WebGLJNLMDenoiser.js +83 -74
  134. package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -1
  135. package/lib/renderer/WebGLRayTraceOutputPass.js +7 -4
  136. package/lib/renderer/WebGLRayTraceOutputPass.js.map +1 -1
  137. package/lib/renderer/WebGLRayTracePass.d.ts +18 -3
  138. package/lib/renderer/WebGLRayTracePass.js +121 -9
  139. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  140. package/lib/renderer/WebGLRenderingPipeline.js +126 -22
  141. package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
  142. package/lib/renderer/WebGLSkyBaker.d.ts +39 -0
  143. package/lib/renderer/WebGLSkyBaker.js +422 -0
  144. package/lib/renderer/WebGLSkyBaker.js.map +1 -0
  145. package/lib/renderer/WebGLSkySource.d.ts +9 -0
  146. package/lib/renderer/WebGLSkySource.js +28 -0
  147. package/lib/renderer/WebGLSkySource.js.map +1 -0
  148. package/lib/renderer/accumulationTarget.d.ts +6 -0
  149. package/lib/renderer/accumulationTarget.js.map +1 -1
  150. package/lib/renderer/aov.d.ts +42 -0
  151. package/lib/renderer/aov.js +50 -0
  152. package/lib/renderer/aov.js.map +1 -0
  153. package/lib/renderer/aovDisplay.d.ts +14 -0
  154. package/lib/renderer/aovDisplay.js +32 -0
  155. package/lib/renderer/aovDisplay.js.map +1 -0
  156. package/lib/renderer/aovScene.d.ts +21 -0
  157. package/lib/renderer/aovScene.js +139 -0
  158. package/lib/renderer/aovScene.js.map +1 -0
  159. package/lib/renderer/binnedSahBvh.js +2 -1
  160. package/lib/renderer/binnedSahBvh.js.map +1 -1
  161. package/lib/renderer/bvhAccel.d.ts +20 -10
  162. package/lib/renderer/bvhAccel.js +168 -58
  163. package/lib/renderer/bvhAccel.js.map +1 -1
  164. package/lib/renderer/bvhWorkerBuild.d.ts +1 -0
  165. package/lib/renderer/cameraSnapshot.js +2 -1
  166. package/lib/renderer/cameraSnapshot.js.map +1 -1
  167. package/lib/renderer/cameraUniform.d.ts +2 -0
  168. package/lib/renderer/cameraUniform.js +12 -0
  169. package/lib/renderer/cameraUniform.js.map +1 -0
  170. package/lib/renderer/causticDiagnostics.d.ts +31 -0
  171. package/lib/renderer/causticDiagnostics.js +5 -0
  172. package/lib/renderer/causticDiagnostics.js.map +1 -0
  173. package/lib/renderer/causticEmission.d.ts +10 -0
  174. package/lib/renderer/causticEmission.js +40 -0
  175. package/lib/renderer/causticEmission.js.map +1 -0
  176. package/lib/renderer/causticUniform.d.ts +12 -0
  177. package/lib/renderer/causticUniform.js +22 -0
  178. package/lib/renderer/causticUniform.js.map +1 -0
  179. package/lib/renderer/caustics.d.ts +16 -0
  180. package/lib/renderer/caustics.js +93 -0
  181. package/lib/renderer/caustics.js.map +1 -0
  182. package/lib/renderer/committedScene.js +4 -0
  183. package/lib/renderer/committedScene.js.map +1 -1
  184. package/lib/renderer/denoiser.d.ts +3 -11
  185. package/lib/renderer/denoiser.js.map +1 -1
  186. package/lib/renderer/depthQuery.js +4 -1
  187. package/lib/renderer/depthQuery.js.map +1 -1
  188. package/lib/renderer/displacementPreparation.d.ts +11 -0
  189. package/lib/renderer/displacementPreparation.js +351 -0
  190. package/lib/renderer/displacementPreparation.js.map +1 -0
  191. package/lib/renderer/displacementRange.d.ts +1 -0
  192. package/lib/renderer/displacementRange.js +9 -0
  193. package/lib/renderer/displacementRange.js.map +1 -0
  194. package/lib/renderer/displayParityDiagnostics.d.ts +11 -0
  195. package/lib/renderer/displayParityDiagnostics.js +2 -0
  196. package/lib/renderer/displayParityDiagnostics.js.map +1 -0
  197. package/lib/renderer/envMapCreation.d.ts +9 -8
  198. package/lib/renderer/envMapCreation.js +36 -12
  199. package/lib/renderer/envMapCreation.js.map +1 -1
  200. package/lib/renderer/envMapDistribution.d.ts +12 -2
  201. package/lib/renderer/envMapDistribution.js +43 -34
  202. package/lib/renderer/envMapDistribution.js.map +1 -1
  203. package/lib/renderer/geometryBvhBounds.d.ts +4 -0
  204. package/lib/renderer/geometryBvhBounds.js +82 -0
  205. package/lib/renderer/geometryBvhBounds.js.map +1 -0
  206. package/lib/renderer/geometryUpdateState.d.ts +32 -0
  207. package/lib/renderer/geometryUpdateState.js +2 -0
  208. package/lib/renderer/geometryUpdateState.js.map +1 -0
  209. package/lib/renderer/geometryUpdates.d.ts +17 -9
  210. package/lib/renderer/geometryUpdates.js +92 -33
  211. package/lib/renderer/geometryUpdates.js.map +1 -1
  212. package/lib/renderer/glsl/aovDisplay.frag.d.ts +3 -0
  213. package/lib/renderer/glsl/aovDisplay.frag.js +54 -0
  214. package/lib/renderer/glsl/aovDisplay.frag.js.map +1 -0
  215. package/lib/renderer/glsl/aovReflectance.glsl.d.ts +2 -0
  216. package/lib/renderer/glsl/aovReflectance.glsl.js +87 -0
  217. package/lib/renderer/glsl/aovReflectance.glsl.js.map +1 -0
  218. package/lib/renderer/glsl/aovReflectanceSamples.glsl.d.ts +2 -0
  219. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +135 -0
  220. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js.map +1 -0
  221. package/lib/renderer/glsl/aovTrace.frag.d.ts +2 -0
  222. package/lib/renderer/glsl/aovTrace.frag.js +121 -0
  223. package/lib/renderer/glsl/aovTrace.frag.js.map +1 -0
  224. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +12 -12
  225. package/lib/renderer/glsl/chunks/emissiveLight.glsl.d.ts +2 -0
  226. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +35 -0
  227. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js.map +1 -0
  228. package/lib/renderer/glsl/chunks/envMap.glsl.js +73 -67
  229. package/lib/renderer/glsl/chunks/envMap.glsl.js.map +1 -1
  230. package/lib/renderer/glsl/chunks/intersect.glsl.js +432 -434
  231. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
  232. package/lib/renderer/glsl/chunks/materialBuffer.glsl.d.ts +1 -0
  233. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +160 -157
  234. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
  235. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +802 -802
  236. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  237. package/lib/renderer/glsl/chunks/random.glsl.js +6 -6
  238. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.d.ts +1 -0
  239. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +72 -67
  240. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  241. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +94 -76
  242. package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
  243. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -0
  244. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +143 -120
  245. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
  246. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +21 -18
  247. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js.map +1 -1
  248. package/lib/renderer/glsl/chunks/sampling.glsl.js +91 -94
  249. package/lib/renderer/glsl/chunks/sampling.glsl.js.map +1 -1
  250. package/lib/renderer/glsl/chunks/sobol.glsl.js +79 -79
  251. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  252. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +12 -12
  253. package/lib/renderer/glsl/chunks/uvProjection.glsl.js.map +1 -1
  254. package/lib/renderer/glsl/depthQuery.frag.js +7 -7
  255. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +17 -9
  256. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js.map +1 -1
  257. package/lib/renderer/glsl/rayTrace.frag.d.ts +1 -1
  258. package/lib/renderer/glsl/rayTrace.frag.js +271 -248
  259. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
  260. package/lib/renderer/glsl/shadowCatcher.frag.js +37 -32
  261. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  262. package/lib/renderer/glsl/webglPipeline.frag.js +65 -60
  263. package/lib/renderer/glsl/webglPipeline.frag.js.map +1 -1
  264. package/lib/renderer/lightConstants.d.ts +10 -0
  265. package/lib/renderer/lightConstants.js +11 -0
  266. package/lib/renderer/lightConstants.js.map +1 -0
  267. package/lib/renderer/lightCore.d.ts +12 -0
  268. package/lib/renderer/lightCore.js +13 -0
  269. package/lib/renderer/lightCore.js.map +1 -0
  270. package/lib/renderer/lightSampling.d.ts +22 -18
  271. package/lib/renderer/lightSampling.js +135 -62
  272. package/lib/renderer/lightSampling.js.map +1 -1
  273. package/lib/renderer/lightsData.d.ts +21 -0
  274. package/lib/renderer/lightsData.js +192 -0
  275. package/lib/renderer/lightsData.js.map +1 -0
  276. package/lib/renderer/lightsUtil.d.ts +3 -26
  277. package/lib/renderer/lightsUtil.js +3 -153
  278. package/lib/renderer/lightsUtil.js.map +1 -1
  279. package/lib/renderer/materialBufferData.d.ts +70 -0
  280. package/lib/renderer/materialBufferData.js +2 -0
  281. package/lib/renderer/materialBufferData.js.map +1 -0
  282. package/lib/renderer/materialConstants.d.ts +11 -0
  283. package/lib/renderer/materialConstants.js +11 -0
  284. package/lib/renderer/materialConstants.js.map +1 -1
  285. package/lib/renderer/materialCore.d.ts +8 -0
  286. package/lib/renderer/materialCore.js +9 -0
  287. package/lib/renderer/materialCore.js.map +1 -0
  288. package/lib/renderer/materialEmission.d.ts +2 -2
  289. package/lib/renderer/materialEmission.js +3 -3
  290. package/lib/renderer/materialEmission.js.map +1 -1
  291. package/lib/renderer/materialLayout.d.ts +2 -101
  292. package/lib/renderer/materialLayout.js +110 -172
  293. package/lib/renderer/materialLayout.js.map +1 -1
  294. package/lib/renderer/materialLayoutSchema.d.ts +26 -0
  295. package/lib/renderer/materialLayoutSchema.js +172 -0
  296. package/lib/renderer/materialLayoutSchema.js.map +1 -0
  297. package/lib/renderer/materialParams.d.ts +69 -0
  298. package/lib/renderer/materialParams.js +272 -0
  299. package/lib/renderer/materialParams.js.map +1 -0
  300. package/lib/renderer/materialTextureSlots.d.ts +14 -324
  301. package/lib/renderer/materialTextureSlots.js +21 -8
  302. package/lib/renderer/materialTextureSlots.js.map +1 -1
  303. package/lib/renderer/materialTextures.d.ts +6 -0
  304. package/lib/renderer/{texturesFromMaterials.js → materialTextures.js} +1 -2
  305. package/lib/renderer/materialTextures.js.map +1 -0
  306. package/lib/renderer/mergeMeshesToGeometry.js +6 -147
  307. package/lib/renderer/mergeMeshesToGeometry.js.map +1 -1
  308. package/lib/renderer/meshInstances.d.ts +4 -21
  309. package/lib/renderer/meshInstances.js +10 -56
  310. package/lib/renderer/meshInstances.js.map +1 -1
  311. package/lib/renderer/oidnNetwork.d.ts +2 -2
  312. package/lib/renderer/oidnNetwork.js +1 -1
  313. package/lib/renderer/oidnNetwork.js.map +1 -1
  314. package/lib/renderer/openPbrEnergyLut.js +850 -846
  315. package/lib/renderer/openPbrEnergyLut.js.map +1 -1
  316. package/lib/renderer/ownedDenoiser.d.ts +9 -0
  317. package/lib/renderer/ownedDenoiser.js +2 -0
  318. package/lib/renderer/ownedDenoiser.js.map +1 -0
  319. package/lib/renderer/packedMeshInstances.d.ts +23 -0
  320. package/lib/renderer/packedMeshInstances.js +80 -0
  321. package/lib/renderer/packedMeshInstances.js.map +1 -0
  322. package/lib/renderer/prepareMeshBVH.d.ts +12 -47
  323. package/lib/renderer/prepareMeshBVH.js +21 -642
  324. package/lib/renderer/prepareMeshBVH.js.map +1 -1
  325. package/lib/renderer/proceduralEnvironmentPower.d.ts +3 -0
  326. package/lib/renderer/proceduralEnvironmentPower.js +8 -0
  327. package/lib/renderer/proceduralEnvironmentPower.js.map +1 -0
  328. package/lib/renderer/progressiveScheduler.d.ts +1 -0
  329. package/lib/renderer/progressiveScheduler.js +7 -3
  330. package/lib/renderer/progressiveScheduler.js.map +1 -1
  331. package/lib/renderer/renderPipeline.d.ts +4 -1
  332. package/lib/renderer/renderPipeline.js.map +1 -1
  333. package/lib/renderer/renderingLimits.d.ts +9 -0
  334. package/lib/renderer/renderingLimits.js +18 -0
  335. package/lib/renderer/renderingLimits.js.map +1 -0
  336. package/lib/renderer/researchTransport.d.ts +31 -0
  337. package/lib/renderer/researchTransport.js +5 -0
  338. package/lib/renderer/researchTransport.js.map +1 -0
  339. package/lib/renderer/sceneAssembly.d.ts +73 -0
  340. package/lib/renderer/sceneAssembly.js +109 -0
  341. package/lib/renderer/sceneAssembly.js.map +1 -0
  342. package/lib/renderer/sceneChangeCore.d.ts +39 -0
  343. package/lib/renderer/sceneChangeCore.js +307 -0
  344. package/lib/renderer/sceneChangeCore.js.map +1 -0
  345. package/lib/renderer/sceneChangeDetector.d.ts +3 -6
  346. package/lib/renderer/sceneChangeDetector.js +24 -150
  347. package/lib/renderer/sceneChangeDetector.js.map +1 -1
  348. package/lib/renderer/sceneLayoutSchema.d.ts +119 -0
  349. package/lib/renderer/sceneLayoutSchema.js +111 -0
  350. package/lib/renderer/sceneLayoutSchema.js.map +1 -0
  351. package/lib/renderer/sceneLightChanges.d.ts +3 -3
  352. package/lib/renderer/sceneLightChanges.js.map +1 -1
  353. package/lib/renderer/scenePreparation.d.ts +55 -0
  354. package/lib/renderer/scenePreparation.js +360 -0
  355. package/lib/renderer/scenePreparation.js.map +1 -0
  356. package/lib/renderer/scratchSampling.js +18 -18
  357. package/lib/renderer/scratchSampling.js.map +1 -1
  358. package/lib/renderer/shader.d.ts +2 -0
  359. package/lib/renderer/shader.js +2 -0
  360. package/lib/renderer/shader.js.map +1 -1
  361. package/lib/renderer/shaderCapabilities.d.ts +23 -0
  362. package/lib/renderer/shaderCapabilities.js +55 -0
  363. package/lib/renderer/shaderCapabilities.js.map +1 -0
  364. package/lib/renderer/shaderCapacity.d.ts +2 -0
  365. package/lib/renderer/shaderCapacity.js +5 -0
  366. package/lib/renderer/shaderCapacity.js.map +1 -0
  367. package/lib/renderer/skyModel.d.ts +9 -0
  368. package/lib/renderer/skyModel.js +10 -0
  369. package/lib/renderer/skyModel.js.map +1 -0
  370. package/lib/renderer/spectrum.d.ts +21 -0
  371. package/lib/renderer/spectrum.js +154 -0
  372. package/lib/renderer/spectrum.js.map +1 -0
  373. package/lib/renderer/textureAtlas.d.ts +60 -0
  374. package/lib/renderer/textureAtlas.js +145 -0
  375. package/lib/renderer/textureAtlas.js.map +1 -0
  376. package/lib/renderer/textureAtlasPixels.d.ts +7 -0
  377. package/lib/renderer/textureAtlasPixels.js +68 -0
  378. package/lib/renderer/textureAtlasPixels.js.map +1 -0
  379. package/lib/renderer/util.d.ts +1 -1
  380. package/lib/renderer/util.js.map +1 -1
  381. package/lib/renderer/webgl.d.ts +9 -2
  382. package/lib/renderer/webgl.js +54 -9
  383. package/lib/renderer/webgl.js.map +1 -1
  384. package/lib/renderer/webglLightSampling.d.ts +39 -0
  385. package/lib/renderer/webglLightSampling.js +15 -0
  386. package/lib/renderer/webglLightSampling.js.map +1 -0
  387. package/lib/renderer/wgpuBindless.d.ts +26 -0
  388. package/lib/renderer/wgpuBindless.js +95 -0
  389. package/lib/renderer/wgpuBindless.js.map +1 -0
  390. package/lib/renderer/wgpuBindlessSource.d.ts +2 -0
  391. package/lib/renderer/wgpuBindlessSource.js +51 -0
  392. package/lib/renderer/wgpuBindlessSource.js.map +1 -0
  393. package/lib/renderer/wgpuMaterialConstants.d.ts +4 -0
  394. package/lib/renderer/wgpuMaterialConstants.js +52 -0
  395. package/lib/renderer/wgpuMaterialConstants.js.map +1 -0
  396. package/lib/renderer/wgpuSceneUniform.d.ts +42 -0
  397. package/lib/renderer/wgpuSceneUniform.js +125 -0
  398. package/lib/renderer/wgpuSceneUniform.js.map +1 -0
  399. package/lib/renderer/wgpuShaderSource.d.ts +22 -0
  400. package/lib/renderer/wgpuShaderSource.js +33 -0
  401. package/lib/renderer/wgpuShaderSource.js.map +1 -0
  402. package/lib/renderer/wgsl/aovDisplay.wgsl.d.ts +1 -0
  403. package/lib/renderer/wgsl/aovDisplay.wgsl.js +70 -0
  404. package/lib/renderer/wgsl/aovDisplay.wgsl.js.map +1 -0
  405. package/lib/renderer/wgsl/aovReflectance.wgsl.d.ts +2 -0
  406. package/lib/renderer/wgsl/aovReflectance.wgsl.js +98 -0
  407. package/lib/renderer/wgsl/aovReflectance.wgsl.js.map +1 -0
  408. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.d.ts +2 -0
  409. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +135 -0
  410. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js.map +1 -0
  411. package/lib/renderer/wgsl/aovResolve.wgsl.d.ts +5 -0
  412. package/lib/renderer/wgsl/aovResolve.wgsl.js +38 -0
  413. package/lib/renderer/wgsl/aovResolve.wgsl.js.map +1 -0
  414. package/lib/renderer/wgsl/aovSnapshot.wgsl.d.ts +4 -0
  415. package/lib/renderer/wgsl/aovSnapshot.wgsl.js +21 -0
  416. package/lib/renderer/wgsl/aovSnapshot.wgsl.js.map +1 -0
  417. package/lib/renderer/wgsl/aovTrace.wgsl.d.ts +2 -0
  418. package/lib/renderer/wgsl/aovTrace.wgsl.js +115 -0
  419. package/lib/renderer/wgsl/aovTrace.wgsl.js.map +1 -0
  420. package/lib/renderer/wgsl/bloom.wgsl.d.ts +13 -0
  421. package/lib/renderer/wgsl/bloom.wgsl.js +92 -0
  422. package/lib/renderer/wgsl/bloom.wgsl.js.map +1 -0
  423. package/lib/renderer/wgsl/causticLight.compute.d.ts +6 -0
  424. package/lib/renderer/wgsl/causticLight.compute.js +537 -0
  425. package/lib/renderer/wgsl/causticLight.compute.js.map +1 -0
  426. package/lib/renderer/wgsl/chunks/background.wgsl.d.ts +2 -0
  427. package/lib/renderer/wgsl/chunks/background.wgsl.js +102 -0
  428. package/lib/renderer/wgsl/chunks/background.wgsl.js.map +1 -0
  429. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.d.ts +2 -0
  430. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +12 -0
  431. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js.map +1 -0
  432. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.d.ts +2 -0
  433. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +16 -0
  434. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js.map +1 -0
  435. package/lib/renderer/wgsl/chunks/caustics.wgsl.d.ts +1 -0
  436. package/lib/renderer/wgsl/chunks/caustics.wgsl.js +62 -0
  437. package/lib/renderer/wgsl/chunks/caustics.wgsl.js.map +1 -0
  438. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  439. package/lib/renderer/wgsl/chunks/envMap.wgsl.d.ts +1 -1
  440. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +41 -35
  441. package/lib/renderer/wgsl/chunks/envMap.wgsl.js.map +1 -1
  442. package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +13 -1
  443. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +747 -704
  444. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  445. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +16 -16
  446. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -1
  447. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +4 -1
  448. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +83 -79
  449. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  450. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +855 -857
  451. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js.map +1 -1
  452. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +137 -137
  453. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  454. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +3 -1
  455. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +52 -32
  456. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  457. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +1 -1
  458. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +152 -144
  459. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -1
  460. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
  461. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +269 -245
  462. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
  463. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +1 -1
  464. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +27 -14
  465. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -1
  466. package/lib/renderer/wgsl/chunks/sampling.wgsl.d.ts +1 -1
  467. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +91 -95
  468. package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -1
  469. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.d.ts +1 -1
  470. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js +1 -0
  471. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js.map +1 -1
  472. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +83 -83
  473. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +12 -12
  474. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js.map +1 -1
  475. package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +8 -3
  476. package/lib/renderer/wgsl/compose.frag.wgsl.js +143 -118
  477. package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -1
  478. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  479. package/lib/renderer/wgsl/depthQuery.wgsl.js +7 -7
  480. package/lib/renderer/wgsl/jnlm.compute.d.ts +25 -0
  481. package/lib/renderer/wgsl/jnlm.compute.js +315 -0
  482. package/lib/renderer/wgsl/jnlm.compute.js.map +1 -0
  483. package/lib/renderer/wgsl/offlineAdaptive.compute.js +28 -28
  484. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.d.ts +1 -0
  485. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +17 -0
  486. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js.map +1 -0
  487. package/lib/renderer/wgsl/photonMap.compute.d.ts +29 -0
  488. package/lib/renderer/wgsl/photonMap.compute.js +352 -0
  489. package/lib/renderer/wgsl/photonMap.compute.js.map +1 -0
  490. package/lib/renderer/wgsl/proceduralSky.compute.d.ts +1 -0
  491. package/lib/renderer/wgsl/proceduralSky.compute.js +198 -0
  492. package/lib/renderer/wgsl/proceduralSky.compute.js.map +1 -0
  493. package/lib/renderer/wgsl/rayTrace.compute.d.ts +25 -1
  494. package/lib/renderer/wgsl/rayTrace.compute.js +645 -500
  495. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  496. package/lib/scene/Camera.js +7 -3
  497. package/lib/scene/Camera.js.map +1 -1
  498. package/lib/scene/EnvironmentLight.d.ts +5 -9
  499. package/lib/scene/EnvironmentLight.js +4 -14
  500. package/lib/scene/EnvironmentLight.js.map +1 -1
  501. package/lib/scene/EnvironmentLightState.d.ts +18 -0
  502. package/lib/scene/EnvironmentLightState.js +19 -0
  503. package/lib/scene/EnvironmentLightState.js.map +1 -0
  504. package/lib/scene/Geometry.d.ts +12 -6
  505. package/lib/scene/Geometry.js +37 -13
  506. package/lib/scene/Geometry.js.map +1 -1
  507. package/lib/scene/InstanceState.d.ts +39 -0
  508. package/lib/scene/InstanceState.js +77 -0
  509. package/lib/scene/InstanceState.js.map +1 -0
  510. package/lib/scene/InstancedMesh.d.ts +1 -1
  511. package/lib/scene/InstancedMesh.js +3 -0
  512. package/lib/scene/InstancedMesh.js.map +1 -1
  513. package/lib/scene/MaterialState.d.ts +209 -0
  514. package/lib/scene/MaterialState.js +231 -0
  515. package/lib/scene/MaterialState.js.map +1 -0
  516. package/lib/scene/Mesh.d.ts +4 -6
  517. package/lib/scene/Mesh.js +3 -11
  518. package/lib/scene/Mesh.js.map +1 -1
  519. package/lib/scene/MeshState.d.ts +20 -0
  520. package/lib/scene/MeshState.js +35 -0
  521. package/lib/scene/MeshState.js.map +1 -0
  522. package/lib/scene/OpenPBRMaterial.d.ts +6 -168
  523. package/lib/scene/OpenPBRMaterial.js +5 -223
  524. package/lib/scene/OpenPBRMaterial.js.map +1 -1
  525. package/lib/scene/PixelTexture.d.ts +6 -0
  526. package/lib/scene/PixelTexture.js +10 -0
  527. package/lib/scene/PixelTexture.js.map +1 -0
  528. package/lib/scene/ProceduralSky.d.ts +24 -0
  529. package/lib/scene/ProceduralSky.js +40 -0
  530. package/lib/scene/ProceduralSky.js.map +1 -0
  531. package/lib/scene/RectLight.d.ts +2 -13
  532. package/lib/scene/RectLight.js +3 -21
  533. package/lib/scene/RectLight.js.map +1 -1
  534. package/lib/scene/RectLightState.d.ts +31 -0
  535. package/lib/scene/RectLightState.js +26 -0
  536. package/lib/scene/RectLightState.js.map +1 -0
  537. package/lib/scene/Scene.d.ts +15 -4
  538. package/lib/scene/Scene.js.map +1 -1
  539. package/lib/scene/SceneNode.js +7 -6
  540. package/lib/scene/SceneNode.js.map +1 -1
  541. package/lib/scene/Texture.d.ts +10 -41
  542. package/lib/scene/Texture.js +4 -33
  543. package/lib/scene/Texture.js.map +1 -1
  544. package/lib/scene/TextureState.d.ts +35 -0
  545. package/lib/scene/TextureState.js +35 -0
  546. package/lib/scene/TextureState.js.map +1 -0
  547. package/lib/scene/attributeData.d.ts +4 -0
  548. package/lib/scene/attributeData.js +10 -0
  549. package/lib/scene/attributeData.js.map +1 -0
  550. package/lib/scene/lightState.d.ts +8 -0
  551. package/lib/scene/lightState.js +2 -0
  552. package/lib/scene/lightState.js.map +1 -0
  553. package/lib/scene/openPbrSchema.d.ts +7 -12
  554. package/lib/scene/openPbrSchema.js +273 -28
  555. package/lib/scene/openPbrSchema.js.map +1 -1
  556. package/lib/scene/skyParameters.d.ts +20 -0
  557. package/lib/scene/skyParameters.js +28 -0
  558. package/lib/scene/skyParameters.js.map +1 -0
  559. package/lib/scene/textureData.d.ts +9 -0
  560. package/lib/scene/textureData.js +2 -0
  561. package/lib/scene/textureData.js.map +1 -0
  562. package/lib/scene/texturePixels.d.ts +6 -0
  563. package/lib/scene/texturePixels.js +10 -0
  564. package/lib/scene/texturePixels.js.map +1 -0
  565. package/lib/settings/display.d.ts +33 -0
  566. package/lib/settings/display.js +7 -0
  567. package/lib/settings/display.js.map +1 -1
  568. package/lib/settings/render.d.ts +36 -3
  569. package/lib/settings/render.js +4 -1
  570. package/lib/settings/render.js.map +1 -1
  571. package/lib/tinybvh/tinybvh.wasm +0 -0
  572. package/lib/util/commonGeometry.js +7 -7
  573. package/lib/util/commonGeometry.js.map +1 -1
  574. package/lib/util/fromTHREE.d.ts +4 -1
  575. package/lib/util/fromTHREE.js +20 -7
  576. package/lib/util/fromTHREE.js.map +1 -1
  577. package/lib/util/geometry.js +42 -29
  578. package/lib/util/geometry.js.map +1 -1
  579. package/lib/util/loadRGBE.js +3 -4
  580. package/lib/util/loadRGBE.js.map +1 -1
  581. package/lib/util/studioLighting.d.ts +18 -0
  582. package/lib/util/studioLighting.js +36 -0
  583. package/lib/util/studioLighting.js.map +1 -0
  584. package/lib/version.d.ts +1 -1
  585. package/lib/version.js +1 -1
  586. package/lib/version.js.map +1 -1
  587. package/llms.txt +5 -0
  588. package/package.json +33 -7
  589. package/lib/renderer/texturesFromMaterials.d.ts +0 -6
  590. package/lib/renderer/texturesFromMaterials.js.map +0 -1
@@ -0,0 +1,352 @@
1
+ export const PHOTON_BYTES = 20;
2
+ export const PHOTON_GRID_SIZE = 262144;
3
+ export const PHOTON_SCAN_BLOCK = 256;
4
+ export const PHOTON_REFERENCE_COUNT = 2 ** 18;
5
+ /** Internal density A/B, with the same progressive schedule in all modes. */
6
+ export function photonRadius(initial, batch, alpha = 2 / 3, photons = PHOTON_REFERENCE_COUNT, scaling = 'none') {
7
+ const radius = initial * Math.pow(Math.max(1, batch), (alpha - 1) / 2);
8
+ if (scaling === 'none' || photons === PHOTON_REFERENCE_COUNT)
9
+ return radius;
10
+ const exponent = scaling === 'ppm' ? (alpha - 1) / 2 : -1 / 2;
11
+ return radius * Math.pow(Math.max(1, photons) / PHOTON_REFERENCE_COUNT, exponent);
12
+ }
13
+ /** Default photon-map batch: pixel count / 4, capped at 2^18. */
14
+ export function defaultPhotonMapPhotons(width, height, divisor = 4) {
15
+ return Math.min(2 ** 18, Math.max(1, Math.round((width * height) / divisor)));
16
+ }
17
+ /** Power-of-two hash capacity, bounded independently of large photon batches. */
18
+ export function photonBucketCount(photons) {
19
+ return Math.min(PHOTON_GRID_SIZE, 2 ** Math.ceil(Math.log2(Math.max(256, photons * 2))));
20
+ }
21
+ /** Shared texture address contract; payload is stored once, indices twice. */
22
+ export function photonLayout(count, perCasterRadius = false) {
23
+ const buckets = photonBucketCount(count);
24
+ const coarseHeaders = 8;
25
+ const fineHeaders = coarseHeaders + buckets * 2;
26
+ const coarseIndices = fineHeaders + buckets * 2;
27
+ const fineIndices = coarseIndices + count;
28
+ const directions = fineIndices + count;
29
+ return { buckets, coarseHeaders, fineHeaders, coarseIndices, fineIndices, directions, texels: directions + count * (perCasterRadius ? 2 : 1) };
30
+ }
31
+ /** Batch-local hash buckets: count, two-level parallel prefix sum, then parallel scatter. */
32
+ export const photonGridCompute = /* wgsl */ `
33
+ struct Bucket {
34
+ count: atomic<u32>,
35
+ offset: u32,
36
+ cursor: atomic<u32>,
37
+ padding: u32,
38
+ }
39
+ struct Parameters {
40
+ radius: f32,
41
+ count: u32,
42
+ screenPixels: f32,
43
+ skipQuery: f32,
44
+ buckets: u32,
45
+ fineRadius: f32,
46
+ experiments: u32,
47
+ padding2: u32,
48
+ }
49
+ @group(0)@binding(0)var photons:texture_2d<u32>;
50
+ @group(0)@binding(1)var<storage,read_write>grid:array<Bucket>;
51
+ @group(0)@binding(2)var<uniform>parameters:Parameters;
52
+ @group(0)@binding(4)var headers:texture_storage_2d<r32uint,write>;
53
+ fn xu(yp:vec3i)->u32 {
54
+ let p=bitcast<vec3u>(yp);
55
+ return ((p.x*73856093u)^(p.y*19349663u)^(p.z*83492791u))&(parameters.buckets-1u);
56
+ }
57
+ fn tM(p:vec3f,layer:u32)->u32 {
58
+ let radius=select(parameters.radius,parameters.fineRadius,layer==1u);
59
+ let lv=select(radius,2.0*radius,layer==1u);
60
+ return xu(vec3i(floor(p/lv)));
61
+ }
62
+ fn os(layer:u32)->u32 {
63
+ return layer*(parameters.buckets+parameters.buckets/256u);
64
+ }
65
+ fn fm(i:u32,value:u32) {
66
+ let width=textureDimensions(headers).x;
67
+ textureStore(headers,vec2i(vec2u(i%width,i/width)),vec4u(value));
68
+ }
69
+ fn pi(i:u32)->vec4u {
70
+ let width=textureDimensions(photons).x;
71
+ return textureLoad(photons,vec2i(vec2u(i%width,i/width)),0);
72
+ }
73
+ fn qv(i:u32)->vec3f {
74
+ return bitcast<vec3f>(pi(i).xyz);
75
+ }
76
+ @compute @workgroup_size(64)
77
+ fn count(@builtin(global_invocation_id)id:vec3u) {
78
+ if(id.x+id.y*4194240u>=parameters.count) {
79
+ return;
80
+ }
81
+ let index=id.x+id.y*4194240u;
82
+ if(pi(index).w==0u) {
83
+ return;
84
+ }
85
+ for(var layer=0u;layer<2u;layer++) {
86
+ atomicAdd(&grid[os(layer)+tM(qv(index),layer)].count,1u);
87
+ }
88
+ }
89
+
90
+ var<workgroup> scan:array<u32,256>;
91
+ fn iU(local:u32,value:u32)->u32 {
92
+ scan[local]=value;
93
+ workgroupBarrier();
94
+ for(var stride=1u;stride<256u;stride*=2u) {
95
+ var previous=0u;
96
+ if(local>=stride) {
97
+ previous=scan[local-stride];
98
+ }
99
+ workgroupBarrier();
100
+ scan[local]+=previous;
101
+ workgroupBarrier();
102
+ }
103
+ return scan[local];
104
+ }
105
+ @compute @workgroup_size(256)
106
+ fn scanBlocks(@builtin(local_invocation_index)local:u32,@builtin(workgroup_id)group:vec3u) {
107
+ let index=os(group.y)+group.x*256u+local;
108
+ let count=atomicLoad(&grid[index].count);
109
+ let prefix=iU(local,count);
110
+ grid[index].offset=prefix-count;
111
+ if(local==255u) {
112
+ atomicStore(&grid[os(group.y)+parameters.buckets+group.x].count,prefix);
113
+ }
114
+ }
115
+ @compute @workgroup_size(256)
116
+ fn scanSums(@builtin(local_invocation_index)local:u32,@builtin(workgroup_id)group:vec3u) {
117
+ let blocks=parameters.buckets/256u;
118
+ let xo=(blocks+255u)/256u;
119
+ let first=local*xo;
120
+ let start=os(group.y)+parameters.buckets;
121
+ var count=0u;
122
+ for(var i=first;i<min(first+xo,blocks);i++) {
123
+ count+=atomicLoad(&grid[start+i].count);
124
+ }
125
+ let prefix=iU(local,count);
126
+ var offset=prefix-count;
127
+ for(var i=first;i<min(first+xo,blocks);i++) {
128
+ grid[start+i].offset=offset;
129
+ offset+=atomicLoad(&grid[start+i].count);
130
+ }
131
+ if(local==255u&&group.y==0u) {
132
+ fm(0u,bitcast<u32>(parameters.radius));
133
+ fm(1u,prefix);
134
+ fm(2u,bitcast<u32>(parameters.screenPixels));
135
+ fm(3u,bitcast<u32>(parameters.skipQuery));
136
+ fm(4u,parameters.count);
137
+ fm(5u,parameters.buckets);
138
+ fm(6u,bitcast<u32>(parameters.fineRadius));
139
+ fm(7u,parameters.experiments);
140
+ }
141
+ }
142
+ @compute @workgroup_size(64)
143
+ fn scatter(@builtin(global_invocation_id)id:vec3u) {
144
+ let eA=id.x+id.y*4194240u;
145
+ for(var layer=0u;layer<2u;layer++) {
146
+ let start=os(layer);
147
+ if(eA<parameters.buckets) {
148
+ let offset=grid[start+eA].offset+grid[start+parameters.buckets+eA/256u].offset;
149
+ fm(8u+layer*parameters.buckets*2u+eA*2u,offset);
150
+ fm(9u+layer*parameters.buckets*2u+eA*2u,atomicLoad(&grid[start+eA].count));
151
+ }
152
+ if(eA<parameters.count&&pi(eA).w!=0u) {
153
+ let su=tM(qv(eA),layer);
154
+ let index=grid[start+su].offset+grid[start+parameters.buckets+su/256u].offset+atomicAdd(&grid[start+su].cursor,1u);
155
+ fm(8u+parameters.buckets*4u+layer*parameters.count+index,eA);
156
+ }
157
+ }
158
+ }
159
+ `;
160
+ /** Packed photon payload: position f32 x3, RGBE8 flux, two octahedral directions. */
161
+ export const photonPackingWgsl = /* wgsl */ `
162
+ fn rd(v:vec2f)->vec2f {
163
+ return select(vec2f(-1.0),vec2f(1.0),v>=vec2f(0.0));
164
+ }
165
+ fn pN(n:vec3f)->vec2f {
166
+ let p=n/(abs(n.x)+abs(n.y)+abs(n.z));
167
+ let uv=select(p.xy,(vec2f(1.0)-abs(p.yx))*rd(p.xy),p.z<0.0);
168
+ return uv*.5+.5;
169
+ }
170
+ fn pM(uv:vec2f)->vec3f {
171
+ let p=uv*2.0-1.0;
172
+ var n=vec3f(p,1.0-abs(p.x)-abs(p.y));
173
+ if(n.z<0.0) {
174
+ n=vec3f((vec2f(1.0)-abs(n.yx))*rd(n.xy),n.z);
175
+ }
176
+ return normalize(n);
177
+ }
178
+
179
+
180
+ fn sS(value:vec3f)->u32 {
181
+ let peak=max(max(value.x,value.y),value.z);
182
+ if(!(peak>0.0)) {
183
+ return 0u;
184
+ }
185
+ let exponent=clamp(i32(floor(log2(peak)))+1,-126,127);
186
+ let rgb=vec3u(clamp(round(value*exp2(-f32(exponent))*255.0),vec3f(0.0),vec3f(255.0)));
187
+ return rgb.x|(rgb.y<<8u)|(rgb.z<<16u)|(u32(exponent+127)<<24u);
188
+ }
189
+ fn photonDecodeFlux(value:u32)->vec3f {
190
+ if(value==0u) {
191
+ return vec3f(0.0);
192
+ }
193
+ return vec3f(f32(value&255u),f32((value>>8u)&255u),f32((value>>16u)&255u))*exp2(f32(i32(value>>24u)-127))/255.0;
194
+ }
195
+ `;
196
+ export const photonQueryWgsl = /* wgsl */ `${photonPackingWgsl}
197
+ @group(1)@binding(11)var photonMapData:texture_2d<u32>;
198
+ @group(1)@binding(12)var photonMapGrid:texture_2d<u32>;
199
+ fn photonLoad(i:u32)->vec4u {
200
+ let width=textureDimensions(photonMapData).x;
201
+ return textureLoad(photonMapData,vec2i(vec2u(i%width,i/width)),0);
202
+ }
203
+ fn photonIndexWord(i:u32)->u32 {
204
+ let width=textureDimensions(photonMapGrid).x;
205
+ return textureLoad(photonMapGrid,vec2i(vec2u(i%width,i/width)),0).x;
206
+ }
207
+ fn wp(yp:vec3i)->u32 {
208
+ let p=bitcast<vec3u>(yp);
209
+ return ((p.x*73856093u)^(p.y*19349663u)^(p.z*83492791u))&(photonIndexWord(5u)-1u);
210
+ }
211
+
212
+
213
+
214
+ fn photonPixelFootprint(si:SurfaceInteraction)->f32 {
215
+ let inverse=cameraUniform.viewProjectionInv;
216
+ let a=inverse*vec4f(0.0,0.0,-1.0,1.0);
217
+ let b=inverse*vec4f(2.0/rtUniform.outputSize.x,0.0,-1.0,1.0);
218
+ let origin=a.xyz/a.w;
219
+ let offset=b.xyz/b.w;
220
+ let eye=cameraUniform.viewInv[3].xyz;
221
+ let forward=normalize(cameraUniform.viewInv[2].xyz);
222
+ let depth=abs(dot(si.position-eye,forward));
223
+ let xe=max(abs(dot(origin-eye,forward)),1e-8);
224
+ let perspective=abs(inverse[2].w)>1e-8;
225
+ let footprint=length(offset-origin)*select(1.0,depth/xe,perspective);
226
+ let cosine=abs(dot(si.faceNormal,normalize(si.position-eye)));
227
+ return max(1e-8,footprint/sqrt(max(.0625,cosine)));
228
+ }
229
+ fn rI(si:SurfaceInteraction,prepared:OpenPbrPreparedBsdf,vb:bool,visible:bool)->vec3f {
230
+ if(samplingBounce>CAUSTIC_PHOTON_MAX_DEPTH||isCausticSpecular(prepared.material)||prepared.material.materialType==SHADOW_CATCHER) {
231
+ return vec3f(0.0);
232
+ }
233
+ if(CAUSTIC_LIGHT_TRACING&&vb) {
234
+ return vec3f(0.0);
235
+ }
236
+ let mn=bitcast<f32>(photonIndexWord(0u));
237
+ let screenPixels=bitcast<f32>(photonIndexWord(2u));
238
+ if(!(mn>0.0)||bitcast<f32>(photonIndexWord(3u))==1.0||(bitcast<f32>(photonIndexWord(3u))==2.0&&visible)) {
239
+ return vec3f(0.0);
240
+ }
241
+ var radius=mn;
242
+ let experiments=photonIndexWord(7u);
243
+ let wa=f32(experiments>>8u);
244
+ let tf=select(wa,screenPixels,visible);
245
+ if(tf>0.0) {
246
+ radius=min(radius,photonPixelFootprint(si)*tf);
247
+ }
248
+ let layer=select(0u,1u,visible&&screenPixels>0.0);
249
+ let lv=select(mn,2.0*bitcast<f32>(photonIndexWord(6u)),layer==1u);
250
+ let sG=vec3i(floor((si.position-vec3f(radius))/lv));
251
+ let tS=vec3i(floor((si.position+vec3f(radius))/lv));
252
+ let buckets=photonIndexWord(5u);
253
+ let tb=8u+layer*buckets*2u;
254
+ let indexStart=8u+buckets*4u+layer*photonIndexWord(4u);
255
+ let emitted=f32(photonIndexWord(4u));
256
+ var sum=vec3f(0.0);
257
+ for(var z=sG.z;z<=tS.z;z++) {
258
+ for(var y=sG.y;y<=tS.y;y++) {
259
+ for(var x=sG.x;x<=tS.x;x++) {
260
+ let sU=vec3i(x,y,z);
261
+
262
+
263
+ let uP=vec3f(sU)*lv;
264
+ let padding=max(vec3f(lv*1e-5),abs(uP)*1e-6);
265
+ let xV=clamp(si.position,uP-padding,uP+vec3f(lv)+padding);
266
+ if(distance(xV,si.position)>=radius) { continue; }
267
+ let su=wp(sU);
268
+ let offset=photonIndexWord(tb+su*2u);
269
+ let count=photonIndexWord(tb+1u+su*2u);
270
+ for(var i=offset;i<offset+count;i++) {
271
+ let index=photonIndexWord(indexStart+i);
272
+ let record=photonLoad(index);
273
+ let position=bitcast<vec3f>(record.xyz);
274
+
275
+ if(any(vec3i(floor(position/lv))!=sU)||distance(position,si.position)>=radius) {
276
+ continue;
277
+ }
278
+ var jY=radius;
279
+ if((experiments&1u)!=0u) {
280
+ let scale=bitcast<f32>(photonIndexWord(8u+buckets*4u+u32(emitted)*3u+index));
281
+ jY=min(radius,mn*scale);
282
+ if(!(jY>0.0)||distance(position,si.position)>=jY) { continue; }
283
+ }
284
+ let directions=photonIndexWord(8u+buckets*4u+u32(emitted)*2u+index);
285
+ let normal=pM(vec2f(f32(directions&255u)/255.0,f32((directions>>8u)&127u)/127.0));
286
+ if(dot(normal,si.faceNormal)<0.9) {
287
+ continue;
288
+ }
289
+ if(CAUSTIC_MNEE&&samplingBounce<=CAUSTIC_MNEE_MAX_DEPTH&&(directions&32768u)!=0u&&prepared.material.baseWeight*(1.0-prepared.material.baseMetalness)*(1.0-prepared.material.transmissionWeight)>0.0&&prepared.material.subsurfaceWeight==0.0) {
290
+ continue;
291
+ }
292
+ let hQ=pM(vec2f(f32((directions>>16u)&255u),f32(directions>>24u))/255.0);
293
+ let cosine=abs(dot(si.faceNormal,hQ));
294
+ if(cosine<=0.0) {
295
+ continue;
296
+ }
297
+ var flux=photonDecodeFlux(record.w)/emitted;
298
+ if(SPECTRAL) {
299
+ flux=sampling_spectral_rgb_filter(flux,si.spectralChannel);
300
+ }
301
+ var pdf:f32;
302
+ let response=openpbr_eval_prepared(prepared,hQ,&pdf);
303
+ sum+=response*flux/cosine*(radius*radius)/(jY*jY);
304
+ }
305
+ }
306
+ }
307
+ }
308
+ return sum/(PI*radius*radius);
309
+ }
310
+ `;
311
+ // Each translated 2x2 tile assigns all four labels once. Conditional on any
312
+ // stored photon, a uniform pixel label accepts it with probability 1/4; scaling
313
+ // accepted flux by four preserves the original expected density estimate.
314
+ // Only the first camera hit participates; specular prefixes and deeper queries
315
+ // keep the original estimator. Disjoint salts consume no sampling dimensions.
316
+ export function photonDirectQuerySource(enabled = false) {
317
+ if (!enabled)
318
+ return photonQueryWgsl;
319
+ return photonQueryWgsl
320
+ .replace('var sum=vec3f(0.0);', `let rL=ak(aC,rtUniform.sequenceSeed^0x91e10da5u);
321
+ let vT=vec2u(cB(rL^0x68bc21ebu),cB(rL^0x967a889bu));
322
+ let tj=aI+vT;
323
+ let vS=(tj.x&1u)|((tj.y&1u)<<1u);
324
+ var sum=vec3f(0.0);`)
325
+ .replace('let record=photonLoad(index);', `if(vb&&(ak(index,rL^0x02e5be93u)&3u)!=vS) { continue; }
326
+ let record=photonLoad(index);`)
327
+ .replace('var flux=photonDecodeFlux(record.w)/emitted;', `var flux=photonDecodeFlux(record.w)/emitted;
328
+ if(vb) { flux*=4.0; }`);
329
+ }
330
+ /** Evidence-only per-query counters; no extra bindings or public render options. */
331
+ export function photonQuerySource(debugGroup = -1, directSubset = false) {
332
+ const source = photonDirectQuerySource(directSubset);
333
+ if (debugGroup < 50)
334
+ return source;
335
+ // Offline union-of-photons audit. Each depth is replayed with the same seed;
336
+ // payloads are positions/normals rather than radiance, before path throughput.
337
+ if (debugGroup >= 80) {
338
+ const normal = debugGroup >= 130 || debugGroup === 81;
339
+ const visible = debugGroup < 100;
340
+ const depth = debugGroup - (normal ? 130 : 100);
341
+ const selected = visible ? 'visible' : `!visible&&samplingBounce==${depth}u`;
342
+ const payload = debugGroup === 82 ? 'vec3f(photonPixelFootprint(si),radius,1.0)' : normal ? 'si.faceNormal' : 'si.position';
343
+ return 'var<private> photonQueryStats:vec3f;\n' + source.replace('return sum/(PI*radius*radius);', `if(${selected}){photonQueryStats=${payload};}return sum/(PI*radius*radius);`);
344
+ }
345
+ const selected = debugGroup === 50 || debugGroup === 73 ? 'visible' : debugGroup === 72 ? '!visible' : `!visible&&samplingBounce==${debugGroup - 51}u`;
346
+ return 'var<private> photonQueryStats:vec3f;\n' + source
347
+ .replace('var sum=vec3f(0.0);', 'var sum=vec3f(0.0);var reads=0u;var passed=0u;')
348
+ .replace('let index=photonIndexWord(indexStart+i);', 'reads++;let index=photonIndexWord(indexStart+i);')
349
+ .replace(debugGroup === 73 ? 'var flux=photonDecodeFlux' : 'let directions=photonIndexWord', debugGroup === 73 ? 'passed++;var flux=photonDecodeFlux' : 'passed++;let directions=photonIndexWord')
350
+ .replace('return sum/(PI*radius*radius);', `if(${selected}){photonQueryStats${debugGroup === 72 ? '+' : ''}=vec3f(f32(reads),f32(passed),1.0);}return sum/(PI*radius*radius);`);
351
+ }
352
+ //# sourceMappingURL=photonMap.compute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"photonMap.compute.js","sourceRoot":"","sources":["../../../src/renderer/wgsl/photonMap.compute.ts"],"names":[],"mappings":"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","sourcesContent":["export const PHOTON_BYTES = 20;\nexport const PHOTON_GRID_SIZE = 262144;\nexport const PHOTON_SCAN_BLOCK = 256;\nexport const PHOTON_REFERENCE_COUNT = 2 ** 18;\nexport type PhotonRadiusScaling = 'none' | 'ppm' | 'constant-count';\n/** Internal density A/B, with the same progressive schedule in all modes. */\nexport function photonRadius(\n initial: number,\n batch: number,\n alpha = 2 / 3,\n photons = PHOTON_REFERENCE_COUNT,\n scaling: PhotonRadiusScaling = 'none'\n) {\n const radius = initial * Math.pow(Math.max(1, batch), (alpha - 1) / 2);\n if (scaling === 'none' || photons === PHOTON_REFERENCE_COUNT) return radius;\n const exponent = scaling === 'ppm' ? (alpha - 1) / 2 : -1 / 2;\n return radius * Math.pow(Math.max(1, photons) / PHOTON_REFERENCE_COUNT, exponent);\n}\n/** Default photon-map batch: pixel count / 4, capped at 2^18. */\nexport function defaultPhotonMapPhotons(width: number, height: number, divisor = 4) {\n return Math.min(2 ** 18, Math.max(1, Math.round((width * height) / divisor)));\n}\n/** Power-of-two hash capacity, bounded independently of large photon batches. */\nexport function photonBucketCount(photons: number) {\n return Math.min(PHOTON_GRID_SIZE, 2 ** Math.ceil(Math.log2(Math.max(256, photons * 2))));\n}\n/** Shared texture address contract; payload is stored once, indices twice. */\nexport function photonLayout(count: number, perCasterRadius = false) {\n const buckets = photonBucketCount(count);\n const coarseHeaders = 8;\n const fineHeaders = coarseHeaders + buckets * 2;\n const coarseIndices = fineHeaders + buckets * 2;\n const fineIndices = coarseIndices + count;\n const directions = fineIndices + count;\n return {buckets, coarseHeaders, fineHeaders, coarseIndices, fineIndices, directions, texels: directions + count * (perCasterRadius ? 2 : 1)};\n}\n/** Batch-local hash buckets: count, two-level parallel prefix sum, then parallel scatter. */\nexport const photonGridCompute = /* wgsl */ `\n struct Bucket {\n count: atomic<u32>,\n offset: u32,\n cursor: atomic<u32>,\n padding: u32,\n }\n struct Parameters {\n radius: f32,\n count: u32,\n screenPixels: f32,\n skipQuery: f32,\n buckets: u32,\n fineRadius: f32,\n experiments: u32,\n padding2: u32,\n }\n @group(0)@binding(0)var photons:texture_2d<u32>;\n @group(0)@binding(1)var<storage,read_write>grid:array<Bucket>;\n @group(0)@binding(2)var<uniform>parameters:Parameters;\n @group(0)@binding(4)var headers:texture_storage_2d<r32uint,write>;\n fn hashCell(cell:vec3i)->u32 {\n let p=bitcast<vec3u>(cell);\n return ((p.x*73856093u)^(p.y*19349663u)^(p.z*83492791u))&(parameters.buckets-1u);\n }\n fn hashPhoton(p:vec3f,layer:u32)->u32 {\n let radius=select(parameters.radius,parameters.fineRadius,layer==1u);\n let cellSize=select(radius,2.0*radius,layer==1u);\n return hashCell(vec3i(floor(p/cellSize)));\n }\n fn gridStart(layer:u32)->u32 {\n return layer*(parameters.buckets+parameters.buckets/256u);\n }\n fn storeIndex(i:u32,value:u32) {\n let width=textureDimensions(headers).x;\n textureStore(headers,vec2i(vec2u(i%width,i/width)),vec4u(value));\n }\n fn photonRecord(i:u32)->vec4u {\n let width=textureDimensions(photons).x;\n return textureLoad(photons,vec2i(vec2u(i%width,i/width)),0);\n }\n fn photonPosition(i:u32)->vec3f {\n return bitcast<vec3f>(photonRecord(i).xyz);\n }\n @compute @workgroup_size(64)\n fn count(@builtin(global_invocation_id)id:vec3u) {\n if(id.x+id.y*4194240u>=parameters.count) {\n return;\n }\n let index=id.x+id.y*4194240u;\n if(photonRecord(index).w==0u) {\n return;\n }\n for(var layer=0u;layer<2u;layer++) {\n atomicAdd(&grid[gridStart(layer)+hashPhoton(photonPosition(index),layer)].count,1u);\n }\n }\n // Each block scans 256 buckets; the next workgroup scans chunks of block totals.\n var<workgroup> scan:array<u32,256>;\n fn inclusiveScan(local:u32,value:u32)->u32 {\n scan[local]=value;\n workgroupBarrier();\n for(var stride=1u;stride<256u;stride*=2u) {\n var previous=0u;\n if(local>=stride) {\n previous=scan[local-stride];\n }\n workgroupBarrier();\n scan[local]+=previous;\n workgroupBarrier();\n }\n return scan[local];\n }\n @compute @workgroup_size(256)\n fn scanBlocks(@builtin(local_invocation_index)local:u32,@builtin(workgroup_id)group:vec3u) {\n let index=gridStart(group.y)+group.x*256u+local;\n let count=atomicLoad(&grid[index].count);\n let prefix=inclusiveScan(local,count);\n grid[index].offset=prefix-count;\n if(local==255u) {\n atomicStore(&grid[gridStart(group.y)+parameters.buckets+group.x].count,prefix);\n }\n }\n @compute @workgroup_size(256)\n fn scanSums(@builtin(local_invocation_index)local:u32,@builtin(workgroup_id)group:vec3u) {\n let blocks=parameters.buckets/256u;\n let chunk=(blocks+255u)/256u;\n let first=local*chunk;\n let start=gridStart(group.y)+parameters.buckets;\n var count=0u;\n for(var i=first;i<min(first+chunk,blocks);i++) {\n count+=atomicLoad(&grid[start+i].count);\n }\n let prefix=inclusiveScan(local,count);\n var offset=prefix-count;\n for(var i=first;i<min(first+chunk,blocks);i++) {\n grid[start+i].offset=offset;\n offset+=atomicLoad(&grid[start+i].count);\n }\n if(local==255u&&group.y==0u) {\n storeIndex(0u,bitcast<u32>(parameters.radius));\n storeIndex(1u,prefix);\n storeIndex(2u,bitcast<u32>(parameters.screenPixels));\n storeIndex(3u,bitcast<u32>(parameters.skipQuery));\n storeIndex(4u,parameters.count);\n storeIndex(5u,parameters.buckets);\n storeIndex(6u,bitcast<u32>(parameters.fineRadius));\n storeIndex(7u,parameters.experiments);\n }\n }\n @compute @workgroup_size(64)\n fn scatter(@builtin(global_invocation_id)id:vec3u) {\n let invocation=id.x+id.y*4194240u;\n for(var layer=0u;layer<2u;layer++) {\n let start=gridStart(layer);\n if(invocation<parameters.buckets) {\n let offset=grid[start+invocation].offset+grid[start+parameters.buckets+invocation/256u].offset;\n storeIndex(8u+layer*parameters.buckets*2u+invocation*2u,offset);\n storeIndex(9u+layer*parameters.buckets*2u+invocation*2u,atomicLoad(&grid[start+invocation].count));\n }\n if(invocation<parameters.count&&photonRecord(invocation).w!=0u) {\n let bucket=hashPhoton(photonPosition(invocation),layer);\n let index=grid[start+bucket].offset+grid[start+parameters.buckets+bucket/256u].offset+atomicAdd(&grid[start+bucket].cursor,1u);\n storeIndex(8u+parameters.buckets*4u+layer*parameters.count+index,invocation);\n }\n }\n }\n`;\n/** Packed photon payload: position f32 x3, RGBE8 flux, two octahedral directions. */\nexport const photonPackingWgsl = /* wgsl */ `\n fn photonOctSign(v:vec2f)->vec2f {\n return select(vec2f(-1.0),vec2f(1.0),v>=vec2f(0.0));\n }\n fn photonEncodeOct(n:vec3f)->vec2f {\n let p=n/(abs(n.x)+abs(n.y)+abs(n.z));\n let uv=select(p.xy,(vec2f(1.0)-abs(p.yx))*photonOctSign(p.xy),p.z<0.0);\n return uv*.5+.5;\n }\n fn photonDecodeOct(uv:vec2f)->vec3f {\n let p=uv*2.0-1.0;\n var n=vec3f(p,1.0-abs(p.x)-abs(p.y));\n if(n.z<0.0) {\n n=vec3f((vec2f(1.0)-abs(n.yx))*photonOctSign(n.xy),n.z);\n }\n return normalize(n);\n }\n // An eight-bit exponent avoids RGB9E5's limited range for very dim/bright lights.\n // Flux is stored before dividing by emitted count, preserving tiny large batches.\n fn photonEncodeFlux(value:vec3f)->u32 {\n let peak=max(max(value.x,value.y),value.z);\n if(!(peak>0.0)) {\n return 0u;\n }\n let exponent=clamp(i32(floor(log2(peak)))+1,-126,127);\n let rgb=vec3u(clamp(round(value*exp2(-f32(exponent))*255.0),vec3f(0.0),vec3f(255.0)));\n return rgb.x|(rgb.y<<8u)|(rgb.z<<16u)|(u32(exponent+127)<<24u);\n }\n fn photonDecodeFlux(value:u32)->vec3f {\n if(value==0u) {\n return vec3f(0.0);\n }\n return vec3f(f32(value&255u),f32((value>>8u)&255u),f32((value>>16u)&255u))*exp2(f32(i32(value>>24u)-127))/255.0;\n }\n`;\nexport const photonQueryWgsl = /* wgsl */ `${photonPackingWgsl}\n @group(1)@binding(11)var photonMapData:texture_2d<u32>;\n @group(1)@binding(12)var photonMapGrid:texture_2d<u32>;\n fn photonLoad(i:u32)->vec4u {\n let width=textureDimensions(photonMapData).x;\n return textureLoad(photonMapData,vec2i(vec2u(i%width,i/width)),0);\n }\n fn photonIndexWord(i:u32)->u32 {\n let width=textureDimensions(photonMapGrid).x;\n return textureLoad(photonMapGrid,vec2i(vec2u(i%width,i/width)),0).x;\n }\n fn photonHash(cell:vec3i)->u32 {\n let p=bitcast<vec3u>(cell);\n return ((p.x*73856093u)^(p.y*19349663u)^(p.z*83492791u))&(photonIndexWord(5u)-1u);\n }\n // Approximate a specular prefix by the camera-space depth of its first diffuse\n // receiver. Orthographic footprints do not grow with distance. Grazing surfaces\n // expand the disk conservatively; the progressive world radius remains the cap.\n fn photonPixelFootprint(si:SurfaceInteraction)->f32 {\n let inverse=cameraUniform.viewProjectionInv;\n let a=inverse*vec4f(0.0,0.0,-1.0,1.0);\n let b=inverse*vec4f(2.0/rtUniform.outputSize.x,0.0,-1.0,1.0);\n let origin=a.xyz/a.w;\n let offset=b.xyz/b.w;\n let eye=cameraUniform.viewInv[3].xyz;\n let forward=normalize(cameraUniform.viewInv[2].xyz);\n let depth=abs(dot(si.position-eye,forward));\n let nearDepth=max(abs(dot(origin-eye,forward)),1e-8);\n let perspective=abs(inverse[2].w)>1e-8;\n let footprint=length(offset-origin)*select(1.0,depth/nearDepth,perspective);\n let cosine=abs(dot(si.faceNormal,normalize(si.position-eye)));\n return max(1e-8,footprint/sqrt(max(.0625,cosine)));\n }\n fn photonContribution(si:SurfaceInteraction,prepared:OpenPbrPreparedBsdf,primary:bool,visible:bool)->vec3f {\n if(samplingBounce>CAUSTIC_PHOTON_MAX_DEPTH||isCausticSpecular(prepared.material)||prepared.material.materialType==SHADOW_CATCHER) {\n return vec3f(0.0);\n }\n if(CAUSTIC_LIGHT_TRACING&&primary) {\n return vec3f(0.0);\n }\n let globalRadius=bitcast<f32>(photonIndexWord(0u));\n let screenPixels=bitcast<f32>(photonIndexWord(2u));\n if(!(globalRadius>0.0)||bitcast<f32>(photonIndexWord(3u))==1.0||(bitcast<f32>(photonIndexWord(3u))==2.0&&visible)) {\n return vec3f(0.0);\n }\n var radius=globalRadius;\n let experiments=photonIndexWord(7u);\n let deepPixels=f32(experiments>>8u);\n let queryPixels=select(deepPixels,screenPixels,visible);\n if(queryPixels>0.0) {\n radius=min(radius,photonPixelFootprint(si)*queryPixels);\n }\n let layer=select(0u,1u,visible&&screenPixels>0.0);\n let cellSize=select(globalRadius,2.0*bitcast<f32>(photonIndexWord(6u)),layer==1u);\n let firstCell=vec3i(floor((si.position-vec3f(radius))/cellSize));\n let lastCell=vec3i(floor((si.position+vec3f(radius))/cellSize));\n let buckets=photonIndexWord(5u);\n let headerStart=8u+layer*buckets*2u;\n let indexStart=8u+buckets*4u+layer*photonIndexWord(4u);\n let emitted=f32(photonIndexWord(4u));\n var sum=vec3f(0.0);\n for(var z=firstCell.z;z<=lastCell.z;z++) {\n for(var y=firstCell.y;y<=lastCell.y;y++) {\n for(var x=firstCell.x;x<=lastCell.x;x++) {\n let queryCell=vec3i(x,y,z);\n // Reject cube corners before loading their photon lists. Padding keeps\n // the bound conservative when cell multiplication rounds in f32.\n let cellMin=vec3f(queryCell)*cellSize;\n let padding=max(vec3f(cellSize*1e-5),abs(cellMin)*1e-6);\n let closest=clamp(si.position,cellMin-padding,cellMin+vec3f(cellSize)+padding);\n if(distance(closest,si.position)>=radius) { continue; }\n let bucket=photonHash(queryCell);\n let offset=photonIndexWord(headerStart+bucket*2u);\n let count=photonIndexWord(headerStart+1u+bucket*2u);\n for(var i=offset;i<offset+count;i++) {\n let index=photonIndexWord(indexStart+i);\n let record=photonLoad(index);\n let position=bitcast<vec3f>(record.xyz);\n // Hash collisions and neighboring buckets never count a photon twice.\n if(any(vec3i(floor(position/cellSize))!=queryCell)||distance(position,si.position)>=radius) {\n continue;\n }\n var kernelRadius=radius;\n if((experiments&1u)!=0u) {\n let scale=bitcast<f32>(photonIndexWord(8u+buckets*4u+u32(emitted)*3u+index));\n kernelRadius=min(radius,globalRadius*scale);\n if(!(kernelRadius>0.0)||distance(position,si.position)>=kernelRadius) { continue; }\n }\n let directions=photonIndexWord(8u+buckets*4u+u32(emitted)*2u+index);\n let normal=photonDecodeOct(vec2f(f32(directions&255u)/255.0,f32((directions>>8u)&127u)/127.0));\n if(dot(normal,si.faceNormal)<0.9) {\n continue;\n }\n if(CAUSTIC_MNEE&&samplingBounce<=CAUSTIC_MNEE_MAX_DEPTH&&(directions&32768u)!=0u&&prepared.material.baseWeight*(1.0-prepared.material.baseMetalness)*(1.0-prepared.material.transmissionWeight)>0.0&&prepared.material.subsurfaceWeight==0.0) {\n continue;\n }\n let incoming=photonDecodeOct(vec2f(f32((directions>>16u)&255u),f32(directions>>24u))/255.0);\n let cosine=abs(dot(si.faceNormal,incoming));\n if(cosine<=0.0) {\n continue;\n }\n var flux=photonDecodeFlux(record.w)/emitted;\n if(SPECTRAL) {\n flux=sampling_spectral_rgb_filter(flux,si.spectralChannel);\n }\n var pdf:f32;\n let response=openpbr_eval_prepared(prepared,incoming,&pdf);\n sum+=response*flux/cosine*(radius*radius)/(kernelRadius*kernelRadius);\n }\n }\n }\n }\n return sum/(PI*radius*radius);\n }\n`;\n\n// Each translated 2x2 tile assigns all four labels once. Conditional on any\n// stored photon, a uniform pixel label accepts it with probability 1/4; scaling\n// accepted flux by four preserves the original expected density estimate.\n// Only the first camera hit participates; specular prefixes and deeper queries\n// keep the original estimator. Disjoint salts consume no sampling dimensions.\nexport function photonDirectQuerySource(enabled = false) {\n if (!enabled) return photonQueryWgsl;\n return photonQueryWgsl\n .replace('var sum=vec3f(0.0);', `let subsetSeed=sampleSeed(pixelSampleIndex,rtUniform.sequenceSeed^0x91e10da5u);\n let subsetShift=vec2u(sampleHash(subsetSeed^0x68bc21ebu),sampleHash(subsetSeed^0x967a889bu));\n let subsetPixel=samplingPixel+subsetShift;\n let subsetGroup=(subsetPixel.x&1u)|((subsetPixel.y&1u)<<1u);\n var sum=vec3f(0.0);`)\n .replace('let record=photonLoad(index);', `if(primary&&(sampleSeed(index,subsetSeed^0x02e5be93u)&3u)!=subsetGroup) { continue; }\n let record=photonLoad(index);`)\n .replace('var flux=photonDecodeFlux(record.w)/emitted;', `var flux=photonDecodeFlux(record.w)/emitted;\n if(primary) { flux*=4.0; }`);\n}\n/** Evidence-only per-query counters; no extra bindings or public render options. */\nexport function photonQuerySource(debugGroup = -1, directSubset = false) {\n const source = photonDirectQuerySource(directSubset);\n if (debugGroup < 50) return source;\n // Offline union-of-photons audit. Each depth is replayed with the same seed;\n // payloads are positions/normals rather than radiance, before path throughput.\n if (debugGroup >= 80) {\n const normal = debugGroup >= 130 || debugGroup === 81;\n const visible = debugGroup < 100;\n const depth = debugGroup - (normal ? 130 : 100);\n const selected = visible ? 'visible' : `!visible&&samplingBounce==${depth}u`;\n const payload = debugGroup === 82 ? 'vec3f(photonPixelFootprint(si),radius,1.0)' : normal ? 'si.faceNormal' : 'si.position';\n return 'var<private> photonQueryStats:vec3f;\\n' + source.replace('return sum/(PI*radius*radius);', `if(${selected}){photonQueryStats=${payload};}return sum/(PI*radius*radius);`);\n }\n const selected = debugGroup === 50 || debugGroup === 73 ? 'visible' : debugGroup === 72 ? '!visible' : `!visible&&samplingBounce==${debugGroup - 51}u`;\n return 'var<private> photonQueryStats:vec3f;\\n' + source\n .replace('var sum=vec3f(0.0);', 'var sum=vec3f(0.0);var reads=0u;var passed=0u;')\n .replace('let index=photonIndexWord(indexStart+i);', 'reads++;let index=photonIndexWord(indexStart+i);')\n .replace(debugGroup === 73 ? 'var flux=photonDecodeFlux' : 'let directions=photonIndexWord',\n debugGroup === 73 ? 'passed++;var flux=photonDecodeFlux' : 'passed++;let directions=photonIndexWord')\n .replace('return sum/(PI*radius*radius);', `if(${selected}){photonQueryStats${debugGroup === 72 ? '+' : ''}=vec3f(f32(reads),f32(passed),1.0);}return sum/(PI*radius*radius);`);\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare const proceduralSkyWGSL: string;
@@ -0,0 +1,198 @@
1
+ import { TURBIDITY, GROUND_ALBEDO, ILLUMINANCE, REFERENCE_ILLUMINANCE } from '../skyModel.js';
2
+ // Same atmosphere, quadrature and pass order as WebGLSkyBaker. Distances in km.
3
+ export const proceduralSkyWGSL = /* wgsl */ `
4
+ struct Params { sun: vec4f, sunWorld: vec4f, size: vec4f, scale: vec4f, ambient: vec4f }
5
+ @group(0) @binding(0) var<uniform> params: Params;
6
+ @group(0) @binding(1) var transmittanceTable: texture_2d<f32>;
7
+ @group(0) @binding(2) var multipleTable: texture_2d<f32>;
8
+ @group(0) @binding(3) var skyTable: texture_2d<f32>;
9
+ @group(0) @binding(4) var irradianceTable: texture_2d<f32>;
10
+ @group(0) @binding(5) var output: texture_storage_2d<rgba32float, write>;
11
+ const PI = 3.14159265358979;
12
+ const R_GROUND = 6360.0;
13
+ const R_TOP = 6460.0;
14
+ const CAMERA_ALTITUDE = 0.2;
15
+ const RAYLEIGH = vec3f(5.802e-3, 13.558e-3, 33.1e-3);
16
+ const MIE_SCATTERING = 3.996e-3;
17
+ const MIE_EXTINCTION = 4.44e-3;
18
+ const MIE_G = 0.8;
19
+ const OZONE = vec3f(0.65e-3, 1.881e-3, 0.085e-3);
20
+ const ALBEDO = vec3f(${GROUND_ALBEDO.join(', ')});
21
+ const T_SIZE = vec2u(256, 64);
22
+ const MS_ALTITUDES = 32u;
23
+ const SV_SIZE = vec2u(96, 192);
24
+
25
+ fn bj(r: f32, mu: f32, radius: f32) -> f32 { return (radius - r) * (radius + r) + r * r * mu * mu; }
26
+ fn mV(r: f32, mu: f32) -> bool { return mu < 0.0 && bj(r, mu, R_GROUND) >= 0.0; }
27
+ fn kT(r: f32, mu: f32) -> f32 { return max(-r * mu - sqrt(max(bj(r, mu, R_GROUND), 0.0)), 0.0); }
28
+ fn iS(r: f32, mu: f32) -> f32 { return max(-r * mu + sqrt(max(bj(r, mu, R_TOP), 0.0)), 0.0); }
29
+ fn oo(r: f32) -> vec3f {
30
+ let h = max(r - R_GROUND, 0.0);
31
+ return vec3f(exp(-h / 8.0), exp(-h / 1.2) * ${TURBIDITY}, max(0.0, 1.0 - abs(h - 25.0) / 15.0));
32
+ }
33
+ fn extinction(d: vec3f) -> vec3f { return RAYLEIGH * d.x + MIE_EXTINCTION * d.y + OZONE * d.z; }
34
+ fn mB(x: f32) -> f32 { return x * x * (R_TOP - R_GROUND); }
35
+ fn hy(h: f32) -> f32 { return sqrt(clamp(h / (R_TOP - R_GROUND), 0.0, 1.0)); }
36
+ fn eR(table: texture_2d<f32>, p: vec2f) -> vec3f {
37
+ let size = vec2i(textureDimensions(table));
38
+ let q = clamp(p, vec2f(0.0), vec2f(size - 1));
39
+ let i = min(vec2i(floor(q)), max(size - 2, vec2i(0)));
40
+ let f = clamp(q - vec2f(i), vec2f(0.0), vec2f(1.0));
41
+ let j = min(i + 1, size - 1);
42
+ let a = textureLoad(table, i, 0).rgb;
43
+ let b = textureLoad(table, vec2i(j.x, i.y), 0).rgb;
44
+ let c = textureLoad(table, vec2i(i.x, j.y), 0).rgb;
45
+ let d = textureLoad(table, j, 0).rgb;
46
+ return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
47
+ }
48
+ fn fv(r: f32, mu: f32) -> vec3f {
49
+ return eR(transmittanceTable, vec2f((clamp(mu, -1.0, 1.0) + 1.0) * 0.5 * f32(T_SIZE.x - 1u), hy(r - R_GROUND) * f32(T_SIZE.y - 1u)));
50
+ }
51
+ fn mI(nu: f32) -> f32 {
52
+ let g2 = MIE_G * MIE_G;
53
+ return 3.0 / (8.0 * PI) * ((1.0 - g2) * (1.0 + nu * nu)) / ((2.0 + g2) * pow(1.0 + g2 - 2.0 * MIE_G * nu, 1.5));
54
+ }
55
+ struct yk { radiance: vec3f, throughput: vec3f }
56
+ fn vG(origin: vec3f, dir: vec3f, steps: u32, full: bool, uD: vec3f) -> yk {
57
+ let r = length(origin);
58
+ let mu = dot(origin, dir) / r;
59
+ let ground = mV(r, mu);
60
+ var len = iS(r, mu);
61
+ if (ground) { len = kT(r, mu); }
62
+ let nu = dot(dir, params.sun.xyz);
63
+ var ja = 1.0 / (4.0 * PI);
64
+ var sh = ja;
65
+ if (full) { ja = 3.0 / (16.0 * PI) * (1.0 + nu * nu); sh = mI(nu); }
66
+ var result = yk(vec3f(0.0), vec3f(0.0));
67
+ var view = vec3f(1.0);
68
+ var previous = 0.0;
69
+ for (var i = 0u; i < steps; i++) {
70
+ let s = f32(i + 1u) / f32(steps);
71
+ let next = len * s * s;
72
+ let dt = next - previous;
73
+ let p = origin + dir * (0.5 * (previous + next));
74
+ previous = next;
75
+ let pr = length(p);
76
+ let d = oo(pr);
77
+ let e = extinction(d);
78
+ let vk = fv(pr, dot(p, params.sun.xyz) / pr);
79
+ let np = RAYLEIGH * d.x;
80
+ let nl = MIE_SCATTERING * d.y;
81
+ var ms = vec3f(0.0);
82
+ if (full) { ms = eR(multipleTable, vec2f(hy(pr - R_GROUND) * f32(MS_ALTITUDES - 1u), 0.0)); }
83
+ let source = vk * (np * ja + nl * sh) + (np + nl) * ms;
84
+ let segment = exp(-e * dt);
85
+ let weight = (1.0 - segment) / max(e, vec3f(1e-9));
86
+ result.radiance += view * source * weight;
87
+ result.throughput += view * (np + nl) * weight;
88
+ view *= segment;
89
+ }
90
+ if (ground) {
91
+ let p = origin + dir * len;
92
+ let pr = length(p);
93
+ let tD = dot(p, params.sun.xyz) / pr;
94
+ let irradiance = fv(pr, tD) * max(tD, 0.0) + uD;
95
+ result.radiance += view * ALBEDO / PI * irradiance;
96
+ }
97
+ return result;
98
+ }
99
+ fn qd(row: f32) -> f32 {
100
+ let x = row / f32(SV_SIZE.y - 1u) * 2.0 - 1.0;
101
+ return sign(x) * x * x * (PI / 2.0);
102
+ }
103
+ fn hL(e: f32) -> f32 {
104
+ let x = sign(e) * sqrt(abs(e) / (PI / 2.0));
105
+ return clamp((x + 1.0) * 0.5, 0.0, 1.0) * f32(SV_SIZE.y - 1u);
106
+ }
107
+ @compute @workgroup_size(8, 8)
108
+ fn transmittance(@builtin(global_invocation_id) id: vec3u) {
109
+ if (any(id.xy >= T_SIZE)) { return; }
110
+ let mu = f32(id.x) / f32(T_SIZE.x - 1u) * 2.0 - 1.0;
111
+ let r = R_GROUND + mB(f32(id.y) / f32(T_SIZE.y - 1u));
112
+ if (mV(r, mu)) { textureStore(output, vec2i(id.xy), vec4f(0.0, 0.0, 0.0, 1.0)); return; }
113
+ let len = iS(r, mu);
114
+ var depth = vec3f(0.0);
115
+ for (var i = 0u; i < 48u; i++) {
116
+ let t = (f32(i) + 0.5) / 48.0 * len;
117
+ depth += extinction(oo(sqrt(t * t + 2.0 * r * mu * t + r * r))) * (len / 48.0);
118
+ }
119
+ textureStore(output, vec2i(id.xy), vec4f(exp(-depth), 1.0));
120
+ }
121
+ @compute @workgroup_size(8, 8)
122
+ fn multiple(@builtin(global_invocation_id) id: vec3u) {
123
+ if (id.x >= MS_ALTITUDES || id.y > 0u) { return; }
124
+ let r = R_GROUND + mB(f32(id.x) / f32(MS_ALTITUDES - 1u));
125
+ var second = vec3f(0.0);
126
+ var qC = vec3f(0.0);
127
+ for (var i = 0u; i < 64u; i++) {
128
+ let mu = 1.0 - 2.0 * (f32(i) + 0.5) / 64.0;
129
+ let phi = f32(i) * PI * (3.0 - sqrt(5.0));
130
+ let s = sqrt(1.0 - mu * mu);
131
+ let result = vG(vec3f(0.0, r, 0.0), vec3f(s * cos(phi), mu, s * sin(phi)), 20u, false, vec3f(0.0));
132
+ second += result.radiance / 64.0;
133
+ qC += result.throughput / 64.0;
134
+ }
135
+ textureStore(output, vec2i(id.xy), vec4f(second / (1.0 - qC), 1.0));
136
+ }
137
+ @compute @workgroup_size(8, 8)
138
+ fn skyView(@builtin(global_invocation_id) id: vec3u) {
139
+ if (any(id.xy >= SV_SIZE)) { return; }
140
+ let e = qd(f32(id.y));
141
+ let phi = f32(id.x) / f32(SV_SIZE.x - 1u) * PI;
142
+ var sky = vec3f(0.0);
143
+ if (params.size.w > 0.0) { sky = textureLoad(irradianceTable, vec2i(0), 0).rgb; }
144
+ let result = vG(vec3f(0.0, R_GROUND + CAMERA_ALTITUDE, 0.0), vec3f(cos(e) * cos(phi), sin(e), cos(e) * sin(phi)), 40u, true, sky);
145
+ textureStore(output, vec2i(id.xy), vec4f(result.radiance, 1.0));
146
+ }
147
+ @compute @workgroup_size(8, 8)
148
+ fn irradiance(@builtin(global_invocation_id) id: vec3u) {
149
+ if (id.x >= 2u || id.y > 0u) { return; }
150
+ var sky = vec3f(0.0);
151
+ for (var i = 0u; i < 128u; i++) {
152
+ let e = (f32(i) + 0.5) / 128.0 * (PI / 2.0);
153
+ let weight = 2.0 * sin(e) * cos(e) * (PI / 2.0 / 128.0) * (PI / 48.0);
154
+ for (var j = 0u; j < 48u; j++) {
155
+ let phi = (f32(j) + 0.5) / 48.0 * PI;
156
+ sky += eR(skyTable, vec2f(phi / PI * f32(SV_SIZE.x - 1u), hL(e))) * weight;
157
+ }
158
+ }
159
+ if (id.x == 0u) { textureStore(output, vec2i(id.xy), vec4f(sky, 1.0)); return; }
160
+ let vk = fv(R_GROUND + CAMERA_ALTITUDE, params.sun.y);
161
+ let xE = vec3f(0.2126, 0.7152, 0.0722);
162
+ let horizontal = dot(sky, xE) + dot(vk, xE) * max(params.sun.y, 0.0);
163
+ let scale = ${ILLUMINANCE} / sqrt(max(horizontal, ${REFERENCE_ILLUMINANCE} * 1e-3) * ${REFERENCE_ILLUMINANCE});
164
+ textureStore(output, vec2i(id.xy), vec4f(vk, scale));
165
+ }
166
+ fn gU(cR: vec2f) -> vec3f {
167
+ let theta = cR.y / params.size.y * PI;
168
+ let phi = cR.x / params.size.x * 2.0 * PI;
169
+ return vec3f(-sin(theta) * cos(phi), cos(theta), -sin(theta) * sin(phi));
170
+ }
171
+ @compute @workgroup_size(8, 8)
172
+ fn map(@builtin(global_invocation_id) id: vec3u) {
173
+ if (any(id.xy >= vec2u(params.size.xy))) { return; }
174
+ let cR = vec2f(id.xy) + 0.5;
175
+ let dir = gU(cR);
176
+ let tg = abs(atan2(dir.z, dir.x) - params.sun.w);
177
+ let wO = tg - floor(tg / (2.0 * PI)) * (2.0 * PI);
178
+ let dU = min(wO, 2.0 * PI - wO);
179
+ let e = asin(clamp(dir.y, -1.0, 1.0));
180
+ var radiance = eR(skyTable, vec2f(dU / PI * f32(SV_SIZE.x - 1u), hL(e)));
181
+ let sun = textureLoad(irradianceTable, vec2i(1, 0), 0);
182
+ let radius = params.sunWorld.w;
183
+ let rM = PI / params.size.y;
184
+ if (acos(clamp(dot(dir, params.sunWorld.xyz), -1.0, 1.0)) < radius + 3.0 * rM / max(sqrt(1.0 - dir.y * dir.y), 0.05)) {
185
+ var coverage = 0.0;
186
+ for (var y = 0u; y < 6u; y++) { for (var x = 0u; x < 6u; x++) {
187
+ let d = gU(cR - 0.5 + (vec2f(f32(x), f32(y)) + 0.5) / 6.0);
188
+ let angle = 2.0 * asin(min(length(d - params.sunWorld.xyz) * 0.5, 1.0));
189
+ let t = angle / radius;
190
+ if (t < 1.0) { coverage += 1.0 - 0.6 * (1.0 - sqrt(1.0 - t * t)); }
191
+ } }
192
+ let rK = 2.0 * PI * (1.0 - cos(radius));
193
+ radiance += coverage / 36.0 / (rK * (1.0 - 0.6 / 3.0)) * sun.rgb;
194
+ }
195
+ textureStore(output, vec2i(id.xy), vec4f(radiance * sun.a * params.scale.xyz + params.ambient.xyz, 1.0));
196
+ }
197
+ `;
198
+ //# sourceMappingURL=proceduralSky.compute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proceduralSky.compute.js","sourceRoot":"","sources":["../../../src/renderer/wgsl/proceduralSky.compute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE9F,gFAAgF;AAChF,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;uBAiBrB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;8CAWC,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAoIzC,WAAW,2BAA2B,qBAAqB,cAAc,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkC7G,CAAC","sourcesContent":["import { TURBIDITY, GROUND_ALBEDO, ILLUMINANCE, REFERENCE_ILLUMINANCE } from '../skyModel.js';\n\n// Same atmosphere, quadrature and pass order as WebGLSkyBaker. Distances in km.\nexport const proceduralSkyWGSL = /* wgsl */ `\nstruct Params { sun: vec4f, sunWorld: vec4f, size: vec4f, scale: vec4f, ambient: vec4f }\n@group(0) @binding(0) var<uniform> params: Params;\n@group(0) @binding(1) var transmittanceTable: texture_2d<f32>;\n@group(0) @binding(2) var multipleTable: texture_2d<f32>;\n@group(0) @binding(3) var skyTable: texture_2d<f32>;\n@group(0) @binding(4) var irradianceTable: texture_2d<f32>;\n@group(0) @binding(5) var output: texture_storage_2d<rgba32float, write>;\nconst PI = 3.14159265358979;\nconst R_GROUND = 6360.0;\nconst R_TOP = 6460.0;\nconst CAMERA_ALTITUDE = 0.2;\nconst RAYLEIGH = vec3f(5.802e-3, 13.558e-3, 33.1e-3);\nconst MIE_SCATTERING = 3.996e-3;\nconst MIE_EXTINCTION = 4.44e-3;\nconst MIE_G = 0.8;\nconst OZONE = vec3f(0.65e-3, 1.881e-3, 0.085e-3);\nconst ALBEDO = vec3f(${GROUND_ALBEDO.join(', ')});\nconst T_SIZE = vec2u(256, 64);\nconst MS_ALTITUDES = 32u;\nconst SV_SIZE = vec2u(96, 192);\n\nfn discriminant(r: f32, mu: f32, radius: f32) -> f32 { return (radius - r) * (radius + r) + r * r * mu * mu; }\nfn hitsGround(r: f32, mu: f32) -> bool { return mu < 0.0 && discriminant(r, mu, R_GROUND) >= 0.0; }\nfn distanceToGround(r: f32, mu: f32) -> f32 { return max(-r * mu - sqrt(max(discriminant(r, mu, R_GROUND), 0.0)), 0.0); }\nfn distanceToTop(r: f32, mu: f32) -> f32 { return max(-r * mu + sqrt(max(discriminant(r, mu, R_TOP), 0.0)), 0.0); }\nfn densities(r: f32) -> vec3f {\n let h = max(r - R_GROUND, 0.0);\n return vec3f(exp(-h / 8.0), exp(-h / 1.2) * ${TURBIDITY}, max(0.0, 1.0 - abs(h - 25.0) / 15.0));\n}\nfn extinction(d: vec3f) -> vec3f { return RAYLEIGH * d.x + MIE_EXTINCTION * d.y + OZONE * d.z; }\nfn altitudeAt(x: f32) -> f32 { return x * x * (R_TOP - R_GROUND); }\nfn altitudeCoord(h: f32) -> f32 { return sqrt(clamp(h / (R_TOP - R_GROUND), 0.0, 1.0)); }\nfn fetchLinear(table: texture_2d<f32>, p: vec2f) -> vec3f {\n let size = vec2i(textureDimensions(table));\n let q = clamp(p, vec2f(0.0), vec2f(size - 1));\n let i = min(vec2i(floor(q)), max(size - 2, vec2i(0)));\n let f = clamp(q - vec2f(i), vec2f(0.0), vec2f(1.0));\n let j = min(i + 1, size - 1);\n let a = textureLoad(table, i, 0).rgb;\n let b = textureLoad(table, vec2i(j.x, i.y), 0).rgb;\n let c = textureLoad(table, vec2i(i.x, j.y), 0).rgb;\n let d = textureLoad(table, j, 0).rgb;\n return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);\n}\nfn transmittanceTo(r: f32, mu: f32) -> vec3f {\n return fetchLinear(transmittanceTable, vec2f((clamp(mu, -1.0, 1.0) + 1.0) * 0.5 * f32(T_SIZE.x - 1u), altitudeCoord(r - R_GROUND) * f32(T_SIZE.y - 1u)));\n}\nfn cornetteShanks(nu: f32) -> f32 {\n let g2 = MIE_G * MIE_G;\n return 3.0 / (8.0 * PI) * ((1.0 - g2) * (1.0 + nu * nu)) / ((2.0 + g2) * pow(1.0 + g2 - 2.0 * MIE_G * nu, 1.5));\n}\nstruct March { radiance: vec3f, throughput: vec3f }\nfn march(origin: vec3f, dir: vec3f, steps: u32, full: bool, skyIrradiance: vec3f) -> March {\n let r = length(origin);\n let mu = dot(origin, dir) / r;\n let ground = hitsGround(r, mu);\n var len = distanceToTop(r, mu);\n if (ground) { len = distanceToGround(r, mu); }\n let nu = dot(dir, params.sun.xyz);\n var rayleighPhase = 1.0 / (4.0 * PI);\n var miePhase = rayleighPhase;\n if (full) { rayleighPhase = 3.0 / (16.0 * PI) * (1.0 + nu * nu); miePhase = cornetteShanks(nu); }\n var result = March(vec3f(0.0), vec3f(0.0));\n var view = vec3f(1.0);\n var previous = 0.0;\n for (var i = 0u; i < steps; i++) {\n let s = f32(i + 1u) / f32(steps);\n let next = len * s * s;\n let dt = next - previous;\n let p = origin + dir * (0.5 * (previous + next));\n previous = next;\n let pr = length(p);\n let d = densities(pr);\n let e = extinction(d);\n let sunT = transmittanceTo(pr, dot(p, params.sun.xyz) / pr);\n let scatterR = RAYLEIGH * d.x;\n let scatterM = MIE_SCATTERING * d.y;\n var ms = vec3f(0.0);\n if (full) { ms = fetchLinear(multipleTable, vec2f(altitudeCoord(pr - R_GROUND) * f32(MS_ALTITUDES - 1u), 0.0)); }\n let source = sunT * (scatterR * rayleighPhase + scatterM * miePhase) + (scatterR + scatterM) * ms;\n let segment = exp(-e * dt);\n let weight = (1.0 - segment) / max(e, vec3f(1e-9));\n result.radiance += view * source * weight;\n result.throughput += view * (scatterR + scatterM) * weight;\n view *= segment;\n }\n if (ground) {\n let p = origin + dir * len;\n let pr = length(p);\n let cosSun = dot(p, params.sun.xyz) / pr;\n let irradiance = transmittanceTo(pr, cosSun) * max(cosSun, 0.0) + skyIrradiance;\n result.radiance += view * ALBEDO / PI * irradiance;\n }\n return result;\n}\nfn elevationAt(row: f32) -> f32 {\n let x = row / f32(SV_SIZE.y - 1u) * 2.0 - 1.0;\n return sign(x) * x * x * (PI / 2.0);\n}\nfn elevationCoord(e: f32) -> f32 {\n let x = sign(e) * sqrt(abs(e) / (PI / 2.0));\n return clamp((x + 1.0) * 0.5, 0.0, 1.0) * f32(SV_SIZE.y - 1u);\n}\n@compute @workgroup_size(8, 8)\nfn transmittance(@builtin(global_invocation_id) id: vec3u) {\n if (any(id.xy >= T_SIZE)) { return; }\n let mu = f32(id.x) / f32(T_SIZE.x - 1u) * 2.0 - 1.0;\n let r = R_GROUND + altitudeAt(f32(id.y) / f32(T_SIZE.y - 1u));\n if (hitsGround(r, mu)) { textureStore(output, vec2i(id.xy), vec4f(0.0, 0.0, 0.0, 1.0)); return; }\n let len = distanceToTop(r, mu);\n var depth = vec3f(0.0);\n for (var i = 0u; i < 48u; i++) {\n let t = (f32(i) + 0.5) / 48.0 * len;\n depth += extinction(densities(sqrt(t * t + 2.0 * r * mu * t + r * r))) * (len / 48.0);\n }\n textureStore(output, vec2i(id.xy), vec4f(exp(-depth), 1.0));\n}\n@compute @workgroup_size(8, 8)\nfn multiple(@builtin(global_invocation_id) id: vec3u) {\n if (id.x >= MS_ALTITUDES || id.y > 0u) { return; }\n let r = R_GROUND + altitudeAt(f32(id.x) / f32(MS_ALTITUDES - 1u));\n var second = vec3f(0.0);\n var transfer = vec3f(0.0);\n for (var i = 0u; i < 64u; i++) {\n let mu = 1.0 - 2.0 * (f32(i) + 0.5) / 64.0;\n let phi = f32(i) * PI * (3.0 - sqrt(5.0));\n let s = sqrt(1.0 - mu * mu);\n let result = march(vec3f(0.0, r, 0.0), vec3f(s * cos(phi), mu, s * sin(phi)), 20u, false, vec3f(0.0));\n second += result.radiance / 64.0;\n transfer += result.throughput / 64.0;\n }\n textureStore(output, vec2i(id.xy), vec4f(second / (1.0 - transfer), 1.0));\n}\n@compute @workgroup_size(8, 8)\nfn skyView(@builtin(global_invocation_id) id: vec3u) {\n if (any(id.xy >= SV_SIZE)) { return; }\n let e = elevationAt(f32(id.y));\n let phi = f32(id.x) / f32(SV_SIZE.x - 1u) * PI;\n var sky = vec3f(0.0);\n if (params.size.w > 0.0) { sky = textureLoad(irradianceTable, vec2i(0), 0).rgb; }\n let result = march(vec3f(0.0, R_GROUND + CAMERA_ALTITUDE, 0.0), vec3f(cos(e) * cos(phi), sin(e), cos(e) * sin(phi)), 40u, true, sky);\n textureStore(output, vec2i(id.xy), vec4f(result.radiance, 1.0));\n}\n@compute @workgroup_size(8, 8)\nfn irradiance(@builtin(global_invocation_id) id: vec3u) {\n if (id.x >= 2u || id.y > 0u) { return; }\n var sky = vec3f(0.0);\n for (var i = 0u; i < 128u; i++) {\n let e = (f32(i) + 0.5) / 128.0 * (PI / 2.0);\n let weight = 2.0 * sin(e) * cos(e) * (PI / 2.0 / 128.0) * (PI / 48.0);\n for (var j = 0u; j < 48u; j++) {\n let phi = (f32(j) + 0.5) / 48.0 * PI;\n sky += fetchLinear(skyTable, vec2f(phi / PI * f32(SV_SIZE.x - 1u), elevationCoord(e))) * weight;\n }\n }\n if (id.x == 0u) { textureStore(output, vec2i(id.xy), vec4f(sky, 1.0)); return; }\n let sunT = transmittanceTo(R_GROUND + CAMERA_ALTITUDE, params.sun.y);\n let luma = vec3f(0.2126, 0.7152, 0.0722);\n let horizontal = dot(sky, luma) + dot(sunT, luma) * max(params.sun.y, 0.0);\n let scale = ${ILLUMINANCE} / sqrt(max(horizontal, ${REFERENCE_ILLUMINANCE} * 1e-3) * ${REFERENCE_ILLUMINANCE});\n textureStore(output, vec2i(id.xy), vec4f(sunT, scale));\n}\nfn mapDirection(texel: vec2f) -> vec3f {\n let theta = texel.y / params.size.y * PI;\n let phi = texel.x / params.size.x * 2.0 * PI;\n return vec3f(-sin(theta) * cos(phi), cos(theta), -sin(theta) * sin(phi));\n}\n@compute @workgroup_size(8, 8)\nfn map(@builtin(global_invocation_id) id: vec3u) {\n if (any(id.xy >= vec2u(params.size.xy))) { return; }\n let texel = vec2f(id.xy) + 0.5;\n let dir = mapDirection(texel);\n let rawRelative = abs(atan2(dir.z, dir.x) - params.sun.w);\n let wrapped = rawRelative - floor(rawRelative / (2.0 * PI)) * (2.0 * PI);\n let relative = min(wrapped, 2.0 * PI - wrapped);\n let e = asin(clamp(dir.y, -1.0, 1.0));\n var radiance = fetchLinear(skyTable, vec2f(relative / PI * f32(SV_SIZE.x - 1u), elevationCoord(e)));\n let sun = textureLoad(irradianceTable, vec2i(1, 0), 0);\n let radius = params.sunWorld.w;\n let texelAngle = PI / params.size.y;\n if (acos(clamp(dot(dir, params.sunWorld.xyz), -1.0, 1.0)) < radius + 3.0 * texelAngle / max(sqrt(1.0 - dir.y * dir.y), 0.05)) {\n var coverage = 0.0;\n for (var y = 0u; y < 6u; y++) { for (var x = 0u; x < 6u; x++) {\n let d = mapDirection(texel - 0.5 + (vec2f(f32(x), f32(y)) + 0.5) / 6.0);\n let angle = 2.0 * asin(min(length(d - params.sunWorld.xyz) * 0.5, 1.0));\n let t = angle / radius;\n if (t < 1.0) { coverage += 1.0 - 0.6 * (1.0 - sqrt(1.0 - t * t)); }\n } }\n let solidAngle = 2.0 * PI * (1.0 - cos(radius));\n radiance += coverage / 36.0 / (solidAngle * (1.0 - 0.6 / 3.0)) * sun.rgb;\n }\n textureStore(output, vec2i(id.xy), vec4f(radiance * sun.a * params.scale.xyz + params.ambient.xyz, 1.0));\n}\n`;\n"]}
@@ -1,6 +1,23 @@
1
1
  export declare const WORKGROUP_SIZE = 8;
2
+ /** Native input instrumentation; omitted hooks preserve the production source. */
3
+ export interface RayTraceInputHooks {
4
+ declarations: string;
5
+ begin: string;
6
+ primarySurface: string;
7
+ unclampedColor: string;
8
+ end: string;
9
+ uniformJitter: boolean;
10
+ }
2
11
  export interface RayTraceShaderOptions {
3
12
  hasDisplacement: boolean;
13
+ debugGroup?: number;
14
+ /** Invocation block edge; the native host matches dispatch to this value. Default 8. */
15
+ workgroupSize?: number;
16
+ lightTracing?: boolean;
17
+ photonMapping?: boolean;
18
+ photonMaxDepth?: number;
19
+ /** Internal A/B override for directly visible PM receivers. Default true; ignored with light tracing. */
20
+ photonDirectSubset?: boolean;
4
21
  /** Include direction frames only when used, preserving the legacy shader arithmetic otherwise. */
5
22
  hasAnisotropyDirections?: boolean;
6
23
  /** Include independent coat normals only when a material uses that slot. */
@@ -11,6 +28,13 @@ export interface RayTraceShaderOptions {
11
28
  hasSceneAlpha?: boolean;
12
29
  /** Bit mask of the BLAS layouts present in the scene (bvh2, bvh4, bvh-gpu, cwbvh). */
13
30
  blasLayoutMask?: number;
31
+ /** Defined only when pipeline constants are baked into the source. */
32
+ spectral?: boolean;
33
+ sceneCapabilities?: number;
34
+ /** Retained environment support must still respect the current illumination state. */
35
+ dynamicEnvironment?: boolean;
36
+ materialCapabilities?: number;
37
+ lightCapabilities?: number;
14
38
  }
15
39
  /** Generates the WebGPU megakernel path tracing compute shader. */
16
- export default function rayTraceCompute({ hasDisplacement, hasAnisotropyDirections, hasCoatNormals, hasAlpha, hasSceneAlpha, blasLayoutMask }: RayTraceShaderOptions): string;
40
+ export default function rayTraceCompute(options: RayTraceShaderOptions, sceneIntersections?: string, pathDiagnostic?: boolean, inputHooks?: RayTraceInputHooks): string;