@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
package/docs/api.md CHANGED
@@ -5,7 +5,7 @@ See [progressive rendering](./progressive-rendering.md) for complete examples.
5
5
 
6
6
  ## Engine
7
7
 
8
- `new Engine({canvas?, backend?, device?})` manages the device and one GPU
8
+ `new Engine({canvas?, backend?, device?, textureBinding?})` manages the device and one GPU
9
9
  scene. `scene` and `camera` default to undefined. Assign them and call
10
10
  `update()` to commit edits before rendering; see [updates](./updates.md).
11
11
 
@@ -14,6 +14,7 @@ scene. `scene` and `camera` default to undefined. Assign them and call
14
14
  | `canvas` | new HTML canvas, or OffscreenCanvas without document | Accepts either canvas type; default `engine.display.canvas` |
15
15
  | `device` | undefined | Caller-owned WebGPU device; see [requirements](#device-requirements) |
16
16
  | `backend` | `'auto'` | Automatic WebGPU/WebGL selection; `'webgpu'` requires WebGPU; `'webgl'` forces WebGL 2 |
17
+ | `textureBinding` | `'atlas'` | Constructor-only; `'auto'` tries experimental WebGPU bindless textures, with atlas fallback; see [texture bindings](#texture-bindings) |
17
18
  | `bvhBuilder` | `'builtin'` | JavaScript or `'tinybvh'` WebAssembly |
18
19
  | `bvhWorkerCount` | `'auto'` | Hardware concurrency minus one, clamped 1–4; or positive integer |
19
20
  | `bvhLayout` | `'bvh2'` | Static TinyBVH layout; see [BVH](./bvh.md) |
@@ -41,6 +42,28 @@ Events are `progress` (`{stage: 'device' | 'bvh' | 'shaders', progress}`),
41
42
  is reported once; console errors are deduplicated by message. Invalid light
42
43
  values are clamped and reported while rendering continues.
43
44
 
45
+ ### Texture bindings
46
+
47
+ Use `new Engine({textureBinding: 'auto'})` to try bindless material textures
48
+ on WebGPU. The default `'atlas'` uses the existing texture atlas. This option
49
+ is fixed at construction. Check `engine.getDiagnostics()?.materialTextures`
50
+ for the active mode, fallback reason, scale and estimated texture bytes.
51
+
52
+ Bindless requires a resource-table feature enabled on the device and sufficient
53
+ device limits. Chrome currently exposes an experimental implementation behind
54
+ Unsafe WebGPU Support. Devices without it, including WebGL 2, use atlas textures.
55
+ Caller-owned devices must enable `sampling-resource-table` or
56
+ `chromium-experimental-sampling-resource-table` when available;
57
+ `getRecommendedDeviceDescriptor()` does not request these experimental features.
58
+
59
+ `textureAtlasBudgetBytes` applies to both modes. Bindless keeps independent
60
+ textures and scales them together to fit the estimated pixel budget, preserving
61
+ the current LOD 0 filtering and color rules. GPU allocation overhead, resource
62
+ tables and metadata add memory beyond that estimate. Replacing textures can
63
+ temporarily retain the previous GPU resources. Benefits depend on scene texture
64
+ sizes and editing patterns; bindless does not guarantee faster rendering.
65
+ See [texture updates](./updates.md#materials-textures-and-lights).
66
+
44
67
  ### Device requirements
45
68
 
46
69
  `EngineParams.device` defaults to undefined (the library's shared device). A
@@ -104,38 +127,43 @@ other sequences retain their completed samples.
104
127
  | Option | Default | Meaning |
105
128
  | --- | --- | --- |
106
129
  | `maxSamples` | `2048` | Complete sample budget |
130
+ | `aovs` / `aovSamples` | `[]` / `16` | Optional [surface outputs](#surface-outputs) / independent positive integer sample cap |
107
131
  | `bounces` / `clamping` | `3` / `0` | Scattering depth / per-sample radiance clamp; 0 disables clamping |
108
132
  | `samplingPattern` | `'sobol'` | Sobol, ZSobol or random; see [sampling](./sampling.md) |
133
+ | `caustics` | `undefined` | Optional caustics; all estimators default to off. See [caustics](#caustics) |
109
134
  | `directLightCandidates` | `4` | WebGPU light candidates, clamped 1–16; ignored on WebGL |
110
135
  | `bevel` / `bevelSamples` | `true` / `8` | Bevel shading / probes, clamped 1–32 |
111
- | `dispersionWavelengths` | `3` | 3 wavelengths, or one randomly chosen wavelength |
136
+ | `dispersionWavelengths` | `3` | One continuous wavelength per RGB channel, or one randomly chosen channel |
112
137
  | `alphaBlendStrategy` | `'stochastic'` | WebGPU primary BLEND policy; ignored on WebGL |
113
138
  | `transmissiveOutputAlphaMin` | `1` | Path-depth alpha rule over transparent backgrounds; changes restart this render |
114
139
  | `resolutionScale` | `1` | Relative to display canvas; exclusive with fixed width/height |
115
- | `width` / `height` | undefined | Paired fixed constructor dimensions; getters report actual output dimensions |
140
+ | `width` / `height` | undefined | Paired fixed constructor dimensions; `toBlob`, `readPixels` and the getters return exactly this size |
116
141
  | `adaptiveResolution` | `false` | `{targetFrameMs, minScale}` for scale-based renders; both required, positive, minScale ≤ resolutionScale |
117
- | `timeBudgetMs` / `maxTiles` | `21` / `Infinity` | Tile time budget / tiles per call |
118
- | `allowMultipleSamplesPerFrame` | `false` | Add multiple samples when time permits |
142
+ | `timeBudgetMs` / `maxTiles` | `21` / `Infinity` | Target tile time / maximum tile grid size per sample (rounded up to a rectangular grid); fewer tiles make larger tiles, without limiting work per frame or call |
143
+ | `batchSamples` | `false` | Let one refine submit several samples within an estimated timeBudgetMs; one sample or tile can exceed it; see [sample batching](./progressive-rendering.md#sample-batching). `allowMultipleSamplesPerFrame` is a deprecated alias |
119
144
  | `fallback` | `null` | Single-level Render on the same engine |
120
145
  | `denoiser` | `null` | Per-render configuration; read back through the frozen `denoiser` getter and change with `setDenoiser()`; see [denoising](./denoising.md) |
121
146
 
122
147
  `bounces` is rounded and clamped to [1, 20] in both backends; NaN becomes 1.
123
- The path loop allows at most `min(bounces * 3, 20)` events, including transmission,
124
- alpha skips and escape checks. Opaque paths also have their own scattering-depth
125
- termination. This event budget can truncate deep transparent paths even when
126
- the requested scattering depth is larger. Intel Mac WebGL retains its driver
127
- workaround: `min(bounces, 3)` loop events, doubled for scenes with transmission
128
- or alpha, plus its existing early depth termination.
148
+ Paths allow at most `min(bounces * 3, 20)` events, including transmission,
149
+ alpha skips and escape checks. Opaque paths also terminate at their scattering
150
+ limit. The event budget can truncate deep transparent paths before the requested
151
+ scattering depth. On Intel Mac WebGL, the event limit is `min(bounces, 3)`, doubled
152
+ for scenes with transmission or alpha, with earlier scattering termination.
153
+ See [caustic path-length limits](./caustics.md#limits) when comparing renderers.
129
154
 
130
155
  | Method / property | Meaning |
131
156
  | --- | --- |
132
- | `refine()` | Trace within this render's budget; returns status |
157
+ | `refine(channel?, options?)` | Trace beauty or an enabled AOV within this render's budget; returns status |
158
+ | `refineUntil(deadline, {signal}?)` | For custom frame loops: refine once synchronously, then keep sampling until the `performance.now()` deadline or cancellation; returns `Promise<void>`; see [sample batching](progressive-rendering.md#sample-batching) |
133
159
  | `converge(options)` | Deterministic offline image; see below |
134
160
  | `readPixels(kind = 'hdr')` | Read this render; see [pixel outputs](#pixel-outputs) |
135
161
  | `engine` | Owning engine |
136
162
  | `denoising` | Queued/running inference, including intermediate updates; default false |
137
163
  | `on('sample', listener)` | Complete samples: `{samples, isFirstFrame, frameTimeMs}`; returns unsubscribe |
138
164
  | `samples` | Complete samples since restart; stale engine inputs report 0 |
165
+ | `gpuSampleTimeMs` | Deprecated; use `refineUntil` for custom frame loops. Latest WebGPU full beauty sample estimate in ms, extrapolated from tile GPU time when tiled; undefined without timestamps, for stale inputs or during converge |
166
+ | `whenReadyToRefine()` | Deprecated; use `refineUntil`. Wait for WebGPU sampling capacity and return `true` if sampling was queued; return `false` immediately with no sampling, on WebGL, or for only denoising, display or offline convergence work; submits no work; throws after disposal |
139
167
  | `converged` | `samples >= maxSamples`, independently of filtering |
140
168
  | `status` | Preparing, compiling, converging, denoising, finished or error |
141
169
  | `setDenoiser(options)` | Replace the denoiser configuration; resolves when the filter is ready |
@@ -149,6 +177,11 @@ completed filtering. Synchronous execution failures return `'error'` and set
149
177
  engine.lastError. Invalid lifecycle operations (disposed render or refine during
150
178
  converge) throw.
151
179
 
180
+ `refine(undefined, {batchSamples})` overrides batching for one call without
181
+ changing render settings or discarding samples; it defaults to the render's
182
+ `batchSamples`. The `targetBatchTimeMs` and `deferResolve` refine options are
183
+ deprecated; use `refineUntil`.
184
+
152
185
  A fallback gets one sample when the requested render cannot finish its first
153
186
  sample within budget and the fallback has no current complete image. A ready
154
187
  fallback is not traced again. Fallback chains and cycles are rejected.
@@ -172,6 +205,25 @@ Resolves `{samples, averageSamplesPerPixel, pilotSamples, adaptiveSampling,
172
205
  varianceHistory?}` after filtering. It rejects if engine input revisions change.
173
206
  The same render cannot refine concurrently; other renders remain usable.
174
207
 
208
+ ### Caustics
209
+
210
+ ```ts
211
+ render.caustics = {lightTracing: {photonsPerSample: 32768}};
212
+ render.caustics = undefined; // Disable every estimator.
213
+ ```
214
+
215
+ Changing any caustic option restarts accumulation. All estimators are experimental;
216
+ see the [caustics guide](./caustics.md) for choosing estimators, supported paths,
217
+ rendering cost and image-quality limitations.
218
+
219
+ | Option | Default | Meaning |
220
+ | --- | --- | --- |
221
+ | `lightTracing` | `false` | `true` or an object enables directly visible caustic light paths on WebGPU; ignored on WebGL 2 |
222
+ | `lightTracing.photonsPerSample` | pixel count / 4 | Emitted photons per sample, rounded to a positive integer and capped by the device dispatch limit |
223
+ | `photonMapping` | `false` | `true` or an object enables progressive caustic photon mapping on WebGPU; ignored on WebGL 2. See [PM-only denoising limits](./caustics.md#limits) |
224
+ | `photonMapping.photonsPerSample` | pixel count / 4, at most 262144 | Emitted photons per batch; 28 bytes each plus up to 13 MiB of overhead. Positive finite values are rounded to at least 1 and reduced to fit device limits and a 128 MiB batch budget; other values use the default |
225
+ | `photonMapping.initialRadius` | 3% of the caster bounding sphere radius | Positive first-batch gather radius in scene units, independent of `photonsPerSample`; shrinks as batches accumulate. Smaller radii preserve detail but require more photons |
226
+
175
227
  ## RenderLoop and Sync
176
228
 
177
229
  `start()` uses requestAnimationFrame when available and a 16 ms setTimeout
@@ -191,7 +243,8 @@ otherwise. Worker visibility and control forwarding are described in
191
243
  | `coalesceSceneUpdates` | false | Defer commits during preview inference, then commit latest camera/scene |
192
244
 
193
245
  `engine`, `display`, `preview` (possibly undefined) and `final` are read-only.
194
- `changing` defaults false; `samples` counts final only and reports 0 during preview; `status` starts preparing.
246
+ `changing` defaults false; `samples` counts final beauty samples and reports 0 during preview; `status` starts preparing.
247
+ An exception during a tick, such as from a sync, sets `status` to error and `lastError`; the next successful tick clears them.
195
248
  `select({changing})` defaults to changing ? preview : final. `addSync`/`removeSync`
196
249
  manage integrations without disposing them. `tick` executes a manual frame;
197
250
  `start`/`stop` manage animation frames. `converge` accepts the same options as
@@ -217,7 +270,7 @@ Use `engine.display`; creation of additional displays is outside this API.
217
270
  their next refine; fixed renders retain their dimensions.
218
271
  `present(render)` only presents: it returns the render or its ready fallback,
219
272
  or undefined without changing the canvas when neither is ready.
220
- `toBlob(render, {type?, quality?})` composes that render at its actual dimensions,
273
+ `toBlob(render, {type?, quality?})` composes that render at its output dimensions,
221
274
  without resizing or changing the current canvas. MIME defaults to image/png;
222
275
  quality defaults to the browser encoder value.
223
276
 
@@ -228,10 +281,16 @@ quality defaults to the browser encoder value.
228
281
  | `temperature`, `tint`, `vignette` | `0` |
229
282
  | `bloomIntensity`, `bloomThreshold`, `bloomRadius` | `0`, `1`, `0.6` |
230
283
  | `hdrOutputEnabled` | `false`; WebGPU only |
231
- | `channel: DisplayChannel` | `'final'`; also albedo, normal, shadow, shadowCatcher |
284
+ | `channel: DisplayChannel` | `'final'`; also albedo, normal, shadow, shadowCatcher and the seven [AOV kinds](#aov-visualization) |
285
+ | `aovDepthRange` | `[0, 10]`; finite scene-unit black/white depths, `0 <= near < far` |
286
+ | `aovPositionScale` | `1`; finite positive scene-unit half-range around the origin |
287
+ | `aovMotionScale` | `16`; finite positive pixel displacement for full brightness |
288
+ | `aovIdComponent: AovIdComponent` | `'object'`; also instance, material, primitive |
232
289
  | `shadowCatcherColor`, `shadowCatcherAlpha` | `[0, 0, 0]`, `1` |
233
290
 
234
291
  All display settings apply at composition and retain accumulated samples.
292
+ AOV mapping numbers must remain finite in float32; depth endpoints must remain
293
+ distinct after conversion.
235
294
  Use the exported `DisplaySettings` type for a partial batch:
236
295
 
237
296
  ```ts
@@ -259,9 +318,11 @@ semantics are documented in [Custom denoisers](./denoising.md#custom-denoisers).
259
318
 
260
319
  ### Pixel outputs
261
320
 
262
- `readPixels(kind = 'hdr')` returns `{ width, height, data: Float32Array }`,
263
- RGBA with the top row first. Dimensions describe the internal render texture,
264
- which WebGPU rounds up to multiples of 16. Before a pipeline exists, it returns an empty image.
321
+ `readPixels(kind = 'hdr')` returns `{ width, height, data }`. `data` is a
322
+ `Uint32Array` for `id` and a `Float32Array` for every other kind.
323
+ Pixels are RGBA with the top row first. Dimensions describe the internal render
324
+ texture, which WebGPU rounds up to multiples of 16. Before a pipeline exists,
325
+ beauty and OIDN-guide reads return an empty image; AOV reads reject.
265
326
 
266
327
  | Kind | Values |
267
328
  | --- | --- |
@@ -276,6 +337,120 @@ existing pipeline semantics. If no denoiser is attached or denoising has not
276
337
  completed, `denoised` returns `hdr` and warns once per render. The method
277
338
  makes a CPU copy and can be costly; avoid calling it every animation frame.
278
339
 
340
+ ### Surface outputs
341
+
342
+ Request only the surface outputs you need on each render:
343
+
344
+ ```ts
345
+ const render = new Render(engine, {
346
+ aovs: ['depth', 'position', 'id', 'motion'], aovSamples: 16
347
+ });
348
+ await render.converge({samples: 64});
349
+ const depth = await render.readPixels('depth'); // Float32Array, RGBA
350
+ const ids = await render.readPixels('id'); // Uint32Array, RGBA
351
+ ```
352
+
353
+ You can change `render.aovs` or `render.aovSamples` after sampling. Continue
354
+ calling `refine()` to regenerate AOVs for the current view; beauty samples and
355
+ completed denoising are preserved. AOV accumulation restarts when either changes.
356
+
357
+ | Kind | RGBA contents |
358
+ | --- | --- |
359
+ | `depth` | Camera-forward distance in scene units, 0, 0, coverage |
360
+ | `position` | World position xyz, coverage |
361
+ | `roughness` | Specular roughness, metalness, unsupported-reflectance fraction, coverage |
362
+ | `diffuseAlbedo` | Directional-hemispherical diffuse reflectance RGB, valid coverage |
363
+ | `specularAlbedo` | Directional-hemispherical specular reflectance RGB, valid coverage |
364
+ | `id` | Object, local instance (0 for ordinary meshes), material, source triangle index; background is `0xFFFFFFFF` in all channels |
365
+ | `motion` | Previous position minus current position in pixels, x right and y down; z = 0, alpha = 3 for valid history or 0 otherwise |
366
+
367
+ Depth, position, roughness and reflectance average independent jittered primary
368
+ rays, including depth of field, up to `min(samples, aovSamples)`. RGB values use
369
+ hit-count normalization; alpha is hit coverage over all AOV samples. Reflectance
370
+ uses only supported hits for both normalization and valid coverage. A blank pixel
371
+ is zero. These passes preserve beauty samples but do not sample the same paths.
372
+ Alpha holes use the first surface with alpha ≥ 0.5, skipping shadow catchers,
373
+ with at most 32 layers.
374
+
375
+ ID and motion use the unjittered pixel center without depth of field. `Mesh.aovId`
376
+ and `OpenPBRMaterial.aovId` default to process-unique integers. Explicit values
377
+ must be integers from 0 through `0xFFFFFFFE`, unique among the scene's objects
378
+ or materials respectively. Commit changes with `engine.update()`. Keep identities
379
+ stable and avoid reusing an ID for a different object while history is live.
380
+ Instance IDs are local indices; primitive IDs refer to the geometry's original
381
+ triangle order. A ray exactly on a shared edge can select either adjacent
382
+ triangle; host/GPU rounding can choose different IDs at that boundary.
383
+
384
+ Motion history belongs to each render and advances when it produces an AOV
385
+ frame. Camera pose and rigid object transforms can reproject across updates.
386
+ The first frame, changed dimensions or projection, missing identities, changed
387
+ topology or vertex positions, and failed visibility correspondence invalidate
388
+ motion. Device recovery also clears history. Deformed vertices have no motion
389
+ estimate; validity 0 must not be treated as a stationary surface.
390
+
391
+ Reflectance outputs are separate from the existing OIDN `albedo` guide.
392
+ Coat, fuzz, anisotropy, subsurface/volume scattering, bevel, thin film,
393
+ dispersion, partial alpha and nonstandard materials are unsupported by this
394
+ reflectance estimate. Such hits contribute to `roughness.b` and have zero
395
+ reflectance validity. Reflectance uses expensive BSDF quadrature; request it
396
+ only when needed.
397
+
398
+ Reading a kind absent from `render.aovs` rejects. A custom denoiser can request
399
+ its own [AOV inputs](./denoising.md#custom-denoisers). With neither request there
400
+ are no AOV allocations or passes. Enabling any kind costs about 128 GPU bytes
401
+ per pixel on WebGPU or 192 on WebGL, plus scene identity/history data; each
402
+ custom denoiser AOV snapshot adds 16 bytes per pixel. A render may retain one
403
+ reusable snapshot per kind between denoising calls. Readback adds a CPU copy.
404
+ WebGPU dimensions remain subject to device buffer limits. A full-frame AOV
405
+ sample runs independently of tile/adaptive sampling and may exceed the render's
406
+ time budget at large resolutions. WebGL requires `EXT_color_buffer_float`.
407
+
408
+ ### AOV visualization
409
+
410
+ Select an enabled surface output on Display to present or export it:
411
+
412
+ ```ts
413
+ engine.display.channel = 'depth'; // render.aovs must include 'depth'
414
+ engine.display.aovDepthRange = [0, 20];
415
+ engine.display.present(render);
416
+ const png = await engine.display.toBlob(render);
417
+ ```
418
+
419
+ | Channel | Display mapping |
420
+ | --- | --- |
421
+ | `depth` | Black at the near depth, white at the far depth, clamped outside the range |
422
+ | `position` | World xyz mapped to RGB; origin is 0.5 and ±position scale maps to 0/1 |
423
+ | `roughness` | RGB = roughness, metalness, unsupported-reflectance fraction |
424
+ | `diffuseAlbedo`, `specularAlbedo` | Linear reflectance RGB clamped to [0, 1], then sRGB encoded |
425
+ | `id` | Stable pseudocolor for the selected uint32 ID component; colors can collide |
426
+ | `motion` | Direction as hue (+x is red, +y is yellow-green), displacement/scale as brightness |
427
+
428
+ AOV channels bypass tone mapping, grading, bloom, vignette and denoising;
429
+ registered display passes still run. Background and invalid reflectance or
430
+ motion are transparent; accumulated outputs use their coverage as alpha. Zero valid motion
431
+ is opaque black. The first frame's invalid motion is transparent.
432
+ Selecting a kind absent from `render.aovs` rejects, even if a custom denoiser
433
+ requests it. An enabled output awaiting sampling keeps the current canvas;
434
+ export rejects until that output is ready. Display selection alone does not enable tracing.
435
+ Changing the channel or mapping preserves beauty samples, raw AOV values and completed denoising.
436
+ With `RenderLoop`, selecting an enabled AOV traces surface outputs without
437
+ advancing beauty or running a denoiser, including after camera or scene edits.
438
+ When viewing motion, the loop refreshes once inputs settle so stationary surfaces
439
+ return to black. Switching between preview and final first displays zero motion;
440
+ subsequent camera or object changes show motion from that view.
441
+ ID and motion need one center sample; other AOVs stop at the smaller of
442
+ `maxSamples` and `aovSamples`. Loop status can be `finished` while beauty
443
+ `samples` remains zero. Switching back to Final resumes beauty for the current
444
+ view. Direct `render.refine()` and `converge()` still trace beauty and requested
445
+ AOVs together. Use `render.refine(kind)` for a surface-only step and
446
+ `render.aovSamplesRendered` for its progress. The existing `normal` and `albedo` channels keep their OIDN-guide meaning.
447
+
448
+ These mappings also apply to PNG export. Raw `render.readPixels(kind)` retains
449
+ the [surface formats](#surface-outputs) above. WebGPU HDR presentation decodes
450
+ the mapped colors to linear light; the visualization stays within SDR white.
451
+ Visualization retains an extra 8 GPU bytes per render pixel on WebGPU or 4 on
452
+ WebGL until the AOV resources are resized or disposed.
453
+
279
454
  ### Depth sampling
280
455
 
281
456
  After rendering the current scene and camera, call
@@ -311,11 +486,12 @@ Public spatial values use `Vec2` (`[number, number] | Float32Array`), `Vec3` (`[
311
486
  | `Geometry`, `GeometryAttribute` | Triangle data: required `position`; optional `normal` and `indices` are generated at construction; `vertexCount` / `triangleCount` getters; optional `uv`, `uv1`, `tangent`, `color`, `materialIndex` (raw per-vertex indices, itemSize 1; all three corners of each triangle must match; invalid indices fall back to material 0 with one warning); `dynamic` (default `false`) for [deforming geometry](./updates.md#dynamic-geometry) |
312
487
  | `OpenPBRMaterial` | `new OpenPBRMaterial(params?)`; see [materials](./materials.md) |
313
488
  | `Texture` | HTMLImageElement, HTMLCanvasElement, ImageBitmap, OffscreenCanvas or `{ data, width, height }`; `colorSpace`: `'srgb'` or `'linear'`; default undefined uses sRGB for images/bytes and linear for `Float32Array`/`Int32Array`; independent `wrapS` / `wrapT`: `'repeat'` (default), `'clamp-to-edge'`, `'mirrored-repeat'`, applied after UV scale/offset for material textures |
489
+ | `ProceduralSky`, `ProceduralSkyOptions` | Clear-sky environment texture; [usage and options](#proceduralsky) |
314
490
  | `Camera` | `new Camera({ projection: 'perspective', ... })` or orthographic; `position`, `lookAt()`, `copy(source)`, `clone()`; aspect defaults to automatic; depth of field with `fStop`, `focusDistance`, `sensorHeight`, `metersPerUnit` ([details](./getting-started.md#depth-of-field)) |
315
491
  | `RectLight`, `SphereLight`, `SpotLight`, `DirectionalLight`, `EnvironmentLight`, `AmbientLight` | Parameter-object constructors; analytic lights use `transform`, `position`, `lookAt()` and rigid axes. See [lights](./getting-started.md#lights) |
316
492
  | `EnvironmentLight` | `new EnvironmentLight({map, intensity?})`; `intensity` defaults to `1`, scales environment radiance, and accepts `0` to disable lighting. Ambient lights and explicit background textures retain their own brightness. `transform` rotates the environment from local to world space (identity by default); translation and positive axis scale are ignored. An explicit background texture keeps its own orientation |
317
493
  | `IESProfile`, `parseIESProfile(text)` | Photometric profiles for `SpotLight` |
318
- | `SceneBackground` | `[r, g, b, a]`, `Texture` or `GroundedSkyboxBackground`; grounded backgrounds accept `rotation` around +Y in radians (default `0`) and `intensity` (default `1`). These affect only the background; the ground stays level and alpha is preserved |
494
+ | `SceneBackground` | `[r, g, b, a]`, `Texture`, `EquirectBackground` (`{type: 'Equirect', map, transform?, intensity?}`) or `GroundedSkyboxBackground`. Equirect `transform`: column-major map-to-world rotation (default identity); translation and positive axis scale are ignored. Grounded `rotation`: radians around +Y (default `0`). `intensity` on either: nonnegative RGB multiplier, default `1`. These affect only the background; ground stays level and alpha is preserved |
319
495
 
320
496
  `OpenPBRMaterial` accepts canonical `specularRoughnessAnisotropy` (default `0`),
321
497
  `coatRoughnessAnisotropy` (`0`), `subsurfaceScatterAnisotropy` (`0`),
@@ -362,6 +538,39 @@ and `markUpdated(): this`. `Geometry` also has the read-only `topologyVersion`
362
538
  (initially `0`) and `markVerticesUpdated(): this`, which advances only
363
539
  `version`. See [scene updates](./updates.md) for when to call each.
364
540
 
541
+ ### ProceduralSky
542
+
543
+ Use the sky as an environment map, an explicit background, or the map of a
544
+ `GroundedSkyboxBackground`:
545
+
546
+ ```ts
547
+ import { ProceduralSky, EnvironmentLight } from '@meimu/mutracer';
548
+
549
+ const sky = new ProceduralSky({ resolution: [2048, 1024], time: 15 });
550
+ scene.lights.push(new EnvironmentLight({ map: sky }));
551
+ // With no explicit scene.background, the environment is also the background.
552
+ sky.time = 9;
553
+ engine.update();
554
+ ```
555
+
556
+ | Option / property | Default | Behavior |
557
+ | --- | --- | --- |
558
+ | `resolution` | `[2048, 1024]` | Positive integer equirectangular width and height; assign a new pair to resize |
559
+ | `time` | `15` | Local solar time in hours, from `0` to `24`, for an equinox at latitude 40° |
560
+
561
+ Time and resolution assignments follow the normal [scene update rules](./updates.md).
562
+ Use `EnvironmentLight.intensity` and `transform` for brightness and rotation.
563
+ With Three.js, pass the sky as the `environment` option to `THREESync` or
564
+ `fromTHREEScene`; the Three.js scene still supplies intensity and rotation.
565
+
566
+ Higher resolutions use more memory and can exceed device limits. Frequent
567
+ time edits can be slower with WebGL 2. Dispose the engine when finished;
568
+ `ProceduralSky` needs no separate disposal.
569
+
570
+ This is a clear atmosphere without clouds, stars, moonlight or artificial
571
+ light. Very low resolutions can blur or miss the small sun disk. Use the sky
572
+ for environments and backgrounds, not material texture slots.
573
+
365
574
  ## Helpers
366
575
 
367
576
  | Export | Description |
@@ -373,7 +582,7 @@ and `markUpdated(): this`. `Geometry` also has the read-only `topologyVersion`
373
582
  | `THREESync` | Keeps a `THREE.Scene` in sync: `new THREESync(engine, {scene?, camera?, controls?, updateControls?})`; RenderLoop calls update; dispose when done; conversion hooks `convertMaterial` / `convertLight`; see [Three.js](./threejs.md#custom-conversion) |
374
583
  | `fromTHREECamera(camera, options?)` | Converts a Three.js camera; one-shot conversion; THREESync retains and updates cameras. Reads `focus` and the film height; `FromTHREECameraOptions` sets `fStop` (default `0`), `focusDistance` and `metersPerUnit` (default `1`) |
375
584
  | `fromTHREEScene` | One-shot Three.js scene conversion with FromTHREESceneOptions conversion hooks; every call reruns hooks and creates fresh default objects |
376
- | `FromTHREESceneOptions` | Optional `onMeshConverted(mesh, source, group, groupIndex)` callback; default: none |
585
+ | `FromTHREESceneOptions` | Optional `environment` overrides the Three.js environment with a MuTracer `Texture` or `ProceduralSky` (default undefined); optional `onMeshConverted(mesh, source, group, groupIndex)` callback; default: none |
377
586
  | `VERSION` | Library version |
378
587
 
379
588
  `@meimu/mutracer/oidn` exports weight constants (`OIDN_MODEL_FILENAMES`,
@@ -390,7 +599,9 @@ see [denoising](./denoising.md#custom-oidn-networks). The main entry exports
390
599
 
391
600
  `render.getOutputTexture(kind)` borrows native HDR or the latest display image;
392
601
  `display.addPostProcess(pass)` returns unregister and runs on every present/export.
393
- Both are WebGPU-only. See [formats, lifecycle and overlay example](./post-processing.md).
602
+ Both are WebGPU-only. Textures are rounded up to multiples of 16 pixels, so a
603
+ fixed render's texture can include extra pixels around the requested image. See
604
+ [formats, lifecycle and overlay example](./post-processing.md).
394
605
 
395
606
  Anisotropy direction options: `anisotropyMap` (default `undefined`) reads linear RG as a tangent direction and B as a multiplier for base specular strength. `specularAnisotropyRotation` (default `0`) rotates that direction counter-clockwise in radians; `coatAnisotropyRotation` (default `0`) rotates the coat relative to the geometry tangent. See [materials](./materials.md#anisotropy-directions) for frame and fallback conventions.
396
607
 
@@ -0,0 +1,80 @@
1
+ # Caustics
2
+
3
+ Enable caustics on the render that needs them:
4
+
5
+ ```ts
6
+ render.caustics = {lightTracing: true, photonMapping: true};
7
+ ```
8
+
9
+ Choose the estimators for the visible receiver:
10
+
11
+ | Scene | Settings |
12
+ | --- | --- |
13
+ | Glass or metal casting onto a directly visible surface | `{lightTracing: true}` |
14
+ | Water or glass between the camera and the caustic receiver | `{photonMapping: true}` |
15
+ | A mixture of direct, indirect and glass-covered receivers | `{lightTracing: true, photonMapping: true}` |
16
+
17
+ Light tracing preserves narrow, directly visible caustics without a gather
18
+ radius. Photon mapping covers indirect caustics and surfaces seen through glass,
19
+ with additional memory and gather cost. Combined estimators assign path coverage
20
+ automatically. The viewer's Cornell caustic preset enables both estimators.
21
+
22
+ Set `render.caustics = undefined` to disable every estimator. See
23
+ [API options and defaults](./api.md#caustics).
24
+
25
+ ## Options and cost
26
+
27
+ ```ts
28
+ render.caustics = {
29
+ lightTracing: {photonsPerSample: 32768},
30
+ photonMapping: {photonsPerSample: 32768, initialRadius: 0.1}
31
+ };
32
+ ```
33
+
34
+ Both estimators require WebGPU; WebGL ignores those options. HDR readback,
35
+ display and denoising include the combined result. Changes to any option restart
36
+ accumulation. The native SDK provides the same choices through Rust
37
+ `CausticSettings` and the C `MT_CAUSTIC_*` flags.
38
+
39
+ More emitted photons can reduce noise but cost more time and memory. Photon-map
40
+ storage adds 28 bytes per emitted photon plus up to 13 MiB of overhead. Requests
41
+ above the device limits or the 128 MiB batch budget use fewer photons. Photon
42
+ batches cover the full image even when path tracing uses tiles or adaptive
43
+ sampling. Their time counts toward the frame budget, but adaptive variance measures
44
+ only the path-traced component.
45
+
46
+ ## Limits
47
+
48
+ Light tracing follows surfaces with no diffuse, subsurface, fuzz or coat
49
+ contribution and specular roughness at most 0.1. It supports emissive triangles,
50
+ rectangles, spheres, spotlights, directional lights and environment lighting,
51
+ perspective and orthographic cameras, depth of field and dispersion. Photon
52
+ mapping adds caustics throughout the allowed camera path. Volume scattering
53
+ events and shadow catchers remain with ordinary path tracing.
54
+
55
+ Complete caustic light-to-camera paths can be longer than `bounces`. Align total
56
+ path-length limits when comparing radiance with another renderer.
57
+
58
+ Photon mapping starts blurred and shrinks its radius as samples accumulate. A
59
+ small initial radius can be noisy; a large one can blur nearby surfaces and details.
60
+ Distant smooth casters enlarge the automatic radius, so set `initialRadius` if deep
61
+ caustics look too blurred. At the first diffuse surface, the gather radius is capped
62
+ to about two projected pixels to reduce patches after denoising; reflections and
63
+ refractions use an approximate footprint. More photons can help, but not every
64
+ batch improves the image, and more samples do not remove the precision loss in
65
+ stored photon data.
66
+
67
+ With photon mapping alone, directly visible receivers can show fewer cloud-like
68
+ OIDN blotches but grainier raw images. Receivers seen through reflection or
69
+ refraction can still show blotches. Enable light tracing as well for the cleanest
70
+ directly visible receivers.
71
+
72
+ A denoiser can soften narrow caustic lines, so compare raw HDR with denoised output
73
+ when judging detail. Use raw HDR for energy comparisons: displayed or denoised
74
+ brightness can differ even when regional HDR energy agrees.
75
+
76
+ Both estimators fall back to path tracing for the whole scene when a smooth caster
77
+ uses stochastic blend coverage. Cutout coverage remains supported. Environment
78
+ caustics follow path tracing's visible-background behavior through the first smooth
79
+ transmission; an explicit black background suppresses that contribution.
80
+ Quantitative energy agreement with other renderers is not guaranteed.
package/docs/denoising.md CHANGED
@@ -6,7 +6,7 @@ albedo and normal guides.
6
6
  - **JNLM**: a built-in joint non-local means filter, on WebGPU and
7
7
  WebGL 2. It needs no weight download.
8
8
  - **OIDN**: [Intel Open Image Denoise](https://www.openimagedenoise.org/)
9
- networks, run through [`oidn-web`](https://www.npmjs.com/package/oidn-web),
9
+ networks, run through [`oidn-webgpu`](https://github.com/pissang/oidn-webgpu),
10
10
  WebGPU only. They take longer and need weights, but are cleaner at one or
11
11
  two samples per pixel, for example for denoising while the camera moves.
12
12
 
@@ -17,16 +17,17 @@ final.setDenoiser({type: 'oidn', model: 'standard'});
17
17
  final.setDenoiser(null); // disable
18
18
  ```
19
19
 
20
- `type` is required: use `jnlm` or `oidn`. `render.denoiser` returns a frozen
21
- copy of the configuration; call `setDenoiser` again to change it. Unknown types,
20
+ `type` is required: use `jnlm`, `oidn`, or a [custom denoiser](#custom-denoisers).
21
+ `render.denoiser` returns a frozen copy of the configuration; call `setDenoiser`
22
+ again to change it. Unknown types,
22
23
  foreign fields and invalid JNLM settings throw synchronously, preserving the
23
- active network and output. Equal implementation settings share the network;
24
+ active filter and output. Equal built-in settings reuse the loaded network;
24
25
  changing only `schedule` preserves active inference, and passing an identical
25
26
  configuration does nothing.
26
27
  Each render has its own configuration and scheduling. Converge waits for its
27
28
  configured filter; intermediate progressive inference reports converging and
28
- final inference reports denoising. Engine caches equal network configurations
29
- and weights, releasing the network after its last render lease is released.
29
+ final inference reports denoising. Built-in networks and weights are shared
30
+ within an engine and released when no render uses them.
30
31
 
31
32
  `setDenoiser` returns a promise that resolves when the filter is ready, which
32
33
  for OIDN means its weights have loaded, and rejects when loading fails. A
@@ -67,7 +68,7 @@ network prewarm results are discarded.
67
68
  | `model` | OIDN network: `'standard'` (default), `'small'` or `'cleanAuxLarge'` |
68
69
  | `weightsBaseUrl` | Directory containing the OIDN `.tza` files |
69
70
  | `schedule` | `'converged'` (default), `'progressive'`, or `'every-sample'` |
70
- | `maxTileSize` | Maximum OIDN tile size; chosen by oidn-web by default |
71
+ | `maxTileSize` | Maximum output tile edge in pixels; default `512` |
71
72
  | `signal` | `AbortSignal` for the OIDN weight download; default undefined |
72
73
  | `weightsUrl` | Explicit custom network; mutually exclusive with model/base directory |
73
74
  | `aux`, `hdr`, `hdrTransfer` | Custom network metadata only; defaults true, true, `'pu'` |
@@ -112,8 +113,11 @@ preview.setDenoiser({type: 'oidn', model: 'small', schedule: 'every-sample'});
112
113
  ```
113
114
 
114
115
  Converged filters the final sample budget. Progressive filters sample 1,
115
- then 4, 8, 16, … and the final budget, with a ten-second limit between
116
- updates. Every-sample filters every complete sample of its render. Coalescing
116
+ then the first count that is at least double the previous update (and at
117
+ least 4) and comes 500 ms or more after it, and finally the sample budget.
118
+ Updates come at least every ten seconds. With [sample batching](./progressive-rendering.md#sample-batching),
119
+ counts grow faster, so the 500 ms floor skips intermediate doublings.
120
+ Every-sample filters every complete sample of its render. Coalescing
117
121
  continuous scene/camera edits is application loop policy; the engine accepts
118
122
  edits only when update is called. See [progressive rendering](./progressive-rendering.md).
119
123
 
@@ -175,7 +179,7 @@ experimental WebNN path. `precision` defaults to `'auto'` (FP16 when
175
179
  shader-f16 is available), with `'fp32'` and `'fp16'` overrides. `dynamicTile`
176
180
  defaults to `true`; use `false` for fixed tiles or an object with
177
181
  `minTileSize` (256), `initialTileSize` (432), `targetTileTimeMs` (16) and
178
- `adjustmentStep` (16). Tile sizes are clamped/aligned by oidn-web.
182
+ `adjustmentStep` (16).
179
183
 
180
184
  All implementation settings participate in the network cache key; `schedule`
181
185
  and download `signal` do not. Renders with different signals share a pending
@@ -204,7 +208,10 @@ const copy: Denoiser = {
204
208
  device.queue.submit([encoder.finish()]);
205
209
  }
206
210
  };
207
- final.setDenoiser({type: 'custom', denoiser: copy, schedule: 'converged'});
211
+ final.setDenoiser({
212
+ type: 'custom', denoiser: copy, schedule: 'converged',
213
+ aovs: ['depth', 'motion']
214
+ });
208
215
  ```
209
216
 
210
217
  The required `type` and `denoiser` choose this branch; `schedule` defaults to
@@ -219,13 +226,21 @@ render sizes is prepared again. `DenoiseInput` contains these buffers:
219
226
  | `albedo` | Linear RGB albedo averaged over complete samples; alpha is primary-hit coverage |
220
227
  | `normal` | Resolved world-space normal averaged and encoded as `normal*.5+.5`, without renormalization; alpha 1 for valid surface data, otherwise zero RGBA |
221
228
  | `output` | Write all linear HDR RGB; output alpha is ignored and the input path coverage is preserved |
229
+ | `aovs` | Optional map of the requested surface-output buffers, such as `input.aovs?.depth`; absent by default |
222
230
 
223
- All four are tightly packed RGBA float32, top row first, exactly
224
- `width * height * 16` bytes, with STORAGE, COPY_SRC and COPY_DST usages.
231
+ Color, albedo, normal and output are tightly packed RGBA float32, top row first,
232
+ exactly `width * height * 16` bytes, with STORAGE, COPY_SRC and COPY_DST usages.
225
233
  Dimensions describe the actual internal image (WebGPU rounds up to 16).
234
+ `CustomDenoiserOptions.aovs` defaults to `[]`. Requests enable the corresponding
235
+ passes automatically; `render.aovs` is needed only for direct pixel readback.
236
+ Each AOV buffer is top row first, exactly `width * height * 16` bytes: `id` is
237
+ RGBA uint32 and the others RGBA float32. Values, validity and sampling limits
238
+ follow [surface outputs](./api.md#surface-outputs). These are immutable snapshots
239
+ of this invocation and cost 16 additional GPU bytes per pixel per requested kind.
240
+
226
241
  Input buffers are read-only. Buffers are borrowed until the promise settles;
227
- do not retain or destroy them. Resolve after submitting every output write;
228
- MuTracer copies the result, waits for GPU work, then releases its queue lease.
242
+ do not retain or destroy them. Resolve after submitting every output write.
243
+
229
244
  Custom `readPixels('denoised')` returns the filtered native HDR ray color,
230
245
  with input path coverage. Display settings then follow the ordinary compose
231
246
  path: flat backgrounds retain their display-space treatment and catcher
package/docs/materials.md CHANGED
@@ -97,10 +97,11 @@ the substrate through the attenuation term.
97
97
  **Interior media.** Transmission describes a homogeneous volume:
98
98
  `transmissionColor` is the color that survives one `transmissionDepth`, and
99
99
  `transmissionScatter` is the scattering albedo. With `transmissionDepth = 0`
100
- the tint is applied at the surface. Subsurface is a separate layer driven by its
101
- color and per-channel radius. When both are active, their coefficients combine
102
- into one volume. Dispersion (`transmissionDispersionScale > 0`) samples
103
- wavelengths spectrally.
100
+ the tint is applied at the surface. Subsurface has its own color and per-channel
101
+ radius. A positive `transmissionDispersionScale` enables
102
+ wavelength-dependent refraction; values above `1` increase color separation,
103
+ and `0` disables it. Lower `transmissionDispersionAbbeNumber` values also
104
+ increase color separation.
104
105
 
105
106
  ## Compatibility names
106
107
 
@@ -186,7 +187,7 @@ selects `blend`. With none of these inputs, `auto` selects `opaque`.
186
187
 
187
188
  | Property | Description |
188
189
  | --- | --- |
189
- | `shadowCatcher` | Invisible ground that only receives shadows; composite over a transparent background |
190
+ | `shadowCatcher` | Invisible ground that only receives shadows of the environment and analytic lights, not of emissive meshes; composite over a transparent background |
190
191
  | `unlit` | Shows emission without scattering or lighting other surfaces |
191
192
  | `bevelSize` | Rounded-edge shading radius in scene units; `0` disables (see below) |
192
193
 
@@ -18,8 +18,11 @@ A tuning checklist. Each item links to the page with the details.
18
18
  - Use a preview Render with cheaper quality and optional adaptiveResolution:
19
19
  `{targetFrameMs: 20, minScale: .25}`, plus resolutionScale .5. Choose it during
20
20
  motion and configure final.fallback once; see [progressive rendering](./progressive-rendering.md).
21
- - timeBudgetMs (default 21) bounds each render's tile cost. Raise it for exports.
22
- - allowMultipleSamplesPerFrame adds several samples per refine when time permits.
21
+ - `timeBudgetMs` (default 21) targets each render's tile cost. Raise it for exports.
22
+ - `batchSamples` lets a still render use the whole GPU instead of one sample per
23
+ display frame; enable it with `RenderLoop({final: {batchSamples: true}})`. In your
24
+ own loop, a larger `timeBudgetMs` batches more per call but delays the first
25
+ preview after an edit. See [sample batching](./progressive-rendering.md#sample-batching).
23
26
  - For exports, `render.converge` with `targetBatchTimeMs` adapts batch sizes
24
27
  to the GPU; omit `previewIntervalMs` for maximum throughput.
25
28