@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,315 @@
1
+ import shadowCatcherAccumulationWGSL from './chunks/shadowCatcherAccumulation.wgsl.js';
2
+ import { linearToSrgbDefine } from './compose.frag.wgsl.js';
3
+ import { JNLM_DEFAULT_COLOR_SENSITIVITY, JNLM_DEFAULT_SHAPE, JNLM_ALBEDO_FLOOR, JNLM_ALBEDO_REGULARIZATION, JNLM_COVERAGE_BANDWIDTH, jnlmPassDilation } from '../jnlm.js';
4
+ function guideBinding(guides, binding, name) {
5
+ return guides === 'textures'
6
+ ? `@group(0) @binding(${binding}) var ${name}: texture_2d<f32>;`
7
+ : `@group(0) @binding(${binding}) var<storage, read> ${name}: array<vec4f>;`;
8
+ }
9
+ function loadGuide(guides, name, position) {
10
+ return guides === 'textures' ? `textureLoad(${name}, ${position}, 0)` : `${name}[gf(${position})]`;
11
+ }
12
+ // Shared uniform packing also fixes sensitivity and dilation for native callers.
13
+ export function packJNLMParameters(width, height, strength, pass) {
14
+ const bytes = new ArrayBuffer(16);
15
+ new Uint32Array(bytes, 0, 2).set([width, height]);
16
+ new Float32Array(bytes, 8, 2).set([
17
+ JNLM_DEFAULT_COLOR_SENSITIVITY * Math.max(strength, 1e-3), jnlmPassDilation(pass)
18
+ ]);
19
+ return bytes;
20
+ }
21
+ export const JNLM_WORKGROUP_SIZE = 8;
22
+ const paramsWGSL = /* wgsl */ `
23
+ struct JNLMParams {
24
+ size: vec2u,
25
+ colorSensitivity: f32,
26
+
27
+ dilation: f32,
28
+ }
29
+ @group(0) @binding(0) var<uniform> params: JNLMParams;
30
+ `;
31
+ /**
32
+ * Pass 1: the guide mean and the variance of that mean from the accumulated
33
+ * moments. Ray buffers are stored bottom-up; guides use texture rows.
34
+ */
35
+ export const jnlmGuideWGSL = /* wgsl */ `
36
+ ${paramsWGSL}
37
+ ${shadowCatcherAccumulationWGSL}
38
+ @group(0) @binding(1) var<storage, read> accumulation: array<ShadowCatcherAccumulation>;
39
+ @group(0) @binding(2) var<storage, read> normalBuffer: array<vec4f>;
40
+ @group(0) @binding(3) var<storage, read_write> rawGuide: array<vec2f>;
41
+
42
+ @compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)
43
+ fn main(@builtin(global_invocation_id) id: vec3u) {
44
+ let size = params.size;
45
+ if (id.x >= size.x || id.y >= size.y) { return; }
46
+ let qw = id.x + (size.y - 1u - id.y) * size.x;
47
+ let n = normalBuffer[qw].a;
48
+ let moments = accumulation[qw].moments;
49
+ let mean = moments.x / max(n, 1.0);
50
+
51
+ var variance = -1.0;
52
+ if (n >= 2.0) {
53
+ variance = max(moments.y - n * mean * mean, 0.0) / (n * (n - 1.0));
54
+ }
55
+ rawGuide[id.x + id.y * size.x] = vec2f(mean, variance);
56
+ }
57
+ `;
58
+ /**
59
+ * Pass 2: smooth the noisy per-pixel variance over 3 x 3 pixels. Pixels with
60
+ * a single sample take the spatial variance of their neighborhood instead.
61
+ */
62
+ export const jnlmVarianceWGSL = /* wgsl */ `
63
+ ${paramsWGSL}
64
+ @group(0) @binding(1) var<storage, read> rawGuide: array<vec2f>;
65
+ @group(0) @binding(2) var<storage, read_write> guide: array<vec2f>;
66
+
67
+ @compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)
68
+ fn main(@builtin(global_invocation_id) id: vec3u) {
69
+ let size = params.size;
70
+ if (id.x >= size.x || id.y >= size.y) { return; }
71
+ let center = rawGuide[id.x + id.y * size.x];
72
+ var lM = 0.0;
73
+ var je = 0.0;
74
+ var nM = 0.0;
75
+ var iV = 0.0;
76
+ for (var dy = -1; dy <= 1; dy++) {
77
+ for (var dx = -1; dx <= 1; dx++) {
78
+ let q = clamp(vec2i(id.xy) + vec2i(dx, dy), vec2i(0), vec2i(size) - 1);
79
+ let value = rawGuide[u32(q.x) + u32(q.y) * size.x];
80
+ nM += value.x;
81
+ iV += value.x * value.x;
82
+ if (value.y >= 0.0) {
83
+ lM += value.y;
84
+ je += 1.0;
85
+ }
86
+ }
87
+ }
88
+ var variance: f32;
89
+ if (center.y >= 0.0) {
90
+ variance = lM / je;
91
+ } else {
92
+ let lL = nM / 9.0;
93
+ variance = max(iV / 9.0 - lL * lL, 0.0) * 9.0 / 8.0;
94
+ }
95
+ guide[id.x + id.y * size.x] = vec2f(center.x, variance);
96
+ }
97
+ `;
98
+ /** Copies the composed image into the filter's color buffer. */
99
+ export function createJNLMLoadColorWGSL(guides = 'textures') {
100
+ return /* wgsl */ `
101
+ ${paramsWGSL}
102
+ @group(0) @binding(1) var colorTex: texture_2d<f32>;
103
+ @group(0) @binding(2) var<storage, read_write> outColor: array<vec4f>;
104
+ ${guides === 'buffers' ? `${shadowCatcherAccumulationWGSL}
105
+ @group(0) @binding(3) var<storage, read> normalAccumulation: array<vec4f>;
106
+ @group(0) @binding(4) var<storage, read_write> normal: array<vec4f>;
107
+ @group(0) @binding(5) var<storage, read> shadowAccumulation: array<ShadowCatcherAccumulation>;
108
+ @group(0) @binding(6) var<storage, read_write> shadow: array<vec4f>;
109
+ @group(0) @binding(7) var albedoTex: texture_2d<f32>;
110
+ @group(0) @binding(8) var<storage, read_write> albedo: array<vec4f>;` : ''}
111
+
112
+ @compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)
113
+ fn main(@builtin(global_invocation_id) id: vec3u) {
114
+ if (id.x >= params.size.x || id.y >= params.size.y) { return; }
115
+ outColor[id.x + id.y * params.size.x] = textureLoad(colorTex, vec2i(id.xy), 0);
116
+ ${guides === 'buffers' ? ` let index = id.x + id.y * params.size.x;
117
+ let qw = id.x + (params.size.y - 1u - id.y) * params.size.x;
118
+ let n = normalAccumulation[qw];
119
+ let samples = max(n.a, 1.0);
120
+ normal[index] = vec4f(n.rgb / samples * 0.5 + 0.5, select(0.0, 1.0, dot(n.rgb, n.rgb) > 0.1));
121
+ shadow[index] = shadowAccumulation[qw].mask / samples;
122
+ albedo[index] = textureLoad(albedoTex, vec2i(id.xy), 0);` : ''}
123
+ }
124
+ `;
125
+ }
126
+ export const jnlmLoadColorWGSL = createJNLMLoadColorWGSL();
127
+ /**
128
+ * Pass 3: the joint NL-means filter of the composed image. It also filters
129
+ * the guide with the same weights, with the variance of the weighted mean,
130
+ * for a following pass. The albedo regression corrects color only, keeping
131
+ * uncertain fitted texture responses out of the matching guide.
132
+ */
133
+ export function createJNLMFilterWGSL({ searchRadius, patchRadius, albedoBandwidth, normalBandwidth } = JNLM_DEFAULT_SHAPE, guides = 'textures') {
134
+ const patchSize = (2 * patchRadius + 1) ** 2;
135
+ return /* wgsl */ `
136
+ ${paramsWGSL}
137
+ @group(0) @binding(1) var<storage, read> guide: array<vec2f>;
138
+ @group(0) @binding(2) var<storage, read> color: array<vec4f>;
139
+ ${guideBinding(guides, 3, 'albedoTex')}
140
+ ${guideBinding(guides, 4, 'normalTex')}
141
+ @group(0) @binding(5) var<storage, read_write> outColor: array<vec4f>;
142
+ @group(0) @binding(6) var<storage, read_write> outGuide: array<vec2f>;
143
+ ${guideBinding(guides, 7, 'shadowCatcherTex')}
144
+
145
+ const SEARCH_RADIUS = ${searchRadius};
146
+ const PATCH_RADIUS = ${patchRadius};
147
+ const PATCH_SIZE = ${patchSize};
148
+
149
+ const VARIANCE_CANCELLATION = 1.0;
150
+
151
+ const INV_ALBEDO_BANDWIDTH2 = ${(1 / albedoBandwidth ** 2).toFixed(6)};
152
+ const INV_COVERAGE_BANDWIDTH2 = ${(1 / JNLM_COVERAGE_BANDWIDTH ** 2).toFixed(6)};
153
+ const INV_NORMAL_BANDWIDTH2 = ${(1 / normalBandwidth ** 2).toFixed(6)};
154
+
155
+
156
+ const CENTER_WEIGHT_MIN = 0.01;
157
+
158
+ fn gf(p: vec2i) -> u32 {
159
+ let q = clamp(p, vec2i(0), vec2i(params.size) - 1);
160
+ return u32(q.x) + u32(q.y) * params.size.x;
161
+ }
162
+
163
+ fn lP(q: vec2i, bo: vec4f, gO: vec3f) -> f32 {
164
+ let albedo = ${loadGuide(guides, 'albedoTex', 'q')};
165
+
166
+
167
+ let pY = max((albedo.rgb + bo.rgb) * 0.5, vec3f(${JNLM_ALBEDO_FLOOR}));
168
+ let lu = (albedo.rgb - bo.rgb) / pY;
169
+ let iQ = albedo.a - bo.a;
170
+ let lG = ${loadGuide(guides, 'normalTex', 'q')}.rgb - gO;
171
+ return max(
172
+ dot(lu, lu) * INV_ALBEDO_BANDWIDTH2
173
+ + iQ * iQ * INV_COVERAGE_BANDWIDTH2,
174
+ dot(lG, lG) * INV_NORMAL_BANDWIDTH2
175
+ );
176
+ }
177
+
178
+ fn premultiplied(c: vec4f) -> vec4f {
179
+ return vec4f(c.rgb * c.a, c.a);
180
+ }
181
+
182
+ @compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)
183
+ fn main(@builtin(global_invocation_id) id: vec3u) {
184
+ let size = vec2i(params.size);
185
+ let p = vec2i(id.xy);
186
+ if (p.x >= size.x || p.y >= size.y) { return; }
187
+ let step = i32(params.dilation);
188
+ let bo = ${loadGuide(guides, 'albedoTex', 'p')};
189
+ let fC = ${loadGuide(guides, 'normalTex', 'p')};
190
+ let gO = fC.rgb;
191
+ let index = gf(p);
192
+
193
+
194
+ if (fC.a <= 0.0 && ${loadGuide(guides, 'shadowCatcherTex', 'p')}.r <= 0.0) {
195
+ outColor[index] = color[index];
196
+ outGuide[index] = guide[index];
197
+ return;
198
+ }
199
+
200
+ var lA: array<vec2f, PATCH_SIZE>;
201
+ var k = 0;
202
+ for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
203
+ for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
204
+ lA[k] = guide[gf(p + vec2i(dx, dy) * step)];
205
+ k++;
206
+ }
207
+ }
208
+ let k2 = params.colorSensitivity * params.colorSensitivity;
209
+
210
+ var sum = vec4f(0.0);
211
+ let gR = max(bo.rgb, vec3f(${JNLM_ALBEDO_FLOOR}));
212
+ var mQ = vec3f(0.0);
213
+ var gv = vec3f(0.0);
214
+ var hm = vec3f(0.0);
215
+ var qf = 0.0;
216
+ var gx = 0.0;
217
+ var oE = 0.0;
218
+ var kX = 0.0;
219
+ for (var sy = -SEARCH_RADIUS; sy <= SEARCH_RADIUS; sy++) {
220
+ for (var sx = -SEARCH_RADIUS; sx <= SEARCH_RADIUS; sx++) {
221
+ let q = p + vec2i(sx, sy) * step;
222
+ if (
223
+ (sx == 0 && sy == 0) ||
224
+ q.x < 0 || q.y < 0 || q.x >= size.x || q.y >= size.y
225
+ ) { continue; }
226
+
227
+ let features = lP(q, bo, gO);
228
+ if (features > 16.0) { continue; }
229
+
230
+ var fW = 0.0;
231
+ k = 0;
232
+ for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
233
+ for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
234
+ let a = lA[k];
235
+ let b = guide[gf(q + vec2i(dx, dy) * step)];
236
+ let rV = a.x - b.x;
237
+ fW += (rV * rV
238
+ - VARIANCE_CANCELLATION * (a.y + min(a.y, b.y)))
239
+ / (1e-10 + k2 * (a.y + b.y));
240
+ k++;
241
+ }
242
+ }
243
+ fW /= f32(PATCH_SIZE);
244
+
245
+ let weight = exp(-max(max(fW, 0.0), features));
246
+ let index = gf(q);
247
+ let c = color[index];
248
+ let g = guide[index];
249
+
250
+ let a = (${loadGuide(guides, 'albedoTex', 'q')}.rgb - bo.rgb) / gR;
251
+ let value = premultiplied(c);
252
+ sum += value * weight;
253
+ mQ += a * weight;
254
+ gv += a * a * weight;
255
+ hm += a * value.rgb * weight;
256
+ qf += g.x * weight;
257
+ gx += g.y * weight * weight;
258
+ oE += weight;
259
+ kX = max(kX, weight);
260
+ }
261
+ }
262
+
263
+
264
+
265
+ let center = color[index];
266
+ let lw = guide[index];
267
+ let dE = max(kX, CENTER_WEIGHT_MIN);
268
+ let totalWeight = oE + dE;
269
+ let vs = premultiplied(center);
270
+ let mean = (sum + vs * dE) / totalWeight;
271
+
272
+
273
+ let er = mQ / totalWeight;
274
+ let lQ = max(gv / totalWeight - er * er, vec3f(0.0));
275
+ let rq = hm / totalWeight - er * mean.rgb;
276
+
277
+
278
+
279
+ let rD = bo.rgb + er * gR;
280
+ let pd = mean.rgb * gR / max(rD, vec3f(${JNLM_ALBEDO_FLOOR}));
281
+ let xI = clamp(rq / (lQ + vec3f(${JNLM_ALBEDO_REGULARIZATION})), vec3f(0.0), pd);
282
+ let sz = mean.rgb - xI * er;
283
+ let filtered = vec4f(max(sz, vec3f(0.0)), max(mean.a, 0.0));
284
+ let rgb = select(
285
+ center.rgb,
286
+ filtered.rgb / max(filtered.a, 1e-6),
287
+ filtered.a > 1e-6
288
+ );
289
+ outColor[index] = vec4f(rgb, filtered.a);
290
+ outGuide[index] = vec2f(
291
+ (qf + lw.x * dE) / totalWeight,
292
+ (gx + lw.y * dE * dE)
293
+ / (totalWeight * totalWeight)
294
+ );
295
+ }
296
+ `;
297
+ }
298
+ // Compute presentation for hosts that consume the filtered buffer directly.
299
+ // Use the same sRGB transfer as browser display composition.
300
+ export const jnlmEncodeWGSL = /* wgsl */ `
301
+ struct OutputParams { size: vec2u, premultiply: u32, reserved: u32 }
302
+ @group(0) @binding(0) var<uniform> params: OutputParams;
303
+ @group(0) @binding(1) var<storage, read> color: array<vec4f>;
304
+ @group(0) @binding(2) var output: texture_storage_2d<rgba8unorm, write>;
305
+ ${linearToSrgbDefine}
306
+ @compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)
307
+ fn main(@builtin(global_invocation_id) id: vec3u) {
308
+ if (any(id.xy >= params.size)) { return; }
309
+ let c = color[id.y * params.size.x + id.x];
310
+ var rgb = linearToSrgb(c.rgb);
311
+ if (params.premultiply != 0u) { rgb *= c.a; }
312
+ textureStore(output, id.xy, vec4f(rgb, c.a));
313
+ }
314
+ `;
315
+ //# sourceMappingURL=jnlm.compute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jnlm.compute.js","sourceRoot":"","sources":["../../../src/renderer/wgsl/jnlm.compute.ts"],"names":[],"mappings":"AAAA,OAAO,6BAA6B,MAAM,4CAA4C,CAAC;AACvF,OAAO,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACL,8BAA8B,EAAE,kBAAkB,EAAE,iBAAiB,EACrE,0BAA0B,EAAE,uBAAuB,EAAE,gBAAgB,EAEtE,MAAM,YAAY,CAAC;AAIpB,SAAS,YAAY,CAAC,MAAyB,EAAE,OAAe,EAAE,IAAY;IAC5E,OAAO,MAAM,KAAK,UAAU;QAC1B,CAAC,CAAC,sBAAsB,OAAO,SAAS,IAAI,oBAAoB;QAChE,CAAC,CAAC,sBAAsB,OAAO,wBAAwB,IAAI,iBAAiB,CAAC;AACjF,CAAC;AACD,SAAS,SAAS,CAAC,MAAyB,EAAE,IAAY,EAAE,QAAgB;IAC1E,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,eAAe,IAAI,KAAK,QAAQ,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,OAAe,QAAQ,IAAI,CAAC;AAC7G,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,MAAc,EAAE,QAAgB,EAAE,IAAY;IAC9F,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC;IAClC,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAChC,8BAA8B,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,gBAAgB,CAAC,IAAI,CAAC;KAClF,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,MAAM,UAAU,GAAG,UAAU,CAAC;;;;;;;;CAQ7B,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;EACtC,UAAU;EACV,6BAA6B;;;;;2BAKJ,mBAAmB,KAAK,mBAAmB;;;;;;;;;;;;;;;CAerE,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;EACzC,UAAU;;;;2BAIe,mBAAmB,KAAK,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BrE,CAAC;AAEF,gEAAgE;AAChE,MAAM,UAAU,uBAAuB,CAAC,SAA4B,UAAU;IAC5E,OAAO,UAAU,CAAC;EAClB,UAAU;;;EAGV,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,6BAA6B;;;;;;qEAMY,CAAC,CAAC,CAAC,EAAE;;2BAE/C,mBAAmB,KAAK,mBAAmB;;;;EAIpE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC;;;;;;yDAMkC,CAAC,CAAC,CAAC,EAAE;;CAE/D,CAAC;AACF,CAAC;AACD,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,EAAE,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,EACnC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,KACxC,kBAAkB,EAAE,SAA4B,UAAU;IAC7E,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,UAAU,CAAC;EAClB,UAAU;;;EAGV,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,WAAW,CAAC;EACpC,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,WAAW,CAAC;;;EAGpC,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,kBAAkB,CAAC;;wBAErB,YAAY;uBACb,WAAW;qBACb,SAAS;;;;gCAIE,CAAC,CAAC,GAAG,eAAe,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;kCACnC,CAAC,CAAC,GAAG,uBAAuB,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;gCAC/C,CAAC,CAAC,GAAG,eAAe,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;;;;;;;;;;;eAWpD,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC;;;kDAGmB,iBAAiB;;;WAGlE,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC;;;;;;;;;;;;2BAY9B,mBAAmB,KAAK,mBAAmB;;;;;;WAM/C,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC;WAC9B,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC;;;;;qBAKzB,SAAS,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,CAAC;;;;;;;;;;;;;;;;;6BAiB7B,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAuCnD,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCA8BmB,iBAAiB;kCAC5B,0BAA0B;;;;;;;;;;;;;;;CAerF,CAAC;AACF,CAAC;AAED,4EAA4E;AAC5E,6DAA6D;AAC7D,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;;;;;EAKvC,kBAAkB;2BACO,mBAAmB,KAAK,mBAAmB;;;;;;;;CAQrE,CAAC","sourcesContent":["import shadowCatcherAccumulationWGSL from './chunks/shadowCatcherAccumulation.wgsl.js';\nimport {linearToSrgbDefine} from './compose.frag.wgsl.js';\nimport {\n JNLM_DEFAULT_COLOR_SENSITIVITY, JNLM_DEFAULT_SHAPE, JNLM_ALBEDO_FLOOR,\n JNLM_ALBEDO_REGULARIZATION, JNLM_COVERAGE_BANDWIDTH, jnlmPassDilation,\n type JNLMFilterShape\n} from '../jnlm.js';\n\n// Web textures and native normalized guide buffers use the same filter body.\nexport type JNLMGuideBindings = 'textures' | 'buffers';\nfunction guideBinding(guides: JNLMGuideBindings, binding: number, name: string): string {\n return guides === 'textures'\n ? `@group(0) @binding(${binding}) var ${name}: texture_2d<f32>;`\n : `@group(0) @binding(${binding}) var<storage, read> ${name}: array<vec4f>;`;\n}\nfunction loadGuide(guides: JNLMGuideBindings, name: string, position: string): string {\n return guides === 'textures' ? `textureLoad(${name}, ${position}, 0)` : `${name}[pixelIndex(${position})]`;\n}\n\n// Shared uniform packing also fixes sensitivity and dilation for native callers.\nexport function packJNLMParameters(width: number, height: number, strength: number, pass: number): ArrayBuffer {\n const bytes = new ArrayBuffer(16);\n new Uint32Array(bytes, 0, 2).set([width, height]);\n new Float32Array(bytes, 8, 2).set([\n JNLM_DEFAULT_COLOR_SENSITIVITY * Math.max(strength, 1e-3), jnlmPassDilation(pass)\n ]);\n return bytes;\n}\n\nexport const JNLM_WORKGROUP_SIZE = 8;\n\nconst paramsWGSL = /* wgsl */ `\nstruct JNLMParams {\n size: vec2u,\n colorSensitivity: f32,\n // Pixel spacing of the search window and patches in this pass.\n dilation: f32,\n}\n@group(0) @binding(0) var<uniform> params: JNLMParams;\n`;\n\n/**\n * Pass 1: the guide mean and the variance of that mean from the accumulated\n * moments. Ray buffers are stored bottom-up; guides use texture rows.\n */\nexport const jnlmGuideWGSL = /* wgsl */ `\n${paramsWGSL}\n${shadowCatcherAccumulationWGSL}\n@group(0) @binding(1) var<storage, read> accumulation: array<ShadowCatcherAccumulation>;\n@group(0) @binding(2) var<storage, read> normalBuffer: array<vec4f>;\n@group(0) @binding(3) var<storage, read_write> rawGuide: array<vec2f>;\n\n@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)\nfn main(@builtin(global_invocation_id) id: vec3u) {\n let size = params.size;\n if (id.x >= size.x || id.y >= size.y) { return; }\n let rayIndex = id.x + (size.y - 1u - id.y) * size.x;\n let n = normalBuffer[rayIndex].a;\n let moments = accumulation[rayIndex].moments;\n let mean = moments.x / max(n, 1.0);\n // Variance of the mean, or -1 when one sample cannot estimate it.\n var variance = -1.0;\n if (n >= 2.0) {\n variance = max(moments.y - n * mean * mean, 0.0) / (n * (n - 1.0));\n }\n rawGuide[id.x + id.y * size.x] = vec2f(mean, variance);\n}\n`;\n\n/**\n * Pass 2: smooth the noisy per-pixel variance over 3 x 3 pixels. Pixels with\n * a single sample take the spatial variance of their neighborhood instead.\n */\nexport const jnlmVarianceWGSL = /* wgsl */ `\n${paramsWGSL}\n@group(0) @binding(1) var<storage, read> rawGuide: array<vec2f>;\n@group(0) @binding(2) var<storage, read_write> guide: array<vec2f>;\n\n@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)\nfn main(@builtin(global_invocation_id) id: vec3u) {\n let size = params.size;\n if (id.x >= size.x || id.y >= size.y) { return; }\n let center = rawGuide[id.x + id.y * size.x];\n var varianceSum = 0.0;\n var varianceCount = 0.0;\n var meanSum = 0.0;\n var meanSquareSum = 0.0;\n for (var dy = -1; dy <= 1; dy++) {\n for (var dx = -1; dx <= 1; dx++) {\n let q = clamp(vec2i(id.xy) + vec2i(dx, dy), vec2i(0), vec2i(size) - 1);\n let value = rawGuide[u32(q.x) + u32(q.y) * size.x];\n meanSum += value.x;\n meanSquareSum += value.x * value.x;\n if (value.y >= 0.0) {\n varianceSum += value.y;\n varianceCount += 1.0;\n }\n }\n }\n var variance: f32;\n if (center.y >= 0.0) {\n variance = varianceSum / varianceCount;\n } else {\n let spatialMean = meanSum / 9.0;\n variance = max(meanSquareSum / 9.0 - spatialMean * spatialMean, 0.0) * 9.0 / 8.0;\n }\n guide[id.x + id.y * size.x] = vec2f(center.x, variance);\n}\n`;\n\n/** Copies the composed image into the filter's color buffer. */\nexport function createJNLMLoadColorWGSL(guides: JNLMGuideBindings = 'textures'): string {\n return /* wgsl */ `\n${paramsWGSL}\n@group(0) @binding(1) var colorTex: texture_2d<f32>;\n@group(0) @binding(2) var<storage, read_write> outColor: array<vec4f>;\n${guides === 'buffers' ? `${shadowCatcherAccumulationWGSL}\n@group(0) @binding(3) var<storage, read> normalAccumulation: array<vec4f>;\n@group(0) @binding(4) var<storage, read_write> normal: array<vec4f>;\n@group(0) @binding(5) var<storage, read> shadowAccumulation: array<ShadowCatcherAccumulation>;\n@group(0) @binding(6) var<storage, read_write> shadow: array<vec4f>;\n@group(0) @binding(7) var albedoTex: texture_2d<f32>;\n@group(0) @binding(8) var<storage, read_write> albedo: array<vec4f>;` : ''}\n\n@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)\nfn main(@builtin(global_invocation_id) id: vec3u) {\n if (id.x >= params.size.x || id.y >= params.size.y) { return; }\n outColor[id.x + id.y * params.size.x] = textureLoad(colorTex, vec2i(id.xy), 0);\n${guides === 'buffers' ? ` let index = id.x + id.y * params.size.x;\n let rayIndex = id.x + (params.size.y - 1u - id.y) * params.size.x;\n let n = normalAccumulation[rayIndex];\n let samples = max(n.a, 1.0);\n normal[index] = vec4f(n.rgb / samples * 0.5 + 0.5, select(0.0, 1.0, dot(n.rgb, n.rgb) > 0.1));\n shadow[index] = shadowAccumulation[rayIndex].mask / samples;\n albedo[index] = textureLoad(albedoTex, vec2i(id.xy), 0);` : ''}\n}\n`;\n}\nexport const jnlmLoadColorWGSL = createJNLMLoadColorWGSL();\n\n/**\n * Pass 3: the joint NL-means filter of the composed image. It also filters\n * the guide with the same weights, with the variance of the weighted mean,\n * for a following pass. The albedo regression corrects color only, keeping\n * uncertain fitted texture responses out of the matching guide.\n */\nexport function createJNLMFilterWGSL({\n searchRadius, patchRadius, albedoBandwidth, normalBandwidth\n}: JNLMFilterShape = JNLM_DEFAULT_SHAPE, guides: JNLMGuideBindings = 'textures') {\n const patchSize = (2 * patchRadius + 1) ** 2;\n return /* wgsl */ `\n${paramsWGSL}\n@group(0) @binding(1) var<storage, read> guide: array<vec2f>;\n@group(0) @binding(2) var<storage, read> color: array<vec4f>;\n${guideBinding(guides, 3, 'albedoTex')}\n${guideBinding(guides, 4, 'normalTex')}\n@group(0) @binding(5) var<storage, read_write> outColor: array<vec4f>;\n@group(0) @binding(6) var<storage, read_write> outGuide: array<vec2f>;\n${guideBinding(guides, 7, 'shadowCatcherTex')}\n\nconst SEARCH_RADIUS = ${searchRadius};\nconst PATCH_RADIUS = ${patchRadius};\nconst PATCH_SIZE = ${patchSize};\n// Variance cancellation strength alpha of the paper.\nconst VARIANCE_CANCELLATION = 1.0;\n// Inverse squared feature bandwidths. Normals are encoded as n * 0.5 + 0.5.\nconst INV_ALBEDO_BANDWIDTH2 = ${(1 / albedoBandwidth ** 2).toFixed(6)};\nconst INV_COVERAGE_BANDWIDTH2 = ${(1 / JNLM_COVERAGE_BANDWIDTH ** 2).toFixed(6)};\nconst INV_NORMAL_BANDWIDTH2 = ${(1 / normalBandwidth ** 2).toFixed(6)};\n// Lower bound of the center weight, so a pixel unlike all of its neighbors\n// (a thin highlight) is kept rather than replaced by them.\nconst CENTER_WEIGHT_MIN = 0.01;\n\nfn pixelIndex(p: vec2i) -> u32 {\n let q = clamp(p, vec2i(0), vec2i(params.size) - 1);\n return u32(q.x) + u32(q.y) * params.size.x;\n}\n\nfn featureDistance(q: vec2i, centerAlbedo: vec4f, centerNormal: vec3f) -> f32 {\n let albedo = ${loadGuide(guides, 'albedoTex', 'q')};\n // Absolute differences in linear albedo erase low-contrast dark textures.\n // Measure RGB contrast relative to both pixels; keep coverage absolute.\n let albedoScale = max((albedo.rgb + centerAlbedo.rgb) * 0.5, vec3f(${JNLM_ALBEDO_FLOOR}));\n let albedoDelta = (albedo.rgb - centerAlbedo.rgb) / albedoScale;\n let coverageDelta = albedo.a - centerAlbedo.a;\n let normalDelta = ${loadGuide(guides, 'normalTex', 'q')}.rgb - centerNormal;\n return max(\n dot(albedoDelta, albedoDelta) * INV_ALBEDO_BANDWIDTH2\n + coverageDelta * coverageDelta * INV_COVERAGE_BANDWIDTH2,\n dot(normalDelta, normalDelta) * INV_NORMAL_BANDWIDTH2\n );\n}\n\nfn premultiplied(c: vec4f) -> vec4f {\n return vec4f(c.rgb * c.a, c.a);\n}\n\n@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)\nfn main(@builtin(global_invocation_id) id: vec3u) {\n let size = vec2i(params.size);\n let p = vec2i(id.xy);\n if (p.x >= size.x || p.y >= size.y) { return; }\n let step = i32(params.dilation);\n let centerAlbedo = ${loadGuide(guides, 'albedoTex', 'p')};\n let centerNormalTexel = ${loadGuide(guides, 'normalTex', 'p')};\n let centerNormal = centerNormalTexel.rgb;\n let index = pixelIndex(p);\n // Primary misses show the background directly. It has no features that\n // protect its detail and no noise beyond antialiasing, so keep it.\n if (centerNormalTexel.a <= 0.0 && ${loadGuide(guides, 'shadowCatcherTex', 'p')}.r <= 0.0) {\n outColor[index] = color[index];\n outGuide[index] = guide[index];\n return;\n }\n\n var centerPatch: array<vec2f, PATCH_SIZE>;\n var k = 0;\n for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {\n for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {\n centerPatch[k] = guide[pixelIndex(p + vec2i(dx, dy) * step)];\n k++;\n }\n }\n let k2 = params.colorSensitivity * params.colorSensitivity;\n\n var sum = vec4f(0.0);\n let featureScale = max(centerAlbedo.rgb, vec3f(${JNLM_ALBEDO_FLOOR}));\n var featureSum = vec3f(0.0);\n var featureSquareSum = vec3f(0.0);\n var featureColorSum = vec3f(0.0);\n var guideSum = 0.0;\n var guideVarianceSum = 0.0;\n var weightSum = 0.0;\n var maxWeight = 0.0;\n for (var sy = -SEARCH_RADIUS; sy <= SEARCH_RADIUS; sy++) {\n for (var sx = -SEARCH_RADIUS; sx <= SEARCH_RADIUS; sx++) {\n let q = p + vec2i(sx, sy) * step;\n if (\n (sx == 0 && sy == 0) ||\n q.x < 0 || q.y < 0 || q.x >= size.x || q.y >= size.y\n ) { continue; }\n\n let features = featureDistance(q, centerAlbedo, centerNormal);\n if (features > 16.0) { continue; }\n\n var colorDistance = 0.0;\n k = 0;\n for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {\n for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {\n let a = centerPatch[k];\n let b = guide[pixelIndex(q + vec2i(dx, dy) * step)];\n let delta = a.x - b.x;\n colorDistance += (delta * delta\n - VARIANCE_CANCELLATION * (a.y + min(a.y, b.y)))\n / (1e-10 + k2 * (a.y + b.y));\n k++;\n }\n }\n colorDistance /= f32(PATCH_SIZE);\n\n let weight = exp(-max(max(colorDistance, 0.0), features));\n let index = pixelIndex(q);\n let c = color[index];\n let g = guide[index];\n // Filter premultiplied color so coverage and color stay consistent.\n let a = (${loadGuide(guides, 'albedoTex', 'q')}.rgb - centerAlbedo.rgb) / featureScale;\n let value = premultiplied(c);\n sum += value * weight;\n featureSum += a * weight;\n featureSquareSum += a * a * weight;\n featureColorSum += a * value.rgb * weight;\n guideSum += g.x * weight;\n guideVarianceSum += g.y * weight * weight;\n weightSum += weight;\n maxWeight = max(maxWeight, weight);\n }\n }\n\n // Weight the center like its most similar neighbor (Buades et al. 2005)\n // instead of 1, so isolated outliers are not kept unfiltered.\n let center = color[index];\n let centerGuide = guide[index];\n let centerWeight = max(maxWeight, CENTER_WEIGHT_MIN);\n let totalWeight = weightSum + centerWeight;\n let centerValue = premultiplied(center);\n let mean = (sum + centerValue * centerWeight) / totalWeight;\n // Fit each color channel against relative albedo with the same JNLM weights.\n // Centering at this pixel avoids cancellation when the feature is constant.\n let meanFeature = featureSum / totalWeight;\n let featureVariance = max(featureSquareSum / totalWeight - meanFeature * meanFeature, vec3f(0.0));\n let covariance = featureColorSum / totalWeight - meanFeature * mean.rgb;\n // A 1% contrast ridge stabilizes flat guides. Bound the response between no\n // texture dependence and multiplicative albedo modulation; specular color\n // with an unrelated albedo falls back to the weighted mean.\n let meanAlbedo = centerAlbedo.rgb + meanFeature * featureScale;\n let maximumSlope = mean.rgb * featureScale / max(meanAlbedo, vec3f(${JNLM_ALBEDO_FLOOR}));\n let slope = clamp(covariance / (featureVariance + vec3f(${JNLM_ALBEDO_REGULARIZATION})), vec3f(0.0), maximumSlope);\n let corrected = mean.rgb - slope * meanFeature;\n let filtered = vec4f(max(corrected, vec3f(0.0)), max(mean.a, 0.0));\n let rgb = select(\n center.rgb,\n filtered.rgb / max(filtered.a, 1e-6),\n filtered.a > 1e-6\n );\n outColor[index] = vec4f(rgb, filtered.a);\n outGuide[index] = vec2f(\n (guideSum + centerGuide.x * centerWeight) / totalWeight,\n (guideVarianceSum + centerGuide.y * centerWeight * centerWeight)\n / (totalWeight * totalWeight)\n );\n}\n`;\n}\n\n// Compute presentation for hosts that consume the filtered buffer directly.\n// Use the same sRGB transfer as browser display composition.\nexport const jnlmEncodeWGSL = /* wgsl */ `\nstruct OutputParams { size: vec2u, premultiply: u32, reserved: u32 }\n@group(0) @binding(0) var<uniform> params: OutputParams;\n@group(0) @binding(1) var<storage, read> color: array<vec4f>;\n@group(0) @binding(2) var output: texture_storage_2d<rgba8unorm, write>;\n${linearToSrgbDefine}\n@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)\nfn main(@builtin(global_invocation_id) id: vec3u) {\n if (any(id.xy >= params.size)) { return; }\n let c = color[id.y * params.size.x + id.x];\n var rgb = linearToSrgb(c.rgb);\n if (params.premultiply != 0u) { rgb *= c.a; }\n textureStore(output, id.xy, vec4f(rgb, c.a));\n}\n`;\n"]}
@@ -27,8 +27,8 @@ _padding: f32,
27
27
  const LUMINANCE = vec3f(0.2126, 0.7152, 0.0722);
28
28
 
29
29
  @compute @workgroup_size(64)
30
- fn main(@builtin(global_invocation_id) uq: vec3u) {
31
- let tile = uq.x;
30
+ fn main(@builtin(global_invocation_id) eA: vec3u) {
31
+ let tile = eA.x;
32
32
  let tileCount = params.columns * params.rows;
33
33
  if (tile >= tileCount) {
34
34
  return;
@@ -36,18 +36,18 @@ return;
36
36
 
37
37
  let tileX = tile % params.columns;
38
38
  let tileY = tile / params.columns;
39
- let ux = tileX * params.tileSize;
40
- let uy = tileY * params.tileSize;
41
- let wl = min(ux + params.tileSize, params.width);
42
- let wm = min(uy + params.tileSize, params.height);
43
- var mY = 0.0;
44
- var je = 0.0;
39
+ let ws = tileX * params.tileSize;
40
+ let wt = tileY * params.tileSize;
41
+ let yF = min(ws + params.tileSize, params.width);
42
+ let yG = min(wt + params.tileSize, params.height);
43
+ var nM = 0.0;
44
+ var jh = 0.0;
45
45
  var count = 0u;
46
46
 
47
- for (var y = uy; y < wm; y++) {
48
- for (var x = ux; x < wl; x++) {
49
- let fQ = y * params.width + x;
50
- let offset = fQ * 4u;
47
+ for (var y = wt; y < yG; y++) {
48
+ for (var x = ws; x < yF; x++) {
49
+ let pixel = y * params.width + x;
50
+ let offset = pixel * 4u;
51
51
  let samples = pilotMoments[offset + 3u];
52
52
  if (samples <= 0.0) {
53
53
  continue;
@@ -60,28 +60,28 @@ pilotColor[offset + 2u]
60
60
  ),
61
61
  LUMINANCE
62
62
  ) / samples;
63
- let tK = pilotMoments[offset] / samples;
64
- let pi = max(tK - mean * mean, 0.0);
65
- var variance = pi;
63
+ let vj = pilotMoments[offset] / samples;
64
+ let qb = max(vj - mean * mean, 0.0);
65
+ var variance = qb;
66
66
  if (samples > 1.0) {
67
- variance = pi * samples / (samples - 1.0);
67
+ variance = qb * samples / (samples - 1.0);
68
68
  }
69
- mY += mean;
70
- je = max(je, variance);
69
+ nM += mean;
70
+ jh = max(jh, variance);
71
71
  count += 1u;
72
72
  }
73
73
  }
74
74
 
75
- let mean = mY / f32(max(count, 1u));
76
- var oX = 0.0;
75
+ let mean = nM / f32(max(count, 1u));
76
+ var pK = 0.0;
77
77
  if (params.hasPrevious != 0u) {
78
- oX = previousVariance[tile];
78
+ pK = previousVariance[tile];
79
79
  }
80
- let sj = max(je, oX);
81
- let tf = params.absoluteError + params.relativeError * abs(mean);
80
+ let tu = max(jh, pK);
81
+ let uH = params.absoluteError + params.relativeError * abs(mean);
82
82
  let required = ceil(
83
- params.confidence * params.confidence * sj /
84
- max(tf * tf, 1e-16)
83
+ params.confidence * params.confidence * tu /
84
+ max(uH * uH, 1e-16)
85
85
  );
86
86
  let targetSamples = u32(min(
87
87
  f32(params.maxSamples),
@@ -91,11 +91,11 @@ max(f32(params.minSamples), required)
91
91
  tileMeans[tile] = mean;
92
92
 
93
93
 
94
- tileVariances[tile] = je;
94
+ tileVariances[tile] = jh;
95
95
  tileTargets[tile] = targetSamples;
96
96
 
97
- for (var y = uy; y < wm; y++) {
98
- for (var x = ux; x < wl; x++) {
97
+ for (var y = wt; y < yG; y++) {
98
+ for (var x = ws; x < yF; x++) {
99
99
  textureStore(
100
100
  targetTexture,
101
101
  vec2i(i32(x), i32(y)),
@@ -0,0 +1 @@
1
+ export declare const oidnAuxiliaryDefine = "\nfn oidnEncodeAlbedo(value: vec3f) -> vec3f {\n let linear = clamp(value, vec3f(0.0), vec3f(1.0));\n return select(1.055 * pow(linear, vec3f(1.0 / 2.4)) - 0.055,\n 12.92 * linear, linear <= vec3f(0.0031308));\n}\nfn oidnDecodeAlbedo(value: vec3f) -> vec3f {\n let encoded = clamp(value, vec3f(0.0), vec3f(1.0));\n return select(pow((encoded + 0.055) / 1.055, vec3f(2.4)),\n encoded / 12.92, encoded <= vec3f(0.04045));\n}\nfn oidnSanitizeNormal(value: vec3f) -> vec3f {\n return clamp(value, vec3f(0.0), vec3f(1.0));\n}\n";
@@ -0,0 +1,17 @@
1
+ // OIDN's LDR auxiliary networks use sRGB albedo and normals in [0,1].
2
+ export const oidnAuxiliaryDefine = /* wgsl */ `
3
+ fn sQ(value: vec3f) -> vec3f {
4
+ let linear = clamp(value, vec3f(0.0), vec3f(1.0));
5
+ return select(1.055 * pow(linear, vec3f(1.0 / 2.4)) - 0.055,
6
+ 12.92 * linear, linear <= vec3f(0.0031308));
7
+ }
8
+ fn sP(value: vec3f) -> vec3f {
9
+ let encoded = clamp(value, vec3f(0.0), vec3f(1.0));
10
+ return select(pow((encoded + 0.055) / 1.055, vec3f(2.4)),
11
+ encoded / 12.92, encoded <= vec3f(0.04045));
12
+ }
13
+ fn rG(value: vec3f) -> vec3f {
14
+ return clamp(value, vec3f(0.0), vec3f(1.0));
15
+ }
16
+ `;
17
+ //# sourceMappingURL=oidnAuxiliary.wgsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oidnAuxiliary.wgsl.js","sourceRoot":"","sources":["../../../src/renderer/wgsl/oidnAuxiliary.wgsl.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;CAc7C,CAAC","sourcesContent":["// OIDN's LDR auxiliary networks use sRGB albedo and normals in [0,1].\nexport const oidnAuxiliaryDefine = /* wgsl */ `\nfn oidnEncodeAlbedo(value: vec3f) -> vec3f {\n let linear = clamp(value, vec3f(0.0), vec3f(1.0));\n return select(1.055 * pow(linear, vec3f(1.0 / 2.4)) - 0.055,\n 12.92 * linear, linear <= vec3f(0.0031308));\n}\nfn oidnDecodeAlbedo(value: vec3f) -> vec3f {\n let encoded = clamp(value, vec3f(0.0), vec3f(1.0));\n return select(pow((encoded + 0.055) / 1.055, vec3f(2.4)),\n encoded / 12.92, encoded <= vec3f(0.04045));\n}\nfn oidnSanitizeNormal(value: vec3f) -> vec3f {\n return clamp(value, vec3f(0.0), vec3f(1.0));\n}\n`;\n"]}
@@ -0,0 +1,29 @@
1
+ export declare const PHOTON_BYTES = 20;
2
+ export declare const PHOTON_GRID_SIZE = 262144;
3
+ export declare const PHOTON_SCAN_BLOCK = 256;
4
+ export declare const PHOTON_REFERENCE_COUNT: number;
5
+ export type PhotonRadiusScaling = 'none' | 'ppm' | 'constant-count';
6
+ /** Internal density A/B, with the same progressive schedule in all modes. */
7
+ export declare function photonRadius(initial: number, batch: number, alpha?: number, photons?: number, scaling?: PhotonRadiusScaling): number;
8
+ /** Default photon-map batch: pixel count / 4, capped at 2^18. */
9
+ export declare function defaultPhotonMapPhotons(width: number, height: number, divisor?: number): number;
10
+ /** Power-of-two hash capacity, bounded independently of large photon batches. */
11
+ export declare function photonBucketCount(photons: number): number;
12
+ /** Shared texture address contract; payload is stored once, indices twice. */
13
+ export declare function photonLayout(count: number, perCasterRadius?: boolean): {
14
+ buckets: number;
15
+ coarseHeaders: number;
16
+ fineHeaders: number;
17
+ coarseIndices: number;
18
+ fineIndices: number;
19
+ directions: number;
20
+ texels: number;
21
+ };
22
+ /** Batch-local hash buckets: count, two-level parallel prefix sum, then parallel scatter. */
23
+ export declare const photonGridCompute = "\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";
24
+ /** Packed photon payload: position f32 x3, RGBE8 flux, two octahedral directions. */
25
+ export declare const photonPackingWgsl = "\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";
26
+ export declare const photonQueryWgsl = "\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\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";
27
+ export declare function photonDirectQuerySource(enabled?: boolean): string;
28
+ /** Evidence-only per-query counters; no extra bindings or public render options. */
29
+ export declare function photonQuerySource(debugGroup?: number, directSubset?: boolean): string;