@meimu/mutracer 0.2.0 → 0.3.1

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 (372) hide show
  1. package/CHANGELOG.md +222 -0
  2. package/LICENSES/FidelityFX-FSR.txt +19 -0
  3. package/LICENSES/pbrt-v4-Apache-2.0.txt +202 -0
  4. package/README.md +3 -0
  5. package/THIRD_PARTY_NOTICES.md +18 -4
  6. package/dist/assets/bvh.worker.js +1 -1
  7. package/dist/mutracer.umd.js +9328 -7614
  8. package/docs/api.md +83 -35
  9. package/docs/caustics.md +80 -0
  10. package/docs/materials.md +9 -6
  11. package/docs/performance.md +7 -0
  12. package/docs/post-processing.md +62 -9
  13. package/docs/progressive-rendering.md +53 -9
  14. package/docs/sampling.md +4 -0
  15. package/docs/technical/acceleration.md +52 -0
  16. package/docs/technical/aovs.md +79 -0
  17. package/docs/technical/caustics.md +109 -0
  18. package/docs/technical/continuous-spectrum.md +122 -0
  19. package/docs/technical/display-upscale.md +82 -0
  20. package/docs/technical/openpbr.md +99 -0
  21. package/docs/technical/pbrt-import.md +168 -0
  22. package/docs/technical/tiling.md +74 -0
  23. package/docs/technical/webgl.md +53 -0
  24. package/docs/updates.md +3 -1
  25. package/docs/viewer-checklist.md +65 -0
  26. package/docs/viewer.md +18 -6
  27. package/lib/Display.d.ts +19 -5
  28. package/lib/Display.js +10 -7
  29. package/lib/Display.js.map +1 -1
  30. package/lib/Engine.d.ts +4 -1
  31. package/lib/Engine.js +77 -14
  32. package/lib/Engine.js.map +1 -1
  33. package/lib/Render.d.ts +81 -24
  34. package/lib/Render.js +201 -26
  35. package/lib/Render.js.map +1 -1
  36. package/lib/RenderLoop.d.ts +7 -3
  37. package/lib/RenderLoop.js +68 -44
  38. package/lib/RenderLoop.js.map +1 -1
  39. package/lib/main.d.ts +4 -2
  40. package/lib/main.js +1 -0
  41. package/lib/main.js.map +1 -1
  42. package/lib/oidn.d.ts +1 -1
  43. package/lib/renderer/AovPrimitiveCache.js +39 -8
  44. package/lib/renderer/AovPrimitiveCache.js.map +1 -1
  45. package/lib/renderer/DisplayPostProcess.d.ts +8 -3
  46. package/lib/renderer/DisplayPostProcess.js +51 -18
  47. package/lib/renderer/DisplayPostProcess.js.map +1 -1
  48. package/lib/renderer/GPUTraceQueue.d.ts +2 -1
  49. package/lib/renderer/GPUTraceQueue.js +3 -1
  50. package/lib/renderer/GPUTraceQueue.js.map +1 -1
  51. package/lib/renderer/MaterialData.js +7 -2
  52. package/lib/renderer/MaterialData.js.map +1 -1
  53. package/lib/renderer/RenderingPipeline.d.ts +11 -1
  54. package/lib/renderer/RenderingPipeline.js.map +1 -1
  55. package/lib/renderer/TileRender.d.ts +2 -2
  56. package/lib/renderer/TileRender.js +128 -7
  57. package/lib/renderer/TileRender.js.map +1 -1
  58. package/lib/renderer/WGPUAov.d.ts +6 -1
  59. package/lib/renderer/WGPUAov.js +108 -14
  60. package/lib/renderer/WGPUAov.js.map +1 -1
  61. package/lib/renderer/WGPUCanvasSurface.js +12 -1
  62. package/lib/renderer/WGPUCanvasSurface.js.map +1 -1
  63. package/lib/renderer/WGPUCausticLightPass.d.ts +48 -0
  64. package/lib/renderer/WGPUCausticLightPass.js +217 -0
  65. package/lib/renderer/WGPUCausticLightPass.js.map +1 -0
  66. package/lib/renderer/WGPUEnvMapDistribution.js +19 -19
  67. package/lib/renderer/WGPUFullQuadPass.js +3 -3
  68. package/lib/renderer/WGPUPhotonMap.d.ts +37 -0
  69. package/lib/renderer/WGPUPhotonMap.js +191 -0
  70. package/lib/renderer/WGPUPhotonMap.js.map +1 -0
  71. package/lib/renderer/WGPURayTraceOutput.d.ts +13 -1
  72. package/lib/renderer/WGPURayTraceOutput.js +122 -28
  73. package/lib/renderer/WGPURayTraceOutput.js.map +1 -1
  74. package/lib/renderer/WGPURayTracePass.d.ts +65 -21
  75. package/lib/renderer/WGPURayTracePass.js +730 -409
  76. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  77. package/lib/renderer/WGPURenderingPipeline.js +110 -68
  78. package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
  79. package/lib/renderer/WebGLAov.js +3 -3
  80. package/lib/renderer/WebGLAov.js.map +1 -1
  81. package/lib/renderer/WebGLFullQuadPass.d.ts +2 -1
  82. package/lib/renderer/WebGLFullQuadPass.js +10 -0
  83. package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
  84. package/lib/renderer/WebGLJNLMDenoiser.js +66 -66
  85. package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -1
  86. package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
  87. package/lib/renderer/WebGLRayTracePass.d.ts +20 -11
  88. package/lib/renderer/WebGLRayTracePass.js +157 -116
  89. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  90. package/lib/renderer/WebGLRenderingPipeline.js +17 -14
  91. package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
  92. package/lib/renderer/WebGLSkyBaker.js +60 -60
  93. package/lib/renderer/accumulationTarget.d.ts +2 -1
  94. package/lib/renderer/accumulationTarget.js.map +1 -1
  95. package/lib/renderer/aov.d.ts +13 -1
  96. package/lib/renderer/aov.js +21 -2
  97. package/lib/renderer/aov.js.map +1 -1
  98. package/lib/renderer/aovDisplay.js +2 -2
  99. package/lib/renderer/aovDisplay.js.map +1 -1
  100. package/lib/renderer/binnedSahBvh.d.ts +2 -1
  101. package/lib/renderer/binnedSahBvh.js +24 -17
  102. package/lib/renderer/binnedSahBvh.js.map +1 -1
  103. package/lib/renderer/bvhAccel.d.ts +3 -1
  104. package/lib/renderer/bvhAccel.js +36 -6
  105. package/lib/renderer/bvhAccel.js.map +1 -1
  106. package/lib/renderer/cameraUniform.d.ts +1 -1
  107. package/lib/renderer/cameraUniform.js +6 -2
  108. package/lib/renderer/cameraUniform.js.map +1 -1
  109. package/lib/renderer/causticDiagnostics.d.ts +31 -0
  110. package/lib/renderer/causticDiagnostics.js +5 -0
  111. package/lib/renderer/causticDiagnostics.js.map +1 -0
  112. package/lib/renderer/causticEmission.d.ts +10 -0
  113. package/lib/renderer/causticEmission.js +40 -0
  114. package/lib/renderer/causticEmission.js.map +1 -0
  115. package/lib/renderer/causticUniform.d.ts +12 -0
  116. package/lib/renderer/causticUniform.js +22 -0
  117. package/lib/renderer/causticUniform.js.map +1 -0
  118. package/lib/renderer/caustics.d.ts +16 -0
  119. package/lib/renderer/caustics.js +93 -0
  120. package/lib/renderer/caustics.js.map +1 -0
  121. package/lib/renderer/compactVertices.d.ts +14 -0
  122. package/lib/renderer/compactVertices.js +124 -0
  123. package/lib/renderer/compactVertices.js.map +1 -0
  124. package/lib/renderer/easu.d.ts +11 -0
  125. package/lib/renderer/easu.js +156 -0
  126. package/lib/renderer/easu.js.map +1 -0
  127. package/lib/renderer/geometryUpdateState.d.ts +1 -0
  128. package/lib/renderer/geometryUpdateState.js.map +1 -1
  129. package/lib/renderer/geometryUpdates.js +3 -2
  130. package/lib/renderer/geometryUpdates.js.map +1 -1
  131. package/lib/renderer/glsl/aovDisplay.frag.js +5 -5
  132. package/lib/renderer/glsl/aovReflectance.glsl.js +53 -53
  133. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +1 -1
  134. package/lib/renderer/glsl/aovTrace.frag.js +45 -37
  135. package/lib/renderer/glsl/aovTrace.frag.js.map +1 -1
  136. package/lib/renderer/glsl/chunks/cameraProjection.glsl.d.ts +2 -0
  137. package/lib/renderer/glsl/chunks/cameraProjection.glsl.js +16 -0
  138. package/lib/renderer/glsl/chunks/cameraProjection.glsl.js.map +1 -0
  139. package/lib/renderer/glsl/chunks/cameraRay.glsl.d.ts +1 -1
  140. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +9 -16
  141. package/lib/renderer/glsl/chunks/cameraRay.glsl.js.map +1 -1
  142. package/lib/renderer/glsl/chunks/emissiveLight.glsl.d.ts +2 -0
  143. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +35 -0
  144. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js.map +1 -0
  145. package/lib/renderer/glsl/chunks/envMap.glsl.js +73 -73
  146. package/lib/renderer/glsl/chunks/intersect.glsl.js +478 -465
  147. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
  148. package/lib/renderer/glsl/chunks/materialBuffer.glsl.d.ts +1 -0
  149. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +156 -153
  150. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
  151. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +771 -771
  152. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  153. package/lib/renderer/glsl/chunks/random.glsl.js +6 -6
  154. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.d.ts +1 -0
  155. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +70 -63
  156. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  157. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +89 -75
  158. package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
  159. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -0
  160. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +160 -118
  161. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
  162. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +14 -14
  163. package/lib/renderer/glsl/chunks/sampling.glsl.js +88 -91
  164. package/lib/renderer/glsl/chunks/sampling.glsl.js.map +1 -1
  165. package/lib/renderer/glsl/chunks/sobol.glsl.js +79 -79
  166. package/lib/renderer/glsl/chunks/spectralPrefix.glsl.d.ts +6 -0
  167. package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js +47 -0
  168. package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js.map +1 -0
  169. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  170. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
  171. package/lib/renderer/glsl/depthQuery.frag.js +13 -7
  172. package/lib/renderer/glsl/depthQuery.frag.js.map +1 -1
  173. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +10 -10
  174. package/lib/renderer/glsl/rayTrace.frag.d.ts +1 -1
  175. package/lib/renderer/glsl/rayTrace.frag.js +338 -252
  176. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
  177. package/lib/renderer/glsl/shadowCatcher.frag.js +27 -26
  178. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  179. package/lib/renderer/glsl/webglPipeline.frag.js +59 -59
  180. package/lib/renderer/gpuMemory.js +1 -1
  181. package/lib/renderer/gpuMemory.js.map +1 -1
  182. package/lib/renderer/lightSampling.d.ts +3 -2
  183. package/lib/renderer/lightSampling.js +14 -8
  184. package/lib/renderer/lightSampling.js.map +1 -1
  185. package/lib/renderer/openPbrEnergyLut.d.ts +2 -1
  186. package/lib/renderer/openPbrEnergyLut.js +18 -1
  187. package/lib/renderer/openPbrEnergyLut.js.map +1 -1
  188. package/lib/renderer/pathLimits.d.ts +5 -4
  189. package/lib/renderer/pathLimits.js +6 -5
  190. package/lib/renderer/pathLimits.js.map +1 -1
  191. package/lib/renderer/prepareMeshBVH.d.ts +2 -0
  192. package/lib/renderer/prepareMeshBVH.js +5 -3
  193. package/lib/renderer/prepareMeshBVH.js.map +1 -1
  194. package/lib/renderer/progressiveScheduler.js +5 -4
  195. package/lib/renderer/progressiveScheduler.js.map +1 -1
  196. package/lib/renderer/renderPipeline.d.ts +5 -0
  197. package/lib/renderer/renderPipeline.js +1 -0
  198. package/lib/renderer/renderPipeline.js.map +1 -1
  199. package/lib/renderer/researchTransport.d.ts +31 -0
  200. package/lib/renderer/researchTransport.js +5 -0
  201. package/lib/renderer/researchTransport.js.map +1 -0
  202. package/lib/renderer/sceneAssembly.d.ts +1 -1
  203. package/lib/renderer/sceneAssembly.js +4 -3
  204. package/lib/renderer/sceneAssembly.js.map +1 -1
  205. package/lib/renderer/sceneChangeDetector.d.ts +1 -1
  206. package/lib/renderer/sceneChangeDetector.js +3 -1
  207. package/lib/renderer/sceneChangeDetector.js.map +1 -1
  208. package/lib/renderer/sceneLayoutSchema.d.ts +2 -0
  209. package/lib/renderer/sceneLayoutSchema.js +3 -3
  210. package/lib/renderer/sceneLayoutSchema.js.map +1 -1
  211. package/lib/renderer/scenePreparation.d.ts +3 -2
  212. package/lib/renderer/scenePreparation.js +18 -2
  213. package/lib/renderer/scenePreparation.js.map +1 -1
  214. package/lib/renderer/scratchSampling.js +6 -6
  215. package/lib/renderer/spectrum.d.ts +21 -0
  216. package/lib/renderer/spectrum.js +154 -0
  217. package/lib/renderer/spectrum.js.map +1 -0
  218. package/lib/renderer/staticBvhPreparation.d.ts +9 -0
  219. package/lib/renderer/staticBvhPreparation.js +8 -2
  220. package/lib/renderer/staticBvhPreparation.js.map +1 -1
  221. package/lib/renderer/surfaceHit.d.ts +10 -0
  222. package/lib/renderer/surfaceHit.js +22 -0
  223. package/lib/renderer/surfaceHit.js.map +1 -0
  224. package/lib/renderer/tangentRequirements.d.ts +2 -0
  225. package/lib/renderer/tangentRequirements.js +7 -0
  226. package/lib/renderer/tangentRequirements.js.map +1 -0
  227. package/lib/renderer/textureAtlas.d.ts +4 -0
  228. package/lib/renderer/textureAtlas.js +48 -2
  229. package/lib/renderer/textureAtlas.js.map +1 -1
  230. package/lib/renderer/webgl.js +4 -0
  231. package/lib/renderer/webgl.js.map +1 -1
  232. package/lib/renderer/webglLightSampling.d.ts +39 -0
  233. package/lib/renderer/webglLightSampling.js +15 -0
  234. package/lib/renderer/webglLightSampling.js.map +1 -0
  235. package/lib/renderer/webglVertexAttributes.d.ts +17 -0
  236. package/lib/renderer/webglVertexAttributes.js +44 -0
  237. package/lib/renderer/webglVertexAttributes.js.map +1 -0
  238. package/lib/renderer/wgpuBindlessSource.js +3 -3
  239. package/lib/renderer/wgpuMaterialConstants.js +4 -3
  240. package/lib/renderer/wgpuMaterialConstants.js.map +1 -1
  241. package/lib/renderer/wgpuSceneUniform.js +2 -2
  242. package/lib/renderer/wgpuSceneUniform.js.map +1 -1
  243. package/lib/renderer/wgpuShaderSource.d.ts +22 -0
  244. package/lib/renderer/wgpuShaderSource.js +3 -1
  245. package/lib/renderer/wgpuShaderSource.js.map +1 -1
  246. package/lib/renderer/wgsl/aovCompact.wgsl.d.ts +4 -0
  247. package/lib/renderer/wgsl/aovCompact.wgsl.js +26 -0
  248. package/lib/renderer/wgsl/aovCompact.wgsl.js.map +1 -0
  249. package/lib/renderer/wgsl/aovDisplay.wgsl.js +9 -9
  250. package/lib/renderer/wgsl/aovReflectance.wgsl.js +55 -55
  251. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +1 -1
  252. package/lib/renderer/wgsl/aovResolve.wgsl.d.ts +4 -0
  253. package/lib/renderer/wgsl/aovResolve.wgsl.js +21 -2
  254. package/lib/renderer/wgsl/aovResolve.wgsl.js.map +1 -1
  255. package/lib/renderer/wgsl/aovSnapshot.wgsl.js +2 -2
  256. package/lib/renderer/wgsl/aovSnapshot.wgsl.js.map +1 -1
  257. package/lib/renderer/wgsl/aovTrace.wgsl.js +33 -33
  258. package/lib/renderer/wgsl/aovTraceDisplay.wgsl.d.ts +2 -0
  259. package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js +56 -0
  260. package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js.map +1 -0
  261. package/lib/renderer/wgsl/bloom.wgsl.js +18 -18
  262. package/lib/renderer/wgsl/causticLight.compute.d.ts +6 -0
  263. package/lib/renderer/wgsl/causticLight.compute.js +539 -0
  264. package/lib/renderer/wgsl/causticLight.compute.js.map +1 -0
  265. package/lib/renderer/wgsl/chunks/background.wgsl.d.ts +2 -0
  266. package/lib/renderer/wgsl/chunks/background.wgsl.js +102 -0
  267. package/lib/renderer/wgsl/chunks/background.wgsl.js.map +1 -0
  268. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.d.ts +2 -0
  269. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +12 -0
  270. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js.map +1 -0
  271. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.d.ts +2 -0
  272. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +16 -0
  273. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js.map +1 -0
  274. package/lib/renderer/wgsl/chunks/caustics.wgsl.d.ts +1 -0
  275. package/lib/renderer/wgsl/chunks/caustics.wgsl.js +62 -0
  276. package/lib/renderer/wgsl/chunks/caustics.wgsl.js.map +1 -0
  277. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  278. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +37 -37
  279. package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +6 -2
  280. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +634 -620
  281. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  282. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.d.ts +1 -1
  283. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +23 -21
  284. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -1
  285. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +3 -1
  286. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +77 -74
  287. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  288. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +795 -795
  289. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +139 -139
  290. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  291. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +5 -1
  292. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +45 -29
  293. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  294. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +1 -1
  295. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +142 -138
  296. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -1
  297. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
  298. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +228 -189
  299. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
  300. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +1 -1
  301. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +11 -11
  302. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -1
  303. package/lib/renderer/wgsl/chunks/sampling.wgsl.d.ts +1 -1
  304. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +88 -92
  305. package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -1
  306. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +83 -83
  307. package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.d.ts +6 -0
  308. package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js +66 -0
  309. package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js.map +1 -0
  310. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
  311. package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.d.ts +2 -0
  312. package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js +61 -0
  313. package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js.map +1 -0
  314. package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +2 -0
  315. package/lib/renderer/wgsl/compose.frag.wgsl.js +100 -98
  316. package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -1
  317. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  318. package/lib/renderer/wgsl/depthQuery.wgsl.d.ts +1 -1
  319. package/lib/renderer/wgsl/depthQuery.wgsl.js +12 -3
  320. package/lib/renderer/wgsl/depthQuery.wgsl.js.map +1 -1
  321. package/lib/renderer/wgsl/easu.wgsl.d.ts +2 -0
  322. package/lib/renderer/wgsl/easu.wgsl.js +80 -0
  323. package/lib/renderer/wgsl/easu.wgsl.js.map +1 -0
  324. package/lib/renderer/wgsl/easuDetail.wgsl.d.ts +21 -0
  325. package/lib/renderer/wgsl/easuDetail.wgsl.js +230 -0
  326. package/lib/renderer/wgsl/easuDetail.wgsl.js.map +1 -0
  327. package/lib/renderer/wgsl/jnlm.compute.js +74 -74
  328. package/lib/renderer/wgsl/jnlm.compute.js.map +1 -1
  329. package/lib/renderer/wgsl/offlineAdaptive.compute.js +26 -26
  330. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +3 -3
  331. package/lib/renderer/wgsl/photonMap.compute.d.ts +29 -0
  332. package/lib/renderer/wgsl/photonMap.compute.js +352 -0
  333. package/lib/renderer/wgsl/photonMap.compute.js.map +1 -0
  334. package/lib/renderer/wgsl/proceduralSky.compute.js +64 -64
  335. package/lib/renderer/wgsl/rayTrace.compute.d.ts +23 -1
  336. package/lib/renderer/wgsl/rayTrace.compute.js +531 -543
  337. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  338. package/lib/scene/MaterialState.d.ts +2 -2
  339. package/lib/scene/MaterialState.js +2 -2
  340. package/lib/scene/MaterialState.js.map +1 -1
  341. package/lib/scene/Scene.js.map +1 -1
  342. package/lib/settings/render.d.ts +22 -0
  343. package/lib/settings/render.js +2 -0
  344. package/lib/settings/render.js.map +1 -1
  345. package/lib/util/fromTHREE.js +23 -16
  346. package/lib/util/fromTHREE.js.map +1 -1
  347. package/lib/version.d.ts +1 -1
  348. package/lib/version.js +1 -1
  349. package/lib/version.js.map +1 -1
  350. package/llms.txt +2 -1
  351. package/package.json +7 -4
  352. package/lib/oidnBundledWeights.cdn.d.ts +0 -2
  353. package/lib/oidnBundledWeights.cdn.js +0 -5
  354. package/lib/oidnBundledWeights.cdn.js.map +0 -1
  355. package/lib/renderer/bvh.worker.d.ts +0 -1
  356. package/lib/renderer/bvh.worker.js +0 -16
  357. package/lib/renderer/bvh.worker.js.map +0 -1
  358. package/lib/renderer/bvhWorkerBuild.d.ts +0 -13
  359. package/lib/renderer/bvhWorkerBuild.js +0 -17
  360. package/lib/renderer/bvhWorkerBuild.js.map +0 -1
  361. package/lib/renderer/lightCore.d.ts +0 -12
  362. package/lib/renderer/lightCore.js +0 -13
  363. package/lib/renderer/lightCore.js.map +0 -1
  364. package/lib/renderer/materialCore.d.ts +0 -8
  365. package/lib/renderer/materialCore.js +0 -9
  366. package/lib/renderer/materialCore.js.map +0 -1
  367. package/lib/scene/PixelTexture.d.ts +0 -6
  368. package/lib/scene/PixelTexture.js +0 -10
  369. package/lib/scene/PixelTexture.js.map +0 -1
  370. package/lib/util/studioLighting.d.ts +0 -18
  371. package/lib/util/studioLighting.js +0 -36
  372. package/lib/util/studioLighting.js.map +0 -1
@@ -0,0 +1,93 @@
1
+ import { computeGeometryBounds } from './geometryBvhBounds.js';
2
+ import { matrixStorage } from '../math/storage.js';
3
+ import { read, write } from '../math/access.js';
4
+ import { meshInstanceCount, meshInstanceTransform } from './meshInstances.js';
5
+ import { mat4, vec3 } from '../math.js';
6
+ import { resolveMaterialAlphaMode } from '../scene/MaterialState.js';
7
+ export const CAUSTIC_ROUGHNESS_MAX = 0.1;
8
+ /** Material-only classification, shared by caster collection and GPU estimators. */
9
+ export function isCausticSpecular(m) {
10
+ return m.baseWeight * (1 - m.baseMetalness) * (1 - m.transmissionWeight) <= 1e-6 &&
11
+ m.subsurfaceWeight <= 0 && m.fuzzWeight <= 0 && m.coatWeight <= 0 && m.specularRoughness <= CAUSTIC_ROUGHNESS_MAX;
12
+ }
13
+ const casterBounds = new WeakMap();
14
+ function localCasterBounds(geometry) {
15
+ const cached = casterBounds.get(geometry), positions = geometry.position.array;
16
+ if (cached && cached.version === geometry.version && cached.positions === positions)
17
+ return cached.bounds;
18
+ const value = computeGeometryBounds(geometry), bounds = [matrixStorage(value[0]), matrixStorage(value[1])];
19
+ casterBounds.set(geometry, { version: geometry.version, positions, bounds });
20
+ return bounds;
21
+ }
22
+ /** One conservative world-space sphere per smooth mesh instance. */
23
+ export function causticCasterSpheres(meshes) {
24
+ const spheres = [];
25
+ const matrix = mat4.create(), point = vec3.create();
26
+ for (const mesh of meshes) {
27
+ if (!mesh.materials.some(isCausticSpecular))
28
+ continue;
29
+ // Geometry.boundingBox is optional caller metadata and starts at zero.
30
+ // Caster collection must also work for a raw public Geometry descriptor.
31
+ const bounds = localCasterBounds(mesh.geometry), minCorner = bounds[0], maxCorner = bounds[1];
32
+ if (!Number.isFinite(minCorner[0]) || !Number.isFinite(maxCorner[0]))
33
+ continue;
34
+ let expansion = 0;
35
+ for (const material of mesh.materials)
36
+ if (isCausticSpecular(material))
37
+ expansion = Math.max(expansion, Math.abs(material.displacementBias) + (material.displacementMap ? Math.abs(material.displacementScale) : 0));
38
+ for (let instance = 0; instance < meshInstanceCount(mesh); instance++) {
39
+ const min = [Infinity, Infinity, Infinity], max = [-Infinity, -Infinity, -Infinity];
40
+ meshInstanceTransform(mesh, instance, matrix);
41
+ for (let corner = 0; corner < 8; corner++) {
42
+ for (let axis = 0; axis < 3; axis++)
43
+ write(point, axis, ((corner & (1 << axis)) ? maxCorner[axis] + expansion : minCorner[axis] - expansion));
44
+ vec3.transformMat4(point, point, matrix);
45
+ for (let axis = 0; axis < 3; axis++) {
46
+ min[axis] = Math.min(min[axis], read(point, axis));
47
+ max[axis] = Math.max(max[axis], read(point, axis));
48
+ }
49
+ }
50
+ spheres.push([(min[0] + max[0]) * .5, (min[1] + max[1]) * .5, (min[2] + max[2]) * .5, Math.hypot(max[0] - min[0], max[1] - min[1], max[2] - min[2]) * .501]);
51
+ }
52
+ }
53
+ return spheres;
54
+ }
55
+ /** Conservative sphere enclosing the caster mixture. */
56
+ export function causticCasterSphere(meshes) {
57
+ const spheres = causticCasterSpheres(meshes);
58
+ if (!spheres.length)
59
+ return [0, 0, 0, 0];
60
+ const min = [Infinity, Infinity, Infinity], max = [-Infinity, -Infinity, -Infinity];
61
+ for (const s of spheres) {
62
+ const components = [s[0], s[1], s[2]];
63
+ for (let i = 0; i < 3; i++) {
64
+ min[i] = Math.min(min[i], components[i] - s[3]);
65
+ max[i] = Math.max(max[i], components[i] + s[3]);
66
+ }
67
+ }
68
+ const center = min.map((v, i) => (v + max[i]) * .5);
69
+ let radius = 0;
70
+ for (const s of spheres)
71
+ radius = Math.max(radius, Math.hypot(s[0] - center[0], s[1] - center[1], s[2] - center[2]) + s[3]);
72
+ return [center[0], center[1], center[2], radius];
73
+ }
74
+ /** CPU reference for the solid-angle mixture, including overlapping cones. */
75
+ export function casterDirectionPdf(origin, direction, spheres, weights = []) {
76
+ let total = 0, overlaps = 0;
77
+ for (const [index, s] of spheres.entries()) {
78
+ const weight = weights[index] ?? 1;
79
+ const d = Math.hypot(s[0] - origin[0], s[1] - origin[1], s[2] - origin[2]);
80
+ const cosine = d > s[3] ? Math.sqrt(Math.max(0, 1 - (s[3] / d) ** 2)) : -1;
81
+ total += 2 * Math.PI * (1 - cosine) * weight;
82
+ if (d <= s[3] || ((s[0] - origin[0]) * direction[0] + (s[1] - origin[1]) * direction[1] + (s[2] - origin[2]) * direction[2]) / d >= cosine)
83
+ overlaps += weight;
84
+ }
85
+ return total > 0 ? overlaps / total : 0;
86
+ }
87
+ /** Stochastic smooth coverage currently disagrees with PT energy.
88
+ * Keep those scenes on PT until transport and endpoint weights are verified.
89
+ */
90
+ export function hasStochasticCausticCaster(meshes) {
91
+ return meshes.some(mesh => mesh.materials.some(m => isCausticSpecular(m) && resolveMaterialAlphaMode(m) === 'blend'));
92
+ }
93
+ //# sourceMappingURL=caustics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caustics.js","sourceRoot":"","sources":["../../src/renderer/caustics.ts"],"names":[],"mappings":"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","sourcesContent":["import {computeGeometryBounds} from './geometryBvhBounds.js';\nimport type Geometry from '../scene/Geometry.js';\nimport {matrixStorage} from '../math/storage.js';\nimport {read,write} from '../math/access.js';\nimport type Mesh from '../scene/MeshState.js';\nimport {meshInstanceCount,meshInstanceTransform} from './meshInstances.js';\nimport {mat4,vec3} from '../math.js';\nimport type OpenPBRMaterial from '../scene/MaterialState.js';\nimport {resolveMaterialAlphaMode} from '../scene/MaterialState.js';\n\nexport const CAUSTIC_ROUGHNESS_MAX = 0.1;\n/** Material-only classification, shared by caster collection and GPU estimators. */\nexport function isCausticSpecular(m: Pick<OpenPBRMaterial, 'baseWeight' | 'baseMetalness' | 'transmissionWeight' | 'subsurfaceWeight' | 'fuzzWeight' | 'coatWeight' | 'specularRoughness'>) {\n return m.baseWeight * (1 - m.baseMetalness) * (1 - m.transmissionWeight) <= 1e-6 &&\n m.subsurfaceWeight <= 0 && m.fuzzWeight <= 0 && m.coatWeight <= 0 && m.specularRoughness <= CAUSTIC_ROUGHNESS_MAX;\n}\n\nexport type CasterSphere = [number,number,number,number];\nconst casterBounds=new WeakMap<Geometry,{version:number;positions:Float32Array;bounds:[Float64Array,Float64Array]}>();\nfunction localCasterBounds(geometry:Geometry){\n const cached=casterBounds.get(geometry),positions=geometry.position.array;\n if(cached&&cached.version===geometry.version&&cached.positions===positions)return cached.bounds;\n const value=computeGeometryBounds(geometry),bounds:[Float64Array,Float64Array]=[matrixStorage(value[0]),matrixStorage(value[1])];\n casterBounds.set(geometry,{version:geometry.version,positions,bounds});return bounds;\n}\n/** One conservative world-space sphere per smooth mesh instance. */\nexport function causticCasterSpheres(meshes: readonly Mesh[]): CasterSphere[] {\n const spheres:CasterSphere[]=[];\n const matrix=mat4.create(),point=vec3.create();\n for(const mesh of meshes) {\n if(!mesh.materials.some(isCausticSpecular))continue;\n // Geometry.boundingBox is optional caller metadata and starts at zero.\n // Caster collection must also work for a raw public Geometry descriptor.\n const bounds=localCasterBounds(mesh.geometry),minCorner=bounds[0],maxCorner=bounds[1];\n if(!Number.isFinite(minCorner[0])||!Number.isFinite(maxCorner[0]))continue;\n let expansion=0;\n for(const material of mesh.materials)if(isCausticSpecular(material))expansion=Math.max(expansion,\n Math.abs(material.displacementBias)+(material.displacementMap?Math.abs(material.displacementScale):0));\n for(let instance=0;instance<meshInstanceCount(mesh);instance++) {\n const min=[Infinity,Infinity,Infinity],max=[-Infinity,-Infinity,-Infinity];\n meshInstanceTransform(mesh,instance,matrix);\n for(let corner=0;corner<8;corner++) {\n for(let axis=0;axis<3;axis++)write(point,axis,((corner&(1<<axis))?maxCorner[axis]+expansion:minCorner[axis]-expansion));\n vec3.transformMat4(point,point,matrix);\n for(let axis=0;axis<3;axis++){min[axis]=Math.min(min[axis],read(point,axis));max[axis]=Math.max(max[axis],read(point,axis));}\n }\n spheres.push([(min[0]+max[0])*.5,(min[1]+max[1])*.5,(min[2]+max[2])*.5,Math.hypot(max[0]-min[0],max[1]-min[1],max[2]-min[2])*.501]);\n }\n }\n return spheres;\n}\n/** Conservative sphere enclosing the caster mixture. */\nexport function causticCasterSphere(meshes:readonly Mesh[]):CasterSphere {\n const spheres=causticCasterSpheres(meshes);if(!spheres.length)return [0,0,0,0];\n const min=[Infinity,Infinity,Infinity],max=[-Infinity,-Infinity,-Infinity];\n for(const s of spheres){const components:number[]=[s[0],s[1],s[2]];for(let i=0;i<3;i++){min[i]=Math.min(min[i],components[i]-s[3]);max[i]=Math.max(max[i],components[i]+s[3]);}}\n const center=min.map((v,i)=>(v+max[i])*.5);\n let radius=0;for(const s of spheres)radius=Math.max(radius,Math.hypot(s[0]-center[0],s[1]-center[1],s[2]-center[2])+s[3]);\n return [center[0],center[1],center[2],radius];\n}\n/** CPU reference for the solid-angle mixture, including overlapping cones. */\nexport function casterDirectionPdf(origin:readonly number[],direction:readonly number[],spheres:readonly CasterSphere[],weights:readonly number[]=[]) {\n let total=0,overlaps=0;\n for(const [index,s] of spheres.entries()){const weight=weights[index]??1;const d=Math.hypot(s[0]-origin[0],s[1]-origin[1],s[2]-origin[2]);\n const cosine=d>s[3]?Math.sqrt(Math.max(0,1-(s[3]/d)**2)):-1;\n total+=2*Math.PI*(1-cosine)*weight;\n if(d<=s[3]||((s[0]-origin[0])*direction[0]+(s[1]-origin[1])*direction[1]+(s[2]-origin[2])*direction[2])/d>=cosine)overlaps+=weight;\n }\n return total>0?overlaps/total:0;\n}\n\n/** Stochastic smooth coverage currently disagrees with PT energy.\n * Keep those scenes on PT until transport and endpoint weights are verified.\n */\nexport function hasStochasticCausticCaster(meshes:readonly Mesh[]){\n return meshes.some(mesh=>mesh.materials.some(m=>isCausticSpecular(m)&&resolveMaterialAlphaMode(m)==='blend'));\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type Geometry from '../scene/Geometry.js';
2
+ export declare function compactVertexLayout(geometries: readonly Geometry[], normalFloat?: boolean): {
3
+ stride: number;
4
+ offsets: number[];
5
+ constants: Record<string, number | boolean>;
6
+ };
7
+ export declare function encodeNormal(x: number, y: number, z: number): number;
8
+ export declare function encodeTangent(x: number, y: number, z: number, w: number): number;
9
+ /** CPU decoder for layout/precision checks and backend-independent encoding consumers. */
10
+ export declare function decodeDirection(word: number, tangent?: boolean): [number, number, number];
11
+ /** Writes source geometry directly into its resident packed vertex region. */
12
+ export declare function packCompactVertices(geometry: Geometry, output: Uint32Array, stride: number, offsets: readonly number[], first: number, count: number, outputFirst?: number, deformationOnly?: boolean, colorFloat?: boolean, normalFloat?: boolean): void;
13
+ /** Optional material plane, indexed by BVH triangle record. Unused node entries are never read. */
14
+ export declare function packTriangleMaterials(geometry: Geometry, materialIndices: readonly number[], bvh: ArrayBuffer, output: Uint32Array, offset: number): void;
@@ -0,0 +1,124 @@
1
+ import { localMaterialIndex } from './materialIndices.js';
2
+ import { hasGeneratedVertexTangents } from '../util/geometry.js';
3
+ // Word offsets, not vec4 slots. Positions and both UV sets remain f32.
4
+ // An absent secondary UV aliases the primary UV without duplicating its storage.
5
+ export function compactVertexLayout(geometries, normalFloat = false) {
6
+ const has = (name) => geometries.some(g => !!g[name]);
7
+ let colorFloat = false;
8
+ for (const g of geometries)
9
+ if (g.color) {
10
+ for (const value of g.color.array)
11
+ if (!(value >= 0 && value <= 1)) {
12
+ colorFloat = true;
13
+ break;
14
+ }
15
+ }
16
+ let stride = normalFloat ? 6 : 4;
17
+ const offsets = [0, 3, stride, stride, stride, stride, -1];
18
+ if (has('uv') || has('uv1'))
19
+ stride += 2;
20
+ offsets[3] = has('uv1') ? stride : offsets[2];
21
+ if (has('uv1'))
22
+ stride += 2;
23
+ offsets[4] = stride;
24
+ if (has('color'))
25
+ stride += colorFloat ? 3 : 1;
26
+ offsets[5] = stride;
27
+ if (has('tangent'))
28
+ stride++;
29
+ const names = ['POSITION', 'NORMAL', 'UV', 'UV1', 'COLOR', 'TANGENT'];
30
+ const constants = { ATTR_STRIDE: stride, USE_UV: has('uv') || has('uv1'),
31
+ USE_VERTEX_COLOR: has('color'), COLOR_FLOAT: colorFloat, NORMAL_FLOAT: normalFloat, HAS_VERTEX_UV: has('uv') || has('uv1'),
32
+ HAS_VERTEX_TANGENT: has('tangent'), HAS_TRIANGLE_MATERIAL: has('materialIndex'), MATERIALINDEX_OFF: 0 };
33
+ names.forEach((name, i) => { constants[name + '_OFF'] = offsets[i]; });
34
+ return { stride, offsets, constants };
35
+ }
36
+ function oct(x, y, z, maximum, bits) {
37
+ const length = Math.abs(x) + Math.abs(y) + Math.abs(z);
38
+ if (!length)
39
+ return (1 << (bits - 1)) | (1 << (bits * 2 - 1));
40
+ x /= length;
41
+ y /= length;
42
+ if (z < 0) {
43
+ const oldX = x;
44
+ x = (1 - Math.abs(y)) * (oldX < 0 ? -1 : 1);
45
+ y = (1 - Math.abs(oldX)) * (y < 0 ? -1 : 1);
46
+ }
47
+ const mask = (1 << bits) - 1;
48
+ return ((Math.round(x * maximum) & mask) | ((Math.round(y * maximum) & mask) << bits)) >>> 0;
49
+ }
50
+ export function encodeNormal(x, y, z) { return oct(x, y, z, 32767, 16); }
51
+ export function encodeTangent(x, y, z, w) {
52
+ const sign = w > 1.5 ? 3 : w < 0 ? 2 : w > 0 ? 1 : 0;
53
+ return (oct(x, y, z, 16383, 15) | (sign << 30)) >>> 0;
54
+ }
55
+ /** CPU decoder for layout/precision checks and backend-independent encoding consumers. */
56
+ export function decodeDirection(word, tangent = false) {
57
+ const bits = tangent ? 15 : 16, shift = 32 - bits, maximum = (1 << (bits - 1)) - 1;
58
+ const a = (word << shift) >> shift, b = (word << (32 - 2 * bits)) >> shift;
59
+ if (a === -maximum - 1 && b === -maximum - 1)
60
+ return [0, 0, 0];
61
+ let x = a / maximum, y = b / maximum;
62
+ const z = 1 - Math.abs(x) - Math.abs(y);
63
+ if (z < 0) {
64
+ const oldX = x;
65
+ x = (1 - Math.abs(y)) * (oldX < 0 ? -1 : 1);
66
+ y = (1 - Math.abs(oldX)) * (y < 0 ? -1 : 1);
67
+ }
68
+ const length = Math.hypot(x, y, z);
69
+ return [x / length, y / length, z / length];
70
+ }
71
+ /** Writes source geometry directly into its resident packed vertex region. */
72
+ export function packCompactVertices(geometry, output, stride, offsets, first, count, outputFirst = first, deformationOnly = false, colorFloat = false, normalFloat = false) {
73
+ const floats = new Float32Array(output.buffer, output.byteOffset, output.length);
74
+ const p = geometry.position.array, n = geometry.normal.array, tangent = geometry.tangent;
75
+ const uv = geometry.uv, uv1 = geometry.uv1 ?? uv, color = geometry.color;
76
+ const tangentArray = tangent?.array, tangentSize = tangent?.itemSize ?? 0;
77
+ const tangentSign = tangentSize === 4 ? 0 : hasGeneratedVertexTangents(geometry) ? 0 : 2;
78
+ const uvArray = uv?.array, uv1Array = uv1?.array, colorArray = color?.array;
79
+ const uvOffset = offsets[2], uv1Offset = offsets[3], colorOffset = offsets[4], tangentOffset = offsets[5];
80
+ for (let i = first, end = first + count, d = outputFirst * stride; i < end; i++, d += stride) {
81
+ floats[d] = p[i * 3];
82
+ floats[d + 1] = p[i * 3 + 1];
83
+ floats[d + 2] = p[i * 3 + 2];
84
+ if (normalFloat) {
85
+ floats[d + 3] = n[i * 3];
86
+ floats[d + 4] = n[i * 3 + 1];
87
+ floats[d + 5] = n[i * 3 + 2];
88
+ }
89
+ else
90
+ output[d + 3] = encodeNormal(n[i * 3], n[i * 3 + 1], n[i * 3 + 2]);
91
+ if (tangentOffset < stride) {
92
+ const t = i * tangentSize;
93
+ output[d + tangentOffset] = tangentArray ? encodeTangent(tangentArray[t], tangentArray[t + 1], tangentArray[t + 2], tangentSize === 4 ? tangentArray[t + 3] : tangentSign) : encodeTangent(0, 0, 0, 0);
94
+ }
95
+ if (deformationOnly)
96
+ continue;
97
+ if (uvOffset < colorOffset) {
98
+ floats[d + uvOffset] = uvArray?.[i * 2] ?? 0;
99
+ floats[d + uvOffset + 1] = uvArray?.[i * 2 + 1] ?? 0;
100
+ floats[d + uv1Offset] = uv1Array?.[i * 2] ?? 0;
101
+ floats[d + uv1Offset + 1] = uv1Array?.[i * 2 + 1] ?? 0;
102
+ }
103
+ if (colorOffset < tangentOffset) {
104
+ const r = colorArray?.[i * 3] ?? 1, g = colorArray?.[i * 3 + 1] ?? 1, b = colorArray?.[i * 3 + 2] ?? 1;
105
+ if (colorFloat) {
106
+ floats[d + colorOffset] = r;
107
+ floats[d + colorOffset + 1] = g;
108
+ floats[d + colorOffset + 2] = b;
109
+ }
110
+ else
111
+ output[d + colorOffset] = (Math.round(r * 255) | Math.round(g * 255) << 8 | Math.round(b * 255) << 16 | 0xff000000) >>> 0;
112
+ }
113
+ }
114
+ }
115
+ /** Optional material plane, indexed by BVH triangle record. Unused node entries are never read. */
116
+ export function packTriangleMaterials(geometry, materialIndices, bvh, output, offset) {
117
+ const words = new Uint32Array(bvh);
118
+ for (let record = 0; record < words.length / 4; record++) {
119
+ const vertex = words[record * 4];
120
+ output[offset + record] = geometry.materialIndex && vertex < geometry.vertexCount
121
+ ? (materialIndices[localMaterialIndex(geometry, vertex, materialIndices.length)] ?? 0) + 1 : 0;
122
+ }
123
+ }
124
+ //# sourceMappingURL=compactVertices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compactVertices.js","sourceRoot":"","sources":["../../src/renderer/compactVertices.ts"],"names":[],"mappings":"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","sourcesContent":["import {localMaterialIndex} from './materialIndices.js';\nimport type Geometry from '../scene/Geometry.js';\nimport {hasGeneratedVertexTangents} from '../util/geometry.js';\n\n// Word offsets, not vec4 slots. Positions and both UV sets remain f32.\n// An absent secondary UV aliases the primary UV without duplicating its storage.\nexport function compactVertexLayout(geometries: readonly Geometry[], normalFloat = false) {\n const has = (name: 'uv' | 'uv1' | 'color' | 'tangent' | 'materialIndex') => geometries.some(g => !!g[name]);\n let colorFloat = false;\n for (const g of geometries) if (g.color) {\n for (const value of g.color.array) if (!(value >= 0 && value <= 1)) {colorFloat = true; break;}\n }\n let stride = normalFloat ? 6 : 4;\n const offsets = [0, 3, stride, stride, stride, stride, -1];\n if (has('uv') || has('uv1')) stride += 2;\n offsets[3] = has('uv1') ? stride : offsets[2];\n if (has('uv1')) stride += 2;\n offsets[4] = stride;\n if (has('color')) stride += colorFloat ? 3 : 1;\n offsets[5] = stride;\n if (has('tangent')) stride++;\n const names = ['POSITION', 'NORMAL', 'UV', 'UV1', 'COLOR', 'TANGENT'];\n const constants: Record<string, boolean | number> = {ATTR_STRIDE: stride, USE_UV: has('uv') || has('uv1'),\n USE_VERTEX_COLOR: has('color'), COLOR_FLOAT: colorFloat, NORMAL_FLOAT: normalFloat, HAS_VERTEX_UV: has('uv') || has('uv1'),\n HAS_VERTEX_TANGENT: has('tangent'), HAS_TRIANGLE_MATERIAL: has('materialIndex'), MATERIALINDEX_OFF: 0};\n names.forEach((name, i) => {constants[name + '_OFF'] = offsets[i];});\n return {stride, offsets, constants};\n}\n\nfunction oct(x: number, y: number, z: number, maximum: number, bits: number) {\n const length = Math.abs(x) + Math.abs(y) + Math.abs(z);\n if (!length) return (1 << (bits - 1)) | (1 << (bits * 2 - 1));\n x /= length; y /= length;\n if (z < 0) {\n const oldX = x;\n x = (1 - Math.abs(y)) * (oldX < 0 ? -1 : 1);\n y = (1 - Math.abs(oldX)) * (y < 0 ? -1 : 1);\n }\n const mask = (1 << bits) - 1;\n return ((Math.round(x * maximum) & mask) | ((Math.round(y * maximum) & mask) << bits)) >>> 0;\n}\n\nexport function encodeNormal(x: number, y: number, z: number) {return oct(x, y, z, 32767, 16);}\nexport function encodeTangent(x: number, y: number, z: number, w: number) {\n const sign = w > 1.5 ? 3 : w < 0 ? 2 : w > 0 ? 1 : 0;\n return (oct(x, y, z, 16383, 15) | (sign << 30)) >>> 0;\n}\n\n/** CPU decoder for layout/precision checks and backend-independent encoding consumers. */\nexport function decodeDirection(word: number, tangent = false): [number, number, number] {\n const bits = tangent ? 15 : 16, shift = 32 - bits, maximum = (1 << (bits - 1)) - 1;\n const a = (word << shift) >> shift, b = (word << (32 - 2 * bits)) >> shift;\n if (a === -maximum - 1 && b === -maximum - 1) return [0, 0, 0];\n let x = a / maximum, y = b / maximum;\n const z = 1 - Math.abs(x) - Math.abs(y);\n if (z < 0) {\n const oldX = x;\n x = (1 - Math.abs(y)) * (oldX < 0 ? -1 : 1);\n y = (1 - Math.abs(oldX)) * (y < 0 ? -1 : 1);\n }\n const length = Math.hypot(x, y, z);\n return [x / length, y / length, z / length];\n}\n\n/** Writes source geometry directly into its resident packed vertex region. */\nexport function packCompactVertices(geometry: Geometry, output: Uint32Array, stride: number, offsets: readonly number[],\n first: number, count: number, outputFirst = first, deformationOnly = false, colorFloat = false, normalFloat = false) {\n const floats = new Float32Array(output.buffer, output.byteOffset, output.length);\n const p = geometry.position.array, n = geometry.normal.array, tangent = geometry.tangent;\n const uv = geometry.uv, uv1 = geometry.uv1 ?? uv, color = geometry.color;\n const tangentArray = tangent?.array, tangentSize = tangent?.itemSize ?? 0;\n const tangentSign = tangentSize === 4 ? 0 : hasGeneratedVertexTangents(geometry) ? 0 : 2;\n const uvArray = uv?.array, uv1Array = uv1?.array, colorArray = color?.array;\n const uvOffset = offsets[2], uv1Offset = offsets[3], colorOffset = offsets[4], tangentOffset = offsets[5];\n for (let i = first, end = first + count, d = outputFirst * stride; i < end; i++, d += stride) {\n floats[d] = p[i * 3]; floats[d + 1] = p[i * 3 + 1]; floats[d + 2] = p[i * 3 + 2];\n if (normalFloat) {\n floats[d + 3] = n[i * 3]; floats[d + 4] = n[i * 3 + 1]; floats[d + 5] = n[i * 3 + 2];\n } else output[d + 3] = encodeNormal(n[i * 3], n[i * 3 + 1], n[i * 3 + 2]);\n if (tangentOffset < stride) {\n const t = i * tangentSize;\n output[d + tangentOffset] = tangentArray ? encodeTangent(tangentArray[t], tangentArray[t + 1], tangentArray[t + 2],\n tangentSize === 4 ? tangentArray[t + 3] : tangentSign) : encodeTangent(0, 0, 0, 0);\n }\n if (deformationOnly) continue;\n if (uvOffset < colorOffset) {\n floats[d + uvOffset] = uvArray?.[i * 2] ?? 0; floats[d + uvOffset + 1] = uvArray?.[i * 2 + 1] ?? 0;\n floats[d + uv1Offset] = uv1Array?.[i * 2] ?? 0; floats[d + uv1Offset + 1] = uv1Array?.[i * 2 + 1] ?? 0;\n }\n if (colorOffset < tangentOffset) {\n const r = colorArray?.[i * 3] ?? 1, g = colorArray?.[i * 3 + 1] ?? 1, b = colorArray?.[i * 3 + 2] ?? 1;\n if (colorFloat) {floats[d + colorOffset] = r; floats[d + colorOffset + 1] = g; floats[d + colorOffset + 2] = b;}\n else output[d + colorOffset] = (Math.round(r * 255) | Math.round(g * 255) << 8 | Math.round(b * 255) << 16 | 0xff000000) >>> 0;\n }\n }\n}\n\n/** Optional material plane, indexed by BVH triangle record. Unused node entries are never read. */\nexport function packTriangleMaterials(geometry: Geometry, materialIndices: readonly number[], bvh: ArrayBuffer,\n output: Uint32Array, offset: number) {\n const words = new Uint32Array(bvh);\n for (let record = 0; record < words.length / 4; record++) {\n const vertex = words[record * 4];\n output[offset + record] = geometry.materialIndex && vertex < geometry.vertexCount\n ? (materialIndices[localMaterialIndex(geometry, vertex, materialIndices.length)] ?? 0) + 1 : 0;\n }\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import type { PostProcess } from '../Display.js';
2
+ /** createEasuPass options. */
3
+ export interface EasuOptions {
4
+ /** Recover surface texture detail from the displayed render's diffuseColor, specularColor and depth AOVs, traced with aovResolution 'display'. Default false. Warns once when the displayed render lacks that configuration; frames whose AOVs are not ready or do not match the output size use EASU alone. Unsupported surfaces and silhouettes receive no compensation. */ albedoDetail?: boolean;
5
+ }
6
+ /** A display pass with optional scratch images. Dispose after unregistering; it may be used again. */
7
+ export type EasuPass = PostProcess & {
8
+ dispose(): void;
9
+ };
10
+ /** Creates an edge-adaptive display-space upscale pass (AMD FSR 1 EASU), without sharpening. Register with outputSize: (_, display) => display. WebGPU only; supports rgba8unorm and extended-range rgba16float, including alpha. Copies inputs that already have the output size and area-averages larger ones. Default EASU alone. */
11
+ export declare function createEasuPass(options?: EasuOptions): EasuPass;
@@ -0,0 +1,156 @@
1
+ import { areaDownsampleShader, easuShader } from './wgsl/easu.wgsl.js';
2
+ import { albedoDownsampleShader, easuDetailShader, guidedCoefficientShader, toneLutShader, EASU_DETAIL, TONE_LUT_SIZE } from './wgsl/easuDetail.wgsl.js';
3
+ import { borrowedAovRevision } from './WGPUAov.js';
4
+ import { TONE_MAPPING_MODES } from './wgsl/compose.frag.wgsl.js';
5
+ /** Creates an edge-adaptive display-space upscale pass (AMD FSR 1 EASU), without sharpening. Register with outputSize: (_, display) => display. WebGPU only; supports rgba8unorm and extended-range rgba16float, including alpha. Copies inputs that already have the output size and area-averages larger ones. Default EASU alone. */
6
+ export function createEasuPass(options = {}) { return createEasuPassImpl({ albedoDetail: options.albedoDetail }); }
7
+ const DETAIL_AOVS = ['diffuseColor', 'specularColor', 'depth'];
8
+ /** @internal Plain albedo ratios (guided false), the separate-lobe approximation and depth-guided silhouettes are retained for comparisons; not package exports. */
9
+ export function createEasuPassImpl(options = {}, separate = false, silhouettes = false, guided = true) {
10
+ const detailEnabled = options.albedoDetail ?? false;
11
+ let warnedConfiguration = false;
12
+ const [min, max] = options.ratioRange ?? EASU_DETAIL.ratioRange;
13
+ const depth = options.depthThreshold ?? EASU_DETAIL.depthThreshold, coverage = options.coverageThreshold ?? EASU_DETAIL.coverageThreshold;
14
+ if (![min, max, depth, coverage].every(Number.isFinite) || min <= 0 || max < min || depth <= 0 || coverage <= 0 || coverage > 1)
15
+ throw new RangeError('Invalid EASU detail compensation options.');
16
+ const devices = new Map();
17
+ const retire = (device, resources) => {
18
+ // This callback's encoder is submitted after it returns.
19
+ void Promise.resolve().then(() => device.queue.onSubmittedWorkDone()).catch(() => { }).then(() => resources.forEach(resource => resource.destroy()));
20
+ };
21
+ const guideFormats = silhouettes ? ['rgba16float', 'rgba16float', 'rg32float'] : ['rgba16float', 'rgba16float'];
22
+ const owned = (state) => [...(state.scratch ?? []), ...(state.tone ? [state.tone] : []), ...(state.fit ?? [])];
23
+ const pass = ctx => {
24
+ const { device, encoder, input, output, render } = ctx;
25
+ // Nothing to upscale, for example a full-resolution render beside a reduced preview.
26
+ if (input.width === output.width && input.height === output.height) {
27
+ encoder.copyTextureToTexture({ texture: input }, { texture: output }, [input.width, input.height]);
28
+ return;
29
+ }
30
+ for (const [previous, old] of devices)
31
+ if (previous !== device) {
32
+ retire(previous, owned(old));
33
+ devices.delete(previous);
34
+ }
35
+ let state = devices.get(device);
36
+ if (!state) {
37
+ state = { pipelines: new Map() };
38
+ devices.set(device, state);
39
+ }
40
+ const pipeline = (key, code, formats) => {
41
+ let value = state.pipelines.get(key);
42
+ if (!value) {
43
+ const module = device.createShaderModule({ label: key, code });
44
+ value = device.createRenderPipeline({ label: key, layout: 'auto', vertex: { module, entryPoint: 'vertex' },
45
+ fragment: { module, entryPoint: 'fragment', targets: formats.map(format => ({ format })) } });
46
+ state.pipelines.set(key, value);
47
+ }
48
+ return value;
49
+ };
50
+ const buffer = (values) => {
51
+ const value = device.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });
52
+ new Float32Array(value.getMappedRange()).set(values);
53
+ value.unmap();
54
+ retire(device, [value]);
55
+ return value;
56
+ };
57
+ if (input.width >= output.width && input.height >= output.height) {
58
+ // EASU is an enlargement filter; larger renders are area averaged instead.
59
+ const down = pipeline(`Area downsample ${output.format}`, areaDownsampleShader, [output.format]);
60
+ const group = device.createBindGroup({ layout: down.getBindGroupLayout(0), entries: [{ binding: 0, resource: input.createView() }, { binding: 1, resource: { buffer: buffer([output.width, output.height, 0, 0]) } }] });
61
+ const draw = encoder.beginRenderPass({ label: 'Area downsample', colorAttachments: [{ view: output.createView(), loadOp: 'clear', storeOp: 'store' }] });
62
+ draw.setPipeline(down);
63
+ draw.setBindGroup(0, group);
64
+ draw.draw(3);
65
+ draw.end();
66
+ return;
67
+ }
68
+ if (detailEnabled && !warnedConfiguration && (render.aovResolution !== 'display' || !DETAIL_AOVS.every(kind => render.aovs.includes(kind)))) {
69
+ warnedConfiguration = true;
70
+ console.warn("EASU albedoDetail needs the displayed render to enable diffuseColor, specularColor and depth AOVs with aovResolution 'display'; upscaling without detail.");
71
+ }
72
+ const aovs = detailEnabled ? DETAIL_AOVS.map(kind => render.getAovTexture(kind)) : [];
73
+ const detail = aovs.length === 3 && aovs.every(image => image && image.width === output.width && image.height === output.height);
74
+ const entries = [{ binding: 0, resource: input.createView() }, { binding: 1, resource: { buffer: buffer([output.width, output.height, min, max]) } }];
75
+ if (detail) {
76
+ // Cached images are recorded on their own submission so a failed chain cannot leave them stale.
77
+ let cache;
78
+ const cached = () => cache ??= device.createCommandEncoder({ label: 'EASU cache' });
79
+ if (!state.scratch || state.scratch.length !== guideFormats.length || state.scratch[0].width !== input.width || state.scratch[0].height !== input.height) {
80
+ if (state.scratch)
81
+ retire(device, state.scratch);
82
+ // Low diffuse and specular albedo, then (for silhouettes) nearest hit depth with hit coverage.
83
+ state.scratch = guideFormats.map((format, index) => device.createTexture({ label: `EASU low guide ${index}`, size: [input.width, input.height], format, usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT }));
84
+ state.key = undefined;
85
+ }
86
+ // Low albedo depends only on the AOV contents and beauty size; reuse it across presents.
87
+ const key = [state.scratch[0], ...aovs, ...aovs.map(image => borrowedAovRevision.get(image))];
88
+ if (!state.key || key.some((value, index) => value !== state.key[index])) {
89
+ const down = pipeline(`Albedo area downsample ${silhouettes}`, albedoDownsampleShader(silhouettes), guideFormats);
90
+ const group = device.createBindGroup({ layout: down.getBindGroupLayout(0), entries: [
91
+ { binding: 0, resource: aovs[0].createView() }, { binding: 1, resource: aovs[1].createView() },
92
+ { binding: 2, resource: { buffer: buffer([input.width, input.height, 0, 0]) } }, { binding: 3, resource: aovs[2].createView() }
93
+ ] });
94
+ const draw = cached().beginRenderPass({ label: 'Albedo area downsample', colorAttachments: state.scratch.map(image => ({ view: image.createView(), loadOp: 'clear', storeOp: 'store' })) });
95
+ draw.setPipeline(down);
96
+ draw.setBindGroup(0, group);
97
+ draw.draw(3);
98
+ draw.end();
99
+ state.key = key;
100
+ }
101
+ aovs.forEach((image, index) => entries.push({ binding: 2 + index, resource: image.createView() }));
102
+ entries.push({ binding: 5, resource: state.scratch[0].createView() }, { binding: 6, resource: state.scratch[1].createView() });
103
+ if (silhouettes)
104
+ entries.push({ binding: 10, resource: state.scratch[2].createView() });
105
+ entries.push({ binding: 7, resource: { buffer: buffer([EASU_DETAIL.minimumAlbedo, coverage, depth, EASU_DETAIL.depthTolerance]) } });
106
+ // The ratio is applied through the same grading and tone mapping as the composed image,
107
+ // tabulated once per display setting.
108
+ const display = render._engine.display, extended = output.format === 'rgba16float';
109
+ const tone = [TONE_MAPPING_MODES[display.toneMapping] ?? 0, extended ? 16 : 1, display.toneMappingExposure, extended ? 1 : 0];
110
+ const grading = [display.contrast, display.saturation, display.temperature, display.tint];
111
+ const toneKey = [...tone, ...grading].join(',');
112
+ state.tone ??= device.createTexture({ label: 'EASU tone table', size: [TONE_LUT_SIZE, 2], format: 'rgba32float', usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT });
113
+ if (state.toneKey !== toneKey) {
114
+ const build = pipeline('EASU tone table', toneLutShader, ['rgba32float']);
115
+ const group = device.createBindGroup({ layout: build.getBindGroupLayout(0), entries: [{ binding: 0, resource: { buffer: buffer(tone) } }, { binding: 1, resource: { buffer: buffer(grading) } }] });
116
+ const draw = cached().beginRenderPass({ label: 'EASU tone table', colorAttachments: [{ view: state.tone.createView(), loadOp: 'clear', storeOp: 'store' }] });
117
+ draw.setPipeline(build);
118
+ draw.setBindGroup(0, group);
119
+ draw.draw(3);
120
+ draw.end();
121
+ state.toneKey = toneKey;
122
+ }
123
+ const toneEntries = [{ binding: 8, resource: state.tone.createView() }, { binding: 9, resource: { buffer: buffer([tone[1], EASU_DETAIL.guidedEpsilon, 0, 0]) } }];
124
+ entries.push(...toneEntries);
125
+ if (cache)
126
+ device.queue.submit([cache.finish()]);
127
+ if (guided) {
128
+ // The local albedo-radiance fit depends on this frame's image, so it runs on every present.
129
+ if (!state.fit || state.fit[0].width !== input.width || state.fit[0].height !== input.height) {
130
+ if (state.fit)
131
+ retire(device, state.fit);
132
+ state.fit = ['slope', 'offset'].map(name => device.createTexture({ label: `EASU albedo ${name}`, size: [input.width, input.height], format: 'rgba16float', usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT }));
133
+ }
134
+ const fit = pipeline('EASU albedo fit', guidedCoefficientShader, ['rgba16float', 'rgba16float']);
135
+ const group = device.createBindGroup({ layout: fit.getBindGroupLayout(0), entries: [{ binding: 0, resource: input.createView() },
136
+ { binding: 1, resource: state.scratch[0].createView() }, { binding: 2, resource: state.scratch[1].createView() }, ...toneEntries] });
137
+ const draw = encoder.beginRenderPass({ label: 'EASU albedo fit', colorAttachments: state.fit.map(image => ({ view: image.createView(), loadOp: 'clear', storeOp: 'store' })) });
138
+ draw.setPipeline(fit);
139
+ draw.setBindGroup(0, group);
140
+ draw.draw(3);
141
+ draw.end();
142
+ entries.push({ binding: 11, resource: state.fit[0].createView() }, { binding: 12, resource: state.fit[1].createView() });
143
+ }
144
+ }
145
+ const upscale = pipeline(`FSR 1 EASU ${detail ? `detail ${separate} ${silhouettes} ${guided}` : 'color'} ${output.format}`, detail ? easuDetailShader(separate, silhouettes, guided) : easuShader, [output.format]);
146
+ const group = device.createBindGroup({ layout: upscale.getBindGroupLayout(0), entries });
147
+ const draw = encoder.beginRenderPass({ label: 'FSR 1 EASU', colorAttachments: [{ view: output.createView(), loadOp: 'clear', storeOp: 'store' }] });
148
+ draw.setPipeline(upscale);
149
+ draw.setBindGroup(0, group);
150
+ draw.draw(3);
151
+ draw.end();
152
+ };
153
+ return Object.assign(pass, { dispose() { for (const [device, state] of devices)
154
+ retire(device, owned(state)); devices.clear(); } });
155
+ }
156
+ //# sourceMappingURL=easu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"easu.js","sourceRoot":"","sources":["../../src/renderer/easu.ts"],"names":[],"mappings":"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","sourcesContent":["import type {PostProcess} from '../Display.js';\nimport {areaDownsampleShader, easuShader} from './wgsl/easu.wgsl.js';\nimport {albedoDownsampleShader, easuDetailShader, guidedCoefficientShader, toneLutShader, EASU_DETAIL, TONE_LUT_SIZE} from './wgsl/easuDetail.wgsl.js';\nimport {borrowedAovRevision} from './WGPUAov.js';\nimport {TONE_MAPPING_MODES} from './wgsl/compose.frag.wgsl.js';\n\n/** createEasuPass options. */\nexport interface EasuOptions {\n /** Recover surface texture detail from the displayed render's diffuseColor, specularColor and depth AOVs, traced with aovResolution 'display'. Default false. Warns once when the displayed render lacks that configuration; frames whose AOVs are not ready or do not match the output size use EASU alone. Unsupported surfaces and silhouettes receive no compensation. */ albedoDetail?: boolean;\n}\n/** @internal Detail tuning kept for comparisons; not package options. */\nexport interface EasuTuning extends EasuOptions {\n /** Per-channel linear compensation bounds, positive finite min <= max. Default [0.7, 1.43]. */ ratioRange?: readonly [number, number];\n /** Relative departure of neighboring inverse depth from a plane that marks a silhouette, positive finite. Default 0.02. */ depthThreshold?: number;\n /** Minimum valid AOV coverage in (0,1]. Default 0.95. */ coverageThreshold?: number;\n}\n/** A display pass with optional scratch images. Dispose after unregistering; it may be used again. */\nexport type EasuPass = PostProcess & {dispose(): void};\n/** Creates an edge-adaptive display-space upscale pass (AMD FSR 1 EASU), without sharpening. Register with outputSize: (_, display) => display. WebGPU only; supports rgba8unorm and extended-range rgba16float, including alpha. Copies inputs that already have the output size and area-averages larger ones. Default EASU alone. */\nexport function createEasuPass(options: EasuOptions = {}): EasuPass { return createEasuPassImpl({albedoDetail: options.albedoDetail}); }\n\nconst DETAIL_AOVS = ['diffuseColor', 'specularColor', 'depth'] as const;\n\n/** @internal Plain albedo ratios (guided false), the separate-lobe approximation and depth-guided silhouettes are retained for comparisons; not package exports. */\nexport function createEasuPassImpl(options: EasuTuning = {}, separate = false, silhouettes = false, guided = true): EasuPass {\n const detailEnabled = options.albedoDetail ?? false;\n let warnedConfiguration = false;\n const [min, max] = options.ratioRange ?? EASU_DETAIL.ratioRange;\n const depth = options.depthThreshold ?? EASU_DETAIL.depthThreshold, coverage = options.coverageThreshold ?? EASU_DETAIL.coverageThreshold;\n if (![min,max,depth,coverage].every(Number.isFinite) || min <= 0 || max < min || depth <= 0 || coverage <= 0 || coverage > 1) throw new RangeError('Invalid EASU detail compensation options.');\n const devices = new Map<GPUDevice, {pipelines: Map<string, GPURenderPipeline>; scratch?: GPUTexture[]; key?: unknown[]; tone?: GPUTexture; toneKey?: string; fit?: GPUTexture[]}>();\n const retire = (device: GPUDevice, resources: (GPUTexture | GPUBuffer)[]) => {\n // This callback's encoder is submitted after it returns.\n void Promise.resolve().then(() => device.queue.onSubmittedWorkDone()).catch(() => {}).then(() => resources.forEach(resource => resource.destroy()));\n };\n const guideFormats: GPUTextureFormat[] = silhouettes ? ['rgba16float','rgba16float','rg32float'] : ['rgba16float','rgba16float'];\n const owned = (state: {scratch?: GPUTexture[]; tone?: GPUTexture; fit?: GPUTexture[]}) => [...(state.scratch ?? []), ...(state.tone ? [state.tone] : []), ...(state.fit ?? [])];\n const pass: PostProcess = ctx => {\n const {device, encoder, input, output, render} = ctx;\n // Nothing to upscale, for example a full-resolution render beside a reduced preview.\n if (input.width === output.width && input.height === output.height) {\n encoder.copyTextureToTexture({texture: input}, {texture: output}, [input.width, input.height]);\n return;\n }\n for (const [previous, old] of devices) if (previous !== device) {retire(previous,owned(old));devices.delete(previous);}\n let state = devices.get(device);\n if (!state) {state = {pipelines: new Map()}; devices.set(device, state);}\n const pipeline = (key: string, code: string, formats: GPUTextureFormat[]) => {\n let value = state!.pipelines.get(key);\n if (!value) {\n const module = device.createShaderModule({label: key, code});\n value = device.createRenderPipeline({label: key, layout: 'auto', vertex: {module,entryPoint:'vertex'},\n fragment: {module,entryPoint:'fragment',targets:formats.map(format => ({format}))}});\n state!.pipelines.set(key, value);\n }\n return value;\n };\n const buffer = (values: number[]) => {\n const value = device.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:true});\n new Float32Array(value.getMappedRange()).set(values);value.unmap();retire(device,[value]);return value;\n };\n if (input.width >= output.width && input.height >= output.height) {\n // EASU is an enlargement filter; larger renders are area averaged instead.\n const down = pipeline(`Area downsample ${output.format}`,areaDownsampleShader,[output.format]);\n const group = device.createBindGroup({layout:down.getBindGroupLayout(0),entries:[{binding:0,resource:input.createView()},{binding:1,resource:{buffer:buffer([output.width,output.height,0,0])}}]});\n const draw = encoder.beginRenderPass({label:'Area downsample',colorAttachments:[{view:output.createView(),loadOp:'clear',storeOp:'store'}]});\n draw.setPipeline(down);draw.setBindGroup(0,group);draw.draw(3);draw.end();\n return;\n }\n if (detailEnabled && !warnedConfiguration && (render.aovResolution !== 'display' || !DETAIL_AOVS.every(kind => render.aovs.includes(kind)))) {\n warnedConfiguration = true;\n console.warn(\"EASU albedoDetail needs the displayed render to enable diffuseColor, specularColor and depth AOVs with aovResolution 'display'; upscaling without detail.\");\n }\n const aovs = detailEnabled ? DETAIL_AOVS.map(kind => render.getAovTexture(kind)) : [];\n const detail = aovs.length === 3 && aovs.every(image => image && image.width === output.width && image.height === output.height);\n const entries: GPUBindGroupEntry[] = [{binding:0,resource:input.createView()}, {binding:1,resource:{buffer:buffer([output.width,output.height,min,max])}}];\n if (detail) {\n // Cached images are recorded on their own submission so a failed chain cannot leave them stale.\n let cache: GPUCommandEncoder | undefined;\n const cached = () => cache ??= device.createCommandEncoder({label: 'EASU cache'});\n if (!state.scratch || state.scratch.length !== guideFormats.length || state.scratch[0].width !== input.width || state.scratch[0].height !== input.height) {\n if(state.scratch)retire(device,state.scratch);\n // Low diffuse and specular albedo, then (for silhouettes) nearest hit depth with hit coverage.\n state.scratch = guideFormats.map((format, index) => device.createTexture({label:`EASU low guide ${index}`,size:[input.width,input.height],format,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT}));\n state.key = undefined;\n }\n // Low albedo depends only on the AOV contents and beauty size; reuse it across presents.\n const key = [state.scratch[0], ...aovs, ...aovs.map(image => borrowedAovRevision.get(image!))];\n if (!state.key || key.some((value, index) => value !== state.key![index])) {\n const down = pipeline(`Albedo area downsample ${silhouettes}`,albedoDownsampleShader(silhouettes),guideFormats);\n const group = device.createBindGroup({layout:down.getBindGroupLayout(0),entries:[\n {binding:0,resource:aovs[0]!.createView()},{binding:1,resource:aovs[1]!.createView()},\n {binding:2,resource:{buffer:buffer([input.width,input.height,0,0])}},{binding:3,resource:aovs[2]!.createView()}\n ]});\n const draw = cached().beginRenderPass({label:'Albedo area downsample',colorAttachments:state.scratch.map(image=>({view:image.createView(),loadOp:'clear',storeOp:'store'}))});\n draw.setPipeline(down);draw.setBindGroup(0,group);draw.draw(3);draw.end();\n state.key = key;\n }\n aovs.forEach((image,index)=>entries.push({binding:2+index,resource:image!.createView()}));\n entries.push({binding:5,resource:state.scratch[0].createView()},{binding:6,resource:state.scratch[1].createView()});\n if (silhouettes) entries.push({binding:10,resource:state.scratch[2].createView()});\n entries.push({binding:7,resource:{buffer:buffer([EASU_DETAIL.minimumAlbedo,coverage,depth,EASU_DETAIL.depthTolerance])}});\n // The ratio is applied through the same grading and tone mapping as the composed image,\n // tabulated once per display setting.\n const display = render._engine.display, extended = output.format === 'rgba16float';\n const tone = [TONE_MAPPING_MODES[display.toneMapping] ?? 0, extended ? 16 : 1, display.toneMappingExposure, extended ? 1 : 0];\n const grading = [display.contrast, display.saturation, display.temperature, display.tint];\n const toneKey = [...tone, ...grading].join(',');\n state.tone ??= device.createTexture({label:'EASU tone table',size:[TONE_LUT_SIZE,2],format:'rgba32float',usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT});\n if (state.toneKey !== toneKey) {\n const build = pipeline('EASU tone table',toneLutShader,['rgba32float']);\n const group = device.createBindGroup({layout:build.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:buffer(tone)}},{binding:1,resource:{buffer:buffer(grading)}}]});\n const draw = cached().beginRenderPass({label:'EASU tone table',colorAttachments:[{view:state.tone.createView(),loadOp:'clear',storeOp:'store'}]});\n draw.setPipeline(build);draw.setBindGroup(0,group);draw.draw(3);draw.end();\n state.toneKey = toneKey;\n }\n const toneEntries: GPUBindGroupEntry[] = [{binding:8,resource:state.tone.createView()},{binding:9,resource:{buffer:buffer([tone[1],EASU_DETAIL.guidedEpsilon,0,0])}}];\n entries.push(...toneEntries);\n if (cache) device.queue.submit([cache.finish()]);\n if (guided) {\n // The local albedo-radiance fit depends on this frame's image, so it runs on every present.\n if (!state.fit || state.fit[0].width !== input.width || state.fit[0].height !== input.height) {\n if (state.fit) retire(device, state.fit);\n state.fit = ['slope','offset'].map(name => device.createTexture({label:`EASU albedo ${name}`,size:[input.width,input.height],format:'rgba16float',usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT}));\n }\n const fit = pipeline('EASU albedo fit',guidedCoefficientShader,['rgba16float','rgba16float']);\n const group = device.createBindGroup({layout:fit.getBindGroupLayout(0),entries:[{binding:0,resource:input.createView()},\n {binding:1,resource:state.scratch[0].createView()},{binding:2,resource:state.scratch[1].createView()},...toneEntries]});\n const draw = encoder.beginRenderPass({label:'EASU albedo fit',colorAttachments:state.fit.map(image=>({view:image.createView(),loadOp:'clear',storeOp:'store'}))});\n draw.setPipeline(fit);draw.setBindGroup(0,group);draw.draw(3);draw.end();\n entries.push({binding:11,resource:state.fit[0].createView()},{binding:12,resource:state.fit[1].createView()});\n }\n }\n const upscale = pipeline(`FSR 1 EASU ${detail ? `detail ${separate} ${silhouettes} ${guided}` : 'color'} ${output.format}`,detail ? easuDetailShader(separate, silhouettes, guided) : easuShader,[output.format]);\n const group = device.createBindGroup({layout:upscale.getBindGroupLayout(0),entries});\n const draw = encoder.beginRenderPass({label:'FSR 1 EASU',colorAttachments:[{view:output.createView(),loadOp:'clear',storeOp:'store'}]});\n draw.setPipeline(upscale);draw.setBindGroup(0,group);draw.draw(3);draw.end();\n };\n return Object.assign(pass, {dispose() {for(const [device,state] of devices) retire(device,owned(state));devices.clear();}});\n}\n"]}
@@ -18,6 +18,7 @@ export interface GeometryUpdateRegion {
18
18
  }
19
19
  export interface GeometryUpdateState<M extends GeometryUpdateMesh = GeometryUpdateMesh> {
20
20
  geometry: Geometry;
21
+ mergedAttributes?: boolean;
21
22
  geometries: Geometry[];
22
23
  geometryRegions: Map<Geometry, GeometryUpdateRegion>;
23
24
  geometryStates: Map<Geometry, {
@@ -1 +1 @@
1
- {"version":3,"file":"geometryUpdateState.js","sourceRoot":"","sources":["../../src/renderer/geometryUpdateState.ts"],"names":[],"mappings":"","sourcesContent":["import type Geometry from '../scene/Geometry.js';\nimport type MaterialState from '../scene/MaterialState.js';\nimport type { vec3 } from '../math.js';\nimport type { FlattendBVH } from './bvhAccel.js';\n\n// The update algorithm needs no renderer resources or browser scene facade.\nexport interface GeometryUpdateMesh { geometry: Geometry; materials: MaterialState[]; }\nexport interface GeometryUpdateBinding<M extends GeometryUpdateMesh = GeometryUpdateMesh> {\n mesh: M;\n geometry: Geometry;\n bvhBounds: [vec3.Vec3Array, vec3.Vec3Array];\n}\nexport interface GeometryUpdateRegion { vertexOffset: number; indexOffset: number; materialIndices: number[]; }\nexport interface GeometryUpdateState<M extends GeometryUpdateMesh = GeometryUpdateMesh> {\n geometry: Geometry;\n geometries: Geometry[];\n geometryRegions: Map<Geometry, GeometryUpdateRegion>;\n geometryStates: Map<Geometry, {topologyVersion: number; indices: Geometry['indices']['array']; indexCount: number}>;\n instanceBindings: GeometryUpdateBinding<M>[];\n blases: {bvh: FlattendBVH}[];\n}\n"]}
1
+ {"version":3,"file":"geometryUpdateState.js","sourceRoot":"","sources":["../../src/renderer/geometryUpdateState.ts"],"names":[],"mappings":"","sourcesContent":["import type Geometry from '../scene/Geometry.js';\nimport type MaterialState from '../scene/MaterialState.js';\nimport type { vec3 } from '../math.js';\nimport type { FlattendBVH } from './bvhAccel.js';\n\n// The update algorithm needs no renderer resources or browser scene facade.\nexport interface GeometryUpdateMesh { geometry: Geometry; materials: MaterialState[]; }\nexport interface GeometryUpdateBinding<M extends GeometryUpdateMesh = GeometryUpdateMesh> {\n mesh: M;\n geometry: Geometry;\n bvhBounds: [vec3.Vec3Array, vec3.Vec3Array];\n}\nexport interface GeometryUpdateRegion { vertexOffset: number; indexOffset: number; materialIndices: number[]; }\nexport interface GeometryUpdateState<M extends GeometryUpdateMesh = GeometryUpdateMesh> {\n geometry: Geometry;\n mergedAttributes?: boolean;\n geometries: Geometry[];\n geometryRegions: Map<Geometry, GeometryUpdateRegion>;\n geometryStates: Map<Geometry, {topologyVersion: number; indices: Geometry['indices']['array']; indexCount: number}>;\n instanceBindings: GeometryUpdateBinding<M>[];\n blases: {bvh: FlattendBVH}[];\n}\n"]}
@@ -107,9 +107,10 @@ export function updatePreparedGeometries(prepared, changed, options = {}) {
107
107
  blases.push({ blas: bvh, offset });
108
108
  }
109
109
  geometry.version = source.version;
110
- copyRegion(source, prepared.geometry, region, topologyChanged, deformationOnly);
110
+ if (prepared.mergedAttributes !== false)
111
+ copyRegion(source, prepared.geometry, region, topologyChanged, deformationOnly);
111
112
  const count = source.vertexCount, previousVertices = vertices[vertices.length - 1];
112
- if (previousVertices && previousVertices.first + previousVertices.count === region.vertexOffset && previousVertices.topologyChanged === topologyChanged && previousVertices.deformationOnly === deformationOnly)
113
+ if (prepared.mergedAttributes !== false && previousVertices && previousVertices.first + previousVertices.count === region.vertexOffset && previousVertices.topologyChanged === topologyChanged && previousVertices.deformationOnly === deformationOnly)
113
114
  previousVertices.count += count;
114
115
  else
115
116
  vertices.push({ first: region.vertexOffset, count, topologyChanged, deformationOnly });