@meimu/mutracer 0.3.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 (304) 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/THIRD_PARTY_NOTICES.md +18 -4
  5. package/dist/assets/bvh.worker.js +1 -1
  6. package/dist/mutracer.umd.js +6260 -5580
  7. package/docs/api.md +45 -18
  8. package/docs/materials.md +4 -2
  9. package/docs/performance.md +7 -0
  10. package/docs/post-processing.md +62 -9
  11. package/docs/progressive-rendering.md +3 -0
  12. package/docs/sampling.md +4 -0
  13. package/docs/technical/acceleration.md +52 -0
  14. package/docs/technical/aovs.md +79 -0
  15. package/docs/technical/caustics.md +109 -0
  16. package/docs/technical/continuous-spectrum.md +29 -0
  17. package/docs/technical/display-upscale.md +82 -0
  18. package/docs/technical/openpbr.md +99 -0
  19. package/docs/technical/pbrt-import.md +168 -0
  20. package/docs/technical/tiling.md +74 -0
  21. package/docs/technical/webgl.md +53 -0
  22. package/docs/viewer.md +11 -1
  23. package/lib/Display.d.ts +19 -5
  24. package/lib/Display.js +10 -7
  25. package/lib/Display.js.map +1 -1
  26. package/lib/Engine.d.ts +2 -1
  27. package/lib/Engine.js +30 -2
  28. package/lib/Engine.js.map +1 -1
  29. package/lib/Render.d.ts +20 -11
  30. package/lib/Render.js +32 -7
  31. package/lib/Render.js.map +1 -1
  32. package/lib/main.d.ts +3 -1
  33. package/lib/main.js +1 -0
  34. package/lib/main.js.map +1 -1
  35. package/lib/oidn.d.ts +1 -1
  36. package/lib/renderer/AovPrimitiveCache.js +39 -8
  37. package/lib/renderer/AovPrimitiveCache.js.map +1 -1
  38. package/lib/renderer/DisplayPostProcess.d.ts +8 -3
  39. package/lib/renderer/DisplayPostProcess.js +51 -18
  40. package/lib/renderer/DisplayPostProcess.js.map +1 -1
  41. package/lib/renderer/MaterialData.js +7 -2
  42. package/lib/renderer/MaterialData.js.map +1 -1
  43. package/lib/renderer/RenderingPipeline.d.ts +7 -1
  44. package/lib/renderer/RenderingPipeline.js.map +1 -1
  45. package/lib/renderer/TileRender.d.ts +2 -2
  46. package/lib/renderer/TileRender.js +128 -7
  47. package/lib/renderer/TileRender.js.map +1 -1
  48. package/lib/renderer/WGPUAov.d.ts +6 -1
  49. package/lib/renderer/WGPUAov.js +108 -14
  50. package/lib/renderer/WGPUAov.js.map +1 -1
  51. package/lib/renderer/WGPUCanvasSurface.js +12 -1
  52. package/lib/renderer/WGPUCanvasSurface.js.map +1 -1
  53. package/lib/renderer/WGPUEnvMapDistribution.js +19 -19
  54. package/lib/renderer/WGPUFullQuadPass.js +3 -3
  55. package/lib/renderer/WGPURayTraceOutput.js +12 -12
  56. package/lib/renderer/WGPURayTracePass.d.ts +17 -4
  57. package/lib/renderer/WGPURayTracePass.js +194 -71
  58. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  59. package/lib/renderer/WGPURenderingPipeline.js +46 -40
  60. package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
  61. package/lib/renderer/WebGLAov.js +3 -3
  62. package/lib/renderer/WebGLAov.js.map +1 -1
  63. package/lib/renderer/WebGLFullQuadPass.d.ts +1 -1
  64. package/lib/renderer/WebGLFullQuadPass.js +8 -2
  65. package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
  66. package/lib/renderer/WebGLJNLMDenoiser.js +66 -66
  67. package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -1
  68. package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
  69. package/lib/renderer/WebGLRayTracePass.d.ts +14 -10
  70. package/lib/renderer/WebGLRayTracePass.js +115 -111
  71. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  72. package/lib/renderer/WebGLRenderingPipeline.js +10 -3
  73. package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
  74. package/lib/renderer/WebGLSkyBaker.js +57 -57
  75. package/lib/renderer/aov.d.ts +13 -1
  76. package/lib/renderer/aov.js +21 -2
  77. package/lib/renderer/aov.js.map +1 -1
  78. package/lib/renderer/aovDisplay.js +2 -2
  79. package/lib/renderer/aovDisplay.js.map +1 -1
  80. package/lib/renderer/binnedSahBvh.d.ts +2 -1
  81. package/lib/renderer/binnedSahBvh.js +24 -17
  82. package/lib/renderer/binnedSahBvh.js.map +1 -1
  83. package/lib/renderer/bvhAccel.d.ts +3 -1
  84. package/lib/renderer/bvhAccel.js +36 -6
  85. package/lib/renderer/bvhAccel.js.map +1 -1
  86. package/lib/renderer/cameraUniform.d.ts +1 -1
  87. package/lib/renderer/cameraUniform.js +6 -2
  88. package/lib/renderer/cameraUniform.js.map +1 -1
  89. package/lib/renderer/compactVertices.d.ts +14 -0
  90. package/lib/renderer/compactVertices.js +124 -0
  91. package/lib/renderer/compactVertices.js.map +1 -0
  92. package/lib/renderer/easu.d.ts +11 -0
  93. package/lib/renderer/easu.js +156 -0
  94. package/lib/renderer/easu.js.map +1 -0
  95. package/lib/renderer/geometryUpdateState.d.ts +1 -0
  96. package/lib/renderer/geometryUpdateState.js.map +1 -1
  97. package/lib/renderer/geometryUpdates.js +3 -2
  98. package/lib/renderer/geometryUpdates.js.map +1 -1
  99. package/lib/renderer/glsl/aovDisplay.frag.js +5 -5
  100. package/lib/renderer/glsl/aovReflectance.glsl.js +35 -35
  101. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +1 -1
  102. package/lib/renderer/glsl/aovTrace.frag.js +44 -36
  103. package/lib/renderer/glsl/aovTrace.frag.js.map +1 -1
  104. package/lib/renderer/glsl/chunks/cameraProjection.glsl.d.ts +2 -0
  105. package/lib/renderer/glsl/chunks/cameraProjection.glsl.js +16 -0
  106. package/lib/renderer/glsl/chunks/cameraProjection.glsl.js.map +1 -0
  107. package/lib/renderer/glsl/chunks/cameraRay.glsl.d.ts +1 -1
  108. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +9 -16
  109. package/lib/renderer/glsl/chunks/cameraRay.glsl.js.map +1 -1
  110. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +8 -8
  111. package/lib/renderer/glsl/chunks/envMap.glsl.js +67 -67
  112. package/lib/renderer/glsl/chunks/intersect.glsl.js +390 -375
  113. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
  114. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +120 -120
  115. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +562 -562
  116. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  117. package/lib/renderer/glsl/chunks/random.glsl.js +4 -4
  118. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +37 -35
  119. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  120. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +70 -74
  121. package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
  122. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -1
  123. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +107 -88
  124. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
  125. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +11 -11
  126. package/lib/renderer/glsl/chunks/sampling.glsl.js +77 -77
  127. package/lib/renderer/glsl/chunks/sobol.glsl.js +70 -70
  128. package/lib/renderer/glsl/chunks/spectralPrefix.glsl.d.ts +6 -0
  129. package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js +47 -0
  130. package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js.map +1 -0
  131. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  132. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
  133. package/lib/renderer/glsl/depthQuery.frag.js +12 -6
  134. package/lib/renderer/glsl/depthQuery.frag.js.map +1 -1
  135. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +10 -10
  136. package/lib/renderer/glsl/rayTrace.frag.js +233 -170
  137. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
  138. package/lib/renderer/glsl/shadowCatcher.frag.js +10 -9
  139. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  140. package/lib/renderer/glsl/webglPipeline.frag.js +58 -58
  141. package/lib/renderer/gpuMemory.js +1 -1
  142. package/lib/renderer/gpuMemory.js.map +1 -1
  143. package/lib/renderer/openPbrEnergyLut.d.ts +2 -1
  144. package/lib/renderer/openPbrEnergyLut.js +18 -1
  145. package/lib/renderer/openPbrEnergyLut.js.map +1 -1
  146. package/lib/renderer/pathLimits.d.ts +5 -4
  147. package/lib/renderer/pathLimits.js +6 -5
  148. package/lib/renderer/pathLimits.js.map +1 -1
  149. package/lib/renderer/prepareMeshBVH.d.ts +2 -0
  150. package/lib/renderer/prepareMeshBVH.js +5 -3
  151. package/lib/renderer/prepareMeshBVH.js.map +1 -1
  152. package/lib/renderer/progressiveScheduler.js +1 -1
  153. package/lib/renderer/progressiveScheduler.js.map +1 -1
  154. package/lib/renderer/renderPipeline.d.ts +4 -0
  155. package/lib/renderer/renderPipeline.js +1 -0
  156. package/lib/renderer/renderPipeline.js.map +1 -1
  157. package/lib/renderer/researchTransport.d.ts +1 -1
  158. package/lib/renderer/researchTransport.js.map +1 -1
  159. package/lib/renderer/sceneAssembly.d.ts +1 -1
  160. package/lib/renderer/sceneAssembly.js +4 -3
  161. package/lib/renderer/sceneAssembly.js.map +1 -1
  162. package/lib/renderer/sceneChangeDetector.d.ts +1 -1
  163. package/lib/renderer/sceneChangeDetector.js +3 -1
  164. package/lib/renderer/sceneChangeDetector.js.map +1 -1
  165. package/lib/renderer/sceneLayoutSchema.d.ts +1 -0
  166. package/lib/renderer/sceneLayoutSchema.js +2 -2
  167. package/lib/renderer/sceneLayoutSchema.js.map +1 -1
  168. package/lib/renderer/scenePreparation.d.ts +3 -2
  169. package/lib/renderer/scenePreparation.js +18 -2
  170. package/lib/renderer/scenePreparation.js.map +1 -1
  171. package/lib/renderer/scratchSampling.js +6 -6
  172. package/lib/renderer/spectrum.js +2 -2
  173. package/lib/renderer/staticBvhPreparation.d.ts +9 -0
  174. package/lib/renderer/staticBvhPreparation.js +8 -2
  175. package/lib/renderer/staticBvhPreparation.js.map +1 -1
  176. package/lib/renderer/surfaceHit.d.ts +10 -0
  177. package/lib/renderer/surfaceHit.js +22 -0
  178. package/lib/renderer/surfaceHit.js.map +1 -0
  179. package/lib/renderer/tangentRequirements.d.ts +2 -0
  180. package/lib/renderer/tangentRequirements.js +7 -0
  181. package/lib/renderer/tangentRequirements.js.map +1 -0
  182. package/lib/renderer/textureAtlas.d.ts +4 -0
  183. package/lib/renderer/textureAtlas.js +48 -2
  184. package/lib/renderer/textureAtlas.js.map +1 -1
  185. package/lib/renderer/webgl.js +4 -0
  186. package/lib/renderer/webgl.js.map +1 -1
  187. package/lib/renderer/webglVertexAttributes.d.ts +17 -0
  188. package/lib/renderer/webglVertexAttributes.js +44 -0
  189. package/lib/renderer/webglVertexAttributes.js.map +1 -0
  190. package/lib/renderer/wgpuBindlessSource.js +2 -2
  191. package/lib/renderer/wgpuMaterialConstants.js +4 -3
  192. package/lib/renderer/wgpuMaterialConstants.js.map +1 -1
  193. package/lib/renderer/wgpuSceneUniform.js +2 -2
  194. package/lib/renderer/wgpuSceneUniform.js.map +1 -1
  195. package/lib/renderer/wgpuShaderSource.d.ts +15 -0
  196. package/lib/renderer/wgpuShaderSource.js +1 -1
  197. package/lib/renderer/wgpuShaderSource.js.map +1 -1
  198. package/lib/renderer/wgsl/aovCompact.wgsl.d.ts +4 -0
  199. package/lib/renderer/wgsl/aovCompact.wgsl.js +26 -0
  200. package/lib/renderer/wgsl/aovCompact.wgsl.js.map +1 -0
  201. package/lib/renderer/wgsl/aovDisplay.wgsl.js +9 -9
  202. package/lib/renderer/wgsl/aovReflectance.wgsl.js +39 -39
  203. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +1 -1
  204. package/lib/renderer/wgsl/aovResolve.wgsl.d.ts +4 -0
  205. package/lib/renderer/wgsl/aovResolve.wgsl.js +21 -2
  206. package/lib/renderer/wgsl/aovResolve.wgsl.js.map +1 -1
  207. package/lib/renderer/wgsl/aovSnapshot.wgsl.js +2 -2
  208. package/lib/renderer/wgsl/aovSnapshot.wgsl.js.map +1 -1
  209. package/lib/renderer/wgsl/aovTrace.wgsl.js +31 -31
  210. package/lib/renderer/wgsl/aovTraceDisplay.wgsl.d.ts +2 -0
  211. package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js +56 -0
  212. package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js.map +1 -0
  213. package/lib/renderer/wgsl/bloom.wgsl.js +18 -18
  214. package/lib/renderer/wgsl/causticLight.compute.d.ts +1 -1
  215. package/lib/renderer/wgsl/causticLight.compute.js +121 -119
  216. package/lib/renderer/wgsl/causticLight.compute.js.map +1 -1
  217. package/lib/renderer/wgsl/chunks/background.wgsl.js +46 -46
  218. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +4 -4
  219. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +3 -3
  220. package/lib/renderer/wgsl/chunks/caustics.wgsl.js +3 -3
  221. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  222. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +30 -30
  223. package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +6 -2
  224. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +550 -542
  225. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  226. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.d.ts +1 -1
  227. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +18 -16
  228. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -1
  229. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +2 -1
  230. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +70 -69
  231. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  232. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +593 -593
  233. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +118 -118
  234. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  235. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +4 -1
  236. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +32 -26
  237. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  238. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +114 -114
  239. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
  240. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +159 -137
  241. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
  242. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +8 -8
  243. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +74 -74
  244. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +74 -74
  245. package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.d.ts +6 -0
  246. package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js +66 -0
  247. package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js.map +1 -0
  248. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
  249. package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.d.ts +2 -0
  250. package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js +61 -0
  251. package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js.map +1 -0
  252. package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +2 -0
  253. package/lib/renderer/wgsl/compose.frag.wgsl.js +99 -97
  254. package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -1
  255. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  256. package/lib/renderer/wgsl/depthQuery.wgsl.d.ts +1 -1
  257. package/lib/renderer/wgsl/depthQuery.wgsl.js +11 -2
  258. package/lib/renderer/wgsl/depthQuery.wgsl.js.map +1 -1
  259. package/lib/renderer/wgsl/easu.wgsl.d.ts +2 -0
  260. package/lib/renderer/wgsl/easu.wgsl.js +80 -0
  261. package/lib/renderer/wgsl/easu.wgsl.js.map +1 -0
  262. package/lib/renderer/wgsl/easuDetail.wgsl.d.ts +21 -0
  263. package/lib/renderer/wgsl/easuDetail.wgsl.js +230 -0
  264. package/lib/renderer/wgsl/easuDetail.wgsl.js.map +1 -0
  265. package/lib/renderer/wgsl/jnlm.compute.js +74 -74
  266. package/lib/renderer/wgsl/jnlm.compute.js.map +1 -1
  267. package/lib/renderer/wgsl/offlineAdaptive.compute.js +26 -26
  268. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +3 -3
  269. package/lib/renderer/wgsl/photonMap.compute.js +89 -89
  270. package/lib/renderer/wgsl/proceduralSky.compute.js +61 -61
  271. package/lib/renderer/wgsl/rayTrace.compute.d.ts +14 -0
  272. package/lib/renderer/wgsl/rayTrace.compute.js +395 -333
  273. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  274. package/lib/scene/Scene.js.map +1 -1
  275. package/lib/settings/render.d.ts +11 -0
  276. package/lib/settings/render.js +1 -0
  277. package/lib/settings/render.js.map +1 -1
  278. package/lib/util/fromTHREE.js +21 -14
  279. package/lib/util/fromTHREE.js.map +1 -1
  280. package/lib/version.d.ts +1 -1
  281. package/lib/version.js +1 -1
  282. package/lib/version.js.map +1 -1
  283. package/package.json +5 -2
  284. package/lib/oidnBundledWeights.cdn.d.ts +0 -2
  285. package/lib/oidnBundledWeights.cdn.js +0 -5
  286. package/lib/oidnBundledWeights.cdn.js.map +0 -1
  287. package/lib/renderer/bvh.worker.d.ts +0 -1
  288. package/lib/renderer/bvh.worker.js +0 -16
  289. package/lib/renderer/bvh.worker.js.map +0 -1
  290. package/lib/renderer/bvhWorkerBuild.d.ts +0 -13
  291. package/lib/renderer/bvhWorkerBuild.js +0 -17
  292. package/lib/renderer/bvhWorkerBuild.js.map +0 -1
  293. package/lib/renderer/lightCore.d.ts +0 -12
  294. package/lib/renderer/lightCore.js +0 -13
  295. package/lib/renderer/lightCore.js.map +0 -1
  296. package/lib/renderer/materialCore.d.ts +0 -8
  297. package/lib/renderer/materialCore.js +0 -9
  298. package/lib/renderer/materialCore.js.map +0 -1
  299. package/lib/scene/PixelTexture.d.ts +0 -6
  300. package/lib/scene/PixelTexture.js +0 -10
  301. package/lib/scene/PixelTexture.js.map +0 -1
  302. package/lib/util/studioLighting.d.ts +0 -18
  303. package/lib/util/studioLighting.js +0 -36
  304. package/lib/util/studioLighting.js.map +0 -1
@@ -5,19 +5,19 @@ let filtered = load_filteredTex(uv, 0).rgb;
5
5
  let foreground = load_foregroundTex(uv, 0);
6
6
  let background = load_backgroundTex(uv, 0);
7
7
 
8
- var mS = foreground;
9
- var mR = background;
8
+ var nU = foreground;
9
+ var nT = background;
10
10
  if (any(filtered != original)) {
11
- let wu = abs(original) > vec3f(0.000001);
12
- let ah = select(vec3f(1.0), original, wu);
13
- let scale = select(vec3f(1.0), filtered / ah, wu);
14
- let vO = select(filtered - original, vec3f(0.0), wu);
15
- mS = vec4f(foreground.rgb * scale + vO, foreground.a);
11
+ let yr = abs(original) > vec3f(0.000001);
12
+ let ah = select(vec3f(1.0), original, yr);
13
+ let scale = select(vec3f(1.0), filtered / ah, yr);
14
+ let xI = select(filtered - original, vec3f(0.0), yr);
15
+ nU = vec4f(foreground.rgb * scale + xI, foreground.a);
16
16
 
17
- mR = vec4f(background.rgb * scale + vO * background.a, background.a);
17
+ nT = vec4f(background.rgb * scale + xI * background.a, background.a);
18
18
  }
19
- output.foreground = mS;
20
- output.background = mR;
19
+ output.foreground = nU;
20
+ output.background = nT;
21
21
  `;
22
22
  /** Custom output alpha is ignored; retain the input composition's coverage. */
23
23
  export const customDenoiseCoverageMain = /* wgsl */ `
@@ -1,3 +1,3 @@
1
1
  /** Extra entry point in the ray-tracing module; reuses its scene bindings. */
2
- declare const _default: "\n@group(3) @binding(4) var<uniform> depthArea: vec4f;\n\n@compute @workgroup_size(7, 7)\nfn depthQuery(@builtin(global_invocation_id) id: vec3u) {\n let index = id.x + id.y * 7u;\n let offset = vec2f(id.xy) / 6.0 * 2.0 - 1.0;\n let uv = depthArea.xy + depthArea.zw * offset * vec2f(1.0, -1.0);\n outColor[index] = vec4f(0.0);\n if (any(uv < vec2f(0.0)) || any(uv > vec2f(1.0))) { return; }\n var ray = initCameraRay(uv);\n let eye = cameraUniform.viewInv[3].xyz;\n let forward = -normalize(cameraUniform.viewInv[2].xyz);\n var si: SurfaceInteraction;\n si.triangleIndex = -1;\n // Ignore invisible catchers and alpha-cutout holes, without stochastic DOF\n // or pixel jitter. A bounded continuation prevents coincident surfaces\n // from keeping the query alive indefinitely.\n for (var layer = 0; layer < 32; layer++) {\n intersectScene(ray, &si, 0, false, false);\n if (!si.hit) { return; }\n var material: OpenPbrResolvedMaterial;\n getMaterial(&material, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);\n if (material.materialType != SHADOW_CATCHER && material.alpha > 0.0) {\n outColor[index] = vec4f(max(dot(si.position - eye, forward), 0.0), 0.0, 0.0, 0.0);\n return;\n }\n ray.o = si.position + ray.d * (EPS * 0.02);\n }\n}\n";
2
+ declare const _default: "\n@group(3) @binding(4) var<uniform> depthArea: vec4f;\n\n@compute @workgroup_size(7, 7)\nfn depthQuery(@builtin(global_invocation_id) id: vec3u) {\n let index = id.x + id.y * 7u;\n let picking = depthArea.z < 0.0;\n if (picking && index != 0u) {return;}\n let offset = vec2f(id.xy) / 6.0 * 2.0 - 1.0;\n let uv = select(depthArea.xy + depthArea.zw * offset * vec2f(1.0, -1.0), depthArea.xy, picking);\n outColor[index] = vec4f(0.0);\n if (any(uv < vec2f(0.0)) || any(uv > vec2f(1.0))) { return; }\n var ray = initCameraRay(uv);\n let eye = cameraUniform.viewInv[3].xyz;\n let forward = -normalize(cameraUniform.viewInv[2].xyz);\n var si: SurfaceInteraction;\n si.triangleIndex = -1;\n // Ignore invisible catchers and alpha-cutout holes, without stochastic DOF\n // or pixel jitter. A bounded continuation prevents coincident surfaces\n // from keeping the query alive indefinitely.\n for (var layer = 0; layer < 32; layer++) {\n intersectScene(ray, &si, 0, false, false);\n if (!si.hit) { return; }\n var material: OpenPbrResolvedMaterial;\n getMaterial(&material, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);\n if (material.materialType != SHADOW_CATCHER && material.alpha > 0.0) {\n if (picking) {\n let instance = u32(si.instanceIndex) + 1u;\n let materialIndex = u32(si.materialIndex) + 1u;\n outColor[index] = vec4f(f32(instance & 65535u), f32(instance >> 16u),\n f32(materialIndex & 65535u), f32(materialIndex >> 16u));\n } else {\n outColor[index] = vec4f(max(dot(si.position - eye, forward), 0.0), 0.0, 0.0, 0.0);\n }\n return;\n }\n ray.o = si.position + ray.d * (EPS * 0.02);\n }\n}\n";
3
3
  export default _default;
@@ -6,11 +6,13 @@ export default /* wgsl */ `
6
6
  @compute @workgroup_size(${DEPTH_SAMPLE_GRID}, ${DEPTH_SAMPLE_GRID})
7
7
  fn depthQuery(@builtin(global_invocation_id) id: vec3u) {
8
8
  let index = id.x + id.y * ${DEPTH_SAMPLE_GRID}u;
9
+ let picking = depthArea.z < 0.0;
10
+ if (picking && index != 0u) {return;}
9
11
  let offset = vec2f(id.xy) / ${DEPTH_SAMPLE_GRID - 1}.0 * 2.0 - 1.0;
10
- let uv = depthArea.xy + depthArea.zw * offset * vec2f(1.0, -1.0);
12
+ let uv = select(depthArea.xy + depthArea.zw * offset * vec2f(1.0, -1.0), depthArea.xy, picking);
11
13
  outColor[index] = vec4f(0.0);
12
14
  if (any(uv < vec2f(0.0)) || any(uv > vec2f(1.0))) { return; }
13
- var ray = eT(uv);
15
+ var ray = cV(uv);
14
16
  let eye = cameraUniform.viewInv[3].xyz;
15
17
  let forward = -normalize(cameraUniform.viewInv[2].xyz);
16
18
  var si: SurfaceInteraction;
@@ -24,7 +26,14 @@ if (!si.hit) { return; }
24
26
  var material: OpenPbrResolvedMaterial;
25
27
  getMaterial(&material, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);
26
28
  if (material.materialType != SHADOW_CATCHER && material.alpha > 0.0) {
29
+ if (picking) {
30
+ let instance = u32(si.instanceIndex) + 1u;
31
+ let materialIndex = u32(si.materialIndex) + 1u;
32
+ outColor[index] = vec4f(f32(instance & 65535u), f32(instance >> 16u),
33
+ f32(materialIndex & 65535u), f32(materialIndex >> 16u));
34
+ } else {
27
35
  outColor[index] = vec4f(max(dot(si.position - eye, forward), 0.0), 0.0, 0.0, 0.0);
36
+ }
28
37
  return;
29
38
  }
30
39
  ray.o = si.position + ray.d * (EPS * 0.02);
@@ -1 +1 @@
1
- {"version":3,"file":"depthQuery.wgsl.js","sourceRoot":"","sources":["../../../src/renderer/wgsl/depthQuery.wgsl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,8EAA8E;AAC9E,eAAe,UAAU,CAAC;;;2BAGC,iBAAiB,KAAK,iBAAiB;;4BAEpC,iBAAiB;8BACf,iBAAiB,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;CAwBpD,CAAC","sourcesContent":["import { DEPTH_SAMPLE_GRID } from '../depthQuery.js';\n\n/** Extra entry point in the ray-tracing module; reuses its scene bindings. */\nexport default /* wgsl */ `\n@group(3) @binding(4) var<uniform> depthArea: vec4f;\n\n@compute @workgroup_size(${DEPTH_SAMPLE_GRID}, ${DEPTH_SAMPLE_GRID})\nfn depthQuery(@builtin(global_invocation_id) id: vec3u) {\n let index = id.x + id.y * ${DEPTH_SAMPLE_GRID}u;\n let offset = vec2f(id.xy) / ${DEPTH_SAMPLE_GRID - 1}.0 * 2.0 - 1.0;\n let uv = depthArea.xy + depthArea.zw * offset * vec2f(1.0, -1.0);\n outColor[index] = vec4f(0.0);\n if (any(uv < vec2f(0.0)) || any(uv > vec2f(1.0))) { return; }\n var ray = initCameraRay(uv);\n let eye = cameraUniform.viewInv[3].xyz;\n let forward = -normalize(cameraUniform.viewInv[2].xyz);\n var si: SurfaceInteraction;\n si.triangleIndex = -1;\n // Ignore invisible catchers and alpha-cutout holes, without stochastic DOF\n // or pixel jitter. A bounded continuation prevents coincident surfaces\n // from keeping the query alive indefinitely.\n for (var layer = 0; layer < 32; layer++) {\n intersectScene(ray, &si, 0, false, false);\n if (!si.hit) { return; }\n var material: OpenPbrResolvedMaterial;\n getMaterial(&material, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);\n if (material.materialType != SHADOW_CATCHER && material.alpha > 0.0) {\n outColor[index] = vec4f(max(dot(si.position - eye, forward), 0.0), 0.0, 0.0, 0.0);\n return;\n }\n ray.o = si.position + ray.d * (EPS * 0.02);\n }\n}\n`;\n"]}
1
+ {"version":3,"file":"depthQuery.wgsl.js","sourceRoot":"","sources":["../../../src/renderer/wgsl/depthQuery.wgsl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,8EAA8E;AAC9E,eAAe,UAAU,CAAC;;;2BAGC,iBAAiB,KAAK,iBAAiB;;4BAEpC,iBAAiB;;;8BAGf,iBAAiB,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BpD,CAAC","sourcesContent":["import { DEPTH_SAMPLE_GRID } from '../depthQuery.js';\n\n/** Extra entry point in the ray-tracing module; reuses its scene bindings. */\nexport default /* wgsl */ `\n@group(3) @binding(4) var<uniform> depthArea: vec4f;\n\n@compute @workgroup_size(${DEPTH_SAMPLE_GRID}, ${DEPTH_SAMPLE_GRID})\nfn depthQuery(@builtin(global_invocation_id) id: vec3u) {\n let index = id.x + id.y * ${DEPTH_SAMPLE_GRID}u;\n let picking = depthArea.z < 0.0;\n if (picking && index != 0u) {return;}\n let offset = vec2f(id.xy) / ${DEPTH_SAMPLE_GRID - 1}.0 * 2.0 - 1.0;\n let uv = select(depthArea.xy + depthArea.zw * offset * vec2f(1.0, -1.0), depthArea.xy, picking);\n outColor[index] = vec4f(0.0);\n if (any(uv < vec2f(0.0)) || any(uv > vec2f(1.0))) { return; }\n var ray = initCameraRay(uv);\n let eye = cameraUniform.viewInv[3].xyz;\n let forward = -normalize(cameraUniform.viewInv[2].xyz);\n var si: SurfaceInteraction;\n si.triangleIndex = -1;\n // Ignore invisible catchers and alpha-cutout holes, without stochastic DOF\n // or pixel jitter. A bounded continuation prevents coincident surfaces\n // from keeping the query alive indefinitely.\n for (var layer = 0; layer < 32; layer++) {\n intersectScene(ray, &si, 0, false, false);\n if (!si.hit) { return; }\n var material: OpenPbrResolvedMaterial;\n getMaterial(&material, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);\n if (material.materialType != SHADOW_CATCHER && material.alpha > 0.0) {\n if (picking) {\n let instance = u32(si.instanceIndex) + 1u;\n let materialIndex = u32(si.materialIndex) + 1u;\n outColor[index] = vec4f(f32(instance & 65535u), f32(instance >> 16u),\n f32(materialIndex & 65535u), f32(materialIndex >> 16u));\n } else {\n outColor[index] = vec4f(max(dot(si.position - eye, forward), 0.0), 0.0, 0.0, 0.0);\n }\n return;\n }\n ray.o = si.position + ray.d * (EPS * 0.02);\n }\n}\n`;\n"]}
@@ -0,0 +1,2 @@
1
+ export declare const easuShader = "\n@group(0) @binding(0) var colorImage: texture_2d<f32>;\n@group(0) @binding(1) var<uniform> outputSize: vec4f;\n@vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {\n let p = vec2f(f32((index << 1u) & 2u), f32(index & 2u));\n return vec4f(p * 2.0 - 1.0, 0.0, 1.0);\n}\nconst offsets = array<vec2i,12>(vec2i(0,-1),vec2i(1,-1),vec2i(-1,0),vec2i(0,0),vec2i(1,0),vec2i(2,0),\n vec2i(-1,1),vec2i(0,1),vec2i(1,1),vec2i(2,1),vec2i(0,2),vec2i(1,2));\nfn loadColor(p: vec2i) -> vec4f {return textureLoad(colorImage, clamp(p,vec2i(0),vec2i(textureDimensions(colorImage))-1),0);}\nfn gradient(a: f32,b: f32,c: f32,d: f32,e: f32,w: f32) -> vec3f {\n let direction = vec2f(d-b,e-a);\n let length = clamp(abs(direction)/max(vec2f(max(abs(d-c),abs(c-b)),max(abs(e-c),abs(c-a))),vec2f(1e-8)),vec2f(0),vec2f(1));\n return vec3f(direction,dot(length,length))*w;\n}\nfn easuWeight(offset: vec2f, direction: vec2f, length: vec2f, lobe: f32) -> f32 {\n let v = vec2f(dot(offset,direction),dot(offset,vec2f(-direction.y,direction.x)))*length;\n let distance = min(dot(v,v),1.0/lobe);\n let b = 0.4*distance-1.0;\n let a = lobe*distance-1.0;\n return (1.5625*b*b-0.5625)*a*a;\n}\n@fragment fn fragment(@builtin(position) position: vec4f) -> @location(0) vec4f {\n let point = position.xy*vec2f(textureDimensions(colorImage))/outputSize.xy-0.5;\n let base = vec2i(floor(point)); let phase = fract(point);\n var colors: array<vec4f,12>;\n var luma: array<f32,12>;\n // FSR expects [0,1]. Normalize the neighborhood for direction estimation\n // in extended-range output; filter the original RGB without clipping it to 1.\n var range = 1.0;\n for(var i=0u;i<12u;i++){colors[i]=loadColor(base+offsets[i]);range=max(range,max(max(colors[i].r,colors[i].g),colors[i].b));}\n for(var i=0u;i<12u;i++){luma[i]=dot(colors[i].rgb/range,vec3f(0.5,1.0,0.5));}\n let g = gradient(luma[0],luma[2],luma[3],luma[4],luma[7],(1.0-phase.x)*(1.0-phase.y))+\n gradient(luma[1],luma[3],luma[4],luma[5],luma[8],phase.x*(1.0-phase.y))+\n gradient(luma[3],luma[6],luma[7],luma[8],luma[10],(1.0-phase.x)*phase.y)+\n gradient(luma[4],luma[7],luma[8],luma[9],luma[11],phase.x*phase.y);\n var direction = vec2f(1.0,0.0);\n if(dot(g.xy,g.xy)>=1.0/32768.0){direction=normalize(g.xy);}\n let edge = (g.z*0.5)*(g.z*0.5);\n let stretch = dot(direction,direction)/max(abs(direction.x),abs(direction.y));\n let length = vec2f(1.0+(stretch-1.0)*edge,1.0-0.5*edge);\n let lobe = 0.5+(0.21-0.5)*edge;\n var result=vec4f(0); var total=0.0;\n for(var i=0u;i<12u;i++){\n let weight=easuWeight(vec2f(offsets[i])-phase,direction,length,lobe);\n result+=colors[i]*weight;total+=weight;\n }\n let lower=min(min(colors[3],colors[4]),min(colors[7],colors[8]));\n let upper=max(max(colors[3],colors[4]),max(colors[7],colors[8]));\n return clamp(result/total,lower,upper);\n}\n";
2
+ export declare const areaDownsampleShader = "\n@group(0) @binding(0) var colorImage: texture_2d<f32>;\n@group(0) @binding(1) var<uniform> outputSize: vec4f;\n@vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {\n let p = vec2f(f32((index << 1u) & 2u), f32(index & 2u));\n return vec4f(p * 2.0 - 1.0, 0.0, 1.0);\n}\n@fragment fn fragment(@builtin(position) position: vec4f) -> @location(0) vec4f {\n let scale = vec2f(textureDimensions(colorImage))/outputSize.xy;\n let start = floor(position.xy)*scale; let end = start+scale;\n var sum = vec4f(0);\n for (var y = i32(floor(start.y)); y < i32(ceil(end.y)); y++) {\n for (var x = i32(floor(start.x)); x < i32(ceil(end.x)); x++) {\n let overlap = max(vec2f(0), min(vec2f(vec2i(x+1,y+1)), end)-max(vec2f(vec2i(x,y)), start));\n let color = textureLoad(colorImage, vec2i(x,y), 0);\n sum += vec4f(color.rgb*color.a, color.a)*overlap.x*overlap.y;\n }\n }\n return vec4f(sum.rgb/max(sum.a, 1e-8), sum.a/(scale.x*scale.y));\n}\n";
@@ -0,0 +1,80 @@
1
+ // Adapted from AMD FidelityFX FSR 1, ffx_fsr1.h v1.20210629,
2
+ // FsrEasuSetF/FsrEasuTapF/FsrEasuF (32-bit path). MIT; see LICENSES/FidelityFX-FSR.txt.
3
+ // https://github.com/GPUOpen-Effects/FidelityFX-FSR/blob/master/ffx-fsr/ffx_fsr1.h
4
+ // Uses exact reciprocals instead of the reference's low precision approximations.
5
+ export const easuShader = /* wgsl */ `
6
+ @group(0) @binding(0) var colorImage: texture_2d<f32>;
7
+ @group(0) @binding(1) var<uniform> outputSize: vec4f;
8
+ @vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
9
+ let p = vec2f(f32((index << 1u) & 2u), f32(index & 2u));
10
+ return vec4f(p * 2.0 - 1.0, 0.0, 1.0);
11
+ }
12
+ const offsets = array<vec2i,12>(vec2i(0,-1),vec2i(1,-1),vec2i(-1,0),vec2i(0,0),vec2i(1,0),vec2i(2,0),
13
+ vec2i(-1,1),vec2i(0,1),vec2i(1,1),vec2i(2,1),vec2i(0,2),vec2i(1,2));
14
+ fn ns(p: vec2i) -> vec4f {return textureLoad(colorImage, clamp(p,vec2i(0),vec2i(textureDimensions(colorImage))-1),0);}
15
+ fn tB(a: f32,b: f32,c: f32,d: f32,e: f32,w: f32) -> vec3f {
16
+ let direction = vec2f(d-b,e-a);
17
+ let length = clamp(abs(direction)/max(vec2f(max(abs(d-c),abs(c-b)),max(abs(e-c),abs(c-a))),vec2f(1e-8)),vec2f(0),vec2f(1));
18
+ return vec3f(direction,dot(length,length))*w;
19
+ }
20
+ fn sJ(offset: vec2f, direction: vec2f, length: vec2f, lobe: f32) -> f32 {
21
+ let v = vec2f(dot(offset,direction),dot(offset,vec2f(-direction.y,direction.x)))*length;
22
+ let distance = min(dot(v,v),1.0/lobe);
23
+ let b = 0.4*distance-1.0;
24
+ let a = lobe*distance-1.0;
25
+ return (1.5625*b*b-0.5625)*a*a;
26
+ }
27
+ @fragment fn fragment(@builtin(position) position: vec4f) -> @location(0) vec4f {
28
+ let point = position.xy*vec2f(textureDimensions(colorImage))/outputSize.xy-0.5;
29
+ let base = vec2i(floor(point)); let phase = fract(point);
30
+ var colors: array<vec4f,12>;
31
+ var lQ: array<f32,12>;
32
+
33
+
34
+ var range = 1.0;
35
+ for(var i=0u;i<12u;i++){colors[i]=ns(base+offsets[i]);range=max(range,max(max(colors[i].r,colors[i].g),colors[i].b));}
36
+ for(var i=0u;i<12u;i++){lQ[i]=dot(colors[i].rgb/range,vec3f(0.5,1.0,0.5));}
37
+ let g = tB(lQ[0],lQ[2],lQ[3],lQ[4],lQ[7],(1.0-phase.x)*(1.0-phase.y))+
38
+ tB(lQ[1],lQ[3],lQ[4],lQ[5],lQ[8],phase.x*(1.0-phase.y))+
39
+ tB(lQ[3],lQ[6],lQ[7],lQ[8],lQ[10],(1.0-phase.x)*phase.y)+
40
+ tB(lQ[4],lQ[7],lQ[8],lQ[9],lQ[11],phase.x*phase.y);
41
+ var direction = vec2f(1.0,0.0);
42
+ if(dot(g.xy,g.xy)>=1.0/32768.0){direction=normalize(g.xy);}
43
+ let edge = (g.z*0.5)*(g.z*0.5);
44
+ let qD = dot(direction,direction)/max(abs(direction.x),abs(direction.y));
45
+ let length = vec2f(1.0+(qD-1.0)*edge,1.0-0.5*edge);
46
+ let lobe = 0.5+(0.21-0.5)*edge;
47
+ var result=vec4f(0); var total=0.0;
48
+ for(var i=0u;i<12u;i++){
49
+ let weight=sJ(vec2f(offsets[i])-phase,direction,length,lobe);
50
+ result+=colors[i]*weight;total+=weight;
51
+ }
52
+ let lower=min(min(colors[3],colors[4]),min(colors[7],colors[8]));
53
+ let upper=max(max(colors[3],colors[4]),max(colors[7],colors[8]));
54
+ return clamp(result/total,lower,upper);
55
+ }
56
+ `;
57
+ // Not part of FSR: exact area average for inputs larger than the output,
58
+ // alpha-weighted so transparent texels do not darken coverage edges.
59
+ export const areaDownsampleShader = /* wgsl */ `
60
+ @group(0) @binding(0) var colorImage: texture_2d<f32>;
61
+ @group(0) @binding(1) var<uniform> outputSize: vec4f;
62
+ @vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
63
+ let p = vec2f(f32((index << 1u) & 2u), f32(index & 2u));
64
+ return vec4f(p * 2.0 - 1.0, 0.0, 1.0);
65
+ }
66
+ @fragment fn fragment(@builtin(position) position: vec4f) -> @location(0) vec4f {
67
+ let scale = vec2f(textureDimensions(colorImage))/outputSize.xy;
68
+ let start = floor(position.xy)*scale; let end = start+scale;
69
+ var sum = vec4f(0);
70
+ for (var y = i32(floor(start.y)); y < i32(ceil(end.y)); y++) {
71
+ for (var x = i32(floor(start.x)); x < i32(ceil(end.x)); x++) {
72
+ let tK = max(vec2f(0), min(vec2f(vec2i(x+1,y+1)), end)-max(vec2f(vec2i(x,y)), start));
73
+ let color = textureLoad(colorImage, vec2i(x,y), 0);
74
+ sum += vec4f(color.rgb*color.a, color.a)*tK.x*tK.y;
75
+ }
76
+ }
77
+ return vec4f(sum.rgb/max(sum.a, 1e-8), sum.a/(scale.x*scale.y));
78
+ }
79
+ `;
80
+ //# sourceMappingURL=easu.wgsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"easu.wgsl.js","sourceRoot":"","sources":["../../../src/renderer/wgsl/easu.wgsl.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,wFAAwF;AACxF,mFAAmF;AACnF,kFAAkF;AAClF,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmDpC,CAAC;AAEF,yEAAyE;AACzE,qEAAqE;AACrE,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;CAoB9C,CAAC","sourcesContent":["// Adapted from AMD FidelityFX FSR 1, ffx_fsr1.h v1.20210629,\n// FsrEasuSetF/FsrEasuTapF/FsrEasuF (32-bit path). MIT; see LICENSES/FidelityFX-FSR.txt.\n// https://github.com/GPUOpen-Effects/FidelityFX-FSR/blob/master/ffx-fsr/ffx_fsr1.h\n// Uses exact reciprocals instead of the reference's low precision approximations.\nexport const easuShader = /* wgsl */ `\n@group(0) @binding(0) var colorImage: texture_2d<f32>;\n@group(0) @binding(1) var<uniform> outputSize: vec4f;\n@vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {\n let p = vec2f(f32((index << 1u) & 2u), f32(index & 2u));\n return vec4f(p * 2.0 - 1.0, 0.0, 1.0);\n}\nconst offsets = array<vec2i,12>(vec2i(0,-1),vec2i(1,-1),vec2i(-1,0),vec2i(0,0),vec2i(1,0),vec2i(2,0),\n vec2i(-1,1),vec2i(0,1),vec2i(1,1),vec2i(2,1),vec2i(0,2),vec2i(1,2));\nfn loadColor(p: vec2i) -> vec4f {return textureLoad(colorImage, clamp(p,vec2i(0),vec2i(textureDimensions(colorImage))-1),0);}\nfn gradient(a: f32,b: f32,c: f32,d: f32,e: f32,w: f32) -> vec3f {\n let direction = vec2f(d-b,e-a);\n let length = clamp(abs(direction)/max(vec2f(max(abs(d-c),abs(c-b)),max(abs(e-c),abs(c-a))),vec2f(1e-8)),vec2f(0),vec2f(1));\n return vec3f(direction,dot(length,length))*w;\n}\nfn easuWeight(offset: vec2f, direction: vec2f, length: vec2f, lobe: f32) -> f32 {\n let v = vec2f(dot(offset,direction),dot(offset,vec2f(-direction.y,direction.x)))*length;\n let distance = min(dot(v,v),1.0/lobe);\n let b = 0.4*distance-1.0;\n let a = lobe*distance-1.0;\n return (1.5625*b*b-0.5625)*a*a;\n}\n@fragment fn fragment(@builtin(position) position: vec4f) -> @location(0) vec4f {\n let point = position.xy*vec2f(textureDimensions(colorImage))/outputSize.xy-0.5;\n let base = vec2i(floor(point)); let phase = fract(point);\n var colors: array<vec4f,12>;\n var luma: array<f32,12>;\n // FSR expects [0,1]. Normalize the neighborhood for direction estimation\n // in extended-range output; filter the original RGB without clipping it to 1.\n var range = 1.0;\n for(var i=0u;i<12u;i++){colors[i]=loadColor(base+offsets[i]);range=max(range,max(max(colors[i].r,colors[i].g),colors[i].b));}\n for(var i=0u;i<12u;i++){luma[i]=dot(colors[i].rgb/range,vec3f(0.5,1.0,0.5));}\n let g = gradient(luma[0],luma[2],luma[3],luma[4],luma[7],(1.0-phase.x)*(1.0-phase.y))+\n gradient(luma[1],luma[3],luma[4],luma[5],luma[8],phase.x*(1.0-phase.y))+\n gradient(luma[3],luma[6],luma[7],luma[8],luma[10],(1.0-phase.x)*phase.y)+\n gradient(luma[4],luma[7],luma[8],luma[9],luma[11],phase.x*phase.y);\n var direction = vec2f(1.0,0.0);\n if(dot(g.xy,g.xy)>=1.0/32768.0){direction=normalize(g.xy);}\n let edge = (g.z*0.5)*(g.z*0.5);\n let stretch = dot(direction,direction)/max(abs(direction.x),abs(direction.y));\n let length = vec2f(1.0+(stretch-1.0)*edge,1.0-0.5*edge);\n let lobe = 0.5+(0.21-0.5)*edge;\n var result=vec4f(0); var total=0.0;\n for(var i=0u;i<12u;i++){\n let weight=easuWeight(vec2f(offsets[i])-phase,direction,length,lobe);\n result+=colors[i]*weight;total+=weight;\n }\n let lower=min(min(colors[3],colors[4]),min(colors[7],colors[8]));\n let upper=max(max(colors[3],colors[4]),max(colors[7],colors[8]));\n return clamp(result/total,lower,upper);\n}\n`;\n\n// Not part of FSR: exact area average for inputs larger than the output,\n// alpha-weighted so transparent texels do not darken coverage edges.\nexport const areaDownsampleShader = /* wgsl */ `\n@group(0) @binding(0) var colorImage: texture_2d<f32>;\n@group(0) @binding(1) var<uniform> outputSize: vec4f;\n@vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {\n let p = vec2f(f32((index << 1u) & 2u), f32(index & 2u));\n return vec4f(p * 2.0 - 1.0, 0.0, 1.0);\n}\n@fragment fn fragment(@builtin(position) position: vec4f) -> @location(0) vec4f {\n let scale = vec2f(textureDimensions(colorImage))/outputSize.xy;\n let start = floor(position.xy)*scale; let end = start+scale;\n var sum = vec4f(0);\n for (var y = i32(floor(start.y)); y < i32(ceil(end.y)); y++) {\n for (var x = i32(floor(start.x)); x < i32(ceil(end.x)); x++) {\n let overlap = max(vec2f(0), min(vec2f(vec2i(x+1,y+1)), end)-max(vec2f(vec2i(x,y)), start));\n let color = textureLoad(colorImage, vec2i(x,y), 0);\n sum += vec4f(color.rgb*color.a, color.a)*overlap.x*overlap.y;\n }\n }\n return vec4f(sum.rgb/max(sum.a, 1e-8), sum.a/(scale.x*scale.y));\n}\n`;\n"]}
@@ -0,0 +1,21 @@
1
+ /** Scene-linear log2 range covered by the tone lookup table. */
2
+ export declare const TONE_LUT_LOG2: readonly [-24, 24];
3
+ export declare const TONE_LUT_SIZE = 1024;
4
+ /** Detail compensation defaults and fixed regularizers shared by the Web and native passes. */
5
+ export declare const EASU_DETAIL: {
6
+ ratioRange: readonly [0.7, 1.43];
7
+ depthThreshold: number;
8
+ coverageThreshold: number;
9
+ minimumAlbedo: number;
10
+ depthTolerance: number;
11
+ guidedEpsilon: number;
12
+ };
13
+ /**
14
+ * guided: scale only the albedo-correlated part of local scene-linear radiance (default);
15
+ * separate: lobe-share approximation; silhouettes: depth-guided edge reconstruction.
16
+ * The last two are retained for comparisons.
17
+ */
18
+ export declare function easuDetailShader(separate?: boolean, silhouettes?: boolean, guided?: boolean): string;
19
+ export declare const albedoDownsampleShader: (depthOutput?: boolean) => string;
20
+ export declare const toneLutShader: string;
21
+ export declare const guidedCoefficientShader: string;
@@ -0,0 +1,230 @@
1
+ import { easuShader } from './easu.wgsl.js';
2
+ import { composeDefine } from './compose.frag.wgsl.js';
3
+ /** Scene-linear log2 range covered by the tone lookup table. */
4
+ export const TONE_LUT_LOG2 = [-24, 24];
5
+ export const TONE_LUT_SIZE = 1024;
6
+ /** Detail compensation defaults and fixed regularizers shared by the Web and native passes. */
7
+ export const EASU_DETAIL = {
8
+ ratioRange: [0.7, 1.43], depthThreshold: 0.02, coverageThreshold: 0.95,
9
+ // Albedo below this is treated as black; relative depth tolerance floor.
10
+ minimumAlbedo: 1e-3, depthTolerance: 1e-4,
11
+ // Regularizes the local albedo variance of the albedo-radiance fit, in squared albedo units.
12
+ guidedEpsilon: 1e-4,
13
+ };
14
+ // Tone table lookups and display encoding shared by the detail passes; tone.x is the maximum display value.
15
+ const toneCodingDefine = /* wgsl */ `
16
+
17
+
18
+ @group(0) @binding(8) var toneLut: texture_2d<f32>;
19
+ @group(0) @binding(9) var<uniform> tone: vec4f;
20
+ fn vZ(row: i32, u: vec3f) -> vec3f {
21
+ let last=f32(textureDimensions(toneLut).x-1u);let p=clamp(u,vec3f(0),vec3f(1))*last;
22
+ let i=vec3i(floor(p));let j=min(i+1,vec3i(i32(last)));let f=p-floor(p);
23
+ var result=vec3f(0);
24
+ for(var c=0;c<3;c++){result[c]=mix(textureLoad(toneLut,vec2i(i[c],row),0)[c],textureLoad(toneLut,vec2i(j[c],row),0)[c],f[c]);}
25
+ return result;
26
+ }
27
+ fn uM(AK: vec3f) -> vec3f {return vZ(0,(AK-(${TONE_LUT_LOG2[0]}.0))/${TONE_LUT_LOG2[1] - TONE_LUT_LOG2[0]}.0);}
28
+ fn uN(d: vec3f) -> vec3f {return vZ(1,sqrt(max(d,vec3f(0))/tone.x));}
29
+
30
+
31
+
32
+
33
+ fn zk(d: vec3f, fw: vec3f) -> vec3f {
34
+ let x=uN(d);
35
+ let changed=max(d+uM(x+log2(max(fw,vec3f(1e-6))))-uM(x),vec3f(0));
36
+ return select(changed,d,abs(fw-vec3f(1))<vec3f(1e-4));
37
+ }
38
+ fn pS(c: vec3f) -> vec3f {
39
+ let a=max(c,vec3f(0));
40
+ return select(pow((a+0.055)/1.055,vec3f(2.4)),a/12.92,a<=vec3f(0.04045));
41
+ }
42
+ fn tp(c: vec3f) -> vec3f {
43
+ let a=max(c,vec3f(0));
44
+ return select(1.055*pow(a,vec3f(1.0/2.4))-0.055,a*12.92,a<=vec3f(0.0031308));
45
+ }
46
+ `;
47
+ /**
48
+ * guided: scale only the albedo-correlated part of local scene-linear radiance (default);
49
+ * separate: lobe-share approximation; silhouettes: depth-guided edge reconstruction.
50
+ * The last two are retained for comparisons.
51
+ */
52
+ export function easuDetailShader(separate = false, silhouettes = false, guided = true) {
53
+ return easuShader.replace(`@vertex fn vertex`, /* wgsl */ `
54
+ @group(0) @binding(2) var diffuseHi: texture_2d<f32>;
55
+ @group(0) @binding(3) var specularHi: texture_2d<f32>;
56
+ @group(0) @binding(4) var depthHi: texture_2d<f32>;
57
+ @group(0) @binding(5) var diffuseLo: texture_2d<f32>;
58
+ @group(0) @binding(6) var specularLo: texture_2d<f32>;
59
+ @group(0) @binding(7) var<uniform> detail: vec4f;
60
+ ${silhouettes ? '@group(0) @binding(10) var depthLo: texture_2d<f32>;' : ''}
61
+ ${guided ? '@group(0) @binding(11) var slopeLo: texture_2d<f32>;\n@group(0) @binding(12) var offsetLo: texture_2d<f32>;' : ''}
62
+ fn cY(image: texture_2d<f32>, p: vec2i) -> vec4f {
63
+ return textureLoad(image,clamp(p,vec2i(0),vec2i(textureDimensions(image))-1),0);
64
+ }
65
+ ${toneCodingDefine}
66
+ @vertex fn vertex`).replace(`return clamp(result/total,lower,upper);`, /* wgsl */ `
67
+ let color=clamp(result/total,lower,upper);
68
+ var diffuse=vec4f(0);var specular=vec4f(0);
69
+ for(var i=0u;i<12u;i++){
70
+
71
+ let weight=sJ(vec2f(offsets[i])-phase,direction,length,lobe);
72
+ diffuse+=cY(diffuseLo,base+offsets[i])*weight;
73
+ specular+=cY(specularLo,base+offsets[i])*weight;
74
+ }
75
+ let dlo=min(min(cY(diffuseLo,base),cY(diffuseLo,base+vec2i(1,0))),min(cY(diffuseLo,base+vec2i(0,1)),cY(diffuseLo,base+vec2i(1,1))));
76
+ let dhi=max(max(cY(diffuseLo,base),cY(diffuseLo,base+vec2i(1,0))),max(cY(diffuseLo,base+vec2i(0,1)),cY(diffuseLo,base+vec2i(1,1))));
77
+ let slo=min(min(cY(specularLo,base),cY(specularLo,base+vec2i(1,0))),min(cY(specularLo,base+vec2i(0,1)),cY(specularLo,base+vec2i(1,1))));
78
+ let shi=max(max(cY(specularLo,base),cY(specularLo,base+vec2i(1,0))),max(cY(specularLo,base+vec2i(0,1)),cY(specularLo,base+vec2i(1,1))));
79
+ diffuse=clamp(diffuse/total,dlo,dhi);specular=clamp(specular/total,slo,shi);
80
+ ${guided ? `var slope=vec4f(0);var pn=vec4f(0);
81
+ for(var i=0u;i<12u;i++){
82
+ let weight=sJ(vec2f(offsets[i])-phase,direction,length,lobe);
83
+ slope+=cY(slopeLo,base+offsets[i])*weight;pn+=cY(offsetLo,base+offsets[i])*weight;
84
+ }
85
+ var qk=cY(slopeLo,base);var te=qk;var kI=cY(offsetLo,base);var ow=kI;
86
+ for(var k=1;k<4;k++){
87
+ let q=base+vec2i(k&1,k>>1u);let a=cY(slopeLo,q);let b=cY(offsetLo,q);
88
+ qk=min(qk,a);te=max(te,a);kI=min(kI,b);ow=max(ow,b);
89
+ }
90
+ slope=clamp(slope/total,qk,te);pn=clamp(pn/total,kI,ow);` : ''}
91
+ let p=vec2i(position.xy);let size=vec2i(textureDimensions(depthHi));
92
+ let d=textureLoad(diffuseHi,p,0);let s=textureLoad(specularHi,p,0);let z=textureLoad(depthHi,p,0).xy;
93
+ let sf=max(detail.w,detail.z*abs(z.x));
94
+ let radius=max(vec2i(1),vec2i(ceil(outputSize.xy/vec2f(textureDimensions(colorImage)))));
95
+
96
+
97
+ var silhouette=false;let inverse=1.0/max(z.x,1e-6);
98
+ let directions=array<vec2i,4>(vec2i(1,0),vec2i(0,1),vec2i(1,1),vec2i(1,-1));
99
+ for(var k=0;k<4;k++){
100
+ let a=textureLoad(depthHi,clamp(p+directions[k]*radius,vec2i(0),size-1),0).xy;
101
+ let b=textureLoad(depthHi,clamp(p-directions[k]*radius,vec2i(0),size-1),0).xy;
102
+ silhouette=silhouette || abs(a.y-z.y)>0.5 || abs(b.y-z.y)>0.5 ||
103
+ (min(min(a.y,b.y),z.y)>0.0 && abs(1.0/max(a.x,1e-6)+1.0/max(b.x,1e-6)-2.0*inverse)>detail.z*inverse);
104
+ }
105
+ ${silhouettes ? `
106
+ let guided=min(d.a,s.a)>=detail.y;
107
+ if(silhouette && z.y>=0.5 && !guided){return color;}
108
+ if(silhouette){
109
+
110
+
111
+
112
+ let center=vec2i(round(point));var front=vec4f(0);var back=vec4f(0);var oK=0.0;var pO=0.0;
113
+ for(var y=-1;y<=1;y++){for(var x=-1;x<=1;x++){
114
+ let q=center+vec2i(x,y);let offset=vec2f(q)-point;
115
+ let rB=cY(depthLo,q).xy;let yO=exp(-dot(offset,offset));
116
+ let Ab=exp(-pow(abs(rB.x-z.x)/sf,2.0));
117
+ let sample=ns(q);let value=vec4f(pS(sample.rgb),sample.a);
118
+ let f=yO*rB.y*rB.y*select(1.0,Ab,z.y>0.0);let b=yO*(1.0-rB.y)*(1.0-rB.y);
119
+ front+=value*f;oK+=f;back+=value*b;pO+=b;
120
+ }}
121
+ let ug=oK>1e-3;let xs=pO>1e-3;
122
+ if(!ug && !xs){return color;}
123
+ var zE=select(back/max(pO,1e-8),front/max(oK,1e-8),ug);
124
+ if(ug && xs){zE=mix(back/pO,front/oK,z.y);}
125
+ return vec4f(tp(zE.rgb),zE.a);
126
+ }
127
+ ` : ' if(silhouette){return color;}\n'} let valid=min(min(d.a,s.a),min(diffuse.a,specular.a))>=detail.y && z.y>=detail.y;
128
+ if(!valid){return color;}
129
+ let low=diffuse.rgb+specular.rgb;
130
+ var fw=clamp((d.rgb+s.rgb)/max(low,vec3f(detail.x)),vec3f(outputSize.z),vec3f(outputSize.w));
131
+ ${separate ? `
132
+
133
+ let share=diffuse.rgb/max(low,vec3f(detail.x));
134
+ let rd=clamp(d.rgb/max(diffuse.rgb,vec3f(detail.x)),vec3f(outputSize.z),vec3f(outputSize.w));
135
+ let rs=clamp(s.rgb/max(specular.rgb,vec3f(detail.x)),vec3f(outputSize.z),vec3f(outputSize.w));
136
+ fw=share*rd+(vec3f(1)-share)*rs;` : ''}
137
+ ${guided ? `
138
+
139
+
140
+ let yJ=slope.rgb*low+pn.rgb;
141
+ fw=select(fw,clamp((slope.rgb*(d.rgb+s.rgb)+pn.rgb)/max(yJ,vec3f(1e-8)),vec3f(outputSize.z),vec3f(outputSize.w)),yJ>vec3f(1e-8));` : ''}
142
+ fw=select(vec3f(1),fw,low>vec3f(detail.x));
143
+
144
+ return vec4f(tp(zk(pS(color.rgb),fw)),color.a);`);
145
+ }
146
+ // Exact box overlap integrates noninteger footprints instead of point sampling.
147
+ export const albedoDownsampleShader = (depthOutput = false) => /* wgsl */ `
148
+ @group(0) @binding(0) var diffuse: texture_2d<f32>;
149
+ @group(0) @binding(1) var specular: texture_2d<f32>;
150
+ @group(0) @binding(2) var<uniform> outputSize: vec4f;
151
+ @group(0) @binding(3) var depth: texture_2d<f32>;
152
+ @vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
153
+ let p=vec2f(f32((index<<1u)&2u),f32(index&2u));return vec4f(p*2.0-1.0,0,1);
154
+ }
155
+ struct uS {@location(0) diffuse: vec4f, @location(1) specular: vec4f, ${depthOutput ? '@location(2) depth: vec4f,' : ''}}
156
+ @fragment fn fragment(@builtin(position) p: vec4f) -> uS {
157
+ let scale=vec2f(textureDimensions(diffuse))/outputSize.xy;
158
+ let start=floor(p.xy)*scale;let end=start+scale;
159
+ var d=vec4f(0);var s=vec4f(0);var nearest=3.4e38;var hits=0.0;
160
+ for(var y=i32(floor(start.y));y<i32(ceil(end.y));y++){
161
+ for(var x=i32(floor(start.x));x<i32(ceil(end.x));x++){
162
+ let tK=max(vec2f(0),min(vec2f(vec2i(x+1,y+1)),end)-max(vec2f(vec2i(x,y)),start));let weight=tK.x*tK.y;
163
+ let a=textureLoad(diffuse,vec2i(x,y),0);let b=textureLoad(specular,vec2i(x,y),0);let z=textureLoad(depth,vec2i(x,y),0).xy;
164
+ d+=vec4f(a.rgb*a.a,a.a)*weight;s+=vec4f(b.rgb*b.a,b.a)*weight;
165
+ hits+=z.y*weight;if(z.y>0.0){nearest=min(nearest,z.x);}
166
+ }
167
+ }
168
+ var result: uS;
169
+ ${depthOutput ? 'result.depth=vec4f(select(0.0,nearest,hits>0.0),hits/(scale.x*scale.y),0,0);' : ''}
170
+ result.diffuse=vec4f(d.rgb/max(d.a,1e-8),d.a/(scale.x*scale.y));
171
+ result.specular=vec4f(s.rgb/max(s.a,1e-8),s.a/(scale.x*scale.y));return result;
172
+ }
173
+ `;
174
+ // Builds the tone lookup rows for the current grading and tone mapping.
175
+ // toneMappingParams: x mode, y maximum display value, z exposure, w 1 for extended output.
176
+ export const toneLutShader = /* wgsl */ `
177
+ @group(0) @binding(0) var<uniform> toneMappingParams: vec4f;
178
+ @group(0) @binding(1) var<uniform> colorGradingParams: vec4f;
179
+ ${composeDefine}
180
+ fn xP(x: f32) -> vec3f {
181
+ var v=fm(vec3f(x)*toneMappingParams.z);
182
+ if(toneMappingParams.w<0.5){v=bH(v);}
183
+ return v;
184
+ }
185
+ @vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
186
+ let p=vec2f(f32((index<<1u)&2u),f32(index&2u));return vec4f(p*2.0-1.0,0,1);
187
+ }
188
+ @fragment fn fragment(@builtin(position) p: vec4f) -> @location(0) vec4f {
189
+ let u=floor(p.x)/${TONE_LUT_SIZE - 1}.0;
190
+ if(p.y<1.0){return vec4f(xP(exp2(mix(${TONE_LUT_LOG2[0]}.0,${TONE_LUT_LOG2[1]}.0,u))),1);}
191
+ let d=u*u*toneMappingParams.y;var result=vec3f(0);
192
+ for(var c=0;c<3;c++){
193
+ var lo=${TONE_LUT_LOG2[0]}.0;var hi=${TONE_LUT_LOG2[1]}.0;
194
+ for(var i=0;i<28;i++){let mid=0.5*(lo+hi);if(xP(exp2(mid))[c]<d){lo=mid;}else{hi=mid;}}
195
+ result[c]=0.5*(lo+hi);
196
+ }
197
+ return vec4f(result,1);
198
+ }
199
+ `;
200
+ // Per low-resolution pixel, fits scene-linear radiance x ~ slope * albedo + offset over a
201
+ // 3x3 window of guided samples, per channel (a guided-filter regression). Flat albedo
202
+ // gives slope ~0, so its radiance is not modulated; tone.y regularizes the variance.
203
+ export const guidedCoefficientShader = /* wgsl */ `
204
+ @group(0) @binding(0) var colorImage: texture_2d<f32>;
205
+ @group(0) @binding(1) var diffuseLo: texture_2d<f32>;
206
+ @group(0) @binding(2) var specularLo: texture_2d<f32>;
207
+ ${toneCodingDefine}
208
+ fn yg(image: texture_2d<f32>, p: vec2i) -> vec4f {return textureLoad(image,clamp(p,vec2i(0),vec2i(textureDimensions(image))-1),0);}
209
+ @vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
210
+ let p=vec2f(f32((index<<1u)&2u),f32(index&2u));return vec4f(p*2.0-1.0,0,1);
211
+ }
212
+ struct uS {@location(0) slope: vec4f, @location(1) offset: vec4f,}
213
+ @fragment fn fragment(@builtin(position) position: vec4f) -> uS {
214
+ let center=vec2i(position.xy);
215
+ var weight=0.0;var gt=vec3f(0);var nj=vec3f(0);var rC=vec3f(0);var sS=vec3f(0);
216
+ for(var y=-1;y<=1;y++){for(var x=-1;x<=1;x++){
217
+ let q=center+vec2i(x,y);let d=yg(diffuseLo,q);let s=yg(specularLo,q);
218
+ let w=step(0.5,min(d.a,s.a));let albedo=d.rgb+s.rgb;
219
+ let radiance=exp2(uN(pS(yg(colorImage,q).rgb)));
220
+ weight+=w;gt+=albedo*w;nj+=radiance*w;rC+=albedo*radiance*w;sS+=albedo*albedo*w;
221
+ }}
222
+ var result: uS;
223
+ if(weight<1.0){return result;}
224
+ gt/=weight;nj/=weight;rC/=weight;sS/=weight;
225
+ let slope=max((rC-gt*nj)/(sS-gt*gt+vec3f(tone.y)),vec3f(0));
226
+ result.slope=vec4f(slope,1);result.offset=vec4f(nj-slope*gt,1);
227
+ return result;
228
+ }
229
+ `;
230
+ //# sourceMappingURL=easuDetail.wgsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"easuDetail.wgsl.js","sourceRoot":"","sources":["../../../src/renderer/wgsl/easuDetail.wgsl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAErD,gEAAgE;AAChE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAU,CAAC;AAChD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAClC,+FAA+F;AAC/F,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,UAAU,EAAE,CAAC,GAAG,EAAE,IAAI,CAAU,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI;IAC/E,yEAAyE;IACzE,aAAa,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI;IACzC,6FAA6F;IAC7F,aAAa,EAAE,IAAI;CACpB,CAAC;AAEF,4GAA4G;AAC5G,MAAM,gBAAgB,GAAG,UAAU,CAAC;;;;;;;;;;;;8CAYiC,aAAa,CAAC,CAAC,CAAC,QAAQ,aAAa,CAAC,CAAC,CAAC,GAAC,aAAa,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;CAmB7H,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAQ,GAAG,KAAK,EAAE,WAAW,GAAG,KAAK,EAAE,MAAM,GAAG,IAAI;IACnF,OAAO,UAAU,CAAC,OAAO,CAAC,mBAAmB,EAAE,UAAU,CAAC;;;;;;;EAO1D,WAAW,CAAC,CAAC,CAAC,sDAAsD,CAAC,CAAC,CAAC,EAAE;EACzE,MAAM,CAAC,CAAC,CAAC,6GAA6G,CAAC,CAAC,CAAC,EAAE;;;;EAI3H,gBAAgB;kBACA,CAAC,CAAC,OAAO,CAAC,yCAAyC,EAAE,UAAU,CAAC;;;;;;;;;;;;;;EAc9E,MAAM,CAAC,CAAC,CAAC;;;;;;;;;;yDAUoG,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;EAelH,WAAW,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;CAsBjB,CAAC,CAAC,CAAC,mCAAmC;;;;EAInC,QAAQ,CAAC,CAAC,CAAC;;;;;iCAKuB,CAAC,CAAC,CAAC,EAAE;EACvC,MAAM,CAAC,CAAC,CAAC;;;;kIAI8I,CAAC,CAAC,CAAC,EAAE;;;gDAGhF,CAAC,CAAC;AAClF,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,WAAW,GAAG,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC;;;;;;;;wEAQE,WAAW,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;EAcvH,WAAW,CAAC,CAAC,CAAC,8EAA8E,CAAC,CAAC,CAAC,EAAE;;;;CAIpG,CAAC;AAEF,wEAAwE;AACxE,2FAA2F;AAC3F,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;;;EAGtC,aAAa;;;;;;;;;;mBAUM,aAAa,GAAG,CAAC;uCACS,aAAa,CAAC,CAAC,CAAC,MAAM,aAAa,CAAC,CAAC,CAAC;;;SAGxE,aAAa,CAAC,CAAC,CAAC,aAAa,aAAa,CAAC,CAAC,CAAC;;;;;;CAMzD,CAAC;AAEF,0FAA0F;AAC1F,sFAAsF;AACtF,qFAAqF;AACrF,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAC;;;;EAIhD,gBAAgB;;;;;;;;;;;;;;;;;;;;;;CAsBjB,CAAC","sourcesContent":["import {easuShader} from './easu.wgsl.js';\nimport {composeDefine} from './compose.frag.wgsl.js';\n\n/** Scene-linear log2 range covered by the tone lookup table. */\nexport const TONE_LUT_LOG2 = [-24, 24] as const;\nexport const TONE_LUT_SIZE = 1024;\n/** Detail compensation defaults and fixed regularizers shared by the Web and native passes. */\nexport const EASU_DETAIL = {\n ratioRange: [0.7, 1.43] as const, depthThreshold: 0.02, coverageThreshold: 0.95,\n // Albedo below this is treated as black; relative depth tolerance floor.\n minimumAlbedo: 1e-3, depthTolerance: 1e-4,\n // Regularizes the local albedo variance of the albedo-radiance fit, in squared albedo units.\n guidedEpsilon: 1e-4,\n};\n\n// Tone table lookups and display encoding shared by the detail passes; tone.x is the maximum display value.\nconst toneCodingDefine = /* wgsl */ `\n// Row 0: display value of a gray scene-linear input at TONE_LUT_LOG2 stops, per channel.\n// Row 1: log2 scene-linear input per channel for display values (sqrt-spaced up to tone.x).\n@group(0) @binding(8) var toneLut: texture_2d<f32>;\n@group(0) @binding(9) var<uniform> tone: vec4f;\nfn toneLutRow(row: i32, u: vec3f) -> vec3f {\n let last=f32(textureDimensions(toneLut).x-1u);let p=clamp(u,vec3f(0),vec3f(1))*last;\n let i=vec3i(floor(p));let j=min(i+1,vec3i(i32(last)));let f=p-floor(p);\n var result=vec3f(0);\n for(var c=0;c<3;c++){result[c]=mix(textureLoad(toneLut,vec2i(i[c],row),0)[c],textureLoad(toneLut,vec2i(j[c],row),0)[c],f[c]);}\n return result;\n}\nfn toneForward(log2x: vec3f) -> vec3f {return toneLutRow(0,(log2x-(${TONE_LUT_LOG2[0]}.0))/${TONE_LUT_LOG2[1]-TONE_LUT_LOG2[0]}.0);}\nfn toneInverse(d: vec3f) -> vec3f {return toneLutRow(1,sqrt(max(d,vec3f(0))/tone.x));}\n// Applies a scene-linear albedo ratio before the display transform: displayed\n// RGB is mapped back to scene-linear per channel, scaled and mapped forward, so\n// curve shoulders and toes respond as the tone mapper would. Only the change is\n// added to the displayed value, which keeps it exact where the ratio is 1.\nfn toneAware(d: vec3f, ratio: vec3f) -> vec3f {\n let x=toneInverse(d);\n let changed=max(d+toneForward(x+log2(max(ratio,vec3f(1e-6))))-toneForward(x),vec3f(0));\n return select(changed,d,abs(ratio-vec3f(1))<vec3f(1e-4));\n}\nfn detailDecode(c: vec3f) -> vec3f {\n let a=max(c,vec3f(0));\n return select(pow((a+0.055)/1.055,vec3f(2.4)),a/12.92,a<=vec3f(0.04045));\n}\nfn detailEncode(c: vec3f) -> vec3f {\n let a=max(c,vec3f(0));\n return select(1.055*pow(a,vec3f(1.0/2.4))-0.055,a*12.92,a<=vec3f(0.0031308));\n}\n`;\n\n/**\n * guided: scale only the albedo-correlated part of local scene-linear radiance (default);\n * separate: lobe-share approximation; silhouettes: depth-guided edge reconstruction.\n * The last two are retained for comparisons.\n */\nexport function easuDetailShader(separate = false, silhouettes = false, guided = true) {\n return easuShader.replace(`@vertex fn vertex`, /* wgsl */ `\n@group(0) @binding(2) var diffuseHi: texture_2d<f32>;\n@group(0) @binding(3) var specularHi: texture_2d<f32>;\n@group(0) @binding(4) var depthHi: texture_2d<f32>;\n@group(0) @binding(5) var diffuseLo: texture_2d<f32>;\n@group(0) @binding(6) var specularLo: texture_2d<f32>;\n@group(0) @binding(7) var<uniform> detail: vec4f;\n${silhouettes ? '@group(0) @binding(10) var depthLo: texture_2d<f32>;' : ''}\n${guided ? '@group(0) @binding(11) var slopeLo: texture_2d<f32>;\\n@group(0) @binding(12) var offsetLo: texture_2d<f32>;' : ''}\nfn loadLow(image: texture_2d<f32>, p: vec2i) -> vec4f {\n return textureLoad(image,clamp(p,vec2i(0),vec2i(textureDimensions(image))-1),0);\n}\n${toneCodingDefine}\n@vertex fn vertex`).replace(`return clamp(result/total,lower,upper);`, /* wgsl */ `\n let color=clamp(result/total,lower,upper);\n var diffuse=vec4f(0);var specular=vec4f(0);\n for(var i=0u;i<12u;i++){\n // Identical direction, phase, support and weights as beauty.\n let weight=easuWeight(vec2f(offsets[i])-phase,direction,length,lobe);\n diffuse+=loadLow(diffuseLo,base+offsets[i])*weight;\n specular+=loadLow(specularLo,base+offsets[i])*weight;\n }\n let dlo=min(min(loadLow(diffuseLo,base),loadLow(diffuseLo,base+vec2i(1,0))),min(loadLow(diffuseLo,base+vec2i(0,1)),loadLow(diffuseLo,base+vec2i(1,1))));\n let dhi=max(max(loadLow(diffuseLo,base),loadLow(diffuseLo,base+vec2i(1,0))),max(loadLow(diffuseLo,base+vec2i(0,1)),loadLow(diffuseLo,base+vec2i(1,1))));\n let slo=min(min(loadLow(specularLo,base),loadLow(specularLo,base+vec2i(1,0))),min(loadLow(specularLo,base+vec2i(0,1)),loadLow(specularLo,base+vec2i(1,1))));\n let shi=max(max(loadLow(specularLo,base),loadLow(specularLo,base+vec2i(1,0))),max(loadLow(specularLo,base+vec2i(0,1)),loadLow(specularLo,base+vec2i(1,1))));\n diffuse=clamp(diffuse/total,dlo,dhi);specular=clamp(specular/total,slo,shi);\n ${guided ? `var slope=vec4f(0);var intercept=vec4f(0);\n for(var i=0u;i<12u;i++){\n let weight=easuWeight(vec2f(offsets[i])-phase,direction,length,lobe);\n slope+=loadLow(slopeLo,base+offsets[i])*weight;intercept+=loadLow(offsetLo,base+offsets[i])*weight;\n }\n var lowerSlope=loadLow(slopeLo,base);var upperSlope=lowerSlope;var lowerIntercept=loadLow(offsetLo,base);var upperIntercept=lowerIntercept;\n for(var k=1;k<4;k++){\n let q=base+vec2i(k&1,k>>1u);let a=loadLow(slopeLo,q);let b=loadLow(offsetLo,q);\n lowerSlope=min(lowerSlope,a);upperSlope=max(upperSlope,a);lowerIntercept=min(lowerIntercept,b);upperIntercept=max(upperIntercept,b);\n }\n slope=clamp(slope/total,lowerSlope,upperSlope);intercept=clamp(intercept/total,lowerIntercept,upperIntercept);` : ''}\n let p=vec2i(position.xy);let size=vec2i(textureDimensions(depthHi));\n let d=textureLoad(diffuseHi,p,0);let s=textureLoad(specularHi,p,0);let z=textureLoad(depthHi,p,0).xy;\n let tolerance=max(detail.w,detail.z*abs(z.x));\n let radius=max(vec2i(1),vec2i(ceil(outputSize.xy/vec2f(textureDimensions(colorImage)))));\n // A silhouette changes hit coverage or breaks the planarity of inverse depth,\n // which is linear in screen space on planes; sloped planes are not silhouettes.\n var silhouette=false;let inverse=1.0/max(z.x,1e-6);\n let directions=array<vec2i,4>(vec2i(1,0),vec2i(0,1),vec2i(1,1),vec2i(1,-1));\n for(var k=0;k<4;k++){\n let a=textureLoad(depthHi,clamp(p+directions[k]*radius,vec2i(0),size-1),0).xy;\n let b=textureLoad(depthHi,clamp(p-directions[k]*radius,vec2i(0),size-1),0).xy;\n silhouette=silhouette || abs(a.y-z.y)>0.5 || abs(b.y-z.y)>0.5 ||\n (min(min(a.y,b.y),z.y)>0.0 && abs(1.0/max(a.x,1e-6)+1.0/max(b.x,1e-6)-2.0*inverse)>detail.z*inverse);\n }\n ${silhouettes ? ` // Transmissive and other unguided hits show surfaces behind their depth; keep EASU there.\n let guided=min(d.a,s.a)>=detail.y;\n if(silhouette && z.y>=0.5 && !guided){return color;}\n if(silhouette){\n // Silhouettes: estimate this surface's color from covered low-resolution neighbors\n // at a similar nearest depth, the background from uncovered ones, and mix them by\n // this pixel's full-resolution hit coverage, which keeps edges antialiased.\n let center=vec2i(round(point));var front=vec4f(0);var back=vec4f(0);var frontWeight=0.0;var backWeight=0.0;\n for(var y=-1;y<=1;y++){for(var x=-1;x<=1;x++){\n let q=center+vec2i(x,y);let offset=vec2f(q)-point;\n let lowDepth=loadLow(depthLo,q).xy;let spatial=exp(-dot(offset,offset));\n let similar=exp(-pow(abs(lowDepth.x-z.x)/tolerance,2.0));\n let sample=loadColor(q);let value=vec4f(detailDecode(sample.rgb),sample.a);\n let f=spatial*lowDepth.y*lowDepth.y*select(1.0,similar,z.y>0.0);let b=spatial*(1.0-lowDepth.y)*(1.0-lowDepth.y);\n front+=value*f;frontWeight+=f;back+=value*b;backWeight+=b;\n }}\n let haveFront=frontWeight>1e-3;let haveBack=backWeight>1e-3;\n if(!haveFront && !haveBack){return color;}\n var mixed=select(back/max(backWeight,1e-8),front/max(frontWeight,1e-8),haveFront);\n if(haveFront && haveBack){mixed=mix(back/backWeight,front/frontWeight,z.y);}\n return vec4f(detailEncode(mixed.rgb),mixed.a);\n }\n` : ' if(silhouette){return color;}\\n'} let valid=min(min(d.a,s.a),min(diffuse.a,specular.a))>=detail.y && z.y>=detail.y;\n if(!valid){return color;}\n let low=diffuse.rgb+specular.rgb;\n var ratio=clamp((d.rgb+s.rgb)/max(low,vec3f(detail.x)),vec3f(outputSize.z),vec3f(outputSize.w));\n ${separate ? `\n // Estimate beauty lobe shares from low albedo; no separate beauty lobes are available.\n let share=diffuse.rgb/max(low,vec3f(detail.x));\n let rd=clamp(d.rgb/max(diffuse.rgb,vec3f(detail.x)),vec3f(outputSize.z),vec3f(outputSize.w));\n let rs=clamp(s.rgb/max(specular.rgb,vec3f(detail.x)),vec3f(outputSize.z),vec3f(outputSize.w));\n ratio=share*rd+(vec3f(1)-share)*rs;` : ''}\n ${guided ? `// Local radiance is modeled as slope * albedo + intercept. Only the albedo-correlated\n // part follows the full-resolution albedo; the intercept, such as specular highlights,\n // does not. Pure diffuse (zero intercept) reduces to the albedo ratio.\n let modeled=slope.rgb*low+intercept.rgb;\n ratio=select(ratio,clamp((slope.rgb*(d.rgb+s.rgb)+intercept.rgb)/max(modeled,vec3f(1e-8)),vec3f(outputSize.z),vec3f(outputSize.w)),modeled>vec3f(1e-8));` : ''}\n ratio=select(vec3f(1),ratio,low>vec3f(detail.x));\n // Albedo ratios are scene-linear; the composed image is tone mapped and sRGB encoded.\n return vec4f(detailEncode(toneAware(detailDecode(color.rgb),ratio)),color.a);`);\n}\n\n// Exact box overlap integrates noninteger footprints instead of point sampling.\nexport const albedoDownsampleShader = (depthOutput = false) => /* wgsl */ `\n@group(0) @binding(0) var diffuse: texture_2d<f32>;\n@group(0) @binding(1) var specular: texture_2d<f32>;\n@group(0) @binding(2) var<uniform> outputSize: vec4f;\n@group(0) @binding(3) var depth: texture_2d<f32>;\n@vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {\n let p=vec2f(f32((index<<1u)&2u),f32(index&2u));return vec4f(p*2.0-1.0,0,1);\n}\nstruct Result {@location(0) diffuse: vec4f, @location(1) specular: vec4f, ${depthOutput ? '@location(2) depth: vec4f,' : ''}}\n@fragment fn fragment(@builtin(position) p: vec4f) -> Result {\n let scale=vec2f(textureDimensions(diffuse))/outputSize.xy;\n let start=floor(p.xy)*scale;let end=start+scale;\n var d=vec4f(0);var s=vec4f(0);var nearest=3.4e38;var hits=0.0;\n for(var y=i32(floor(start.y));y<i32(ceil(end.y));y++){\n for(var x=i32(floor(start.x));x<i32(ceil(end.x));x++){\n let overlap=max(vec2f(0),min(vec2f(vec2i(x+1,y+1)),end)-max(vec2f(vec2i(x,y)),start));let weight=overlap.x*overlap.y;\n let a=textureLoad(diffuse,vec2i(x,y),0);let b=textureLoad(specular,vec2i(x,y),0);let z=textureLoad(depth,vec2i(x,y),0).xy;\n d+=vec4f(a.rgb*a.a,a.a)*weight;s+=vec4f(b.rgb*b.a,b.a)*weight;\n hits+=z.y*weight;if(z.y>0.0){nearest=min(nearest,z.x);}\n }\n }\n var result: Result;\n ${depthOutput ? 'result.depth=vec4f(select(0.0,nearest,hits>0.0),hits/(scale.x*scale.y),0,0);' : ''}\n result.diffuse=vec4f(d.rgb/max(d.a,1e-8),d.a/(scale.x*scale.y));\n result.specular=vec4f(s.rgb/max(s.a,1e-8),s.a/(scale.x*scale.y));return result;\n}\n`;\n\n// Builds the tone lookup rows for the current grading and tone mapping.\n// toneMappingParams: x mode, y maximum display value, z exposure, w 1 for extended output.\nexport const toneLutShader = /* wgsl */ `\n@group(0) @binding(0) var<uniform> toneMappingParams: vec4f;\n@group(0) @binding(1) var<uniform> colorGradingParams: vec4f;\n${composeDefine}\nfn toneGray(x: f32) -> vec3f {\n var v=gradeColor(vec3f(x)*toneMappingParams.z);\n if(toneMappingParams.w<0.5){v=applyToneMapping(v);}\n return v;\n}\n@vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {\n let p=vec2f(f32((index<<1u)&2u),f32(index&2u));return vec4f(p*2.0-1.0,0,1);\n}\n@fragment fn fragment(@builtin(position) p: vec4f) -> @location(0) vec4f {\n let u=floor(p.x)/${TONE_LUT_SIZE - 1}.0;\n if(p.y<1.0){return vec4f(toneGray(exp2(mix(${TONE_LUT_LOG2[0]}.0,${TONE_LUT_LOG2[1]}.0,u))),1);}\n let d=u*u*toneMappingParams.y;var result=vec3f(0);\n for(var c=0;c<3;c++){\n var lo=${TONE_LUT_LOG2[0]}.0;var hi=${TONE_LUT_LOG2[1]}.0;\n for(var i=0;i<28;i++){let mid=0.5*(lo+hi);if(toneGray(exp2(mid))[c]<d){lo=mid;}else{hi=mid;}}\n result[c]=0.5*(lo+hi);\n }\n return vec4f(result,1);\n}\n`;\n\n// Per low-resolution pixel, fits scene-linear radiance x ~ slope * albedo + offset over a\n// 3x3 window of guided samples, per channel (a guided-filter regression). Flat albedo\n// gives slope ~0, so its radiance is not modulated; tone.y regularizes the variance.\nexport const guidedCoefficientShader = /* wgsl */ `\n@group(0) @binding(0) var colorImage: texture_2d<f32>;\n@group(0) @binding(1) var diffuseLo: texture_2d<f32>;\n@group(0) @binding(2) var specularLo: texture_2d<f32>;\n${toneCodingDefine}\nfn loadAt(image: texture_2d<f32>, p: vec2i) -> vec4f {return textureLoad(image,clamp(p,vec2i(0),vec2i(textureDimensions(image))-1),0);}\n@vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {\n let p=vec2f(f32((index<<1u)&2u),f32(index&2u));return vec4f(p*2.0-1.0,0,1);\n}\nstruct Result {@location(0) slope: vec4f, @location(1) offset: vec4f,}\n@fragment fn fragment(@builtin(position) position: vec4f) -> Result {\n let center=vec2i(position.xy);\n var weight=0.0;var meanAlbedo=vec3f(0);var meanRadiance=vec3f(0);var meanProduct=vec3f(0);var meanSquare=vec3f(0);\n for(var y=-1;y<=1;y++){for(var x=-1;x<=1;x++){\n let q=center+vec2i(x,y);let d=loadAt(diffuseLo,q);let s=loadAt(specularLo,q);\n let w=step(0.5,min(d.a,s.a));let albedo=d.rgb+s.rgb;\n let radiance=exp2(toneInverse(detailDecode(loadAt(colorImage,q).rgb)));\n weight+=w;meanAlbedo+=albedo*w;meanRadiance+=radiance*w;meanProduct+=albedo*radiance*w;meanSquare+=albedo*albedo*w;\n }}\n var result: Result;\n if(weight<1.0){return result;}\n meanAlbedo/=weight;meanRadiance/=weight;meanProduct/=weight;meanSquare/=weight;\n let slope=max((meanProduct-meanAlbedo*meanRadiance)/(meanSquare-meanAlbedo*meanAlbedo+vec3f(tone.y)),vec3f(0));\n result.slope=vec4f(slope,1);result.offset=vec4f(meanRadiance-slope*meanAlbedo,1);\n return result;\n}\n`;\n"]}