@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
@@ -1,32 +1,34 @@
1
1
  // Estimate the direct lighting integral using multiple importance sampling
2
2
  // http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html#EstimatingtheDirectLightingIntegral
3
3
  import { glsl } from '../../shader.js';
4
- export function createSampleMaterialGlsl(fragments = {}) {
4
+ export function createSampleMaterialGlsl(fragments = {}, channelIndependentLight = false) {
5
5
  return glsl `
6
6
  float emissiveHitMisWeight(SurfaceInteraction si,Path path) {
7
7
 
8
- float ys=dot(si.faceNormal,-path.ray.d);
9
- if(ys<=0.0&&fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_ALPHA).z<0.5)return 0.0;
8
+ float Ar=dot(si.faceNormal,-path.ray.d);
9
+ if(Ar<=0.0&&fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_ALPHA).z<0.5)return 0.0;
10
10
  #ifdef HAS_EMISSIVE_LIGHTS
11
11
  if(!path.fromEye && emissiveWeightTotal>0.0) {
12
12
  vec3 emission=fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_EMISSION).rgb;
13
13
  float value=dot(emission,vec3(.2126,.7152,.0722)),cosine=dot(si.faceNormal,-path.ray.d);
14
- if(value>0.0&&cosine>0.0){float d=distance(si.position,path.ray.o);return aF(path.scatteringPdf,value/emissiveWeightTotal*d*d/cosine);}
14
+ if(value>0.0&&cosine>0.0){float d=distance(si.position,path.ray.o);return aG(path.scatteringPdf,value/emissiveWeightTotal*d*d/cosine);}
15
15
  }
16
16
  #endif
17
17
  return 1.0;
18
18
  }
19
19
 
20
- vec3 sX(SurfaceInteraction si, OpenPbrResolvedMaterial mat, OpenPbrPreparedBsdf prepared, inout Path path, vec3 ffnormal, bool isSurface) {
21
- float lH = 1.0;
22
- vec3 mZ = vec3(sample2D(bE(LIGHT_POSITION)), sample1D(bE(LIGHT_SELECT)));
20
+ vec3 qY(SurfaceInteraction si, OpenPbrResolvedMaterial mat, OpenPbrPreparedBsdf prepared, inout Path path, vec3 ffnormal, bool isSurface) {
21
+ float mz = 1.0;
22
+ vec3 ob = vec3(sample2D(aX(LIGHT_POSITION)), sample1D(aX(LIGHT_SELECT)));
23
23
 
24
24
  LightSampleRec lightSample;
25
- sampleLight(si.position, mZ, lightSample, false);${fragments['sample0'] ?? ''}
25
+ sampleLight(si.position, ob, lightSample, false);${fragments['sample0'] ?? ''}
26
+ ${channelIndependentLight ? /* glsl */ ` if (dispersionWavelengths == 1) {
26
27
  lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);
28
+ }` : /* glsl */ ` lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);`}
27
29
 
28
30
  vec3 lightDir = lightSample.direction;
29
- vec3 qR = -path.ray.d;
31
+ vec3 sg = -path.ray.d;
30
32
  float lightPdf = lightSample.pdf;
31
33
 
32
34
 
@@ -41,7 +43,12 @@ if (lightPdf <= 0.0 || max(max(lightSample.emission.x, lightSample.emission.y),
41
43
  return vec3(0.0);
42
44
  }
43
45
 
44
- float scatteringPdf = 0.0;
46
+ ${channelIndependentLight ? /* glsl */ `
47
+
48
+ if (dispersionWavelengths != 1) {
49
+ lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);
50
+ }
51
+ ` : ''} float scatteringPdf = 0.0;
45
52
  vec3 f = vec3(0.0);
46
53
  if (isSurface) {
47
54
  if (cosThetaL <= 0.0 && mat.transmissionWeight <= 0.0 && mat.subsurfaceWeight <= 0.0) {
@@ -50,8 +57,8 @@ return vec3(0.0);
50
57
  f = openpbr_eval_prepared(prepared, lightDir, scatteringPdf);
51
58
  }
52
59
  else {
53
- scatteringPdf = bB(
54
- dot(qR, lightDir),
60
+ scatteringPdf = ba(
61
+ dot(sg, lightDir),
55
62
  si.mediumAnisotropy
56
63
  );
57
64
  f = vec3(scatteringPdf);
@@ -61,34 +68,34 @@ if (scatteringPdf <= 0.0 || max(max(f.x, f.y), f.z) <= 0.0) {
61
68
  return vec3(0.0);
62
69
  }
63
70
 
64
- Ray mY;
65
- vec3 eO = si.position + EPS * lightDir;
71
+ Ray oa;
72
+ vec3 eY = si.position + EPS * lightDir;
66
73
  if (isSurface) {
67
74
  const float shadowTerminatorCutoff = 0.1;
68
- float dj = dot(si.normal, lightDir);
75
+ float dl = dot(si.normal, lightDir);
69
76
  #ifdef USE_COAT_NORMAL_FRAMES
70
- if (mat.coatNormalEnabled) { dj = dot(si.faceNormal, lightDir); }
77
+ if (mat.coatNormalEnabled) { dl = dot(si.faceNormal, lightDir); }
71
78
  #endif
72
- vec3 geometricNormal = dj < 0.0 ? -si.faceNormal : si.faceNormal;
73
- dj = abs(dj);
74
- float hO = dot(geometricNormal, lightDir);
75
- float pf = dj < shadowTerminatorCutoff
79
+ vec3 geometricNormal = dl < 0.0 ? -si.faceNormal : si.faceNormal;
80
+ dl = abs(dl);
81
+ float iw = dot(geometricNormal, lightDir);
82
+ float qo = dl < shadowTerminatorCutoff
76
83
  ? clamp(
77
- 2.0 - (hO + dj) / shadowTerminatorCutoff,
84
+ 2.0 - (iw + dl) / shadowTerminatorCutoff,
78
85
  0.0,
79
86
  1.0
80
87
  )
81
- : clamp(1.0 - hO / shadowTerminatorCutoff, 0.0, 1.0);
82
- eO += si.shadowOffset * pf;
88
+ : clamp(1.0 - iw / shadowTerminatorCutoff, 0.0, 1.0);
89
+ eY += si.shadowOffset * qo;
83
90
  }
84
- float qz=lightSample.dist-EPS;
85
- vec3 pO=lightDir;
91
+ float rM=lightSample.dist-EPS;
92
+ vec3 qS=lightDir;
86
93
  if(lightSample.sourceType==1){
87
94
  vec3 endpoint=si.position+lightDir*lightSample.dist+EPS*lightSample.normal;
88
- pO=normalize(endpoint-eO);qz=distance(endpoint,eO);
95
+ qS=normalize(endpoint-eY);rM=distance(endpoint,eY);
89
96
  }
90
- initRay(mY, eO, pO);
91
- if (intersectSceneShadow(mY, qz, si.triangleIndex)) {
97
+ initRay(oa, eY, qS);
98
+ if (intersectSceneShadow(oa, rM, si.triangleIndex)) {
92
99
  return vec3(0.0);
93
100
  }
94
101
 
@@ -96,7 +103,7 @@ return vec3(0.0);
96
103
 
97
104
 
98
105
  if (isSurface && cosThetaL < 0.0 && lightSample.sourceType == 0) {
99
- vec4 background = cn(mY.o, lightDir);
106
+ vec4 background = cq(oa.o, lightDir);
100
107
  lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.a, pathChannel);
101
108
  }
102
109
  #endif
@@ -105,45 +112,45 @@ lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.
105
112
 
106
113
  float misWeight = lightSample.isDelta
107
114
  ? 1.0
108
- : aF(lightPdf, scatteringPdf);
115
+ : aG(lightPdf, scatteringPdf);
109
116
  ${fragments['sample1'] ?? ''} return misWeight > 0.0
110
117
  ? misWeight * lightSample.emission * f / lightPdf
111
118
  : vec3(0.0);
112
119
  }
113
120
 
114
121
  #ifdef USE_COAT_NORMAL_FRAMES
115
- vec3 fE(vec3 ql, vec3 face, vec3 view) {
122
+ vec3 fQ(vec3 ru, vec3 face, vec3 view) {
116
123
  bool front = dot(face, view) >= 0.0;
117
- vec3 wd = front ? face : -face;
118
- vec3 rY = front ? ql : -ql;
119
- if (dot(ql, face) <= 0.0 || dot(rY, view) <= 1e-6) { return wd; }
120
- return rY;
124
+ vec3 yc = front ? face : -face;
125
+ vec3 tv = front ? ru : -ru;
126
+ if (dot(ru, face) <= 0.0 || dot(tv, view) <= 1e-6) { return yc; }
127
+ return tv;
121
128
  }
122
129
  #endif
123
- void mx(inout SurfaceInteraction si, OpenPbrResolvedMaterial mat, inout Path path) {
124
- vec3 wh = vec3(sample2D(bE(BSDF_DIRECTION)), sample1D(bE(BSDF_LOBE)));
130
+ void nB(inout SurfaceInteraction si, OpenPbrResolvedMaterial mat, inout Path path) {
131
+ vec3 yh = vec3(sample2D(aX(BSDF_DIRECTION)), sample1D(aX(BSDF_LOBE)));
125
132
  #ifdef USE_COAT_NORMAL_FRAMES
126
- vec3 bA = si.faceNormal;
127
- vec3 ni = si.normal;
133
+ vec3 bC = si.faceNormal;
134
+ vec3 oh = si.normal;
128
135
  #endif
129
- float sL = -dot(si.faceNormal, path.ray.d);
130
- float tY = -dot(si.normal, path.ray.d);
136
+ float uk = -dot(si.faceNormal, path.ray.d);
137
+ float vH = -dot(si.normal, path.ray.d);
131
138
  if ((mat.transmissionWeight > 0.0 || mat.subsurfaceWeight > 0.0) && mat.thinWalled) {
132
139
 
133
- if (sL < 0.0) {
140
+ if (uk < 0.0) {
134
141
  si.faceNormal = -si.faceNormal;
135
- sL = -sL;
142
+ uk = -uk;
136
143
  }
137
- if (tY < 0.0) {
144
+ if (vH < 0.0) {
138
145
  si.normal = -si.normal;
139
- tY = -tY;
146
+ vH = -vH;
140
147
  }
141
148
  }
142
149
 
143
150
 
144
- bool qE = sL >= 0.0 && tY < 0.0;
145
- float ndv = qE ? sL : tY;
146
- vec3 normal = qE ? si.faceNormal : si.normal;
151
+ bool rS = uk >= 0.0 && vH < 0.0;
152
+ float ndv = rS ? uk : vH;
153
+ vec3 normal = rS ? si.faceNormal : si.normal;
147
154
 
148
155
  mat.inside = ndv <= 0.0 && !mat.thinWalled;
149
156
 
@@ -152,96 +159,105 @@ vec3 ffnormal = ndv >= 0.0 ? normal : -normal;
152
159
  #ifdef USE_COAT_NORMAL_FRAMES
153
160
  if (mat.coatNormalEnabled) {
154
161
  vec3 view = -path.ray.d;
155
- float fZ = dot(bA, view);
156
- mat.geometricNormal = fZ >= 0.0 ? bA : -bA;
157
- ffnormal = fE(ni, bA, view);
158
- mat.coatNormal = fE(si.coatNormal, bA, view);
159
- mat.inside = fZ <= 0.0 && !mat.thinWalled;
160
- mat.relativeIor = (fZ > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;
162
+ float gr = dot(bC, view);
163
+ mat.geometricNormal = gr >= 0.0 ? bC : -bC;
164
+ ffnormal = fQ(oh, bC, view);
165
+ mat.coatNormal = fQ(si.coatNormal, bC, view);
166
+ mat.inside = gr <= 0.0 && !mat.thinWalled;
167
+ mat.relativeIor = (gr > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;
161
168
  }
162
169
  #endif
163
170
 
164
171
 
165
172
  float scatteringPdf;
166
- vec3 df;
173
+ vec3 di;
167
174
  path.scatteringIsDelta = false;
168
175
  bool mediumSampled = false;
169
- bool hj = false;
176
+ bool hE = false;
170
177
  OpenPbrPreparedBsdf prepared;
171
178
 
172
179
  #ifdef HAS_MEDIUM
173
180
  int mediumType = si.mediumType;
174
181
  float d = distance(si.position, path.ray.o);
175
- vec3 od = path.ray.o;
182
+ vec3 pd = path.ray.o;
176
183
  vec3 extinction = si.mediumExtinction;
177
184
  vec3 scattering = min(si.mediumScattering, extinction);
178
- float tU = max(max(extinction.x, extinction.y), extinction.z);
179
- if (mediumType > 0 && tU > 0.0) {
185
+ float vD = max(max(extinction.x, extinction.y), extinction.z);
186
+ if (mediumType > 0 && vD > 0.0) {
180
187
 
181
188
 
182
189
 
183
190
 
184
- int nX = min(int(sample1D(bE(MEDIUM_CHANNEL)) * 3.0), 2);
185
- float fD = extinction[nX];
186
- float ij = fD > 0.0
187
- ? min(-log(max(sample1D(bE(MEDIUM_DISTANCE)), 1e-7)) / fD, d)
191
+ int oW = min(int(sample1D(aX(MEDIUM_CHANNEL)) * 3.0), 2);
192
+ float fP = extinction[oW];
193
+ float iO = fP > 0.0
194
+ ? min(-log(max(sample1D(aX(MEDIUM_DISTANCE)), 1e-7)) / fP, d)
188
195
  : d;
189
- mediumSampled = ij < d;
190
- vec3 transmittance = exp(-extinction * ij);
191
- vec3 oK = mediumSampled
196
+ mediumSampled = iO < d;
197
+ vec3 transmittance = exp(-extinction * iO);
198
+ vec3 density = mediumSampled
192
199
  ? extinction * transmittance
193
200
  : transmittance;
194
201
  float mediumPdf = max(
195
- (oK.x + oK.y + oK.z) / 3.0,
202
+ (density.x + density.y + density.z) / 3.0,
196
203
  1e-8
197
204
  );
198
205
  if (mediumSampled) {
199
206
  path.beta *= transmittance * scattering / mediumPdf;
200
207
 
201
- path.ray.o = od + ij * path.ray.d;
208
+ if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }
209
+
210
+ path.ray.o = pd + iO * path.ray.d;
202
211
  si.position = path.ray.o;
203
- path.li += sX(si, mat, prepared, path, ffnormal, false) * path.beta;
204
212
 
213
+ si.triangleIndex = -1;
214
+ si.instanceIndex = -1;
215
+ path.li += qY(si, mat, prepared, path, ffnormal, false) * path.beta;
205
216
 
206
- df = fj(
217
+
218
+ di = dQ(
207
219
  -path.ray.d,
208
220
  si.mediumAnisotropy,
209
- sample2D(bE(PHASE_DIRECTION))
221
+ sample2D(aX(PHASE_DIRECTION))
210
222
  );
211
- scatteringPdf = bB(
212
- dot(df, -path.ray.d),
223
+ scatteringPdf = ba(
224
+ dot(di, -path.ray.d),
213
225
  si.mediumAnisotropy
214
226
  );
215
227
  }
216
228
  else {
217
229
  path.beta *= transmittance / mediumPdf;
230
+
231
+ if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }
218
232
  }
219
233
  }
220
234
  #endif
221
235
 
222
236
 
223
237
  if (!mediumSampled) {
224
- ${fragments['sample2'] ?? ''}path.li += emissiveHitMisWeight(si,path) * mat.emission * path.beta;${fragments['sample3'] ?? ''}
238
+
239
+ vec3 surfaceEmission = sampling_spectral_rgb_filter(mat.emission, pathChannel);
240
+ ${fragments['sample2'] ?? ''}path.li += emissiveHitMisWeight(si,path) * surfaceEmission * path.beta;${fragments['sample3'] ?? ''}
225
241
  if (mat.materialType == UNLIT) {
226
242
  path.abort = true;
227
243
  return;
228
244
  }
229
- vec3 qB = vec3(0.0);
245
+ vec3 rP = vec3(0.0);
230
246
  #ifdef USE_TANGENT
231
- qB = si.tangent;
247
+ rP = si.tangent;
232
248
  #endif
233
249
  mat.directionTangent = si.directionTangent;
234
250
  mat.directionBitangent = si.directionBitangent;
235
251
  mat.geometryTangent = si.geometryTangent;
236
252
  mat.geometryBitangent = si.geometryBitangent;
237
- prepared = bV(qB, mat, -path.ray.d, ffnormal);
238
- path.li += sX(si, mat, prepared, path, ffnormal, true) * path.beta;
253
+ prepared = bX(rP, mat, -path.ray.d, ffnormal);
254
+ path.li += qY(si, mat, prepared, path, ffnormal, true) * path.beta;
239
255
  ${fragments['sample4'] ?? ''}
240
256
  bool isNextRefraction;
241
- vec3 f = dl(
257
+ vec3 f = dr(
242
258
  prepared,
243
- wh,
244
- df,
259
+ yh,
260
+ di,
245
261
  scatteringPdf,
246
262
  isNextRefraction
247
263
  );
@@ -253,25 +269,27 @@ prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] >= 1.0 - 1e-6;
253
269
 
254
270
 
255
271
  if (!(scatteringPdf > 0.0) || any(isnan(f)) || any(isinf(f)) ||
256
- dot(df, df) < 0.5) {
272
+ dot(di, di) < 0.5) {
257
273
  path.scatteringPdf = 0.0;
258
274
  path.abort = true;
259
275
  return;
260
276
  }
261
277
  ${fragments['sample5'] ?? ''} path.beta *= f / scatteringPdf;
262
- hj = !mat.thinWalled &&
278
+
279
+ if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }
280
+ hE = !mat.thinWalled &&
263
281
  isNextRefraction;
264
282
  path.isNextRefraction = isNextRefraction;
265
283
 
266
284
 
267
- path.ray.o = si.position + EPS * df;
285
+ path.ray.o = si.position + EPS * di;
268
286
  #ifdef USE_COAT_NORMAL_FRAMES
269
- if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(bA, df) >= 0.0 ? bA : -bA); }
287
+ if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(bC, di) >= 0.0 ? bC : -bC); }
270
288
  #endif
271
289
  }
272
290
 
273
291
  path.scatteringPdf = scatteringPdf;
274
- initRay(path.ray, path.ray.o, df);
292
+ initRay(path.ray, path.ray.o, di);
275
293
  if (mediumSampled) {${fragments['sample6'] ?? ''}
276
294
  path.isNextRefraction = false;
277
295
  }
@@ -280,11 +298,12 @@ path.fromEye = false;
280
298
  #ifdef HAS_MEDIUM
281
299
 
282
300
 
283
- if (!mediumSampled && hj && mat.mediumType > 0) {
284
- if (sL >= 0.0) {
301
+ if (!mediumSampled && hE && mat.mediumType > 0) {
302
+ if (uk >= 0.0) {
285
303
  si.mediumType = mat.mediumType;
286
304
  si.mediumExtinction = mat.mediumExtinction;
287
305
  si.mediumScattering = mat.mediumScattering;
306
+ path.scatteringMediumEntered = path.scatteringMediumEntered || any(greaterThan(mat.mediumScattering, vec3(0.0)));
288
307
  si.mediumAnisotropy = mat.mediumAnisotropy;
289
308
  }
290
309
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"sampleMaterial.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/sampleMaterial.glsl.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,iIAAiI;AAEjI,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,MAAM,UAAU,wBAAwB,CAAC,YAA8C,EAAE;IAAI,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;mDAoB7C,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoFnF,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmHtB,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,uEAAuE,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;EAe/H,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;EAsB1B,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;sBAcJ,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;CAwBjD,CAAC;AACF,CAAC;AACD,eAAe,wBAAwB,EAAE,CAAC","sourcesContent":["// Estimate the direct lighting integral using multiple importance sampling\n// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html#EstimatingtheDirectLightingIntegral\n\nimport { glsl } from '../../shader.js';\nexport function createSampleMaterialGlsl(fragments: Readonly<Record<string, string>> = {}) { return glsl`\nfloat emissiveHitMisWeight(SurfaceInteraction si,Path path) {\n // Secondary intersections remain two-sided, but one-sided emission does not.\n float facing=dot(si.faceNormal,-path.ray.d);\n if(facing<=0.0&&fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_ALPHA).z<0.5)return 0.0;\n#ifdef HAS_EMISSIVE_LIGHTS\n if(!path.fromEye && emissiveWeightTotal>0.0) {\n vec3 emission=fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_EMISSION).rgb;\n float value=dot(emission,vec3(.2126,.7152,.0722)),cosine=dot(si.faceNormal,-path.ray.d);\n if(value>0.0&&cosine>0.0){float d=distance(si.position,path.ray.o);return sampling_power_heuristic(path.scatteringPdf,value/emissiveWeightTotal*d*d/cosine);}\n }\n#endif\n return 1.0;\n}\n\nvec3 DirectLight(SurfaceInteraction si, OpenPbrResolvedMaterial mat, OpenPbrPreparedBsdf prepared, inout Path path, vec3 ffnormal, bool isSurface) {\n float occluded = 1.0;\n vec3 lightRnd = vec3(sample2D(bounceDim(LIGHT_POSITION)), sample1D(bounceDim(LIGHT_SELECT)));\n\n LightSampleRec lightSample;\n sampleLight(si.position, lightRnd, lightSample, false);${fragments['sample0'] ?? ''}\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);\n\n vec3 lightDir = lightSample.direction;\n vec3 viewDir = -path.ray.d;\n float lightPdf = lightSample.pdf;\n // Opaque surfaces are rendered two-sided by the core renderer. Use the\n // face-forward shading normal here as well, otherwise the early-out rejects\n // every direct-light sample seen from the back of a triangle (for example\n // the inside of an imported room wall).\n float cosThetaL = dot(ffnormal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (isSurface && mat.coatNormalEnabled) { cosThetaL = dot(mat.geometricNormal, lightDir); }\n#endif\n\n if (lightPdf <= 0.0 || max(max(lightSample.emission.x, lightSample.emission.y), lightSample.emission.z) <= 0.0) {\n return vec3(0.0);\n }\n\n float scatteringPdf = 0.0;\n vec3 f = vec3(0.0);\n if (isSurface) {\n if (cosThetaL <= 0.0 && mat.transmissionWeight <= 0.0 && mat.subsurfaceWeight <= 0.0) {\n return vec3(0.0);\n }\n f = openpbr_eval_prepared(prepared, lightDir, scatteringPdf);\n }\n else {\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(viewDir, lightDir),\n si.mediumAnisotropy\n );\n f = vec3(scatteringPdf);\n }\n\n if (scatteringPdf <= 0.0 || max(max(f.x, f.y), f.z) <= 0.0) {\n return vec3(0.0);\n }\n\n Ray lightRay;\n vec3 shadowOrigin = si.position + EPS * lightDir;\n if (isSurface) {\n const float shadowTerminatorCutoff = 0.1;\n float normalLight = dot(si.normal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { normalLight = dot(si.faceNormal, lightDir); }\n#endif\n vec3 geometricNormal = normalLight < 0.0 ? -si.faceNormal : si.faceNormal;\n normalLight = abs(normalLight);\n float geometricLight = dot(geometricNormal, lightDir);\n float offsetAmount = normalLight < shadowTerminatorCutoff\n ? clamp(\n 2.0 - (geometricLight + normalLight) / shadowTerminatorCutoff,\n 0.0,\n 1.0\n )\n : clamp(1.0 - geometricLight / shadowTerminatorCutoff, 0.0, 1.0);\n shadowOrigin += si.shadowOffset * offsetAmount;\n }\n float shadowDistance=lightSample.dist-EPS;\n vec3 shadowDirection=lightDir;\n if(lightSample.sourceType==1){\n vec3 endpoint=si.position+lightDir*lightSample.dist+EPS*lightSample.normal;\n shadowDirection=normalize(endpoint-shadowOrigin);shadowDistance=distance(endpoint,shadowOrigin);\n }\n initRay(lightRay, shadowOrigin, shadowDirection);\n if (intersectSceneShadow(lightRay, shadowDistance, si.triangleIndex)) {\n return vec3(0.0);\n }\n\n#ifdef USE_ENVMAP\n // Match the endpoint used by a BSDF-sampled surface transmission, including\n // a separately displayed or grounded background and its coverage.\n if (isSurface && cosThetaL < 0.0 && lightSample.sourceType == 0) {\n vec4 background = sampleBackgroundFromRay(lightRay.o, lightDir);\n lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.a, pathChannel);\n }\n#endif\n\n // Delta lights cannot be sampled by the BSDF strategy, so their MIS weight\n // is exactly one even when their light-selection PMF is small.\n float misWeight = lightSample.isDelta\n ? 1.0\n : sampling_power_heuristic(lightPdf, scatteringPdf);\n${fragments['sample1'] ?? ''} return misWeight > 0.0\n ? misWeight * lightSample.emission * f / lightPdf\n : vec3(0.0);\n}\n\n#ifdef USE_COAT_NORMAL_FRAMES\nvec3 coat_frame_normal(vec3 inputNormal, vec3 face, vec3 view) {\n bool front = dot(face, view) >= 0.0;\n vec3 ffFace = front ? face : -face;\n vec3 ffInput = front ? inputNormal : -inputNormal;\n if (dot(inputNormal, face) <= 0.0 || dot(ffInput, view) <= 1e-6) { return ffFace; }\n return ffInput;\n}\n#endif\nvoid SampleMaterial(inout SurfaceInteraction si, OpenPbrResolvedMaterial mat, inout Path path) {\n vec3 matRnd = vec3(sample2D(bounceDim(BSDF_DIRECTION)), sample1D(bounceDim(BSDF_LOBE)));\n#ifdef USE_COAT_NORMAL_FRAMES\n vec3 originalFace = si.faceNormal;\n vec3 originalNormal = si.normal;\n#endif\n float ndv1 = -dot(si.faceNormal, path.ray.d);\n float ndv2 = -dot(si.normal, path.ray.d);\n if ((mat.transmissionWeight > 0.0 || mat.subsurfaceWeight > 0.0) && mat.thinWalled) {\n // Always treat thin material as entering medium\n if (ndv1 < 0.0) {\n si.faceNormal = -si.faceNormal;\n ndv1 = -ndv1;\n }\n if (ndv2 < 0.0) {\n si.normal = -si.normal;\n ndv2 = -ndv2;\n }\n }\n // In same edge cases normal is not torwards the camera while we can still see the face.\n // We need to choose faceNormal in this case.\n bool useFaceN = ndv1 >= 0.0 && ndv2 < 0.0;\n float ndv = useFaceN ? ndv1 : ndv2;\n vec3 normal = useFaceN ? si.faceNormal : si.normal;\n\n mat.inside = ndv <= 0.0 && !mat.thinWalled;\n // In or out\n mat.relativeIor = ndv > 0.0 ? (1.0 / mat.specularIor) : mat.specularIor;\n vec3 ffnormal = ndv >= 0.0 ? normal : -normal;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) {\n vec3 view = -path.ray.d;\n float geometricView = dot(originalFace, view);\n mat.geometricNormal = geometricView >= 0.0 ? originalFace : -originalFace;\n ffnormal = coat_frame_normal(originalNormal, originalFace, view);\n mat.coatNormal = coat_frame_normal(si.coatNormal, originalFace, view);\n mat.inside = geometricView <= 0.0 && !mat.thinWalled;\n mat.relativeIor = (geometricView > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;\n }\n#endif\n\n\n float scatteringPdf;\n vec3 scatterDir;\n path.scatteringIsDelta = false;\n bool mediumSampled = false;\n bool crossedBoundary = false;\n OpenPbrPreparedBsdf prepared;\n\n#ifdef HAS_MEDIUM\n int mediumType = si.mediumType;\n float d = distance(si.position, path.ray.o);\n vec3 segmentOrigin = path.ray.o;\n vec3 extinction = si.mediumExtinction;\n vec3 scattering = min(si.mediumScattering, extinction);\n float majorant = max(max(extinction.x, extinction.y), extinction.z);\n if (mediumType > 0 && majorant > 0.0) {\n // Sample one RGB extinction channel and divide by the mixture PDF. This\n // is the homogeneous-medium estimator used by PBRT and avoids the very\n // large exp((majorant - extinction) * distance) weights produced by\n // majorant tracking when OpenPBR SSS radii differ strongly by channel.\n int mediumChannel = min(int(sample1D(bounceDim(MEDIUM_CHANNEL)) * 3.0), 2);\n float channelExtinction = extinction[mediumChannel];\n float scatterDist = channelExtinction > 0.0\n ? min(-log(max(sample1D(bounceDim(MEDIUM_DISTANCE)), 1e-7)) / channelExtinction, d)\n : d;\n mediumSampled = scatterDist < d;\n vec3 transmittance = exp(-extinction * scatterDist);\n vec3 density = mediumSampled\n ? extinction * transmittance\n : transmittance;\n float mediumPdf = max(\n (density.x + density.y + density.z) / 3.0,\n 1e-8\n );\n if (mediumSampled) {\n path.beta *= transmittance * scattering / mediumPdf;\n // Move from the start of the segment, not from its end surface.\n path.ray.o = segmentOrigin + scatterDist * path.ray.d;\n si.position = path.ray.o;\n path.li += DirectLight(si, mat, prepared, path, ffnormal, false) * path.beta;\n\n // Pick a new direction based on the phase function\n scatterDir = sampling_henyey_greenstein(\n -path.ray.d,\n si.mediumAnisotropy,\n sample2D(bounceDim(PHASE_DIRECTION))\n );\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(scatterDir, -path.ray.d),\n si.mediumAnisotropy\n );\n }\n else {\n path.beta *= transmittance / mediumPdf;\n }\n }\n#endif\n\n // Direct lighting\n if (!mediumSampled) {\n ${fragments['sample2'] ?? ''}path.li += emissiveHitMisWeight(si,path) * mat.emission * path.beta;${fragments['sample3'] ?? ''}\n if (mat.materialType == UNLIT) {\n path.abort = true;\n return;\n }\n vec3 surfaceTangent = vec3(0.0);\n#ifdef USE_TANGENT\n surfaceTangent = si.tangent;\n#endif\n mat.directionTangent = si.directionTangent;\n mat.directionBitangent = si.directionBitangent;\n mat.geometryTangent = si.geometryTangent;\n mat.geometryBitangent = si.geometryBitangent;\n prepared = openpbr_prepare(surfaceTangent, mat, -path.ray.d, ffnormal);\n path.li += DirectLight(si, mat, prepared, path, ffnormal, true) * path.beta;\n${fragments['sample4'] ?? ''} // Sample BSDF for color and outgoing direction\n bool isNextRefraction;\n vec3 f = openpbr_sample_prepared(\n prepared,\n matRnd,\n scatterDir,\n scatteringPdf,\n isNextRefraction\n );\n // Null-boundary transmission is discrete and has no NEE competitor.\n path.scatteringIsDelta = !prepared.material.thinWalled &&\n abs(prepared.material.relativeIor - 1.0) <= 1e-6 &&\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] >= 1.0 - 1e-6;\n // Match WebGPU: rejected VNDF/refraction proposals have no continuation.\n // Tracing their fallback direction with the incoming throughput invents\n // light paths, especially after total internal reflection inside glass.\n if (!(scatteringPdf > 0.0) || any(isnan(f)) || any(isinf(f)) ||\n dot(scatterDir, scatterDir) < 0.5) {\n path.scatteringPdf = 0.0;\n path.abort = true;\n return;\n }\n${fragments['sample5'] ?? ''} path.beta *= f / scatteringPdf;\n crossedBoundary = !mat.thinWalled &&\n isNextRefraction;\n path.isNextRefraction = isNextRefraction;\n // TODO prefer the opaque surface when transmission surface and opaque surface are overlapped.\n // Or the ray go out from transmission material will miss the opque surface.\n path.ray.o = si.position + EPS * scatterDir;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(originalFace, scatterDir) >= 0.0 ? originalFace : -originalFace); }\n#endif\n }\n\n path.scatteringPdf = scatteringPdf;\n initRay(path.ray, path.ray.o, scatterDir);\n if (mediumSampled) {${fragments['sample6'] ?? ''}\n path.isNextRefraction = false;\n }\n path.fromEye = false;\n\n#ifdef HAS_MEDIUM\n // A reflected ray stays in its current medium. Only a sampled transmission\n // event crosses the boundary of a medium-bearing closed mesh.\n if (!mediumSampled && crossedBoundary && mat.mediumType > 0) {\n if (ndv1 >= 0.0) {\n si.mediumType = mat.mediumType;\n si.mediumExtinction = mat.mediumExtinction;\n si.mediumScattering = mat.mediumScattering;\n si.mediumAnisotropy = mat.mediumAnisotropy;\n }\n else {\n si.mediumType = 0;\n si.mediumExtinction = vec3(0.0);\n si.mediumScattering = vec3(0.0);\n si.mediumAnisotropy = 0.0;\n }\n }\n#endif\n}\n`;\n}\nexport default createSampleMaterialGlsl();\n"]}
1
+ {"version":3,"file":"sampleMaterial.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/sampleMaterial.glsl.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,iIAAiI;AAEjI,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,MAAM,UAAU,wBAAwB,CAAC,YAA8C,EAAE,EAAE,uBAAuB,GAAG,KAAK;IAAI,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;mDAoB9E,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;EACnF,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;EAEnC,CAAC,CAAC,CAAC,UAAU,CAAC,2FAA2F;;;;;;;;;;;;;;;;;;EAkB3G,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;CAKtC,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiEJ,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4HtB,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,0EAA0E,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;EAelI,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;EAsB1B,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;sBAgBJ,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;CAyBjD,CAAC;AACF,CAAC;AACD,eAAe,wBAAwB,EAAE,CAAC","sourcesContent":["// Estimate the direct lighting integral using multiple importance sampling\n// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html#EstimatingtheDirectLightingIntegral\n\nimport { glsl } from '../../shader.js';\nexport function createSampleMaterialGlsl(fragments: Readonly<Record<string, string>> = {}, channelIndependentLight = false) { return glsl`\nfloat emissiveHitMisWeight(SurfaceInteraction si,Path path) {\n // Secondary intersections remain two-sided, but one-sided emission does not.\n float facing=dot(si.faceNormal,-path.ray.d);\n if(facing<=0.0&&fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_ALPHA).z<0.5)return 0.0;\n#ifdef HAS_EMISSIVE_LIGHTS\n if(!path.fromEye && emissiveWeightTotal>0.0) {\n vec3 emission=fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_EMISSION).rgb;\n float value=dot(emission,vec3(.2126,.7152,.0722)),cosine=dot(si.faceNormal,-path.ray.d);\n if(value>0.0&&cosine>0.0){float d=distance(si.position,path.ray.o);return sampling_power_heuristic(path.scatteringPdf,value/emissiveWeightTotal*d*d/cosine);}\n }\n#endif\n return 1.0;\n}\n\nvec3 DirectLight(SurfaceInteraction si, OpenPbrResolvedMaterial mat, OpenPbrPreparedBsdf prepared, inout Path path, vec3 ffnormal, bool isSurface) {\n float occluded = 1.0;\n vec3 lightRnd = vec3(sample2D(bounceDim(LIGHT_POSITION)), sample1D(bounceDim(LIGHT_SELECT)));\n\n LightSampleRec lightSample;\n sampleLight(si.position, lightRnd, lightSample, false);${fragments['sample0'] ?? ''}\n${channelIndependentLight ? /* glsl */ ` if (dispersionWavelengths == 1) {\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);\n }` : /* glsl */ ` lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);`}\n\n vec3 lightDir = lightSample.direction;\n vec3 viewDir = -path.ray.d;\n float lightPdf = lightSample.pdf;\n // Opaque surfaces are rendered two-sided by the core renderer. Use the\n // face-forward shading normal here as well, otherwise the early-out rejects\n // every direct-light sample seen from the back of a triangle (for example\n // the inside of an imported room wall).\n float cosThetaL = dot(ffnormal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (isSurface && mat.coatNormalEnabled) { cosThetaL = dot(mat.geometricNormal, lightDir); }\n#endif\n\n if (lightPdf <= 0.0 || max(max(lightSample.emission.x, lightSample.emission.y), lightSample.emission.z) <= 0.0) {\n return vec3(0.0);\n }\n\n${channelIndependentLight ? /* glsl */ ` // Test the full emission before filtering, so black spectral components\n // still consume the same visibility walk and random stream.\n if (dispersionWavelengths != 1) {\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);\n }\n` : ''} float scatteringPdf = 0.0;\n vec3 f = vec3(0.0);\n if (isSurface) {\n if (cosThetaL <= 0.0 && mat.transmissionWeight <= 0.0 && mat.subsurfaceWeight <= 0.0) {\n return vec3(0.0);\n }\n f = openpbr_eval_prepared(prepared, lightDir, scatteringPdf);\n }\n else {\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(viewDir, lightDir),\n si.mediumAnisotropy\n );\n f = vec3(scatteringPdf);\n }\n\n if (scatteringPdf <= 0.0 || max(max(f.x, f.y), f.z) <= 0.0) {\n return vec3(0.0);\n }\n\n Ray lightRay;\n vec3 shadowOrigin = si.position + EPS * lightDir;\n if (isSurface) {\n const float shadowTerminatorCutoff = 0.1;\n float normalLight = dot(si.normal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { normalLight = dot(si.faceNormal, lightDir); }\n#endif\n vec3 geometricNormal = normalLight < 0.0 ? -si.faceNormal : si.faceNormal;\n normalLight = abs(normalLight);\n float geometricLight = dot(geometricNormal, lightDir);\n float offsetAmount = normalLight < shadowTerminatorCutoff\n ? clamp(\n 2.0 - (geometricLight + normalLight) / shadowTerminatorCutoff,\n 0.0,\n 1.0\n )\n : clamp(1.0 - geometricLight / shadowTerminatorCutoff, 0.0, 1.0);\n shadowOrigin += si.shadowOffset * offsetAmount;\n }\n float shadowDistance=lightSample.dist-EPS;\n vec3 shadowDirection=lightDir;\n if(lightSample.sourceType==1){\n vec3 endpoint=si.position+lightDir*lightSample.dist+EPS*lightSample.normal;\n shadowDirection=normalize(endpoint-shadowOrigin);shadowDistance=distance(endpoint,shadowOrigin);\n }\n initRay(lightRay, shadowOrigin, shadowDirection);\n if (intersectSceneShadow(lightRay, shadowDistance, si.triangleIndex)) {\n return vec3(0.0);\n }\n\n#ifdef USE_ENVMAP\n // Match the endpoint used by a BSDF-sampled surface transmission, including\n // a separately displayed or grounded background and its coverage.\n if (isSurface && cosThetaL < 0.0 && lightSample.sourceType == 0) {\n vec4 background = sampleBackgroundFromRay(lightRay.o, lightDir);\n lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.a, pathChannel);\n }\n#endif\n\n // Delta lights cannot be sampled by the BSDF strategy, so their MIS weight\n // is exactly one even when their light-selection PMF is small.\n float misWeight = lightSample.isDelta\n ? 1.0\n : sampling_power_heuristic(lightPdf, scatteringPdf);\n${fragments['sample1'] ?? ''} return misWeight > 0.0\n ? misWeight * lightSample.emission * f / lightPdf\n : vec3(0.0);\n}\n\n#ifdef USE_COAT_NORMAL_FRAMES\nvec3 coat_frame_normal(vec3 inputNormal, vec3 face, vec3 view) {\n bool front = dot(face, view) >= 0.0;\n vec3 ffFace = front ? face : -face;\n vec3 ffInput = front ? inputNormal : -inputNormal;\n if (dot(inputNormal, face) <= 0.0 || dot(ffInput, view) <= 1e-6) { return ffFace; }\n return ffInput;\n}\n#endif\nvoid SampleMaterial(inout SurfaceInteraction si, OpenPbrResolvedMaterial mat, inout Path path) {\n vec3 matRnd = vec3(sample2D(bounceDim(BSDF_DIRECTION)), sample1D(bounceDim(BSDF_LOBE)));\n#ifdef USE_COAT_NORMAL_FRAMES\n vec3 originalFace = si.faceNormal;\n vec3 originalNormal = si.normal;\n#endif\n float ndv1 = -dot(si.faceNormal, path.ray.d);\n float ndv2 = -dot(si.normal, path.ray.d);\n if ((mat.transmissionWeight > 0.0 || mat.subsurfaceWeight > 0.0) && mat.thinWalled) {\n // Always treat thin material as entering medium\n if (ndv1 < 0.0) {\n si.faceNormal = -si.faceNormal;\n ndv1 = -ndv1;\n }\n if (ndv2 < 0.0) {\n si.normal = -si.normal;\n ndv2 = -ndv2;\n }\n }\n // In same edge cases normal is not torwards the camera while we can still see the face.\n // We need to choose faceNormal in this case.\n bool useFaceN = ndv1 >= 0.0 && ndv2 < 0.0;\n float ndv = useFaceN ? ndv1 : ndv2;\n vec3 normal = useFaceN ? si.faceNormal : si.normal;\n\n mat.inside = ndv <= 0.0 && !mat.thinWalled;\n // In or out\n mat.relativeIor = ndv > 0.0 ? (1.0 / mat.specularIor) : mat.specularIor;\n vec3 ffnormal = ndv >= 0.0 ? normal : -normal;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) {\n vec3 view = -path.ray.d;\n float geometricView = dot(originalFace, view);\n mat.geometricNormal = geometricView >= 0.0 ? originalFace : -originalFace;\n ffnormal = coat_frame_normal(originalNormal, originalFace, view);\n mat.coatNormal = coat_frame_normal(si.coatNormal, originalFace, view);\n mat.inside = geometricView <= 0.0 && !mat.thinWalled;\n mat.relativeIor = (geometricView > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;\n }\n#endif\n\n\n float scatteringPdf;\n vec3 scatterDir;\n path.scatteringIsDelta = false;\n bool mediumSampled = false;\n bool crossedBoundary = false;\n OpenPbrPreparedBsdf prepared;\n\n#ifdef HAS_MEDIUM\n int mediumType = si.mediumType;\n float d = distance(si.position, path.ray.o);\n vec3 segmentOrigin = path.ray.o;\n vec3 extinction = si.mediumExtinction;\n vec3 scattering = min(si.mediumScattering, extinction);\n float majorant = max(max(extinction.x, extinction.y), extinction.z);\n if (mediumType > 0 && majorant > 0.0) {\n // Sample one RGB extinction channel and divide by the mixture PDF. This\n // is the homogeneous-medium estimator used by PBRT and avoids the very\n // large exp((majorant - extinction) * distance) weights produced by\n // majorant tracking when OpenPBR SSS radii differ strongly by channel.\n int mediumChannel = min(int(sample1D(bounceDim(MEDIUM_CHANNEL)) * 3.0), 2);\n float channelExtinction = extinction[mediumChannel];\n float scatterDist = channelExtinction > 0.0\n ? min(-log(max(sample1D(bounceDim(MEDIUM_DISTANCE)), 1e-7)) / channelExtinction, d)\n : d;\n mediumSampled = scatterDist < d;\n vec3 transmittance = exp(-extinction * scatterDist);\n vec3 density = mediumSampled\n ? extinction * transmittance\n : transmittance;\n float mediumPdf = max(\n (density.x + density.y + density.z) / 3.0,\n 1e-8\n );\n if (mediumSampled) {\n path.beta *= transmittance * scattering / mediumPdf;\n // Zero throughput cannot contribute at subsequent vertices or light connections.\n if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }\n // Move from the start of the segment, not from its end surface.\n path.ray.o = segmentOrigin + scatterDist * path.ray.d;\n si.position = path.ray.o;\n // A volume vertex has no originating surface to skip on continuation or shadow rays.\n si.triangleIndex = -1;\n si.instanceIndex = -1;\n path.li += DirectLight(si, mat, prepared, path, ffnormal, false) * path.beta;\n\n // Pick a new direction based on the phase function\n scatterDir = sampling_henyey_greenstein(\n -path.ray.d,\n si.mediumAnisotropy,\n sample2D(bounceDim(PHASE_DIRECTION))\n );\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(scatterDir, -path.ray.d),\n si.mediumAnisotropy\n );\n }\n else {\n path.beta *= transmittance / mediumPdf;\n // Zero throughput cannot contribute at subsequent vertices or light connections.\n if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }\n }\n }\n#endif\n\n // Direct lighting\n if (!mediumSampled) {\n // Match NEE and background radiance when RGB wavelength passes are added.\n vec3 surfaceEmission = sampling_spectral_rgb_filter(mat.emission, pathChannel);\n ${fragments['sample2'] ?? ''}path.li += emissiveHitMisWeight(si,path) * surfaceEmission * path.beta;${fragments['sample3'] ?? ''}\n if (mat.materialType == UNLIT) {\n path.abort = true;\n return;\n }\n vec3 surfaceTangent = vec3(0.0);\n#ifdef USE_TANGENT\n surfaceTangent = si.tangent;\n#endif\n mat.directionTangent = si.directionTangent;\n mat.directionBitangent = si.directionBitangent;\n mat.geometryTangent = si.geometryTangent;\n mat.geometryBitangent = si.geometryBitangent;\n prepared = openpbr_prepare(surfaceTangent, mat, -path.ray.d, ffnormal);\n path.li += DirectLight(si, mat, prepared, path, ffnormal, true) * path.beta;\n${fragments['sample4'] ?? ''} // Sample BSDF for color and outgoing direction\n bool isNextRefraction;\n vec3 f = openpbr_sample_prepared(\n prepared,\n matRnd,\n scatterDir,\n scatteringPdf,\n isNextRefraction\n );\n // Null-boundary transmission is discrete and has no NEE competitor.\n path.scatteringIsDelta = !prepared.material.thinWalled &&\n abs(prepared.material.relativeIor - 1.0) <= 1e-6 &&\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] >= 1.0 - 1e-6;\n // Match WebGPU: rejected VNDF/refraction proposals have no continuation.\n // Tracing their fallback direction with the incoming throughput invents\n // light paths, especially after total internal reflection inside glass.\n if (!(scatteringPdf > 0.0) || any(isnan(f)) || any(isinf(f)) ||\n dot(scatterDir, scatterDir) < 0.5) {\n path.scatteringPdf = 0.0;\n path.abort = true;\n return;\n }\n${fragments['sample5'] ?? ''} path.beta *= f / scatteringPdf;\n // Zero throughput cannot contribute at subsequent vertices or light connections.\n if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }\n crossedBoundary = !mat.thinWalled &&\n isNextRefraction;\n path.isNextRefraction = isNextRefraction;\n // TODO prefer the opaque surface when transmission surface and opaque surface are overlapped.\n // Or the ray go out from transmission material will miss the opque surface.\n path.ray.o = si.position + EPS * scatterDir;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(originalFace, scatterDir) >= 0.0 ? originalFace : -originalFace); }\n#endif\n }\n\n path.scatteringPdf = scatteringPdf;\n initRay(path.ray, path.ray.o, scatterDir);\n if (mediumSampled) {${fragments['sample6'] ?? ''}\n path.isNextRefraction = false;\n }\n path.fromEye = false;\n\n#ifdef HAS_MEDIUM\n // A reflected ray stays in its current medium. Only a sampled transmission\n // event crosses the boundary of a medium-bearing closed mesh.\n if (!mediumSampled && crossedBoundary && mat.mediumType > 0) {\n if (ndv1 >= 0.0) {\n si.mediumType = mat.mediumType;\n si.mediumExtinction = mat.mediumExtinction;\n si.mediumScattering = mat.mediumScattering;\n path.scatteringMediumEntered = path.scatteringMediumEntered || any(greaterThan(mat.mediumScattering, vec3(0.0)));\n si.mediumAnisotropy = mat.mediumAnisotropy;\n }\n else {\n si.mediumType = 0;\n si.mediumExtinction = vec3(0.0);\n si.mediumScattering = vec3(0.0);\n si.mediumAnisotropy = 0.0;\n }\n }\n#endif\n}\n`;\n}\nexport default createSampleMaterialGlsl();\n"]}
@@ -12,34 +12,34 @@ export default glsl `
12
12
 
13
13
  const uint SHADOW_CATCHER_LIGHT_SAMPLES = 4u;
14
14
 
15
- uint kJ(uint candidate, uint slot) {
16
- return candidate == 0u ? bE(slot) : bE(9u + (candidate - 1u) * 3u + slot);
15
+ uint lA(uint candidate, uint slot) {
16
+ return candidate == 0u ? aX(slot) : aX(9u + (candidate - 1u) * 3u + slot);
17
17
  }
18
18
 
19
19
 
20
20
 
21
21
  vec2 sampleShadowCatcher(SurfaceInteraction si, int bounce, inout Path path) {
22
- vec3 qR = -path.ray.d;
22
+ vec3 sg = -path.ray.d;
23
23
  vec2 counts = vec2(0.0);
24
24
 
25
25
  #if defined(NUM_LIGHTS) || defined(USE_ENVMAP)
26
26
  for (uint candidate = 0u; candidate < SHADOW_CATCHER_LIGHT_SAMPLES; candidate++) {
27
27
  LightSampleRec lightSample;
28
- vec3 mZ = vec3(
29
- sample2D(kJ(candidate, LIGHT_POSITION)),
30
- sample1D(kJ(candidate, LIGHT_SELECT))
28
+ vec3 ob = vec3(
29
+ sample2D(lA(candidate, LIGHT_POSITION)),
30
+ sample1D(lA(candidate, LIGHT_SELECT))
31
31
  );
32
- sampleLight(si.position, mZ, lightSample, false);
32
+ sampleLight(si.position, ob, lightSample, false);
33
33
 
34
34
  vec3 lightDir = lightSample.direction;
35
35
  float cosThetaL = dot(si.normal, lightDir);
36
- float qt = dot(si.normal, qR) * cosThetaL;
37
- if (lightSample.pdf > 0.0 && qt >= 0.0) {
36
+ float rG = dot(si.normal, sg) * cosThetaL;
37
+ if (lightSample.pdf > 0.0 && rG >= 0.0) {
38
38
  if (dot(lightSample.emission, luminance) * abs(cosThetaL) > 0.0) {
39
39
  Ray ray;
40
40
  initRay(ray, si.position + EPS * lightDir, lightDir);
41
- bool lH = intersectSceneShadow(ray, lightSample.dist - EPS, si.triangleIndex);
42
- counts += vec2(lH ? 1.0 : 0.0, 1.0);
41
+ bool mz = intersectSceneShadow(ray, lightSample.dist - EPS, si.triangleIndex);
42
+ counts += vec2(mz ? 1.0 : 0.0, 1.0);
43
43
  }
44
44
  }
45
45
  }