@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
@@ -1,9 +1,15 @@
1
+ import { hdrResolveWGSL } from './wgsl/compose.frag.wgsl.js';
2
+ import { oidnAuxiliaryDefine } from './wgsl/oidnAuxiliary.wgsl.js';
3
+ import { displayAovKind, DEFAULT_AOV_DISPLAY } from './aovDisplay.js';
4
+ import { WGPUAov } from './WGPUAov.js';
5
+ import { aovMask } from './aov.js';
1
6
  import { DisplayPostProcess } from './DisplayPostProcess.js';
2
7
  import { customDenoiseLayersMain, customDenoiseCoverageMain } from './wgsl/customDenoise.wgsl.js';
3
8
  import { WGPUCanvasSurface } from './WGPUCanvasSurface.js';
4
9
  import { WGPUScratchBuffer } from './WGPUScratchBuffer.js';
5
10
  import { WGPUScratchTexture } from './WGPUScratchTexture.js';
6
11
  import { ScratchPool } from './ScratchPool.js';
12
+ import { GPUTraceQueue } from './GPUTraceQueue.js';
7
13
  import { makeRenderPipeline } from './renderPipeline.js';
8
14
  import { textureBytes } from './gpuMemory.js';
9
15
  import { WGPUFullQuadPass } from './WGPUFullQuadPass.js';
@@ -21,60 +27,50 @@ export const oidnAlbedoSrgbEncodeMain = /* wgsl */ `
21
27
  if (globalId.x >= u32(imageSize.x) || globalId.y >= u32(imageSize.y)) { return; }
22
28
  let index = globalId.x + globalId.y * u32(imageSize.x);
23
29
  let raw = textureLoad(in_albedo, vec2u(globalId.xy), 0);
24
- let linear = clamp(raw.rgb, vec3f(0.0), vec3f(1.0));
25
- let encoded = select(
26
- 1.055 * pow(linear, vec3f(1.0 / 2.4)) - 0.055,
27
- 12.92 * linear,
28
- linear <= vec3f(0.0031308)
29
- );
30
+ let encoded = sQ(raw.rgb);
30
31
  out_albedo[index] = vec4f(encoded, raw.a);
31
32
  `;
32
33
  export const oidnAlbedoSrgbDecodeMain = /* wgsl */ `
33
34
  if (globalId.x >= u32(imageSize.x) || globalId.y >= u32(imageSize.y)) { return; }
34
35
  let index = globalId.x + globalId.y * u32(imageSize.x);
35
36
  let filtered = in_albedo[index];
36
- let encoded = clamp(filtered.rgb, vec3f(0.0), vec3f(1.0));
37
- let linear = select(
38
- pow((encoded + 0.055) / 1.055, vec3f(2.4)),
39
- encoded / 12.92,
40
- encoded <= vec3f(0.04045)
41
- );
37
+ let linear = sP(filtered.rgb);
42
38
  var result = linear;
43
- let jg = textureLoad(in_rawAlbedo, vec2i(globalId.xy), 0).a;
39
+ let jj = textureLoad(in_rawAlbedo, vec2i(globalId.xy), 0).a;
44
40
  if (preserveSurfaceTexture != 0u) {
45
41
 
46
42
 
47
43
 
48
- let fQ = vec2i(globalId.xy);
49
- let center = textureLoad(in_rawNormal, fQ, 0);
44
+ let pixel = vec2i(globalId.xy);
45
+ let center = textureLoad(in_rawNormal, pixel, 0);
50
46
  let n = normalize(center.rgb * 2.0 - 1.0 + vec3f(1e-8));
51
- var nf = 0.0;
47
+ var nS = 0.0;
52
48
  for (var y = -1; y <= 1; y++) {
53
49
  for (var x = -1; x <= 1; x++) {
54
- let tV = textureLoad(in_rawNormal,
55
- clamp(fQ + vec2i(x, y), vec2i(0), imageSize - 1), 0);
56
- let nn = normalize(tV.rgb * 2.0 - 1.0 + vec3f(1e-8));
57
- nf = max(nf,
58
- max(1.0 - dot(n, nn), abs(center.a - tV.a)));
50
+ let vI = textureLoad(in_rawNormal,
51
+ clamp(pixel + vec2i(x, y), vec2i(0), imageSize - 1), 0);
52
+ let nn = normalize(vI.rgb * 2.0 - 1.0 + vec3f(1e-8));
53
+ nS = max(nS,
54
+ max(1.0 - dot(n, nn), abs(center.a - vI.a)));
59
55
  }
60
56
  }
61
- let un = smoothstep(0.02, 0.1, nf);
62
- let raw = clamp(textureLoad(in_rawAlbedo, fQ, 0).rgb,
57
+ let wc = smoothstep(0.02, 0.1, nS);
58
+ let raw = clamp(textureLoad(in_rawAlbedo, pixel, 0).rgb,
63
59
  vec3f(0.0), vec3f(1.0));
64
- result = mix(raw, linear, un);
60
+ result = mix(raw, linear, wc);
65
61
  }
66
- out_albedo[index] = vec4f(result, jg);
62
+ out_albedo[index] = vec4f(result, jj);
67
63
  `;
68
64
  export const oidnNormalSanitizeMain = /* wgsl */ `
69
65
  if (globalId.x >= u32(imageSize.x) || globalId.y >= u32(imageSize.y)) { return; }
70
66
  let index = globalId.x + globalId.y * u32(imageSize.x);
71
- out_normal[index] = vec4f(clamp(in_normal[index].rgb, vec3f(0.0), vec3f(1.0)), 1.0);
67
+ out_normal[index] = vec4f(rG(in_normal[index].rgb), 1.0);
72
68
  `;
73
69
  function createTimeQuery(device) {
74
70
  try {
75
71
  const querySet = device.createQuerySet({
76
72
  type: 'timestamp',
77
- count: 2
73
+ count: 16
78
74
  });
79
75
  const resolveBuffer = device.createBuffer({
80
76
  size: querySet.count * 8,
@@ -95,17 +91,29 @@ function createTimeQuery(device) {
95
91
  return undefined;
96
92
  }
97
93
  }
98
- function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scratch, customJobs) {
94
+ function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scratch, customJobs, traceQueue) {
99
95
  let sampleRenderedCallback = () => { };
100
- let allowMultipleSamplesPerFrame = false;
96
+ let batchSamples = false;
97
+ let realtimeBatchBudgetMs = Infinity;
98
+ // Samples traced between display frames skip the resolve and composition;
99
+ // the next presentation or read resolves them once.
100
+ let realtimeDeferPostProcess = false;
101
+ let postProcessPending = false;
102
+ // Resolve uses the configuration that produced these buffers, even if another
103
+ // target has since changed the shared trace pass's caustic settings.
104
+ let sampledOutput;
101
105
  let offlineSamplesPerBatch = 0;
102
106
  let deferPostProcess = false;
103
107
  let sampleSequenceOffset = 0;
108
+ const aov = new WGPUAov(device);
109
+ let aovCamera;
104
110
  let sampleCount = 0;
105
111
  let elapsedFrameTime = 32;
106
112
  let elapsedTileTime;
107
113
  let tileTimingGeneration = 0;
114
+ let causticBatchTimeMs = 0, photonBatchTimeMs = 0;
108
115
  let lastGpuTraceTiming;
116
+ let displayTrace;
109
117
  let diagnosticsReadbackPromise = Promise.resolve();
110
118
  let isFirstFrame = true;
111
119
  let disposed = false;
@@ -127,6 +135,8 @@ function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scrat
127
135
  let denoiseValid = false;
128
136
  let maxTimePerTile = 21;
129
137
  let bloomIntensity = 0;
138
+ // Sample count of this accumulation's last bloom refresh.
139
+ let bloomSamples = 0;
130
140
  let bloomThreshold = 1;
131
141
  let bloomRadius = 0.6;
132
142
  let exposure = 1;
@@ -139,6 +149,7 @@ function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scrat
139
149
  let hdrOutputRequested = false;
140
150
  let hdrOutputActive = false;
141
151
  let output = 'final';
152
+ let aovDisplayOptions = DEFAULT_AOV_DISPLAY;
142
153
  let shadowCatcherColor = vec3.create();
143
154
  let shadowCatcherAlpha = 1;
144
155
  let pageLeaveTime = performance.now();
@@ -227,6 +238,8 @@ function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scrat
227
238
  tileTimingGeneration++;
228
239
  tileRenderWithPredict?.needsUpdatePredicting();
229
240
  lastGpuTraceTiming = undefined;
241
+ causticBatchTimeMs = 0;
242
+ photonBatchTimeMs = 0;
230
243
  // A changed render configuration needs fresh timing. Refresh
231
244
  // its estimator without submitting a hidden probe in that mode.
232
245
  needsUpdatePredicting = offlineSamplesPerBatch === 0;
@@ -248,12 +261,14 @@ function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scrat
248
261
  inputs: ['colorTex', 'coverageTex'],
249
262
  outputs: ['color'],
250
263
  uniforms: [{ label: 'flatBackgroundColor', type: 'vec4f', data: [0, 0, 0, 0] }],
264
+ fsDefine: hdrResolveWGSL,
251
265
  fsMain: /* wgsl */ `
252
266
  var color = load_colorTex(uv, 0);
253
267
  let coverage = clamp(load_coverageTex(uv, 0).a, 0.0, 1.0);
254
- if (flatBackgroundColor.a > 0.5 && coverage > 0.0) {
255
- color = vec4f(color.rgb * coverage, color.a);
256
- }
268
+ color = vec4f(
269
+ jx(color.r, coverage, flatBackgroundColor.a > 0.5, true),
270
+ jx(color.g, coverage, flatBackgroundColor.a > 0.5, true),
271
+ jx(color.b, coverage, flatBackgroundColor.a > 0.5, true), color.a);
257
272
  output.color = color;
258
273
  `
259
274
  }));
@@ -337,7 +352,6 @@ output.color = color;
337
352
  fsMain: compositeDenoiseDisplayMain,
338
353
  fsDefine: linearToSrgbDefine,
339
354
  uniforms: [
340
- { label: 'hdrOutputEnabled', type: 'f32', data: 0 },
341
355
  { label: 'denoisedAlpha', type: 'f32', data: 0 }
342
356
  ],
343
357
  outputs: ['color'], inputs: ['colorTex', 'composedTex']
@@ -354,6 +368,7 @@ output.color = color;
354
368
  inputs: ['albedo'],
355
369
  outputs: ['albedo'],
356
370
  uniforms: auxiliaryPassUniforms,
371
+ csDefine: oidnAuxiliaryDefine,
357
372
  csMain: oidnAlbedoSrgbEncodeMain
358
373
  }));
359
374
  const oidnAlbedoDecodePass = scratch.get('oidnAlbedoDecodePass', () => new WGPUComputePass('OIDN albedo sRGB decode', device, {
@@ -362,12 +377,14 @@ output.color = color;
362
377
  uniforms: [...auxiliaryPassUniforms, {
363
378
  label: 'preserveSurfaceTexture', type: 'u32', data: 0
364
379
  }],
380
+ csDefine: oidnAuxiliaryDefine,
365
381
  csMain: oidnAlbedoSrgbDecodeMain
366
382
  }));
367
383
  const oidnNormalSanitizePass = scratch.get('oidnNormalSanitizePass', () => new WGPUComputePass('OIDN normal sanitize', device, {
368
384
  inputs: ['normal'],
369
385
  outputs: ['normal'],
370
386
  uniforms: auxiliaryPassUniforms,
387
+ csDefine: oidnAuxiliaryDefine,
371
388
  csMain: oidnNormalSanitizeMain
372
389
  }));
373
390
  oidnAlbedoEncodePass.setOutputParams({ albedo: { channels: 4 } });
@@ -375,11 +392,11 @@ output.color = color;
375
392
  oidnNormalSanitizePass.setOutputParams({ normal: { channels: 4 } });
376
393
  const outputPass = scratch.get('outputPass', () => new WGPUFullQuadPass('output', device, {
377
394
  fsMain: /* wgsl */ `
378
- let vM = min(
395
+ let xW = min(
379
396
  vec2i(uv2 * vec2f(colorTexRegion())),
380
397
  vec2i(colorTexRegion()) - vec2i(1)
381
398
  );
382
- var color = load_colorTex(vM, 0);
399
+ var color = load_colorTex(xW, 0);
383
400
  color = vec4(color.rgb * color.a, color.a);
384
401
  output.color = color;
385
402
  `,
@@ -412,7 +429,8 @@ output.color = color;
412
429
  _updateSeed(renderWidth, renderHeight);
413
430
  const activeTimeQuery = timeQuery;
414
431
  const isUnmapped = activeTimeQuery?.resultBuffer.mapState === 'unmapped';
415
- rayTracePass.createPass(encoder, clear, tiles, activeTimeQuery ? { querySet: activeTimeQuery.querySet } : undefined);
432
+ const measuredCausticBatch = rayTracePass.createPass(encoder, clear, tiles, activeTimeQuery ? { querySet: activeTimeQuery.querySet } : undefined);
433
+ sampledOutput = rayTracePass.getOutputBuffer();
416
434
  if (activeTimeQuery) {
417
435
  encoder.resolveQuerySet(activeTimeQuery.querySet, 0, activeTimeQuery.querySet.count, activeTimeQuery.resolveBuffer, 0);
418
436
  if (isUnmapped) {
@@ -428,14 +446,25 @@ output.color = color;
428
446
  diagnosticsReadbackPromise = activeTimeQuery.resultBuffer
429
447
  .mapAsync(GPUMapMode.READ).then(() => {
430
448
  const mappedRange = activeTimeQuery.resultBuffer.getMappedRange();
431
- const times = new BigInt64Array(mappedRange, 0, 2);
432
- const traceTime = Math.max(Number(times[1] - times[0]) / 1_000_000, 0.1);
449
+ const times = new BigInt64Array(mappedRange, 0, 16);
450
+ const causticTime = (measuredCausticBatch & 1) ? Math.max(Number(times[3] - times[2] + times[5] - times[4]) / 1_000_000, 0) : 0;
451
+ // Independent timestamp pairs avoid Metal's cross-pass counter bug.
452
+ const photonTime = (measuredCausticBatch & 2) ? Math.max(Number(times[7] - times[6] + times[9] - times[8] + times[11] - times[10] + times[13] - times[12] + times[15] - times[14]) / 1_000_000, 0) : 0;
453
+ const ptTime = Math.max(Number(times[1] - times[0]) / 1_000_000, 0);
433
454
  // A readback may finish after scene preparation or a mode switch.
434
455
  // It must not overwrite throughput learned for the current scene.
435
456
  const timingIsCurrent = !disposed && submittedTimingGeneration === tileTimingGeneration &&
436
457
  !isFirstFrame;
437
458
  if (timingIsCurrent) {
459
+ if (measuredCausticBatch & 1)
460
+ causticBatchTimeMs = causticTime;
461
+ if (measuredCausticBatch & 2)
462
+ photonBatchTimeMs = photonTime;
463
+ const traceTime = Math.max(ptTime + (causticBatchTimeMs + photonBatchTimeMs) / submittedTileCount, .1);
438
464
  lastGpuTraceTiming = {
465
+ causticTimeMs: causticBatchTimeMs, photonMappingTimeMs: photonBatchTimeMs,
466
+ photonStagesMs: (measuredCausticBatch & 2) ? [6, 8, 10, 12, 14].map(i => Math.max(Number(times[i + 1] - times[i]) / 1_000_000, 0)) : undefined,
467
+ pathTracingTimeMs: ptTime,
439
468
  tileTimeMs: traceTime,
440
469
  tileTimePerSampleMs: traceTime,
441
470
  estimatedFullFrameTimeMs: traceTime * submittedTileCount,
@@ -498,7 +527,6 @@ output.color = color;
498
527
  composePass.setUniform('shadowCatcherAlpha', shadowCatcherAlpha);
499
528
  compositeDenoiseDisplayPass.setSize(renderWidth, renderHeight);
500
529
  compositeDenoiseDisplayPass.setOutputParams({ color: { format: composeColorFormat } });
501
- compositeDenoiseDisplayPass.setUniform('hdrOutputEnabled', +hdrOutputActive);
502
530
  compositeDenoiseDisplayPass.setUniform('denoisedAlpha', denoiseValid && denoisedDisplayLinear ? +rayTracePass.needsDenoiseAlpha() : 0);
503
531
  }
504
532
  function snapshotInput(encoder, key, texture, exact = false) {
@@ -529,6 +557,15 @@ output.color = color;
529
557
  }
530
558
  composePass.setUniform('flatBackgroundColor', resolvedFlatBackground);
531
559
  rawOutputPass.setUniform('flatBackgroundColor', resolvedFlatBackground);
560
+ const aovKind = displayAovKind(output);
561
+ if (aovKind && sampleCount === 0) {
562
+ if (!execution?.aovs?.includes(aovKind))
563
+ throw new Error(`AOV ${aovKind} is not enabled`);
564
+ if (!aov.samples)
565
+ return;
566
+ finishPresentation(encoder, aov.visualize(aovKind, aovDisplayOptions, hdrOutputActive));
567
+ return;
568
+ }
532
569
  if (resolvedSamples < 1)
533
570
  return;
534
571
  prepareComposition();
@@ -536,7 +573,7 @@ output.color = color;
536
573
  denoisedTexture = prepareDenoisedTexture(encoder, denoisedBuffer, denoisedTexture);
537
574
  if (resolve) {
538
575
  rayTraceOutputPass.setSampleCount(sampleCount);
539
- rayTraceOutputPass.createPass(encoder, rayTracePass.getOutputBuffer(), resolvedHasShadowCatcher);
576
+ rayTraceOutputPass.createPass(encoder, sampledOutput ?? rayTracePass.getOutputBuffer(), resolvedHasShadowCatcher);
540
577
  }
541
578
  composePass.setUniform('shadowCatcherEnabled', +resolvedHasShadowCatcher);
542
579
  let foregroundTexture = getFrameInput(resolvedHasShadowCatcher ? 'foreground' : 'color');
@@ -550,17 +587,18 @@ output.color = color;
550
587
  }));
551
588
  layers.setOutputParams({ foreground: { format: 'rgba32float' }, background: { format: 'rgba32float' } });
552
589
  layers.setSize(renderWidth, renderHeight);
590
+ displayTrace?.push('CorrectLayers:SceneLinear');
553
591
  layers.createPass(encoder, { originalTex: getFrameInput('color'), filteredTex: denoisedTexture,
554
592
  foregroundTex: foregroundTexture, backgroundTex: catcherBackgroundTexture });
555
593
  foregroundTexture = layers.getOutput('foreground');
556
594
  catcherBackgroundTexture = layers.getOutput('background');
557
595
  }
558
596
  const bloomEnabled = bloomIntensity > 0.0;
559
- // Progressive accumulation refreshes bloom every ten samples.
560
- const samplesSkipped = sampleCount < 10 || sampleCount % 10 > 0;
597
+ // Progressive accumulation refreshes bloom after every ten new samples,
598
+ // including when several samples are resolved at once.
561
599
  const bloomState = scratch.get('bloom state', () => ({ owner: undefined, settings: '', dispose() { } }));
562
600
  const bloomSettings = `${bloomThreshold}/${bloomRadius}/${+(denoiseValid && denoisedHDR)}`;
563
- const needsUpdateBloom = bloomEnabled && sampleCount >= 10 && (!samplesSkipped || bloomState.owner !== targetKey || bloomState.settings !== bloomSettings);
601
+ const needsUpdateBloom = bloomEnabled && sampleCount >= 10 && (sampleCount - bloomSamples >= 10 || bloomState.owner !== targetKey || bloomState.settings !== bloomSettings);
564
602
  let bloomIntensityToUpdate = bloomIntensity;
565
603
  if (needsUpdateBloom) {
566
604
  if (!bloomPass) {
@@ -570,14 +608,17 @@ output.color = color;
570
608
  bloomPass.setSize(renderWidth, renderHeight);
571
609
  bloomState.owner = targetKey;
572
610
  bloomState.settings = bloomSettings;
611
+ bloomSamples = sampleCount;
573
612
  bloomPass.setBrightThreshold(bloomThreshold);
574
613
  bloomPass.setRadius(bloomRadius);
614
+ displayTrace?.push('Bloom:SceneLinear');
575
615
  bloomPass.createPass(encoder, colorTexture);
576
616
  }
577
617
  else if (bloomEnabled && sampleCount < 10) {
578
618
  bloomIntensityToUpdate = 0;
579
619
  }
580
620
  composePass.setUniform('bloomIntensity', bloomIntensityToUpdate);
621
+ displayTrace?.push('Compose:DisplayLinear+DisplayEncoded');
581
622
  composePass.createPass(encoder, {
582
623
  colorTex: colorTexture,
583
624
  foregroundTex: foregroundTexture,
@@ -588,6 +629,7 @@ output.color = color;
588
629
  bloomTex: bloomEnabled && bloomPass ? bloomPass.getOutput() : colorTexture
589
630
  });
590
631
  if (denoiseValid && !denoisedHDR && denoisedDisplayLinear && denoisedTexture) {
632
+ displayTrace?.push('Encode:DisplayEncoded');
591
633
  compositeDenoiseDisplayPass.createPass(encoder, {
592
634
  colorTex: denoisedTexture,
593
635
  composedTex: composePass.getOutput('denoiseColor')
@@ -596,14 +638,24 @@ output.color = color;
596
638
  let displayTexture = (denoiseValid && denoisedBuffer ? (denoisedHDR ? composePass.getOutput('color') : denoisedDisplayLinear
597
639
  ? compositeDenoiseDisplayPass.getOutput('color') : denoisedTexture) : undefined) ||
598
640
  composePass.getOutput('color');
641
+ if (aovKind) {
642
+ if (!execution?.aovs?.includes(aovKind))
643
+ throw new Error(`AOV ${aovKind} is not enabled`);
644
+ displayTexture = aov.visualize(aovKind, aovDisplayOptions, hdrOutputActive);
645
+ }
646
+ finishPresentation(encoder, displayTexture);
647
+ }
648
+ function finishPresentation(encoder, displayTexture) {
599
649
  const activeHDRPeakMeter = hdrOutputActive
600
650
  ? (hdrPeakMeter ??= scratch.get('hdrPeak', () => new WGPUHDRPeakMeter(device)))
601
651
  : undefined;
602
652
  const hdrPeakReadbackSubmitted = activeHDRPeakMeter?.encode(encoder, displayTexture, renderWidth, renderHeight) ?? false;
603
653
  if (output === 'normal' || output === 'albedo') {
654
+ displayTrace?.push('AOV:Raw');
604
655
  displayTexture = getFrameInput(output);
605
656
  }
606
657
  else if (output === 'shadowCatcher') {
658
+ displayTrace?.push('AOV:Raw');
607
659
  displayTexture = getFrameInput('shadowCatcher');
608
660
  }
609
661
  if (displayTexture.width < renderWidth || displayTexture.height < renderHeight) {
@@ -632,36 +684,46 @@ output.color = color;
632
684
  void activeHDRPeakMeter?.resolve();
633
685
  }
634
686
  }
687
+ function flushPostProcess() {
688
+ if (!postProcessPending)
689
+ return;
690
+ postProcessPending = false;
691
+ drawPostProcess(device.createCommandEncoder(), false, true);
692
+ }
635
693
  function trace(camera, maxSamples) {
694
+ applyTraceQuality();
636
695
  // A call to draw means accumulation has been invalidated. Cancel OIDN
637
696
  // before checking shader compilation: pipeline-affecting parameter changes
638
697
  // otherwise leave the previous asynchronous denoise alive while resources
639
698
  // and bind groups are being replaced.
640
699
  cancelDenoise();
641
- if (rayTracePass.isCompilingShader()) {
642
- isFirstFrame = true;
643
- sampleCount = 0;
644
- return true;
645
- }
646
700
  // Update the camera before compiling and sampling.
647
701
  rayTracePass.setCamera(camera);
702
+ aovCamera = camera;
703
+ rayTracePass.updatePipeline();
704
+ const pipelineError = rayTracePass.getPipelineError();
705
+ if (pipelineError)
706
+ throw pipelineError;
707
+ // Waiting for a shader is not an input change: this render's samples and
708
+ // complete image stay valid, and only Render's restart discards them.
709
+ if (rayTracePass.isCompilingShader() || !rayTracePass.isPipelineReady())
710
+ return true;
711
+ if (execution?.aovs?.length && !rayTracePass.prepareAovs(execution.aovs))
712
+ return true;
648
713
  const resetAccumulation = isFirstFrame;
714
+ if (resetAccumulation)
715
+ aov.reset();
649
716
  if (resetAccumulation) {
717
+ postProcessPending = false;
718
+ bloomSamples = 0;
650
719
  denoiseValid = false;
651
720
  tileTimingGeneration++;
652
721
  elapsedTileTime = undefined;
653
- rayTracePass.setCamera(camera);
654
722
  (tileRenderWithPredict || tileRender).reset();
655
723
  // Reset
656
724
  isFirstFrame = false;
657
725
  sampleCount = 0;
658
726
  }
659
- rayTracePass.updatePipeline();
660
- if (rayTracePass.isCompilingShader() || !rayTracePass.isPipelineReady()) {
661
- isFirstFrame = true;
662
- sampleCount = 0;
663
- return true;
664
- }
665
727
  // Keep the last completed denoise visible while a static while-converging batch
666
728
  // accumulates, including the incomplete first sample after a scene edit.
667
729
  if (!preserveDenoisedOutput || isFirstFrame) {
@@ -687,16 +749,32 @@ output.color = color;
687
749
  needsUpdatePredicting = false;
688
750
  }
689
751
  const frameSampleCount = sampleCount;
752
+ const sampleTimeMs = lastGpuTraceTiming?.estimatedFullFrameTimeMs;
753
+ const realtime = offlineSamplesPerBatch === 0 && batchSamples;
754
+ const realtimeBudget = Math.min(maxTimePerTile, realtimeBatchBudgetMs);
755
+ if (realtime && !resetAccumulation && !isPredictingFrame && sampleTimeMs !== undefined &&
756
+ traceQueue.available(realtimeBudget) < Math.min(sampleTimeMs, realtimeBudget))
757
+ return false;
758
+ // Only batch a measured, unchanged full-frame workload. New cameras get
759
+ // their first sample immediately; expensive samples retain tiled execution.
760
+ const realtimeBatch = realtime && sampleCount > 0 &&
761
+ !resetAccumulation && !isPredictingFrame && lastGpuTraceTiming?.tileCount === 1 && sampleTimeMs !== undefined &&
762
+ sampleTimeMs <= realtimeBudget / 2;
763
+ const realtimeSamples = realtimeBatch
764
+ ? Math.min(64, Math.floor(traceQueue.available(realtimeBudget) / sampleTimeMs)) : 1;
765
+ if (realtimeBatch && realtimeSamples === 0)
766
+ return false;
767
+ const batchStarted = performance.now();
690
768
  _startRecordFrameTime(!resetAccumulation);
691
769
  const renderSampleTarget = maxSamples;
692
- const batchTarget = Math.min(renderSampleTarget, sampleCount + Math.max(offlineSamplesPerBatch, 1));
770
+ const batchTarget = Math.min(renderSampleTarget, sampleCount + (offlineSamplesPerBatch > 0 ? offlineSamplesPerBatch : realtimeSamples));
693
771
  do {
694
772
  let { xIndex, yIndex, columns, rows, isFirstTile, isLastTile, samplesPerFrame } = (tileRenderWithPredict || tileRender).nextTile(elapsedTileTime);
695
773
  rayTraceOutputPass.setSampleTileGrid(columns, rows);
696
- if (offlineSamplesPerBatch > 0 && columns * rows === 1) {
774
+ if ((offlineSamplesPerBatch > 0 || realtimeBatch) && columns * rows === 1) {
697
775
  samplesPerFrame = batchTarget - sampleCount;
698
776
  }
699
- else if (!allowMultipleSamplesPerFrame) {
777
+ else if (!batchSamples) {
700
778
  samplesPerFrame = 1;
701
779
  }
702
780
  if (columns * rows === 1) {
@@ -708,11 +786,21 @@ output.color = color;
708
786
  sample(sampleCount === 0, [1, 1]);
709
787
  sampleCount++;
710
788
  samplesSubmitted++;
789
+ if (realtime && !isPredictingFrame && sampleTimeMs !== undefined)
790
+ traceQueue.track(sampleTimeMs);
791
+ if (realtimeBatch) {
792
+ // Encoding many tiny samples must also leave the main thread free
793
+ // to receive camera input. Yield before encoding another batch.
794
+ if (performance.now() - batchStarted >= 4)
795
+ break;
796
+ }
711
797
  }
712
798
  }
713
799
  else {
714
800
  rayTracePass.setSampleTiles(columns, rows, xIndex, yIndex);
715
801
  sample(sampleCount === 0 && isFirstTile, [columns, rows]);
802
+ if (realtime && !isPredictingFrame && sampleTimeMs !== undefined)
803
+ traceQueue.track(sampleTimeMs / (columns * rows));
716
804
  if (isLastTile)
717
805
  sampleCount++;
718
806
  }
@@ -727,7 +815,14 @@ output.color = color;
727
815
  sampleCount = 0;
728
816
  return false;
729
817
  }
730
- if (sampleCount !== frameSampleCount && (!deferPostProcess || sampleCount >= renderSampleTarget)) {
818
+ if (sampleCount !== frameSampleCount && execution?.aovs?.length) {
819
+ rayTracePass.renderAovs(aov, camera, sampleCount, execution.aovSamples ?? 16, execution.aovs);
820
+ }
821
+ if (sampleCount !== frameSampleCount && realtime && realtimeDeferPostProcess && sampleCount < renderSampleTarget) {
822
+ postProcessPending = true;
823
+ }
824
+ else if (sampleCount !== frameSampleCount && (!deferPostProcess || sampleCount >= renderSampleTarget)) {
825
+ postProcessPending = false;
731
826
  const encoder = device.createCommandEncoder();
732
827
  drawPostProcess(encoder, sampleCount >= renderSampleTarget, true);
733
828
  }
@@ -759,6 +854,7 @@ output.color = color;
759
854
  // The target retains its complete presentation texture through the resize.
760
855
  clearDenoisedOutput();
761
856
  tileTimingGeneration++;
857
+ sampledOutput = undefined;
762
858
  renderWidth = nextRenderWidth;
763
859
  renderHeight = nextRenderHeight;
764
860
  (tileRenderWithPredict || tileRender).setSize(renderWidth, renderHeight);
@@ -856,7 +952,6 @@ output.color = color;
856
952
  hdrPeakMeter?.reset();
857
953
  }
858
954
  compositeDenoiseDisplayPass.setOutputParams({ color: { format: composeColorFormat } });
859
- compositeDenoiseDisplayPass.setUniform('hdrOutputEnabled', hdrOutputActive ? 1 : 0);
860
955
  composePass.setUniform('hdrOutputEnabled', hdrOutputActive ? 1 : 0);
861
956
  return wasActive !== hdrOutputActive;
862
957
  }
@@ -893,6 +988,7 @@ output.color = color;
893
988
  jnlmPass ??= scratch.get('jnlm', () => new WGPUJNLMDenoisePass(device));
894
989
  const rayBuffers = rayTracePass.getOutputBuffer();
895
990
  const encoder = device.createCommandEncoder({ label: 'JNLM denoise' });
991
+ displayTrace?.push('Denoise:DisplayLinear');
896
992
  const output = jnlmPass.encode(encoder, {
897
993
  width: renderWidth,
898
994
  height: renderHeight,
@@ -917,7 +1013,7 @@ output.color = color;
917
1013
  return completed;
918
1014
  });
919
1015
  }
920
- function performCustomDenoise(denoiser, schedule, signal) {
1016
+ function performCustomDenoise(denoiser, schedule, signal, requestedAovs = []) {
921
1017
  const generation = denoiseGeneration;
922
1018
  const controller = activeCustomController = new AbortController();
923
1019
  const abort = () => controller.abort();
@@ -932,7 +1028,15 @@ output.color = color;
932
1028
  const albedo = copyGuide('Custom albedo', getFrameInput('albedo'), true);
933
1029
  const normal = copyGuide('Custom normal', getFrameInput('normal'), true);
934
1030
  const output = scratch.get('Custom output', () => new WGPUScratchBuffer(device)).get(width * height * 16, true);
935
- await denoiser.denoise({ device, width, height, color, albedo, normal, output }, { signal: controller.signal, schedule });
1031
+ const aovs = requestedAovs.length ? aov.snapshot(requestedAovs) : undefined;
1032
+ displayTrace?.push('Denoise:SceneLinear');
1033
+ try {
1034
+ await denoiser.denoise({ device, width, height, color, albedo, normal, output, aovs }, { signal: controller.signal, schedule });
1035
+ }
1036
+ finally {
1037
+ if (aovs)
1038
+ void device.queue.onSubmittedWorkDone().catch(() => undefined).then(() => aov.releaseSnapshot(aovs));
1039
+ }
936
1040
  if (controller.signal.aborted || disposed || generation !== denoiseGeneration)
937
1041
  return false;
938
1042
  const coverage = scratch.get('custom coverage', () => new WGPUComputePass('Custom coverage', device, {
@@ -965,8 +1069,11 @@ output.color = color;
965
1069
  cancelDenoise();
966
1070
  if (isFirstFrame || sampleCount < 1)
967
1071
  return Promise.resolve(false);
1072
+ if (output !== 'final' && output !== 'shadow')
1073
+ return Promise.resolve(true);
1074
+ flushPostProcess();
968
1075
  if (attachedDenoiser.kind === 'custom')
969
- return performCustomDenoise(attachedDenoiser.denoiser, denoiseSchedule, signal);
1076
+ return performCustomDenoise(attachedDenoiser.denoiser, denoiseSchedule, signal, attachedDenoiser.aovs);
970
1077
  denoisedHDR = false;
971
1078
  if (attachedDenoiser.kind === 'jnlm')
972
1079
  return performJNLMDenoise(attachedDenoiser.denoiser);
@@ -991,7 +1098,7 @@ output.color = color;
991
1098
  wholeImage: denoiseSchedule === 'every-sample'
992
1099
  } : {}),
993
1100
  // A preview frame is one whole-image pass. Settled images can take many
994
- // tiles; oidn-web 0.5 runs those back to back by default, which starves
1101
+ // tiles; oidn-webgpu runs those back to back by default, which starves
995
1102
  // the page at 4K, so pace them to display frames instead.
996
1103
  scheduling: denoiseSchedule === 'every-sample' ? 'event-loop' : 'animation-frame'
997
1104
  };
@@ -1081,6 +1188,7 @@ output.color = color;
1081
1188
  return Promise.resolve();
1082
1189
  // Snapshot the complete raw composition; never feed a previous denoise
1083
1190
  // back into the network during progressive updates.
1191
+ displayTrace?.push('Denoise:DisplayLinear');
1084
1192
  return runOIDNPhase(generation, (finish, fail) => denoiser.tileExecute({
1085
1193
  ...convergingTileOptions,
1086
1194
  color: { data: colorInput, ...size },
@@ -1189,35 +1297,59 @@ output.color = color;
1189
1297
  diagnosticsReadbackPromise
1190
1298
  ]).then(() => {
1191
1299
  rayTracePass.releaseTarget(targetKey);
1300
+ aov.dispose();
1192
1301
  denoisedBuffer?.destroy();
1193
1302
  presentationTexture?.destroy();
1194
1303
  displayPostProcess.dispose();
1195
1304
  rayTraceOutputPass.dispose();
1196
1305
  });
1197
1306
  }
1307
+ // Keep tracing quality out of presentation: an old fallback must not
1308
+ // invalidate a new caustic pipeline while it is compiling.
1309
+ function applyTraceQuality() {
1310
+ if (execution) {
1311
+ rayTracePass.setQuality(execution);
1312
+ rayTracePass.setBevelSamples(execution.bevelSamples);
1313
+ rayTracePass.setAlphaBlendStrategy(execution.alphaBlendStrategy);
1314
+ rayTracePass.setSamplingPattern(execution.samplingPattern, execution.maxSamples);
1315
+ }
1316
+ }
1198
1317
  function activate() {
1199
1318
  rayTracePass.useTarget(targetKey);
1200
1319
  if (renderWidth && renderHeight)
1201
1320
  rayTracePass.setSize(renderWidth, renderHeight, screenWidth / screenHeight);
1202
1321
  if (execution) {
1203
- rayTracePass.setQuality(execution);
1204
1322
  rayTracePass.setClamping(execution.clamping);
1205
1323
  rayTracePass.setTransmissiveOutputAlphaMin(execution.transmissiveOutputAlphaMin);
1206
- rayTracePass.setBevelSamples(execution.bevelSamples);
1207
- rayTracePass.setAlphaBlendStrategy(execution.alphaBlendStrategy);
1208
- rayTracePass.setSamplingPattern(execution.samplingPattern, execution.maxSamples);
1209
1324
  }
1210
1325
  }
1211
1326
  return {
1212
1327
  invalidateTiming: invalidateTilePrediction,
1213
1328
  invalidateDenoisedOutput() { cancelDenoise(); denoiseValid = false; preserveDenoisedOutput = false; },
1214
1329
  configure(settings) {
1215
- const timingKeys = ['bounces', 'bevel', 'bevelSamples', 'directLightCandidates', 'dispersionWavelengths', 'alphaBlendStrategy', 'samplingPattern', 'clamping', 'transmissiveOutputAlphaMin'];
1330
+ const timingKeys = ['bounces', 'bevel', 'bevelSamples', 'directLightCandidates', 'dispersionWavelengths', 'alphaBlendStrategy', 'samplingPattern', 'clamping', 'transmissiveOutputAlphaMin', 'caustics'];
1216
1331
  if (!execution || timingKeys.some(key => execution[key] !== settings[key]))
1217
1332
  invalidateTilePrediction();
1218
- execution = { ...settings };
1333
+ if (settings.aovs?.length && (!Number.isInteger(settings.aovSamples ?? 16) || (settings.aovSamples ?? 16) < 1))
1334
+ throw new RangeError('aovSamples must be a positive integer');
1335
+ const previousMask = aovMask(execution?.aovs ?? []), nextMask = aovMask(settings.aovs ?? []);
1336
+ if (previousMask !== nextMask || execution?.aovSamples !== settings.aovSamples)
1337
+ aov.samples = 0;
1338
+ execution = { ...settings, aovs: [...(settings.aovs ?? [])] };
1339
+ // Presentation may still name the previous preview's AOV. Drop that
1340
+ // selection before tracing with a smaller set; Display validates and
1341
+ // reapplies the current channel when the new image is presented.
1342
+ const displayedAov = displayAovKind(output);
1343
+ if (displayedAov && !settings.aovs?.includes(displayedAov))
1344
+ output = 'final';
1345
+ if (previousMask && !nextMask) {
1346
+ aov.dispose();
1347
+ aov.history.clear();
1348
+ aov.width = aov.height = 0;
1349
+ aov.reset();
1350
+ }
1219
1351
  maxTimePerTile = Math.max(1, settings.timeBudgetMs);
1220
- allowMultipleSamplesPerFrame = settings.allowMultipleSamplesPerFrame;
1352
+ batchSamples = settings.batchSamples;
1221
1353
  tileRender.setDesiredMsPerTile(maxTimePerTile);
1222
1354
  tileRender.setMaxTiles(settings.maxTiles);
1223
1355
  tileRenderWithPredict?.setDesiredMsPerTile(maxTimePerTile);
@@ -1228,6 +1360,11 @@ output.color = color;
1228
1360
  canCompleteSampleWithin(timeBudgetMs) {
1229
1361
  return (lastGpuTraceTiming?.estimatedFullFrameTimeMs ?? elapsedFrameTime) <= timeBudgetMs;
1230
1362
  },
1363
+ setRealtimeBatchBudget(milliseconds) { realtimeBatchBudgetMs = milliseconds; },
1364
+ setRealtimeDeferPostProcess(defer) { realtimeDeferPostProcess = defer; },
1365
+ getRealtimeSampleTime() { return lastGpuTraceTiming?.estimatedFullFrameTimeMs; },
1366
+ getRealtimeTileTime() { return lastGpuTraceTiming?.tileTimePerSampleMs; },
1367
+ whenTraceAvailable() { return traceQueue.whenAvailable(); },
1231
1368
  get presentationComplete() { return !!presentationTexture; },
1232
1369
  get presentationDenoised() { return presentationDenoised; },
1233
1370
  present() {
@@ -1242,13 +1379,14 @@ output.color = color;
1242
1379
  getMemory() {
1243
1380
  return {
1244
1381
  width: renderWidth, height: renderHeight,
1245
- bytes: rayTracePass.getTargetMemoryBytes(targetKey) + rayTraceOutputPass.getMemoryBytes() + textureBytes(presentationTexture) + displayPostProcess.getMemoryBytes() + (denoisedBuffer?.size ?? 0)
1382
+ bytes: aov.bytes + rayTracePass.getTargetMemoryBytes(targetKey) + rayTraceOutputPass.getMemoryBytes() + textureBytes(presentationTexture) + displayPostProcess.getMemoryBytes() + (denoisedBuffer?.size ?? 0)
1246
1383
  };
1247
1384
  },
1248
1385
  isFirstFrame() {
1249
1386
  return isFirstFrame;
1250
1387
  },
1251
1388
  restartSamples() {
1389
+ aov.reset();
1252
1390
  // Input edits reset accumulation, not learned throughput. Re-arming a
1253
1391
  // hidden probe here starves continuously changing scenes of visible samples.
1254
1392
  tileTimingGeneration++;
@@ -1257,16 +1395,17 @@ output.color = color;
1257
1395
  denoiseValid = false;
1258
1396
  presentationDenoised = false;
1259
1397
  resolvedSamples = 0;
1398
+ postProcessPending = false;
1399
+ bloomSamples = 0;
1260
1400
  (tileRenderWithPredict || tileRender).reset();
1261
1401
  isPredictingFrame = false;
1262
1402
  isFirstFrame = true;
1263
1403
  sampleCount = 0;
1264
1404
  },
1265
1405
  getOutputTexture(kind) {
1266
- if (resolvedSamples < 1)
1267
- return;
1406
+ flushPostProcess();
1268
1407
  if (kind === 'hdr')
1269
- return getFrameInput('color');
1408
+ return resolvedSamples > 0 ? getFrameInput('color') : undefined;
1270
1409
  return displayPostProcess.output ?? presentationTexture;
1271
1410
  },
1272
1411
  applyPostProcesses(passes, render) {
@@ -1275,8 +1414,9 @@ output.color = color;
1275
1414
  },
1276
1415
  trace,
1277
1416
  drawPostProcess() {
1278
- const encoder = device.createCommandEncoder();
1279
- drawPostProcess(encoder, true);
1417
+ const resolve = postProcessPending;
1418
+ postProcessPending = false;
1419
+ drawPostProcess(device.createCommandEncoder(), true, resolve);
1280
1420
  },
1281
1421
  performDenoise,
1282
1422
  cancelDenoise,
@@ -1291,9 +1431,11 @@ output.color = color;
1291
1431
  const bytesPerRow = Math.ceil(width * 16 / 256) * 256;
1292
1432
  const buffer = device.createBuffer({ size: bytesPerRow * height, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ });
1293
1433
  const encoder = device.createCommandEncoder();
1294
- readbackPass.setSize(width, height);
1295
- readbackPass.createPass(encoder, { inputTex: image });
1296
- encoder.copyTextureToBuffer({ texture: readbackPass.getOutput('color') }, { buffer, bytesPerRow }, { width, height });
1434
+ const presentationReadback = hdrOutputActive && displayAovKind(output) ? scratch.get('AOV encoded readback', () => new WGPUFullQuadPass('AOV encoded readback', device, { textureWillBeRead: true, inputs: ['inputTex'], outputs: ['color'], fsMain: `let c=load_inputTex(uv,0);let rgb=select(1.055*pow(max(c.rgb,vec3f(0.0)),vec3f(1.0/2.4))-0.055,12.92*c.rgb,c.rgb<=vec3f(0.0031308));output.color=vec4f(rgb,c.a);` })) : readbackPass;
1435
+ presentationReadback.setOutputParams({ color: { format: 'rgba32float' } });
1436
+ presentationReadback.setSize(width, height);
1437
+ presentationReadback.createPass(encoder, { inputTex: image });
1438
+ encoder.copyTextureToBuffer({ texture: presentationReadback.getOutput('color') }, { buffer, bytesPerRow }, { width, height });
1297
1439
  device.queue.submit([encoder.finish()]);
1298
1440
  try {
1299
1441
  await buffer.mapAsync(GPUMapMode.READ);
@@ -1308,7 +1450,46 @@ output.color = color;
1308
1450
  buffer.destroy();
1309
1451
  }
1310
1452
  },
1453
+ aovReady(kind) { return !!execution?.aovs?.includes(kind) && aov.samples > 0; },
1454
+ getAovSamples() { return aov.samples; },
1455
+ restartAovs() { aov.reset(); },
1456
+ refineAovs(camera, samples = sampleCount) {
1457
+ if (samples < 1 || !execution?.aovs?.length)
1458
+ return true;
1459
+ applyTraceQuality();
1460
+ rayTracePass.setCamera(camera);
1461
+ aovCamera = camera;
1462
+ rayTracePass.updatePipeline();
1463
+ const pipelineError = rayTracePass.getPipelineError();
1464
+ if (pipelineError)
1465
+ throw pipelineError;
1466
+ if (rayTracePass.isCompilingShader() || !rayTracePass.isPipelineReady())
1467
+ return false;
1468
+ return rayTracePass.renderAovs(aov, camera, samples, execution.aovSamples ?? 16, execution.aovs);
1469
+ },
1470
+ async readAov(kind) {
1471
+ if (!execution?.aovs?.includes(kind) || !aovCamera || (sampleCount < 1 && aov.samples < 1))
1472
+ throw new Error('AOV output is not ready');
1473
+ for (;;) {
1474
+ if (disposed)
1475
+ throw new Error('AOV compilation was interrupted');
1476
+ activate();
1477
+ applyTraceQuality();
1478
+ rayTracePass.setCamera(aovCamera);
1479
+ rayTracePass.updatePipeline();
1480
+ const pipelineError = rayTracePass.getPipelineError();
1481
+ if (pipelineError)
1482
+ throw pipelineError;
1483
+ if (!rayTracePass.isCompilingShader() && rayTracePass.isPipelineReady() &&
1484
+ rayTracePass.renderAovs(aov, aovCamera, Math.max(sampleCount, aov.samples), execution.aovSamples ?? 16, execution.aovs))
1485
+ break;
1486
+ // Display frames stop on a hidden page, but compilation still completes.
1487
+ await new Promise(resolve => setTimeout(resolve, 16));
1488
+ }
1489
+ return aov.read(kind);
1490
+ },
1311
1491
  async readOutput(kind) {
1492
+ flushPostProcess();
1312
1493
  rawOutputPass.setUniform('flatBackgroundColor', resolvedFlatBackground);
1313
1494
  const width = renderWidth, height = renderHeight;
1314
1495
  const bytesPerRow = Math.ceil(width * 16 / 256) * 256;
@@ -1377,6 +1558,38 @@ output.color = color;
1377
1558
  getTotalSamplesRendered() {
1378
1559
  return sampleCount;
1379
1560
  },
1561
+ /** @internal */
1562
+ _displayParity() {
1563
+ return {
1564
+ record(trace) { displayTrace = trace; },
1565
+ load(input) {
1566
+ cancelDenoise();
1567
+ clearDenoisedOutput();
1568
+ setSize(input.width, input.height);
1569
+ rayTracePass.useTarget(targetKey);
1570
+ rayTracePass.setSize(renderWidth, renderHeight, screenWidth / screenHeight);
1571
+ const buffers = sampledOutput = rayTracePass.getOutputBuffer();
1572
+ const shadow = new Float32Array(input.width * input.height * 12);
1573
+ for (let i = 0; i < input.width * input.height; i++) {
1574
+ shadow.set(input.shadow.subarray(i * 8, i * 8 + 8), i * 12);
1575
+ shadow.set(input.moments.subarray(i * 4, i * 4 + 4), i * 12 + 8);
1576
+ }
1577
+ for (const [buffer, data] of [[buffers.color, input.color], [buffers.albedo, input.albedo],
1578
+ [buffers.normal, input.normal], [buffers.shadowCatcher, shadow]])
1579
+ device.queue.writeBuffer(buffer, 0, data);
1580
+ sampleCount = resolvedSamples = input.samples;
1581
+ resolvedHasShadowCatcher = input.catcher;
1582
+ isFirstFrame = false;
1583
+ postProcessPending = false;
1584
+ bloomSamples = 0;
1585
+ rayTraceOutputPass.setSampleCount(sampleCount);
1586
+ rayTraceOutputPass.setSampleTileGrid(1, 1);
1587
+ const encoder = device.createCommandEncoder();
1588
+ rayTraceOutputPass.createPass(encoder, buffers, resolvedHasShadowCatcher);
1589
+ device.queue.submit([encoder.finish()]);
1590
+ }
1591
+ };
1592
+ },
1380
1593
  getDiagnostics() {
1381
1594
  return {
1382
1595
  ...rayTracePass.getDiagnostics(),
@@ -1421,6 +1634,7 @@ output.color = color;
1421
1634
  setOnSampleRendered(cb) {
1422
1635
  sampleRenderedCallback = cb;
1423
1636
  },
1637
+ setAovDisplayOptions(options) { aovDisplayOptions = { ...options, depthRange: [...options.depthRange] }; },
1424
1638
  setOutput(nextOutput) {
1425
1639
  if (output === nextOutput)
1426
1640
  return false;
@@ -1432,7 +1646,8 @@ output.color = color;
1432
1646
  }
1433
1647
  /** Independent render targets, without preview or presentation policy. */
1434
1648
  export function makeWGPURenderTargets(canvas, device, options = {}) {
1435
- const rayTracePass = new WGPURayTracePass(device);
1649
+ const rayTracePass = new WGPURayTracePass(device, options.materialTextures);
1650
+ const traceQueue = new GPUTraceQueue(device.queue);
1436
1651
  const customJobs = new Set();
1437
1652
  const scratch = new ScratchPool(work => {
1438
1653
  // A cancelled custom filter can keep submitting GPU work until its promise settles.
@@ -1443,7 +1658,7 @@ export function makeWGPURenderTargets(canvas, device, options = {}) {
1443
1658
  });
1444
1659
  const surface = scratch.get('canvas', () => new WGPUCanvasSurface(canvas, device, options.presentationFormat ?? navigator.gpu.getPreferredCanvasFormat()));
1445
1660
  return makeRenderPipeline(rayTracePass, () => {
1446
- const target = makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scratch, customJobs);
1661
+ const target = makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scratch, customJobs, traceQueue);
1447
1662
  return target;
1448
1663
  }, false, scratch);
1449
1664
  }