@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 +1 @@
1
- {"version":3,"file":"intersect.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/intersect.glsl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,qDAAqD;AACrD,sDAAsD;AACtD,kFAAkF;AAElF,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAElE,SAAS,kBAAkB,CACzB,aAAqB,EACrB,gBAAgB,GAAG,EAAE,EACrB,WAAW,GAAG,kBAAkB;IAEhC,MAAM,kBAAkB,GAAG,IAAI,CAAA;0DACqC,oBAAoB;;;EAG9E,gBAAgB;;;;;;;;;;;;;;;;+BAgBqB,oBAAoB;;;;;;;;;EASvD,aAAa;;;CAG1B,CAAC;IACA,OAAO,IAAI,CAAA;;;;eAII,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBA8BE,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;;;;;;;;;;;wDAWiC,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmN/F,kBAAkB;;;CAGzB,CAAC;AACF,CAAC;AAED,eAAe,iBAAiB,CAAC;IAC/B,QAAQ,EAAE;QACR,cAAc,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QAC3C,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QACzC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QAC1C,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QACrC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QACtC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QACxC,mBAAmB,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QAEhD,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QACtC,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;QAE5C,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACpC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAEvC,gBAAgB,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAE1C,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;QAEjC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;KACrC;IACD,IAAI,EAAE,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyjBV,kBAAkB,CAAC,IAAI,CAAA;;;;;;;;CAQxB,CAAC;;;;yDAImF,oBAAoB;;;;gBAI5E,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;;;gBAGpB,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoC/C,kBAAkB,CAClB,IAAI,CAAA;;;;;;;;CAQL,EACC,IAAI,CAAA;;;;CAIL,EACC,aAAa,CACd;;;;yDAIoF,oBAAoB;;;gBAG5E,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;;;gBAGpB,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;gBACpB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiC/C,kBAAkB,CAClB,IAAI,CAAA;;;;;;;;;0DAS6E,oBAAoB;;;;;;;;;;;;;;;;uBAgB5E,sBAAsB,CAAC,KAAK,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkD3D,EACC,IAAI,CAAA;;;;CAIL,EACC,gDAAgD,CACjD;;;CAGA;CACA,CAAC,CAAC","sourcesContent":["import { mapAlphaUsageConstants } from '../../materialConstants.js';\n// Portions adapted from ray-tracing-renderer@0.10.15\n// (https://github.com/hoverinc/ray-tracing-renderer).\n// Copyright (c) 2019 HOVER, MIT license; see LICENSES/RayTracingRenderer-MIT.txt.\n\nimport { INSTANCE_VEC4_STRIDE } from '../../bvhAccel.js';\nimport { createShaderMixin, glsl, Shader } from '../../shader.js';\n\nfunction getBVHTraverseCode(\n handleHitCode: string,\n skipTriangleCode = '',\n initialTMax = 'RAY_MAX_DISTANCE'\n) {\n const intersectTriangles = glsl`\n ivec3 vertexOffset = ivec3(floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).y));\n for (int k = 0; k < primitiveCount; k++) {\n int triangleIndex = primitiveOffset + k;\n ${skipTriangleCode}\n vec4 r3 = fetchBVH(triangleIndex);\n ivec3 index = floatBitsToInt(r3.xyz) + vertexOffset;\n Triangle tri = Triangle(\n fetchData(positionBuffer, index.x, vertexColumns).xyz,\n fetchData(positionBuffer, index.y, vertexColumns).xyz,\n fetchData(positionBuffer, index.z, vertexColumns).xyz\n );\n TriangleIntersect hit = intersectTriangle(o, d, tri, maxDim, shear, tMax);\n\n if (hit.t > 0.0) {\n tMax = hit.t;\n vec3 e1 = tri.p1 - tri.p0;\n vec3 e2 = tri.p2 - tri.p0;\n vec3 faceNormal = normalize(cross(e1, e2));\n int sideMaterialIndex = int(unpackMaterialIndex(\n floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).z)\n ).x);\n bool materialDoubleSided = fetchMatData(\n sideMaterialIndex * MAT_DATA_SIZE + MAT_ROW_ALPHA\n ).z > 0.5;\n if (!doubleSided && !materialDoubleSided && dot(faceNormal, d) > 0.0) {\n continue;\n }\n\n ${handleHitCode}\n }\n }\n`;\n return glsl`\n ivec2 stack[STACK_SIZE];\n int top = -1;\n int prevInsIdx = -1;\n float tMax = ${initialTMax};\n\n vec3 o = ray.o;\n vec3 d = ray.d;\n\n bool isHit = false;\n vec3 hitFaceNormal;\n vec3 hitBarycentric;\n ivec3 hitIndex;\n\n Triangle hitTri;\n\n // TODO not sure why. but do root node check here will cause rendering wrong in windows.\n top = 0;\n stack[0] = ivec2(0, -1);\n\n int iter = 0;\n while(top >= 0 && iter < 5000) {\n iter++;\n ivec2 node = stack[top--];\n\n int insIdx = node.y;\n\n if (insIdx != prevInsIdx) {\n if (insIdx < 0) {\n o = ray.o;\n d = ray.d;\n }\n else {\n mat4 w2l = mat4(\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n o = (w2l * vec4(ray.o, 1.0)).xyz;\n d = (w2l * vec4(ray.d, 0.0)).xyz;\n }\n maxDim = maxDimension(abs(d));\n shear = getShear(d, maxDim);\n prevInsIdx = insIdx;\n }\n\n int bufferOff = insIdx < 0 ? 0 : blasOffset;\n uint encodedBlasOffset = insIdx < 0 ? 0u : floatBitsToUint(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).x);\n int blasLayout = int(encodedBlasOffset >> 30u);\n int blasInsOffset = int(encodedBlasOffset & 0x3fffffffu);\n int primitiveCount = 0;\n int primitiveOffset = 0;\n\n if (blasLayout == 3) {\n uint nodeInfo = uint(node.x);\n if ((nodeInfo & 0x80000000u) != 0u) {\n primitiveCount = int((nodeInfo >> 23u) & 0xffu);\n primitiveOffset = bufferOff + blasInsOffset + int(nodeInfo & 0x007fffffu);\n }\n else {\n int i = node.x + bufferOff;\n vec4 compressed0 = fetchBVH(i);\n vec4 compressed1 = fetchBVH(i + 1);\n vec4 compressed2 = fetchBVH(i + 2);\n vec4 compressed3 = fetchBVH(i + 3);\n vec4 compressed4 = fetchBVH(i + 4);\n uint header = floatBitsToUint(compressed0.w);\n int exponentX = int(header << 24u) >> 24;\n int exponentY = int((header >> 8u) << 24u) >> 24;\n int exponentZ = int((header >> 16u) << 24u) >> 24;\n vec3 quantizationScale = vec3(\n uintBitsToFloat(uint(exponentX + 127) << 23u),\n uintBitsToFloat(uint(exponentY + 127) << 23u),\n uintBitsToFloat(uint(exponentZ + 127) << 23u)\n );\n uint childBase = floatBitsToUint(compressed1.x);\n uint triangleBase = floatBitsToUint(compressed1.y);\n uint internalMask = header >> 24u;\n uint octant = (d.x < 0.0 ? 4u : 0u) |\n (d.y < 0.0 ? 2u : 0u) |\n (d.z < 0.0 ? 1u : 0u);\n uint quantizedWords[12] = uint[12](\n floatBitsToUint(compressed2.x), floatBitsToUint(compressed2.y),\n floatBitsToUint(compressed2.z), floatBitsToUint(compressed2.w),\n floatBitsToUint(compressed3.x), floatBitsToUint(compressed3.y),\n floatBitsToUint(compressed3.z), floatBitsToUint(compressed3.w),\n floatBitsToUint(compressed4.x), floatBitsToUint(compressed4.y),\n floatBitsToUint(compressed4.z), floatBitsToUint(compressed4.w)\n );\n\n for (int order = 7; order >= 0; order--) {\n uint slot = uint(order) ^ octant;\n uint metaWord = slot >= 4u\n ? floatBitsToUint(compressed1.w)\n : floatBitsToUint(compressed1.z);\n uint meta = (metaWord >> ((slot & 3u) * 8u)) & 0xffu;\n if (meta == 0u) continue;\n uint byteShift = (slot & 3u) * 8u;\n uint wordOffset = slot >> 2u;\n vec3 quantizedMin = vec3(\n float((quantizedWords[wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[2u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[4u + wordOffset] >> byteShift) & 0xffu)\n );\n vec3 quantizedMax = vec3(\n float((quantizedWords[6u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[8u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[10u + wordOffset] >> byteShift) & 0xffu)\n );\n vec3 childMin = compressed0.xyz + quantizedMin * quantizationScale;\n vec3 childMax = compressed0.xyz + quantizedMax * quantizationScale;\n if (intersectBox(o, d, childMin, childMax, tMax) <= 0.0) continue;\n uint localOffset = meta & 0x1fu;\n if (localOffset >= 24u) {\n uint precedingMask = internalMask & ((1u << slot) - 1u);\n uint internalIndex = childBase + countBvhBits(precedingMask);\n stack[++top] = ivec2(\n blasInsOffset + int(internalIndex * 5u), insIdx\n );\n }\n else {\n uint triangleCount = countBvhBits(meta >> 5u);\n uint primitiveAddress = triangleBase + localOffset;\n uint leafInfo = 0x80000000u |\n (triangleCount << 23u) |\n (primitiveAddress & 0x007fffffu);\n stack[++top] = ivec2(int(leafInfo), insIdx);\n }\n }\n }\n }\n else if (blasLayout == 2) {\n int i = node.x + bufferOff;\n vec4 gpu0 = fetchBVH(i);\n vec4 gpu1 = fetchBVH(i + 1);\n vec4 gpu2 = fetchBVH(i + 2);\n vec4 gpu3 = fetchBVH(i + 3);\n primitiveCount = int(floatBitsToUint(gpu2.w));\n if (primitiveCount > 0) {\n primitiveOffset = bufferOff + blasInsOffset + int(floatBitsToUint(gpu3.w));\n }\n else {\n int left = blasInsOffset + int(floatBitsToUint(gpu0.w) * 4u);\n int right = blasInsOffset + int(floatBitsToUint(gpu1.w) * 4u);\n float d0 = intersectBox(o, d, gpu0.xyz, gpu1.xyz, tMax);\n float d1 = intersectBox(o, d, gpu2.xyz, gpu3.xyz, tMax);\n if (d0 > d1) {\n if (d0 > 0.0) stack[++top] = ivec2(left, insIdx);\n if (d1 > 0.0) stack[++top] = ivec2(right, insIdx);\n }\n else {\n if (d1 > 0.0) stack[++top] = ivec2(right, insIdx);\n if (d0 > 0.0) stack[++top] = ivec2(left, insIdx);\n }\n }\n }\n else if (blasLayout == 1) {\n uint nodeInfo = uint(node.x);\n if ((nodeInfo & 0x80000000u) != 0u) {\n primitiveCount = int((nodeInfo >> 23u) & 0xffu);\n primitiveOffset = bufferOff + blasInsOffset + int(nodeInfo & 0x007fffffu);\n }\n else {\n int i = node.x + bufferOff;\n vec4 wide0 = fetchBVH(i);\n vec4 wide1 = fetchBVH(i + 1);\n vec4 wide2 = fetchBVH(i + 2);\n vec4 wide3 = fetchBVH(i + 3);\n vec3 nodeMin = wide0.xyz;\n vec3 nodeExtent = vec3(wide0.w, wide1.x, wide1.y);\n uint childInfos[4] = uint[4](\n floatBitsToUint(wide1.z), floatBitsToUint(wide1.w),\n floatBitsToUint(wide2.x), floatBitsToUint(wide2.y)\n );\n vec4 childMinX = unpackBvh4Bounds(floatBitsToUint(wide2.z));\n vec4 childMinY = unpackBvh4Bounds(floatBitsToUint(wide2.w));\n vec4 childMinZ = unpackBvh4Bounds(floatBitsToUint(wide3.x));\n vec4 childMaxX = unpackBvh4Bounds(floatBitsToUint(wide3.y));\n vec4 childMaxY = unpackBvh4Bounds(floatBitsToUint(wide3.z));\n vec4 childMaxZ = unpackBvh4Bounds(floatBitsToUint(wide3.w));\n vec3 invD = traversalInverse(d);\n vec3 padding = depthSlabPadding(invD, o);\n vec4 tx0 = (nodeMin.x + childMinX * nodeExtent.x - o.x) * invD.x;\n vec4 tx1 = (nodeMin.x + childMaxX * nodeExtent.x - o.x) * invD.x;\n vec4 ty0 = (nodeMin.y + childMinY * nodeExtent.y - o.y) * invD.y;\n vec4 ty1 = (nodeMin.y + childMaxY * nodeExtent.y - o.y) * invD.y;\n vec4 tz0 = (nodeMin.z + childMinZ * nodeExtent.z - o.z) * invD.z;\n vec4 tz1 = (nodeMin.z + childMaxZ * nodeExtent.z - o.z) * invD.z;\n vec4 tNear = max(max((min(tx0, tx1) - vec4(padding.x)), (min(ty0, ty1) - vec4(padding.y))), (min(tz0, tz1) - vec4(padding.z)));\n vec4 tFar = min(min((max(tx0, tx1) + vec4(padding.x)), (max(ty0, ty1) + vec4(padding.y))), (max(tz0, tz1) + vec4(padding.z)));\n vec4 distance = mix(tFar, tNear, greaterThan(tNear, vec4(0.0)));\n distance = mix(distance, vec4(-1.0), greaterThan(tNear, min(tFar, vec4(tMax))));\n float childDistances[4] = float[4](distance.x, distance.y, distance.z, distance.w);\n\n // Push far-to-near so that the closest child is popped first.\n for (int order = 0; order < 4; order++) {\n float farthestDistance = -1.0;\n int farthestChild = -1;\n for (int child = 0; child < 4; child++) {\n if (childInfos[child] != 0u && childDistances[child] > farthestDistance) {\n farthestDistance = childDistances[child];\n farthestChild = child;\n }\n }\n if (farthestChild >= 0 && farthestDistance > 0.0) {\n uint childInfo = childInfos[farthestChild];\n int childAddress = int(childInfo);\n if ((childInfo & 0x80000000u) == 0u) {\n childAddress += blasInsOffset;\n }\n stack[++top] = ivec2(childAddress, insIdx);\n childDistances[farthestChild] = -1.0;\n }\n }\n }\n }\n else {\n int i = node.x + bufferOff;\n vec4 r1 = fetchBVH(i);\n int pointerToRightOrNumPrims = floatBitsToInt(r1.w);\n\n if (pointerToRightOrNumPrims >= 0) {\n int left = node.x + 2;\n int right = pointerToRightOrNumPrims + blasInsOffset;\n\n float d0 = intersectBox(o, d, fetchBVH(left + bufferOff).xyz, fetchBVH(left + 1 + bufferOff).xyz, tMax);\n float d1 = intersectBox(o, d, fetchBVH(right + bufferOff).xyz, fetchBVH(right + 1 + bufferOff).xyz, tMax);\n if (d0 > d1) {\n if (d0 > 0.0) {\n stack[++top] = ivec2(left, insIdx);\n }\n if (d1 > 0.0) {\n stack[++top] = ivec2(right, insIdx);\n }\n }\n else {\n if (d1 > 0.0) {\n stack[++top] = ivec2(right, insIdx);\n }\n if (d0 > 0.0) {\n stack[++top] = ivec2(left, insIdx);\n }\n }\n }\n else {\n if (insIdx < 0) {\n for (int k = 0; k < -pointerToRightOrNumPrims; k++) {\n vec4 r3 = fetchBVH(i + 2 + k);\n stack[++top] = ivec2(floatBitsToInt(r3.y), floatBitsToInt(r3.x));\n }\n }\n else {\n primitiveCount = -pointerToRightOrNumPrims;\n primitiveOffset = i + 2;\n }\n }\n }\n if (primitiveCount > 0) {\n ${intersectTriangles}\n }\n }\n`;\n}\n\nexport default createShaderMixin({\n uniforms: {\n positionBuffer: Shader.uniform('sampler2D'),\n normalBuffer: Shader.uniform('sampler2D'),\n tangentBuffer: Shader.uniform('sampler2D'),\n uvBuffer: Shader.uniform('sampler2D'),\n uv1Buffer: Shader.uniform('sampler2D'),\n colorBuffer: Shader.uniform('sampler2D'),\n materialIndexBuffer: Shader.uniform('sampler2D'),\n\n bvhBuffer: Shader.uniform('sampler2D'),\n instancesBuffer: Shader.uniform('sampler2D'),\n\n bvhColumns: Shader.uniform('int', 1),\n vertexColumns: Shader.uniform('int', 1),\n\n instancesColumns: Shader.uniform('int', 1),\n\n blasOffset: Shader.uniform('int'),\n\n isEmptyScene: Shader.uniform('bool')\n },\n main: glsl`\n\nstruct Triangle {\n vec3 p0;\n vec3 p1;\n vec3 p2;\n};\n#ifdef NUM_LIGHTS\nfloat intersectSphere(float rad, vec3 pos, Ray r) {\n vec3 op = pos - r.o;\n float eps = 0.001;\n float b = dot(op, r.d);\n float det = b * b - dot(op, op) + rad * rad;\n if (det < 0.0)\n return INF;\n\n det = sqrt(det);\n float t1 = b - det;\n if (t1 > eps)\n return t1;\n\n float t2 = b + det;\n if (t2 > eps)\n return t2;\n\n return INF;\n}\n\nfloat intersectRect(vec3 pos, vec3 u, vec3 v, vec3 n, Ray r) {\n float dt = dot(r.d, n);\n float t = (dot(n, pos) - dot(n, r.o)) / dt;\n\n if (t > EPS) {\n vec3 p = r.o + r.d * t;\n vec3 vi = p - pos;\n float a1 = dot(u / dot(u, u), vi);\n if (a1 >= 0.0 && a1 <= 1.0) {\n float a2 = dot(v / dot(v, v), vi);\n if (a2 >= 0.0 && a2 <= 1.0) {\n return t;\n }\n }\n }\n\n return INF;\n}\n\nfloat sphereSolidAnglePdf(vec3 origin, vec3 center, float radius) {\n float centerDistance = distance(origin, center);\n if (centerDistance <= radius) return INV4PI;\n float sinThetaMaxSquared = min(1.0, radius * radius / (centerDistance * centerDistance));\n float cosThetaMax = sqrt(max(0.0, 1.0 - sinThetaMaxSquared));\n // Match the cancellation-free solid angle used by direct light sampling.\n float oneMinusCosThetaMax = sinThetaMaxSquared / (1.0 + cosThetaMax);\n return 1.0 / max(TWOPI * oneMinusCosThetaMax, 1e-8);\n}\n\nfloat intersectLight(Ray r, Light light, out LightSampleRec lightSample) {\n // Directional lights are delta sources without finite geometry. Start at\n // INF so they cannot accidentally terminate a BSDF continuation as a\n // geometric light hit; rect and sphere branches overwrite this value.\n float d = INF;\n vec3 u = light.u;\n vec3 v = light.v;\n int type = int(light.type);\n\n#ifdef HAS_RECT_LIGHTS\n if (type == RECT_LIGHT) {\n // Adjust the position from center to start corner\n vec3 pos = light.position-u*0.5-v*0.5;\n vec3 normal = normalize(cross(u, v));\n if (dot(normal, r.d) > 0.) // Hide backfacing quad light\n return INF;\n\n d = intersectRect(pos, u, v, normal, r);\n if (d < 0.) {\n d = INF;\n }\n else {\n float cosTheta = dot(-r.d, normal);\n float spread = light.spread;\n if (cosTheta >= cos(spread * PI / 2.0)) {\n lightSample.pdf = (d * d) / (light.area * cosTheta);\n lightSample.emission = light.emission;\n }\n }\n }\n#endif\n#ifdef HAS_SPHERE_LIGHTS\n if (type == SPHERE_LIGHT) {\n if (light.radius <= 0.0) {\n vec3 toPoint = light.position - r.o;\n float projection = dot(toPoint, r.d);\n vec3 perpendicular = toPoint - projection * r.d;\n if (projection <= EPS || dot(perpendicular, perpendicular) > 1e-8) return INF;\n d = projection;\n lightSample.direction = r.d;\n lightSample.normal = -r.d;\n lightSample.dist = d;\n lightSample.pdf = 1.0;\n lightSample.isDelta = true;\n } else {\n d = intersectSphere(light.radius, light.position, r);\n lightSample.isDelta = false;\n }\n if (d < 0.) {\n d = INF;\n }\n else {\n if (light.radius > 0.0) {\n lightSample.pdf = sphereSolidAnglePdf(r.o, light.position, light.radius);\n }\n lightSample.emission = light.radius <= 0.0\n ? light.emission / max(d * d, 1e-8)\n : light.emission;\n }\n }\n#endif\n#ifdef HAS_SPOT_LIGHTS\n if (type == SPOT_LIGHT) {\n if (light.radius <= 0.0) {\n vec3 toPoint = light.position - r.o;\n float projection = dot(toPoint, r.d);\n vec3 perpendicular = toPoint - projection * r.d;\n if (projection <= EPS || dot(perpendicular, perpendicular) > 1e-8) return INF;\n d = projection;\n lightSample.direction = r.d;\n lightSample.normal = -r.d;\n lightSample.dist = d;\n lightSample.pdf = 1.0;\n lightSample.isDelta = true;\n } else {\n d = intersectSphere(light.radius, light.position, r);\n lightSample.isDelta = false;\n }\n if (d != INF) {\n vec3 hitPt = r.o + d * r.d;\n float multiplier = evaluateSpotEmissionMultiplier(light, normalize(r.o - hitPt));\n if (multiplier <= 0.0) return INF;\n if (light.radius > 0.0) {\n lightSample.pdf = sphereSolidAnglePdf(r.o, light.position, light.radius);\n }\n lightSample.emission = light.emission * multiplier * (light.radius <= 0.0\n ? 1.0 / max(d * d, 1e-8)\n : 1.0);\n }\n }\n#endif\n\n return d;\n}\n#endif\n\nint randomPickMaterial(ivec4 m0, ivec4 m1, ivec4 m2, vec3 bary) {\n vec2 m00 = unpackMaterialIndex(m0.x);\n vec2 m01 = unpackMaterialIndex(m0.y);\n vec2 m02 = unpackMaterialIndex(m0.z);\n vec2 m10 = unpackMaterialIndex(m1.x);\n vec2 m11 = unpackMaterialIndex(m1.y);\n vec2 m12 = unpackMaterialIndex(m1.z);\n vec2 m20 = unpackMaterialIndex(m2.x);\n vec2 m21 = unpackMaterialIndex(m2.y);\n vec2 m22 = unpackMaterialIndex(m2.z);\n float w00 = m00.y * bary.x;\n float w01 = m01.y * bary.x;\n float w02 = m02.y * bary.x;\n float w10 = m10.y * bary.y;\n float w11 = m11.y * bary.y;\n float w12 = m12.y * bary.y;\n float w20 = m20.y * bary.z;\n float w21 = m21.y * bary.z;\n float w22 = m22.y * bary.z;\n\n float wTotal = w00 + w01 + w02 + w10 + w11 + w12 + w20 + w21 + w22;\n // Accumulate weights\n w00 = w00 / wTotal;\n w01 = w01 / wTotal + w00;\n w02 = w02 / wTotal + w01;\n w10 = w10 / wTotal + w02;\n w11 = w11 / wTotal + w10;\n w12 = w12 / wTotal + w11;\n w20 = w20 / wTotal + w12;\n w21 = w21 / wTotal + w20;\n w22 = w22 / wTotal + w21;\n\n float rand = hashedSample(0u);\n float mIdx;\n if (rand < w00) {\n mIdx = m00.x;\n } else if (rand < w01) {\n mIdx = m01.x;\n } else if (rand < w02) {\n mIdx = m02.x;\n } else if (rand < w10) {\n mIdx = m10.x;\n } else if (rand < w11) {\n mIdx = m11.x;\n } else if (rand < w12) {\n mIdx = m12.x;\n } else if (rand < w20) {\n mIdx = m20.x;\n } else if (rand < w21) {\n mIdx = m21.x;\n } else {\n mIdx = m22.x;\n }\n return int(mIdx);\n}\n\n\nvec4 fetchIns(int i);\n\n\nmat2x3 anisotropy_axes(vec3 normal, vec3 dp1, vec3 dp2, vec2 duv1, vec2 duv2, vec4 inputTangent) {\n float determinant = duv1.x * duv2.y - duv1.y * duv2.x;\n vec3 t = inputTangent.xyz;\n vec3 b = vec3(0.0);\n // Internal W=2 marks an authored XYZ tangent whose sign is derived from UVs.\n float handedness = abs(inputTangent.w) > 1.5 ? 0.0 : inputTangent.w;\n if (abs(determinant) > 1e-12) {\n vec3 dt = (dp1 * duv2.y - dp2 * duv1.y) / determinant;\n vec3 db = (dp2 * duv1.x - dp1 * duv2.x) / determinant;\n if (dot(t, t) < 1e-8) { t = dt; }\n if (handedness == 0.0) { handedness = (dot(cross(normal, dt), db) < 0.0 ? -1.0 : 1.0); }\n }\n t -= normal * dot(normal, t);\n if (dot(t, t) < 1e-8) {\n float signZ = (normal.z >= 0.0 ? 1.0 : -1.0);\n float factor = -1.0 / (signZ + normal.z);\n float xy = normal.x * normal.y * factor;\n t = vec3(1.0 + signZ * normal.x * normal.x * factor, signZ * xy, -signZ * normal.x);\n b = vec3(xy, signZ + normal.y * normal.y * factor, -normal.y);\n }\n else { t = normalize(t); b = normalize(cross(normal, t)); }\n return mat2x3(t, b * (handedness < 0.0 ? -1.0 : 1.0));\n}\n\nvoid fetchAttributes(inout SurfaceInteraction si, Triangle tri, vec3 barycentric, ivec3 index) {\n si.hit = true;\n si.position = barycentric.x * tri.p0 + barycentric.y * tri.p1 + barycentric.z * tri.p2;\n ivec2 i0 = unpackTexel(index.x, vertexColumns);\n ivec2 i1 = unpackTexel(index.y, vertexColumns);\n ivec2 i2 = unpackTexel(index.z, vertexColumns);\n si.vertexColor = vec3(1.0);\n#ifdef USE_VERTEX_COLOR\n si.vertexColor = barycentric.x * texelFetch(colorBuffer, i0, 0).rgb\n + barycentric.y * texelFetch(colorBuffer, i1, 0).rgb\n + barycentric.z * texelFetch(colorBuffer, i2, 0).rgb;\n#endif\n\n vec3 n0 = texelFetch(normalBuffer, i0, 0).xyz;\n vec3 n1 = texelFetch(normalBuffer, i1, 0).xyz;\n vec3 n2 = texelFetch(normalBuffer, i2, 0).xyz;\n vec3 normal = normalize(barycentric.x * n0 + barycentric.y * n1 + barycentric.z * n2);\n si.vertexNormal = normal;\n\n // Approximate the smooth limit surface at this triangle hit. Direct-light\n // rays use this geometric offset only near the shadow terminator, avoiding\n // false self-shadowing by adjacent facets without moving ordinary hits.\n // Architecture follows Cycles' shadow_ray_smooth_surface_offset.\n vec3 geometricNormal = normalize(cross(tri.p1 - tri.p0, tri.p2 - tri.p0));\n vec3 smoothNormal = barycentric.x * n0 + barycentric.y * n1 + barycentric.z * n2;\n float a = dot(n2 - n0, tri.p0 - tri.p2);\n float b = dot(n2 - n1, tri.p1 - tri.p2);\n float c = dot(n1 - n0, tri.p1 - tri.p0);\n float h = a * barycentric.x * (barycentric.x - 1.0)\n + (a + b + c) * barycentric.x * barycentric.y\n + b * barycentric.y * (barycentric.y - 1.0);\n if (dot(smoothNormal, geometricNormal) > 0.0) {\n float h0 = max(max(dot(tri.p1 - tri.p0, n0), dot(tri.p2 - tri.p0, n0)), 0.0);\n float h1 = max(max(dot(tri.p0 - tri.p1, n1), dot(tri.p2 - tri.p1, n1)), 0.0);\n float h2 = max(max(dot(tri.p0 - tri.p2, n2), dot(tri.p1 - tri.p2, n2)), 0.0);\n h0 = max(dot(tri.p0 - si.position, n0) + h0, 0.0);\n h1 = max(dot(tri.p1 - si.position, n1) + h1, 0.0);\n h2 = max(dot(tri.p2 - si.position, n2) + h2, 0.0);\n h = max(min(min(h0, h1), h2), h * 0.5);\n }\n else {\n float h0 = max(max(dot(tri.p0 - tri.p1, n0), dot(tri.p0 - tri.p2, n0)), 0.0);\n float h1 = max(max(dot(tri.p1 - tri.p0, n1), dot(tri.p1 - tri.p2, n1)), 0.0);\n float h2 = max(max(dot(tri.p2 - tri.p0, n2), dot(tri.p2 - tri.p1, n2)), 0.0);\n h0 = max(dot(si.position - tri.p0, n0) + h0, 0.0);\n h1 = max(dot(si.position - tri.p1, n1) + h1, 0.0);\n h2 = max(dot(si.position - tri.p2, n2) + h2, 0.0);\n h = min(-min(min(h0, h1), h2), h * 0.5);\n }\n si.shadowOffset = smoothNormal * h;\n\n // TODO currently isampler doesn't work\n ivec4 m0 = ivec4(texelFetch(materialIndexBuffer, i0, 0));\n ivec4 m1 = ivec4(texelFetch(materialIndexBuffer, i1, 0));\n ivec4 m2 = ivec4(texelFetch(materialIndexBuffer, i2, 0));\n \n if (m0.x > 0 || m1.x > 0 || m2.x > 0) {\n si.materialIndex = randomPickMaterial(m0, m1, m2, barycentric);\n }\n \n vec2 uv0 = texelFetch(uvBuffer, i0, 0).xy;\n vec2 uv1 = texelFetch(uvBuffer, i1, 0).xy;\n vec2 uv2 = texelFetch(uvBuffer, i2, 0).xy;\n #if defined(NUM_DIFFUSE_MAPS) || defined(NUM_NORMAL_MAPS) || defined(NUM_METALLIC_ROUGHNESS_MAPS) || defined(NUM_ROUGHNESS_MAPS) || defined(NUM_METALNESS_MAPS) || defined(NUM_EMISSIVE_MAPS) || defined(NUM_THIN_FILM_MAPS) || defined(NUM_ANISOTROPY_MAPS) || defined(NUM_COAT_NORMAL_MAPS)\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec2 secondaryUv0 = texelFetch(uv1Buffer, i0, 0).xy;\n vec2 secondaryUv1 = texelFetch(uv1Buffer, i1, 0).xy;\n vec2 secondaryUv2 = texelFetch(uv1Buffer, i2, 0).xy;\n vec2 secondaryUv = barycentric.x * secondaryUv0\n + barycentric.y * secondaryUv1\n + barycentric.z * secondaryUv2;\n\n vec4 uvInfo = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, si.position, normal, uvInfo.zw);\n secondaryUv = uv;\n } else {\n uv *= uvInfo.zw;\n secondaryUv *= uvInfo.zw;\n }\n #else\n vec2 uv = vec2(0.0);\n vec2 secondaryUv = vec2(0.0);\n #endif\n\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normal;\n#ifdef NUM_COAT_NORMAL_MAPS\n float coatNormalIndex = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_LAYER_MAPS).z;\n#endif\n#endif\n vec4 directionMaterial = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_DIRECTION_NORMAL);\n float coatRotation = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_FILM_TEXTURE).x;\n if (directionMaterial.x >= 0.0 || directionMaterial.y != 0.0 || coatRotation != 0.0\n#ifdef USE_COAT_NORMAL_FRAMES\n || fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_COAT).w > 0.0\n#endif\n ) {\n vec3 dp1 = tri.p0 - tri.p2;\n vec3 dp2 = tri.p1 - tri.p2;\n vec4 inputTangent = vec4(0.0);\n#ifdef USE_TANGENT\n inputTangent = barycentric.x * texelFetch(tangentBuffer, i0, 0)\n + barycentric.y * texelFetch(tangentBuffer, i1, 0)\n + barycentric.z * texelFetch(tangentBuffer, i2, 0);\n#endif\n mat2x3 geometryAxes = anisotropy_axes(normal, dp1, dp2, uv0-uv2, uv1-uv2, inputTangent);\n si.geometryTangent = geometryAxes[0];\n si.geometryBitangent = geometryAxes[1];\n mat2x3 directionAxes = geometryAxes;\n#ifdef NUM_ANISOTROPY_MAPS\n if (directionMaterial.x >= 0.0 && mapUvChannel[int(directionMaterial.x)] > 0.5) {\n vec2 a = texelFetch(uv1Buffer, i0, 0).xy;\n vec2 b = texelFetch(uv1Buffer, i1, 0).xy;\n vec2 c = texelFetch(uv1Buffer, i2, 0).xy;\n directionAxes = anisotropy_axes(normal, dp1, dp2, a-c, b-c, (inputTangent.w == 0.0 ? vec4(0.0) : inputTangent));\n }\n#endif\n si.directionTangent = directionAxes[0];\n si.directionBitangent = directionAxes[1];\n#if defined(USE_COAT_NORMAL_FRAMES) && defined(NUM_COAT_NORMAL_MAPS)\n if (coatNormalIndex >= 0.0) {\n int coatIndex = int(coatNormalIndex);\n mat2x3 coatAxes = geometryAxes;\n if (mapUvChannel[coatIndex] > 0.5) {\n vec2 a = texelFetch(uv1Buffer, i0, 0).xy;\n vec2 b = texelFetch(uv1Buffer, i1, 0).xy;\n vec2 c = texelFetch(uv1Buffer, i2, 0).xy;\n coatAxes = anisotropy_axes(normal, dp1, dp2, a-c, b-c,\n inputTangent.w == 0.0 ? vec4(0.0) : inputTangent);\n }\n vec3 decoded = sampleMap(coatIndex, getMapUvSet(coatIndex, uv, secondaryUv)).rgb * 2.0 - 1.0;\n vec3 mapped = coatAxes[0] * decoded.x * directionMaterial.z\n + coatAxes[1] * decoded.y * directionMaterial.w + normal * decoded.z;\n if (dot(mapped, mapped) > 1e-12) { si.coatNormal = normalize(mapped); }\n }\n#endif\n }\n\n si.uv = uv;\n si.uv1 = secondaryUv;\n\n #ifdef USE_TANGENT\n vec3 t0 = texelFetch(tangentBuffer, i0, 0).xyz;\n vec3 t1 = texelFetch(tangentBuffer, i1, 0).xyz;\n vec3 t2 = texelFetch(tangentBuffer, i2, 0).xyz;\n si.tangent = normalize(barycentric.x * t0 + barycentric.y * t1 + barycentric.z * t2);\n #endif\n #if defined(NUM_NORMAL_MAPS)\n vec3 dp1 = tri.p0 - tri.p2;\n vec3 dp2 = tri.p1 - tri.p2;\n vec2 duv1 = uv0 - uv2;\n vec2 duv2 = uv1 - uv2;\n si.normal = getMatNormal(\n si.materialIndex, uv, normal, dp1, dp2, duv1, duv2\n );\n #else\n si.normal = normal;\n #endif\n}\n\nstruct TriangleIntersect {\n float t;\n vec3 barycentric;\n};\n\nvec4 fetchBVH(int i) {\n return fetchData(bvhBuffer, i, bvhColumns);\n}\n\nvec4 fetchIns(int i) {\n return fetchData(instancesBuffer, i, instancesColumns);\n}\n\n// GLSL ES 3.00 has no bitCount intrinsic. Count the CWBVH mask bits using\n// integer operations supported by WebGL 2.\nuint countBvhBits(uint value) {\n value -= (value >> 1u) & 0x55555555u;\n value = (value & 0x33333333u) + ((value >> 2u) & 0x33333333u);\n value = (value + (value >> 4u)) & 0x0f0f0f0fu;\n return (value * 0x01010101u) >> 24u;\n}\n\nvec4 unpackBvh4Bounds(uint packedBounds) {\n return vec4(\n float(packedBounds & 0xffu),\n float((packedBounds >> 8u) & 0xffu),\n float((packedBounds >> 16u) & 0xffu),\n float(packedBounds >> 24u)\n ) / 255.0;\n}\n\n// Triangle-ray intersection\n// Faster than the classic Möller–Trumbore intersection algorithm\n// http://www.pbr-book.org/3ed-2018/Shapes/Triangle_Meshes.html#TriangleIntersection\nTriangleIntersect intersectTriangle(vec3 o, vec3 d, Triangle tri, int maxDim, vec3 shear, float tMax) {\n TriangleIntersect ti;\n\n // translate vertices based on ray origin\n vec3 p0t = tri.p0 - o;\n vec3 p1t = tri.p1 - o;\n vec3 p2t = tri.p2 - o;\n\n // permute components of triangle vertices\n if (maxDim == 0) {\n p0t = p0t.yzx;\n p1t = p1t.yzx;\n p2t = p2t.yzx;\n } else if (maxDim == 1) {\n p0t = p0t.zxy;\n p1t = p1t.zxy;\n p2t = p2t.zxy;\n }\n\n // apply shear transformation to translated vertex positions\n p0t.xy += shear.xy * p0t.z;\n p1t.xy += shear.xy * p1t.z;\n p2t.xy += shear.xy * p2t.z;\n\n // compute edge function coefficients\n vec3 e = vec3(\n p1t.x * p2t.y - p1t.y * p2t.x,\n p2t.x * p0t.y - p2t.y * p0t.x,\n p0t.x * p1t.y - p0t.y * p1t.x\n );\n\n#ifdef DEPTH_QUERY_MODE\n vec3 edgeScale = abs(vec3(p1t.x * p2t.y, p2t.x * p0t.y, p0t.x * p1t.y))\n + abs(vec3(p1t.y * p2t.x, p2t.y * p0t.x, p0t.y * p1t.x));\n e = mix(e, vec3(0.0), lessThanEqual(abs(e), edgeScale * 1e-6));\n#endif\n\n // check if intersection is inside triangle\n if (any(lessThan(e, vec3(0))) && any(greaterThan(e, vec3(0)))) {\n return ti;\n }\n\n float det = e.x + e.y + e.z;\n#ifdef DEPTH_QUERY_MODE\n if (det == 0.0) return ti;\n#endif\n\n p0t.z *= shear.z;\n p1t.z *= shear.z;\n p2t.z *= shear.z;\n float tScaled = (e.x * p0t.z + e.y * p1t.z + e.z * p2t.z);\n\n // check if closer intersection already exists\n if (abs(tScaled) > abs(tMax * det)) {\n return ti;\n }\n\n float invDet = 1. / det;\n ti.t = tScaled * invDet;\n ti.barycentric = e * invDet;\n\n return ti;\n}\n\nstruct Box {\n vec3 min;\n vec3 max;\n};\n\n// Conservative slabs only for the unjittered depth query shader.\nvec3 traversalInverse(vec3 d) {\n#ifdef DEPTH_QUERY_MODE\n vec3 denominator = mix(d, mix(vec3(1e-20), vec3(-1e-20), lessThan(d, vec3(0.0))), lessThan(abs(d), vec3(1e-20)));\n return 1.0 / denominator;\n#else\n return 1.0 / d;\n#endif\n}\n\nvec3 depthSlabPadding(vec3 invD, vec3 o) {\n#ifdef DEPTH_QUERY_MODE\n return abs(invD) * max(vec3(1.0), abs(o)) * 1e-6;\n#else\n return vec3(0.0);\n#endif\n}\n\n// Branchless ray/box intersection\n// https://tavianator.com/fast-branchless-raybounding-box-intersections/\nfloat intersectBox(vec3 o, vec3 d, vec3 bmin, vec3 bmax, float tMax) {\n#ifdef DEPTH_QUERY_MODE\n vec3 invD = traversalInverse(d);\n vec3 tBot = (bmin - o) * invD;\n vec3 tTop = (bmax - o) * invD;\n vec3 padding = depthSlabPadding(invD, o);\n#else\n vec3 tBot = (bmin - o) / d;\n vec3 tTop = (bmax - o) / d;\n vec3 padding = vec3(0.0);\n#endif\n vec3 tNear = min(tBot, tTop) - padding;\n vec3 tFar = max(tBot, tTop) + padding;\n float t0 = max(tNear.x, max(tNear.y, tNear.z));\n float t1 = min(tFar.x, min(tFar.y, tFar.z));\n\n return (t0 > t1 || t0 > tMax) ? -1.0 : (t0 > 0.0 ? t0 : t1);\n}\n\nint maxDimension(vec3 v) {\n return v.x > v.y ? (v.x > v.z ? 0 : 2) : (v.y > v.z ? 1 : 2);\n}\n\nvec3 getShear(vec3 d, int maxDim) {\n // Permute space so that the z dimension is the one where the absolute value of the ray's direction is largest.\n // Then create a shear transformation that aligns ray direction with the +z axis\n if (maxDim == 0) {\n return vec3(-d.y, -d.z, 1.0) / d.x;\n } else if (maxDim == 1) {\n return vec3(-d.z, -d.x, 1.0) / d.y;\n } else {\n return vec3(-d.x, -d.y, 1.0) / d.z;\n }\n}\n\n// Traverse BVH, find closest triangle intersection, and return surface information\nvoid intersectScene(in Ray ray, inout SurfaceInteraction si, bool doubleSided) {\n si.hit = false;\n\n if (isEmptyScene) {\n return;\n }\n\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n int hitInsIdx;\n\n${getBVHTraverseCode(glsl`\n si.triangleIndex = triangleIndex;\n hitTri = tri;\n hitFaceNormal = faceNormal;\n hitBarycentric = hit.barycentric;\n hitIndex = index;\n isHit = true;\n hitInsIdx = insIdx;\n`)}\n\n if (isHit) {\n si.instanceIndex = hitInsIdx;\n si.materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n // fetchAttributes before transform to world space.\n fetchAttributes(si, hitTri, hitBarycentric, hitIndex);\n mat4 l2w = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 5),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 6),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 7),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 8)\n );\n mat4 w2l = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n mat3 normalTransform = transpose(mat3(w2l));\n si.faceNormal = normalize(normalTransform * hitFaceNormal);\n si.vertexNormal = normalize(normalTransform * si.vertexNormal);\n si.normal = normalize(normalTransform * si.normal);\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normalize(normalTransform * si.coatNormal);\n#endif\n#ifdef USE_TANGENT\n if (dot(si.tangent, si.tangent) > 0.0) {\n si.tangent = normalize(mat3(l2w) * si.tangent);\n }\n#endif\n si.shadowOffset = (l2w * vec4(si.shadowOffset, 0.0)).xyz;\n si.directionTangent = mat3(l2w) * si.directionTangent;\n si.directionBitangent = mat3(l2w) * si.directionBitangent;\n si.geometryTangent = mat3(l2w) * si.geometryTangent;\n si.geometryBitangent = mat3(l2w) * si.geometryBitangent;\n si.position = (l2w * vec4(si.position, 1.0)).xyz;\n }\n}\n\n// Local intersection helper for shader bevel.\nvoid intersectSceneBevel(in Ray ray, inout SurfaceInteraction si, int instanceIndex, float maxDistance) {\n si.hit = false;\n\n if (isEmptyScene) {\n return;\n }\n\n bool doubleSided = true;\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n int hitInsIdx;\n\n${getBVHTraverseCode(\n glsl`\n si.triangleIndex = triangleIndex;\n hitTri = tri;\n hitFaceNormal = faceNormal;\n hitBarycentric = hit.barycentric;\n hitIndex = index;\n isHit = true;\n hitInsIdx = insIdx;\n`,\n glsl`\n if (insIdx != instanceIndex) {\n continue;\n }\n`,\n 'maxDistance'\n)}\n\n if (isHit) {\n si.instanceIndex = hitInsIdx;\n si.materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n fetchAttributes(si, hitTri, hitBarycentric, hitIndex);\n mat4 l2w = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 5),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 6),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 7),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 8)\n );\n mat4 w2l = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n mat3 normalTransform = transpose(mat3(w2l));\n si.faceNormal = normalize(normalTransform * hitFaceNormal);\n si.vertexNormal = normalize(normalTransform * si.vertexNormal);\n si.normal = normalize(normalTransform * si.normal);\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normalize(normalTransform * si.coatNormal);\n#endif\n#ifdef USE_TANGENT\n if (dot(si.tangent, si.tangent) > 0.0) {\n si.tangent = normalize(mat3(l2w) * si.tangent);\n }\n#endif\n si.shadowOffset = (l2w * vec4(si.shadowOffset, 0.0)).xyz;\n si.directionTangent = mat3(l2w) * si.directionTangent;\n si.directionBitangent = mat3(l2w) * si.directionBitangent;\n si.geometryTangent = mat3(l2w) * si.geometryTangent;\n si.geometryBitangent = mat3(l2w) * si.geometryBitangent;\n si.position = (l2w * vec4(si.position, 1.0)).xyz;\n }\n}\n\nbool intersectSceneShadow(in Ray ray, float lightDistance, int currTriangleIndex) {\n\n if (isEmptyScene) {\n return false;\n }\n\n bool doubleSided = true;\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n\n${getBVHTraverseCode(\n glsl`\n // Traversal is clipped to lightDistance. Affine instance transforms keep\n // the ray parameter unchanged because local directions are not normalized.\n bool isOccluded = true;\n vec3 barycentric = hit.barycentric;\n vec3 position = barycentric.x * tri.p0 + barycentric.y * tri.p1 + barycentric.z * tri.p2;\n\n if (isOccluded) {\n#ifdef HAS_ALPHA\n int materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n ivec2 i0 = unpackTexel(index.x, vertexColumns);\n ivec2 i1 = unpackTexel(index.y, vertexColumns);\n ivec2 i2 = unpackTexel(index.z, vertexColumns);\n ivec4 m0 = ivec4(texelFetch(materialIndexBuffer, i0, 0));\n ivec4 m1 = ivec4(texelFetch(materialIndexBuffer, i1, 0));\n ivec4 m2 = ivec4(texelFetch(materialIndexBuffer, i2, 0));\n \n if (m0.x > 0 || m1.x > 0 || m2.x > 0) {\n materialIndex = randomPickMaterial(m0, m1, m2, barycentric);\n }\n \n int ii = materialIndex * MAT_DATA_SIZE;\n int mapAlphaUsage = int(fetchMatData(ii + MAT_ROW_MISC).a);\n float alpha = fetchMatData(ii + MAT_ROW_ALPHA_FILM).r;\n #ifdef NUM_DIFFUSE_MAPS\n if (mapAlphaUsage == ${mapAlphaUsageConstants.alpha + ''}) {\n int diffuseMapIndex = int(fetchMatData(ii + MAT_ROW_METALLIC_MAPS).z);\n if (diffuseMapIndex >= 0) {\n vec2 uv0 = texelFetch(uvBuffer, i0, 0).xy;\n vec2 uv1 = texelFetch(uvBuffer, i1, 0).xy;\n vec2 uv2 = texelFetch(uvBuffer, i2, 0).xy;\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec4 uvInfo = fetchMatData(ii + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, position, hitFaceNormal, uvInfo.zw);\n } else {\n uv *= uvInfo.zw;\n }\n \n alpha *= sampleMap(diffuseMapIndex, uv).a;\n }\n }\n #endif\n #ifdef NUM_ALPHA_MAPS\n int alphaMapIndex = int(fetchMatData(ii + MAT_ROW_STANDALONE_MAPS).z);\n if (alphaMapIndex >= 0) {\n vec2 uv0 = texelFetch(uvBuffer, i0, 0).xy;\n vec2 uv1 = texelFetch(uvBuffer, i1, 0).xy;\n vec2 uv2 = texelFetch(uvBuffer, i2, 0).xy;\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec4 uvInfo = fetchMatData(ii + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, position, hitFaceNormal, uvInfo.zw);\n } else {\n uv *= uvInfo.zw;\n }\n alpha *= sampleMap(alphaMapIndex, uv).g;\n }\n #endif\n float alphaCutoff = fetchMatData(ii + MAT_ROW_STANDALONE_MAPS).a;\n alpha = resolveMaterialAlpha(\n alpha, int(fetchMatData(ii + MAT_ROW_ALPHA).w), alphaCutoff\n );\n if (hashedSample(0u) > alpha) {\n // Continue after a transparent hit without traversing beyond the light.\n tMax = min(max(lightDistance, 0.0), RAY_MAX_DISTANCE);\n isOccluded = false;\n }\n#endif\n }\n if (isOccluded) {\n return true;\n }\n`,\n glsl`\n if (triangleIndex == currTriangleIndex) {\n continue;\n }\n`,\n 'min(max(lightDistance, 0.0), RAY_MAX_DISTANCE)'\n)}\n return false;\n}\n`\n});\n"]}
1
+ {"version":3,"file":"intersect.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/intersect.glsl.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapAlphaUsageConstants } from '../../materialConstants.js';\n// Portions adapted from ray-tracing-renderer@0.10.15\n// (https://github.com/hoverinc/ray-tracing-renderer).\n// Copyright (c) 2019 HOVER, MIT license; see LICENSES/RayTracingRenderer-MIT.txt.\n\nimport { INSTANCE_VEC4_STRIDE } from '../../bvhAccel.js';\nimport { createShaderMixin, glsl, Shader } from '../../shader.js';\n\nfunction getBVHTraverseCode(\n handleHitCode: string,\n skipTriangleCode = '',\n initialTMax = 'RAY_MAX_DISTANCE'\n) {\n const intersectTriangles = glsl`\n ivec3 vertexOffset = ivec3(floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).y));\n for (int k = 0; k < primitiveCount; k++) {\n int triangleIndex = primitiveOffset + k;\n ${skipTriangleCode}\n vec4 r3 = fetchBVH(triangleIndex);\n ivec3 index = floatBitsToInt(r3.xyz) + vertexOffset;\n Triangle tri = Triangle(\n fetchData(positionBuffer, index.x, vertexColumns).xyz,\n fetchData(positionBuffer, index.y, vertexColumns).xyz,\n fetchData(positionBuffer, index.z, vertexColumns).xyz\n );\n TriangleIntersect hit = intersectTriangle(o, d, tri, maxDim, shear, tMax);\n\n if (hit.t > 0.0) {\n tMax = hit.t;\n vec3 e1 = tri.p1 - tri.p0;\n vec3 e2 = tri.p2 - tri.p0;\n vec3 faceNormal = normalize(cross(e1, e2));\n int sideMaterialIndex = int(unpackMaterialIndex(\n floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).z)\n ).x);\n bool materialDoubleSided = fetchMatData(\n sideMaterialIndex * MAT_DATA_SIZE + MAT_ROW_ALPHA\n ).z > 0.5;\n if (!doubleSided && !materialDoubleSided && dot(faceNormal, d) > 0.0) {\n continue;\n }\n\n ${handleHitCode}\n }\n }\n`;\n return glsl`\n ivec2 stack[STACK_SIZE];\n int top = -1;\n int prevInsIdx = -1;\n float tMax = ${initialTMax};\n\n vec3 o = ray.o;\n vec3 d = ray.d;\n\n bool isHit = false;\n vec3 hitFaceNormal;\n vec3 hitBarycentric;\n ivec3 hitIndex;\n\n Triangle hitTri;\n\n // TODO not sure why. but do root node check here will cause rendering wrong in windows.\n top = 0;\n stack[0] = ivec2(0, -1);\n\n int iter = 0;\n while(top >= 0 && iter < 5000) {\n iter++;\n ivec2 node = stack[top--];\n\n int insIdx = node.y;\n\n if (insIdx != prevInsIdx) {\n if (insIdx < 0) {\n o = ray.o;\n d = ray.d;\n }\n else {\n mat4 w2l = mat4(\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n o = (w2l * vec4(ray.o, 1.0)).xyz;\n d = (w2l * vec4(ray.d, 0.0)).xyz;\n }\n maxDim = maxDimension(abs(d));\n shear = getShear(d, maxDim);\n prevInsIdx = insIdx;\n }\n\n int bufferOff = insIdx < 0 ? 0 : blasOffset;\n uint encodedBlasOffset = insIdx < 0 ? 0u : floatBitsToUint(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).x);\n int blasLayout = int(encodedBlasOffset >> 30u);\n int blasInsOffset = int(encodedBlasOffset & 0x3fffffffu);\n int primitiveCount = 0;\n int primitiveOffset = 0;\n\n if (blasLayout == 3) {\n uint nodeInfo = uint(node.x);\n if ((nodeInfo & 0x80000000u) != 0u) {\n primitiveCount = int((nodeInfo >> 23u) & 0xffu);\n primitiveOffset = bufferOff + blasInsOffset + int(nodeInfo & 0x007fffffu);\n }\n else {\n int i = node.x + bufferOff;\n vec4 compressed0 = fetchBVH(i);\n vec4 compressed1 = fetchBVH(i + 1);\n vec4 compressed2 = fetchBVH(i + 2);\n vec4 compressed3 = fetchBVH(i + 3);\n vec4 compressed4 = fetchBVH(i + 4);\n uint header = floatBitsToUint(compressed0.w);\n int exponentX = int(header << 24u) >> 24;\n int exponentY = int((header >> 8u) << 24u) >> 24;\n int exponentZ = int((header >> 16u) << 24u) >> 24;\n vec3 quantizationScale = vec3(\n uintBitsToFloat(uint(exponentX + 127) << 23u),\n uintBitsToFloat(uint(exponentY + 127) << 23u),\n uintBitsToFloat(uint(exponentZ + 127) << 23u)\n );\n uint childBase = floatBitsToUint(compressed1.x);\n uint triangleBase = floatBitsToUint(compressed1.y);\n uint internalMask = header >> 24u;\n uint octant = (d.x < 0.0 ? 4u : 0u) |\n (d.y < 0.0 ? 2u : 0u) |\n (d.z < 0.0 ? 1u : 0u);\n uint quantizedWords[12] = uint[12](\n floatBitsToUint(compressed2.x), floatBitsToUint(compressed2.y),\n floatBitsToUint(compressed2.z), floatBitsToUint(compressed2.w),\n floatBitsToUint(compressed3.x), floatBitsToUint(compressed3.y),\n floatBitsToUint(compressed3.z), floatBitsToUint(compressed3.w),\n floatBitsToUint(compressed4.x), floatBitsToUint(compressed4.y),\n floatBitsToUint(compressed4.z), floatBitsToUint(compressed4.w)\n );\n\n for (int order = 7; order >= 0; order--) {\n uint slot = uint(order) ^ octant;\n uint metaWord = slot >= 4u\n ? floatBitsToUint(compressed1.w)\n : floatBitsToUint(compressed1.z);\n uint meta = (metaWord >> ((slot & 3u) * 8u)) & 0xffu;\n if (meta == 0u) continue;\n uint byteShift = (slot & 3u) * 8u;\n uint wordOffset = slot >> 2u;\n vec3 quantizedMin = vec3(\n float((quantizedWords[wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[2u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[4u + wordOffset] >> byteShift) & 0xffu)\n );\n vec3 quantizedMax = vec3(\n float((quantizedWords[6u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[8u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[10u + wordOffset] >> byteShift) & 0xffu)\n );\n vec3 childMin = compressed0.xyz + quantizedMin * quantizationScale;\n vec3 childMax = compressed0.xyz + quantizedMax * quantizationScale;\n if (intersectBox(o, d, childMin, childMax, tMax) <= 0.0) continue;\n uint localOffset = meta & 0x1fu;\n if (localOffset >= 24u) {\n uint precedingMask = internalMask & ((1u << slot) - 1u);\n uint internalIndex = childBase + countBvhBits(precedingMask);\n stack[++top] = ivec2(\n blasInsOffset + int(internalIndex * 5u), insIdx\n );\n }\n else {\n uint triangleCount = countBvhBits(meta >> 5u);\n uint primitiveAddress = triangleBase + localOffset;\n uint leafInfo = 0x80000000u |\n (triangleCount << 23u) |\n (primitiveAddress & 0x007fffffu);\n stack[++top] = ivec2(int(leafInfo), insIdx);\n }\n }\n }\n }\n else if (blasLayout == 2) {\n int i = node.x + bufferOff;\n vec4 gpu0 = fetchBVH(i);\n vec4 gpu1 = fetchBVH(i + 1);\n vec4 gpu2 = fetchBVH(i + 2);\n vec4 gpu3 = fetchBVH(i + 3);\n primitiveCount = int(floatBitsToUint(gpu2.w));\n if (primitiveCount > 0) {\n primitiveOffset = bufferOff + blasInsOffset + int(floatBitsToUint(gpu3.w));\n }\n else {\n int left = blasInsOffset + int(floatBitsToUint(gpu0.w) * 4u);\n int right = blasInsOffset + int(floatBitsToUint(gpu1.w) * 4u);\n float d0 = intersectBox(o, d, gpu0.xyz, gpu1.xyz, tMax);\n float d1 = intersectBox(o, d, gpu2.xyz, gpu3.xyz, tMax);\n if (d0 > d1) {\n if (d0 > 0.0) stack[++top] = ivec2(left, insIdx);\n if (d1 > 0.0) stack[++top] = ivec2(right, insIdx);\n }\n else {\n if (d1 > 0.0) stack[++top] = ivec2(right, insIdx);\n if (d0 > 0.0) stack[++top] = ivec2(left, insIdx);\n }\n }\n }\n else if (blasLayout == 1) {\n uint nodeInfo = uint(node.x);\n if ((nodeInfo & 0x80000000u) != 0u) {\n primitiveCount = int((nodeInfo >> 23u) & 0xffu);\n primitiveOffset = bufferOff + blasInsOffset + int(nodeInfo & 0x007fffffu);\n }\n else {\n int i = node.x + bufferOff;\n vec4 wide0 = fetchBVH(i);\n vec4 wide1 = fetchBVH(i + 1);\n vec4 wide2 = fetchBVH(i + 2);\n vec4 wide3 = fetchBVH(i + 3);\n vec3 nodeMin = wide0.xyz;\n vec3 nodeExtent = vec3(wide0.w, wide1.x, wide1.y);\n uint childInfos[4] = uint[4](\n floatBitsToUint(wide1.z), floatBitsToUint(wide1.w),\n floatBitsToUint(wide2.x), floatBitsToUint(wide2.y)\n );\n vec4 childMinX = unpackBvh4Bounds(floatBitsToUint(wide2.z));\n vec4 childMinY = unpackBvh4Bounds(floatBitsToUint(wide2.w));\n vec4 childMinZ = unpackBvh4Bounds(floatBitsToUint(wide3.x));\n vec4 childMaxX = unpackBvh4Bounds(floatBitsToUint(wide3.y));\n vec4 childMaxY = unpackBvh4Bounds(floatBitsToUint(wide3.z));\n vec4 childMaxZ = unpackBvh4Bounds(floatBitsToUint(wide3.w));\n vec3 invD = traversalInverse(d);\n vec3 padding = depthSlabPadding(invD, o);\n vec4 tx0 = (nodeMin.x + childMinX * nodeExtent.x - o.x) * invD.x;\n vec4 tx1 = (nodeMin.x + childMaxX * nodeExtent.x - o.x) * invD.x;\n vec4 ty0 = (nodeMin.y + childMinY * nodeExtent.y - o.y) * invD.y;\n vec4 ty1 = (nodeMin.y + childMaxY * nodeExtent.y - o.y) * invD.y;\n vec4 tz0 = (nodeMin.z + childMinZ * nodeExtent.z - o.z) * invD.z;\n vec4 tz1 = (nodeMin.z + childMaxZ * nodeExtent.z - o.z) * invD.z;\n vec4 tNear = max(max((min(tx0, tx1) - vec4(padding.x)), (min(ty0, ty1) - vec4(padding.y))), (min(tz0, tz1) - vec4(padding.z)));\n vec4 tFar = min(min((max(tx0, tx1) + vec4(padding.x)), (max(ty0, ty1) + vec4(padding.y))), (max(tz0, tz1) + vec4(padding.z)));\n vec4 distance = mix(tFar, tNear, greaterThan(tNear, vec4(0.0)));\n distance = mix(distance, vec4(-1.0), greaterThan(tNear, min(tFar, vec4(tMax))));\n float childDistances[4] = float[4](distance.x, distance.y, distance.z, distance.w);\n\n // Push far-to-near so that the closest child is popped first.\n for (int order = 0; order < 4; order++) {\n float farthestDistance = -1.0;\n int farthestChild = -1;\n for (int child = 0; child < 4; child++) {\n if (childInfos[child] != 0u && childDistances[child] > farthestDistance) {\n farthestDistance = childDistances[child];\n farthestChild = child;\n }\n }\n if (farthestChild >= 0 && farthestDistance > 0.0) {\n uint childInfo = childInfos[farthestChild];\n int childAddress = int(childInfo);\n if ((childInfo & 0x80000000u) == 0u) {\n childAddress += blasInsOffset;\n }\n stack[++top] = ivec2(childAddress, insIdx);\n childDistances[farthestChild] = -1.0;\n }\n }\n }\n }\n else {\n int i = node.x + bufferOff;\n vec4 r1 = fetchBVH(i);\n int pointerToRightOrNumPrims = floatBitsToInt(r1.w);\n\n if (pointerToRightOrNumPrims >= 0) {\n int left = node.x + 2;\n int right = pointerToRightOrNumPrims + blasInsOffset;\n\n float d0 = intersectBox(o, d, fetchBVH(left + bufferOff).xyz, fetchBVH(left + 1 + bufferOff).xyz, tMax);\n float d1 = intersectBox(o, d, fetchBVH(right + bufferOff).xyz, fetchBVH(right + 1 + bufferOff).xyz, tMax);\n if (d0 > d1) {\n if (d0 > 0.0) {\n stack[++top] = ivec2(left, insIdx);\n }\n if (d1 > 0.0) {\n stack[++top] = ivec2(right, insIdx);\n }\n }\n else {\n if (d1 > 0.0) {\n stack[++top] = ivec2(right, insIdx);\n }\n if (d0 > 0.0) {\n stack[++top] = ivec2(left, insIdx);\n }\n }\n }\n else {\n if (insIdx < 0) {\n for (int k = 0; k < -pointerToRightOrNumPrims; k++) {\n vec4 r3 = fetchBVH(i + 2 + k);\n int box = floatBitsToInt(r3.w);\n if (intersectBox(ray.o, ray.d, fetchBVH(box).xyz, fetchBVH(box + 1).xyz, tMax) > 0.0) {\n stack[++top] = ivec2(floatBitsToInt(r3.y), floatBitsToInt(r3.x));\n }\n }\n }\n else {\n primitiveCount = -pointerToRightOrNumPrims;\n primitiveOffset = i + 2;\n }\n }\n }\n if (primitiveCount > 0) {\n ${intersectTriangles}\n }\n }\n`;\n}\n\nexport default createShaderMixin({\n defines: {\n VERTEX_ATTRIBUTE_STRIDE: 2\n },\n uniforms: {\n positionBuffer: Shader.uniform('sampler2D'),\n // Interleaved shading attributes; layout in webglVertexAttributes.ts.\n vertexAttributes: Shader.uniform('sampler2D'),\n\n // TLAS, BLASes and then the instance records.\n bvhBuffer: Shader.uniform('sampler2D'),\n\n bvhColumns: Shader.uniform('int', 1),\n vertexColumns: Shader.uniform('int', 1),\n vertexAttributeColumns: Shader.uniform('int', 1),\n\n instancesOffset: Shader.uniform('int', 0),\n\n blasOffset: Shader.uniform('int'),\n\n isEmptyScene: Shader.uniform('bool')\n },\n main: glsl`\n\nstruct Triangle {\n vec3 p0;\n vec3 p1;\n vec3 p2;\n};\n#ifdef NUM_LIGHTS\nfloat intersectSphere(float rad, vec3 pos, Ray r) {\n vec3 op = pos - r.o;\n float eps = 0.001;\n float b = dot(op, r.d);\n float det = b * b - dot(op, op) + rad * rad;\n if (det < 0.0)\n return INF;\n\n det = sqrt(det);\n float t1 = b - det;\n if (t1 > eps)\n return t1;\n\n float t2 = b + det;\n if (t2 > eps)\n return t2;\n\n return INF;\n}\n\nfloat intersectRect(vec3 pos, vec3 u, vec3 v, vec3 n, Ray r) {\n float dt = dot(r.d, n);\n float t = (dot(n, pos) - dot(n, r.o)) / dt;\n\n if (t > EPS) {\n vec3 p = r.o + r.d * t;\n vec3 vi = p - pos;\n float a1 = dot(u / dot(u, u), vi);\n if (a1 >= 0.0 && a1 <= 1.0) {\n float a2 = dot(v / dot(v, v), vi);\n if (a2 >= 0.0 && a2 <= 1.0) {\n return t;\n }\n }\n }\n\n return INF;\n}\n\nfloat sphereSolidAnglePdf(vec3 origin, vec3 center, float radius) {\n float centerDistance = distance(origin, center);\n if (centerDistance <= radius) return INV4PI;\n float sinThetaMaxSquared = min(1.0, radius * radius / (centerDistance * centerDistance));\n float cosThetaMax = sqrt(max(0.0, 1.0 - sinThetaMaxSquared));\n // Match the cancellation-free solid angle used by direct light sampling.\n float oneMinusCosThetaMax = sinThetaMaxSquared / (1.0 + cosThetaMax);\n return 1.0 / max(TWOPI * oneMinusCosThetaMax, 1e-8);\n}\n\nfloat intersectLight(Ray r, Light light, out LightSampleRec lightSample) {\n // Directional lights are delta sources without finite geometry. Start at\n // INF so they cannot accidentally terminate a BSDF continuation as a\n // geometric light hit; rect and sphere branches overwrite this value.\n float d = INF;\n vec3 u = light.u;\n vec3 v = light.v;\n int type = int(light.type);\n\n#ifdef HAS_RECT_LIGHTS\n if (type == RECT_LIGHT) {\n // Adjust the position from center to start corner\n vec3 pos = light.position-u*0.5-v*0.5;\n vec3 normal = normalize(cross(u, v));\n if (dot(normal, r.d) > 0.) // Hide backfacing quad light\n return INF;\n\n d = intersectRect(pos, u, v, normal, r);\n if (d < 0.) {\n d = INF;\n }\n else {\n float cosTheta = dot(-r.d, normal);\n float spread = light.spread;\n if (cosTheta >= cos(spread * PI / 2.0)) {\n lightSample.pdf = (d * d) / (light.area * cosTheta);\n lightSample.emission = light.emission;\n }\n }\n }\n#endif\n#ifdef HAS_SPHERE_LIGHTS\n if (type == SPHERE_LIGHT) {\n if (light.radius <= 0.0) {\n vec3 toPoint = light.position - r.o;\n float projection = dot(toPoint, r.d);\n vec3 perpendicular = toPoint - projection * r.d;\n if (projection <= EPS || dot(perpendicular, perpendicular) > 1e-8) return INF;\n d = projection;\n lightSample.direction = r.d;\n lightSample.normal = -r.d;\n lightSample.dist = d;\n lightSample.pdf = 1.0;\n lightSample.isDelta = true;\n } else {\n d = intersectSphere(light.radius, light.position, r);\n lightSample.isDelta = false;\n }\n if (d < 0.) {\n d = INF;\n }\n else {\n if (light.radius > 0.0) {\n lightSample.pdf = sphereSolidAnglePdf(r.o, light.position, light.radius);\n }\n lightSample.emission = light.radius <= 0.0\n ? light.emission / max(d * d, 1e-8)\n : light.emission;\n }\n }\n#endif\n#ifdef HAS_SPOT_LIGHTS\n if (type == SPOT_LIGHT) {\n if (light.radius <= 0.0) {\n vec3 toPoint = light.position - r.o;\n float projection = dot(toPoint, r.d);\n vec3 perpendicular = toPoint - projection * r.d;\n if (projection <= EPS || dot(perpendicular, perpendicular) > 1e-8) return INF;\n d = projection;\n lightSample.direction = r.d;\n lightSample.normal = -r.d;\n lightSample.dist = d;\n lightSample.pdf = 1.0;\n lightSample.isDelta = true;\n } else {\n d = intersectSphere(light.radius, light.position, r);\n lightSample.isDelta = false;\n }\n if (d != INF) {\n vec3 hitPt = r.o + d * r.d;\n float multiplier = evaluateSpotEmissionMultiplier(light, normalize(r.o - hitPt));\n if (multiplier <= 0.0) return INF;\n if (light.radius > 0.0) {\n lightSample.pdf = sphereSolidAnglePdf(r.o, light.position, light.radius);\n }\n lightSample.emission = light.emission * multiplier * (light.radius <= 0.0\n ? 1.0 / max(d * d, 1e-8)\n : 1.0);\n }\n }\n#endif\n\n return d;\n}\n#endif\n\nint randomPickMaterial(ivec4 m0, ivec4 m1, ivec4 m2, vec3 bary) {\n vec2 m00 = unpackMaterialIndex(m0.x);\n vec2 m01 = unpackMaterialIndex(m0.y);\n vec2 m02 = unpackMaterialIndex(m0.z);\n vec2 m10 = unpackMaterialIndex(m1.x);\n vec2 m11 = unpackMaterialIndex(m1.y);\n vec2 m12 = unpackMaterialIndex(m1.z);\n vec2 m20 = unpackMaterialIndex(m2.x);\n vec2 m21 = unpackMaterialIndex(m2.y);\n vec2 m22 = unpackMaterialIndex(m2.z);\n float w00 = m00.y * bary.x;\n float w01 = m01.y * bary.x;\n float w02 = m02.y * bary.x;\n float w10 = m10.y * bary.y;\n float w11 = m11.y * bary.y;\n float w12 = m12.y * bary.y;\n float w20 = m20.y * bary.z;\n float w21 = m21.y * bary.z;\n float w22 = m22.y * bary.z;\n\n float wTotal = w00 + w01 + w02 + w10 + w11 + w12 + w20 + w21 + w22;\n // Accumulate weights\n w00 = w00 / wTotal;\n w01 = w01 / wTotal + w00;\n w02 = w02 / wTotal + w01;\n w10 = w10 / wTotal + w02;\n w11 = w11 / wTotal + w10;\n w12 = w12 / wTotal + w11;\n w20 = w20 / wTotal + w12;\n w21 = w21 / wTotal + w20;\n w22 = w22 / wTotal + w21;\n\n float rand = hashedSample(0u);\n float mIdx;\n if (rand < w00) {\n mIdx = m00.x;\n } else if (rand < w01) {\n mIdx = m01.x;\n } else if (rand < w02) {\n mIdx = m02.x;\n } else if (rand < w10) {\n mIdx = m10.x;\n } else if (rand < w11) {\n mIdx = m11.x;\n } else if (rand < w12) {\n mIdx = m12.x;\n } else if (rand < w20) {\n mIdx = m20.x;\n } else if (rand < w21) {\n mIdx = m21.x;\n } else {\n mIdx = m22.x;\n }\n return int(mIdx);\n}\n\n\nvec4 fetchIns(int i);\n\nvec4 fetchVertexAttribute(int vertex, int slot) {\n return fetchData(vertexAttributes, vertex * VERTEX_ATTRIBUTE_STRIDE + slot, vertexAttributeColumns);\n}\nvec3 fetchVertexNormal(int vertex) { return fetchVertexAttribute(vertex, 0).xyz; }\nvec2 fetchVertexUv(int vertex) { return fetchVertexAttribute(vertex, 1).xy; }\nivec4 fetchVertexMaterial(int vertex) {\n return ivec4(fetchVertexAttribute(vertex, 0).w, fetchVertexAttribute(vertex, 1).zw, 0.0);\n}\nvec2 fetchVertexUv1(int vertex) {\n#ifdef USE_UV1\n return fetchVertexAttribute(vertex, VERTEX_UV1_SLOT).xy;\n#else\n return vec2(0.0);\n#endif\n}\n#ifdef USE_TANGENT\nvec4 fetchVertexTangent(int vertex) { return fetchVertexAttribute(vertex, VERTEX_TANGENT_SLOT); }\n#endif\n\n\nmat2x3 anisotropy_axes(vec3 normal, vec3 dp1, vec3 dp2, vec2 duv1, vec2 duv2, vec4 inputTangent) {\n float determinant = duv1.x * duv2.y - duv1.y * duv2.x;\n vec3 t = inputTangent.xyz;\n vec3 b = vec3(0.0);\n // Internal W=2 marks an authored XYZ tangent whose sign is derived from UVs.\n float handedness = abs(inputTangent.w) > 1.5 ? 0.0 : inputTangent.w;\n if (abs(determinant) > 1e-12) {\n vec3 dt = (dp1 * duv2.y - dp2 * duv1.y) / determinant;\n vec3 db = (dp2 * duv1.x - dp1 * duv2.x) / determinant;\n if (dot(t, t) < 1e-8) { t = dt; }\n if (handedness == 0.0) { handedness = (dot(cross(normal, dt), db) < 0.0 ? -1.0 : 1.0); }\n }\n t -= normal * dot(normal, t);\n if (dot(t, t) < 1e-8) {\n float signZ = (normal.z >= 0.0 ? 1.0 : -1.0);\n float factor = -1.0 / (signZ + normal.z);\n float xy = normal.x * normal.y * factor;\n t = vec3(1.0 + signZ * normal.x * normal.x * factor, signZ * xy, -signZ * normal.x);\n b = vec3(xy, signZ + normal.y * normal.y * factor, -normal.y);\n }\n else { t = normalize(t); b = normalize(cross(normal, t)); }\n return mat2x3(t, b * (handedness < 0.0 ? -1.0 : 1.0));\n}\n\nvoid fetchAttributes(inout SurfaceInteraction si, Triangle tri, vec3 barycentric, ivec3 index) {\n si.hit = true;\n si.position = barycentric.x * tri.p0 + barycentric.y * tri.p1 + barycentric.z * tri.p2;\n si.vertexColor = vec3(1.0);\n#ifdef USE_VERTEX_COLOR\n si.vertexColor = barycentric.x * fetchVertexAttribute(index.x, VERTEX_COLOR_SLOT).rgb\n + barycentric.y * fetchVertexAttribute(index.y, VERTEX_COLOR_SLOT).rgb\n + barycentric.z * fetchVertexAttribute(index.z, VERTEX_COLOR_SLOT).rgb;\n#endif\n\n vec3 n0 = fetchVertexNormal(index.x);\n vec3 n1 = fetchVertexNormal(index.y);\n vec3 n2 = fetchVertexNormal(index.z);\n vec3 normal = normalize(barycentric.x * n0 + barycentric.y * n1 + barycentric.z * n2);\n si.vertexNormal = normal;\n\n // Approximate the smooth limit surface at this triangle hit. Direct-light\n // rays use this geometric offset only near the shadow terminator, avoiding\n // false self-shadowing by adjacent facets without moving ordinary hits.\n // Architecture follows Cycles' shadow_ray_smooth_surface_offset.\n vec3 geometricNormal = normalize(cross(tri.p1 - tri.p0, tri.p2 - tri.p0));\n vec3 smoothNormal = barycentric.x * n0 + barycentric.y * n1 + barycentric.z * n2;\n float a = dot(n2 - n0, tri.p0 - tri.p2);\n float b = dot(n2 - n1, tri.p1 - tri.p2);\n float c = dot(n1 - n0, tri.p1 - tri.p0);\n float h = a * barycentric.x * (barycentric.x - 1.0)\n + (a + b + c) * barycentric.x * barycentric.y\n + b * barycentric.y * (barycentric.y - 1.0);\n if (dot(smoothNormal, geometricNormal) > 0.0) {\n float h0 = max(max(dot(tri.p1 - tri.p0, n0), dot(tri.p2 - tri.p0, n0)), 0.0);\n float h1 = max(max(dot(tri.p0 - tri.p1, n1), dot(tri.p2 - tri.p1, n1)), 0.0);\n float h2 = max(max(dot(tri.p0 - tri.p2, n2), dot(tri.p1 - tri.p2, n2)), 0.0);\n h0 = max(dot(tri.p0 - si.position, n0) + h0, 0.0);\n h1 = max(dot(tri.p1 - si.position, n1) + h1, 0.0);\n h2 = max(dot(tri.p2 - si.position, n2) + h2, 0.0);\n h = max(min(min(h0, h1), h2), h * 0.5);\n }\n else {\n float h0 = max(max(dot(tri.p0 - tri.p1, n0), dot(tri.p0 - tri.p2, n0)), 0.0);\n float h1 = max(max(dot(tri.p1 - tri.p0, n1), dot(tri.p1 - tri.p2, n1)), 0.0);\n float h2 = max(max(dot(tri.p2 - tri.p0, n2), dot(tri.p2 - tri.p1, n2)), 0.0);\n h0 = max(dot(si.position - tri.p0, n0) + h0, 0.0);\n h1 = max(dot(si.position - tri.p1, n1) + h1, 0.0);\n h2 = max(dot(si.position - tri.p2, n2) + h2, 0.0);\n h = min(-min(min(h0, h1), h2), h * 0.5);\n }\n si.shadowOffset = smoothNormal * h;\n\n ivec4 m0 = fetchVertexMaterial(index.x);\n ivec4 m1 = fetchVertexMaterial(index.y);\n ivec4 m2 = fetchVertexMaterial(index.z);\n \n if (m0.x > 0 || m1.x > 0 || m2.x > 0) {\n si.materialIndex = randomPickMaterial(m0, m1, m2, barycentric);\n }\n \n vec2 uv0 = fetchVertexUv(index.x);\n vec2 uv1 = fetchVertexUv(index.y);\n vec2 uv2 = fetchVertexUv(index.z);\n #if defined(NUM_DIFFUSE_MAPS) || defined(NUM_NORMAL_MAPS) || defined(NUM_METALLIC_ROUGHNESS_MAPS) || defined(NUM_ROUGHNESS_MAPS) || defined(NUM_METALNESS_MAPS) || defined(NUM_EMISSIVE_MAPS) || defined(NUM_THIN_FILM_MAPS) || defined(NUM_ANISOTROPY_MAPS) || defined(NUM_COAT_NORMAL_MAPS)\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec2 secondaryUv0 = fetchVertexUv1(index.x);\n vec2 secondaryUv1 = fetchVertexUv1(index.y);\n vec2 secondaryUv2 = fetchVertexUv1(index.z);\n vec2 secondaryUv = barycentric.x * secondaryUv0\n + barycentric.y * secondaryUv1\n + barycentric.z * secondaryUv2;\n\n vec4 uvInfo = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, si.position, normal, uvInfo.zw);\n secondaryUv = uv;\n } else {\n uv *= uvInfo.zw;\n secondaryUv *= uvInfo.zw;\n }\n #else\n vec2 uv = vec2(0.0);\n vec2 secondaryUv = vec2(0.0);\n #endif\n\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normal;\n#ifdef NUM_COAT_NORMAL_MAPS\n float coatNormalIndex = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_LAYER_MAPS).z;\n#endif\n#endif\n vec4 directionMaterial = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_DIRECTION_NORMAL);\n float coatRotation = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_FILM_TEXTURE).x;\n if (directionMaterial.x >= 0.0 || directionMaterial.y != 0.0 || coatRotation != 0.0\n#ifdef USE_COAT_NORMAL_FRAMES\n || fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_COAT).w > 0.0\n#endif\n ) {\n vec3 dp1 = tri.p0 - tri.p2;\n vec3 dp2 = tri.p1 - tri.p2;\n vec4 inputTangent = vec4(0.0);\n#ifdef USE_TANGENT\n inputTangent = barycentric.x * fetchVertexTangent(index.x)\n + barycentric.y * fetchVertexTangent(index.y)\n + barycentric.z * fetchVertexTangent(index.z);\n#endif\n mat2x3 geometryAxes = anisotropy_axes(normal, dp1, dp2, uv0-uv2, uv1-uv2, inputTangent);\n si.geometryTangent = geometryAxes[0];\n si.geometryBitangent = geometryAxes[1];\n mat2x3 directionAxes = geometryAxes;\n#ifdef NUM_ANISOTROPY_MAPS\n if (directionMaterial.x >= 0.0 && mapUvChannel[int(directionMaterial.x)] > 0.5) {\n vec2 a = fetchVertexUv1(index.x);\n vec2 b = fetchVertexUv1(index.y);\n vec2 c = fetchVertexUv1(index.z);\n directionAxes = anisotropy_axes(normal, dp1, dp2, a-c, b-c, (inputTangent.w == 0.0 ? vec4(0.0) : inputTangent));\n }\n#endif\n si.directionTangent = directionAxes[0];\n si.directionBitangent = directionAxes[1];\n#if defined(USE_COAT_NORMAL_FRAMES) && defined(NUM_COAT_NORMAL_MAPS)\n if (coatNormalIndex >= 0.0) {\n int coatIndex = int(coatNormalIndex);\n mat2x3 coatAxes = geometryAxes;\n if (mapUvChannel[coatIndex] > 0.5) {\n vec2 a = fetchVertexUv1(index.x);\n vec2 b = fetchVertexUv1(index.y);\n vec2 c = fetchVertexUv1(index.z);\n coatAxes = anisotropy_axes(normal, dp1, dp2, a-c, b-c,\n inputTangent.w == 0.0 ? vec4(0.0) : inputTangent);\n }\n vec3 decoded = sampleMap(coatIndex, getMapUvSet(coatIndex, uv, secondaryUv)).rgb * 2.0 - 1.0;\n vec3 mapped = coatAxes[0] * decoded.x * directionMaterial.z\n + coatAxes[1] * decoded.y * directionMaterial.w + normal * decoded.z;\n if (dot(mapped, mapped) > 1e-12) { si.coatNormal = normalize(mapped); }\n }\n#endif\n }\n\n si.uv = uv;\n si.uv1 = secondaryUv;\n\n #ifdef USE_TANGENT\n vec3 t0 = fetchVertexTangent(index.x).xyz;\n vec3 t1 = fetchVertexTangent(index.y).xyz;\n vec3 t2 = fetchVertexTangent(index.z).xyz;\n si.tangent = normalize(barycentric.x * t0 + barycentric.y * t1 + barycentric.z * t2);\n #endif\n #if defined(NUM_NORMAL_MAPS)\n vec3 dp1 = tri.p0 - tri.p2;\n vec3 dp2 = tri.p1 - tri.p2;\n vec2 duv1 = uv0 - uv2;\n vec2 duv2 = uv1 - uv2;\n si.normal = getMatNormal(\n si.materialIndex, uv, normal, dp1, dp2, duv1, duv2\n );\n #else\n si.normal = normal;\n #endif\n}\n\nstruct TriangleIntersect {\n float t;\n vec3 barycentric;\n};\n\nvec4 fetchBVH(int i) {\n return fetchData(bvhBuffer, i, bvhColumns);\n}\n\nvec4 fetchIns(int i) {\n return fetchData(bvhBuffer, instancesOffset + i, bvhColumns);\n}\n\n// GLSL ES 3.00 has no bitCount intrinsic. Count the CWBVH mask bits using\n// integer operations supported by WebGL 2.\nuint countBvhBits(uint value) {\n value -= (value >> 1u) & 0x55555555u;\n value = (value & 0x33333333u) + ((value >> 2u) & 0x33333333u);\n value = (value + (value >> 4u)) & 0x0f0f0f0fu;\n return (value * 0x01010101u) >> 24u;\n}\n\nvec4 unpackBvh4Bounds(uint packedBounds) {\n return vec4(\n float(packedBounds & 0xffu),\n float((packedBounds >> 8u) & 0xffu),\n float((packedBounds >> 16u) & 0xffu),\n float(packedBounds >> 24u)\n ) / 255.0;\n}\n\n// Triangle-ray intersection\n// Faster than the classic Möller–Trumbore intersection algorithm\n// http://www.pbr-book.org/3ed-2018/Shapes/Triangle_Meshes.html#TriangleIntersection\nTriangleIntersect intersectTriangle(vec3 o, vec3 d, Triangle tri, int maxDim, vec3 shear, float tMax) {\n TriangleIntersect ti;\n\n // translate vertices based on ray origin\n vec3 p0t = tri.p0 - o;\n vec3 p1t = tri.p1 - o;\n vec3 p2t = tri.p2 - o;\n\n // permute components of triangle vertices\n if (maxDim == 0) {\n p0t = p0t.yzx;\n p1t = p1t.yzx;\n p2t = p2t.yzx;\n } else if (maxDim == 1) {\n p0t = p0t.zxy;\n p1t = p1t.zxy;\n p2t = p2t.zxy;\n }\n\n // apply shear transformation to translated vertex positions\n p0t.xy += shear.xy * p0t.z;\n p1t.xy += shear.xy * p1t.z;\n p2t.xy += shear.xy * p2t.z;\n\n // compute edge function coefficients\n vec3 e = vec3(\n p1t.x * p2t.y - p1t.y * p2t.x,\n p2t.x * p0t.y - p2t.y * p0t.x,\n p0t.x * p1t.y - p0t.y * p1t.x\n );\n\n#ifdef DEPTH_QUERY_MODE\n vec3 edgeScale = abs(vec3(p1t.x * p2t.y, p2t.x * p0t.y, p0t.x * p1t.y))\n + abs(vec3(p1t.y * p2t.x, p2t.y * p0t.x, p0t.y * p1t.x));\n e = mix(e, vec3(0.0), lessThanEqual(abs(e), edgeScale * 1e-6));\n#endif\n\n // check if intersection is inside triangle\n if (any(lessThan(e, vec3(0))) && any(greaterThan(e, vec3(0)))) {\n return ti;\n }\n\n float det = e.x + e.y + e.z;\n#ifdef DEPTH_QUERY_MODE\n if (det == 0.0) return ti;\n#endif\n\n p0t.z *= shear.z;\n p1t.z *= shear.z;\n p2t.z *= shear.z;\n float tScaled = (e.x * p0t.z + e.y * p1t.z + e.z * p2t.z);\n\n // check if closer intersection already exists\n if (abs(tScaled) > abs(tMax * det)) {\n return ti;\n }\n\n float invDet = 1. / det;\n ti.t = tScaled * invDet;\n ti.barycentric = e * invDet;\n\n return ti;\n}\n\nstruct Box {\n vec3 min;\n vec3 max;\n};\n\n// Conservative slabs only for the unjittered depth query shader.\nvec3 traversalInverse(vec3 d) {\n#ifdef DEPTH_QUERY_MODE\n vec3 denominator = mix(d, mix(vec3(1e-20), vec3(-1e-20), lessThan(d, vec3(0.0))), lessThan(abs(d), vec3(1e-20)));\n return 1.0 / denominator;\n#else\n return 1.0 / d;\n#endif\n}\n\nvec3 depthSlabPadding(vec3 invD, vec3 o) {\n#ifdef DEPTH_QUERY_MODE\n return abs(invD) * max(vec3(1.0), abs(o)) * 1e-6;\n#else\n return vec3(0.0);\n#endif\n}\n\n// Branchless ray/box intersection\n// https://tavianator.com/fast-branchless-raybounding-box-intersections/\nfloat intersectBox(vec3 o, vec3 d, vec3 bmin, vec3 bmax, float tMax) {\n#ifdef DEPTH_QUERY_MODE\n vec3 invD = traversalInverse(d);\n vec3 tBot = (bmin - o) * invD;\n vec3 tTop = (bmax - o) * invD;\n vec3 padding = depthSlabPadding(invD, o);\n#else\n vec3 tBot = (bmin - o) / d;\n vec3 tTop = (bmax - o) / d;\n vec3 padding = vec3(0.0);\n#endif\n vec3 tNear = min(tBot, tTop) - padding;\n vec3 tFar = max(tBot, tTop) + padding;\n float t0 = max(tNear.x, max(tNear.y, tNear.z));\n float t1 = min(tFar.x, min(tFar.y, tFar.z));\n\n return (t0 > t1 || t0 > tMax) ? -1.0 : (t0 > 0.0 ? t0 : t1);\n}\n\nint maxDimension(vec3 v) {\n return v.x > v.y ? (v.x > v.z ? 0 : 2) : (v.y > v.z ? 1 : 2);\n}\n\nvec3 getShear(vec3 d, int maxDim) {\n // Permute space so that the z dimension is the one where the absolute value of the ray's direction is largest.\n // Then create a shear transformation that aligns ray direction with the +z axis\n if (maxDim == 0) {\n return vec3(-d.y, -d.z, 1.0) / d.x;\n } else if (maxDim == 1) {\n return vec3(-d.z, -d.x, 1.0) / d.y;\n } else {\n return vec3(-d.x, -d.y, 1.0) / d.z;\n }\n}\n\n// Traverse BVH, find closest triangle intersection, and return surface information\nvoid intersectScene(in Ray ray, inout SurfaceInteraction si, bool doubleSided) {\n si.hit = false;\n\n if (isEmptyScene) {\n return;\n }\n\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n int hitInsIdx;\n\n${getBVHTraverseCode(glsl`\n si.triangleIndex = triangleIndex;\n hitTri = tri;\n hitFaceNormal = faceNormal;\n hitBarycentric = hit.barycentric;\n hitIndex = index;\n isHit = true;\n hitInsIdx = insIdx;\n`)}\n\n if (isHit) {\n si.instanceIndex = hitInsIdx;\n si.materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n // fetchAttributes before transform to world space.\n fetchAttributes(si, hitTri, hitBarycentric, hitIndex);\n mat4 l2w = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 5),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 6),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 7),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 8)\n );\n mat4 w2l = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n mat3 normalTransform = transpose(mat3(w2l));\n si.faceNormal = normalize(normalTransform * hitFaceNormal);\n si.vertexNormal = normalize(normalTransform * si.vertexNormal);\n si.normal = normalize(normalTransform * si.normal);\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normalize(normalTransform * si.coatNormal);\n#endif\n#ifdef USE_TANGENT\n if (dot(si.tangent, si.tangent) > 0.0) {\n si.tangent = normalize(mat3(l2w) * si.tangent);\n }\n#endif\n si.shadowOffset = (l2w * vec4(si.shadowOffset, 0.0)).xyz;\n si.directionTangent = mat3(l2w) * si.directionTangent;\n si.directionBitangent = mat3(l2w) * si.directionBitangent;\n si.geometryTangent = mat3(l2w) * si.geometryTangent;\n si.geometryBitangent = mat3(l2w) * si.geometryBitangent;\n si.position = (l2w * vec4(si.position, 1.0)).xyz;\n }\n}\n\n// Local intersection helper for shader bevel.\nvoid intersectSceneBevel(in Ray ray, inout SurfaceInteraction si, int instanceIndex, float maxDistance) {\n si.hit = false;\n\n if (isEmptyScene) {\n return;\n }\n\n bool doubleSided = true;\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n int hitInsIdx;\n\n${getBVHTraverseCode(\n glsl`\n si.triangleIndex = triangleIndex;\n hitTri = tri;\n hitFaceNormal = faceNormal;\n hitBarycentric = hit.barycentric;\n hitIndex = index;\n isHit = true;\n hitInsIdx = insIdx;\n`,\n glsl`\n if (insIdx != instanceIndex) {\n continue;\n }\n`,\n 'maxDistance'\n)}\n\n if (isHit) {\n si.instanceIndex = hitInsIdx;\n si.materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n fetchAttributes(si, hitTri, hitBarycentric, hitIndex);\n mat4 l2w = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 5),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 6),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 7),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 8)\n );\n mat4 w2l = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n mat3 normalTransform = transpose(mat3(w2l));\n si.faceNormal = normalize(normalTransform * hitFaceNormal);\n si.vertexNormal = normalize(normalTransform * si.vertexNormal);\n si.normal = normalize(normalTransform * si.normal);\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normalize(normalTransform * si.coatNormal);\n#endif\n#ifdef USE_TANGENT\n if (dot(si.tangent, si.tangent) > 0.0) {\n si.tangent = normalize(mat3(l2w) * si.tangent);\n }\n#endif\n si.shadowOffset = (l2w * vec4(si.shadowOffset, 0.0)).xyz;\n si.directionTangent = mat3(l2w) * si.directionTangent;\n si.directionBitangent = mat3(l2w) * si.directionBitangent;\n si.geometryTangent = mat3(l2w) * si.geometryTangent;\n si.geometryBitangent = mat3(l2w) * si.geometryBitangent;\n si.position = (l2w * vec4(si.position, 1.0)).xyz;\n }\n}\n\nbool intersectSceneShadow(in Ray ray, float lightDistance, int currTriangleIndex) {\n\n if (isEmptyScene) {\n return false;\n }\n\n bool doubleSided = true;\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n\n${getBVHTraverseCode(\n glsl`\n // Traversal is clipped to lightDistance. Affine instance transforms keep\n // the ray parameter unchanged because local directions are not normalized.\n bool isOccluded = true;\n vec3 barycentric = hit.barycentric;\n vec3 position = barycentric.x * tri.p0 + barycentric.y * tri.p1 + barycentric.z * tri.p2;\n\n if (isOccluded) {\n#ifdef HAS_ALPHA\n int materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n ivec4 m0 = fetchVertexMaterial(index.x);\n ivec4 m1 = fetchVertexMaterial(index.y);\n ivec4 m2 = fetchVertexMaterial(index.z);\n \n if (m0.x > 0 || m1.x > 0 || m2.x > 0) {\n materialIndex = randomPickMaterial(m0, m1, m2, barycentric);\n }\n \n int ii = materialIndex * MAT_DATA_SIZE;\n int mapAlphaUsage = int(fetchMatData(ii + MAT_ROW_MISC).a);\n float alpha = fetchMatData(ii + MAT_ROW_ALPHA_FILM).r;\n #ifdef NUM_DIFFUSE_MAPS\n if (mapAlphaUsage == ${mapAlphaUsageConstants.alpha + ''}) {\n int diffuseMapIndex = int(fetchMatData(ii + MAT_ROW_METALLIC_MAPS).z);\n if (diffuseMapIndex >= 0) {\n vec2 uv0 = fetchVertexUv(index.x);\n vec2 uv1 = fetchVertexUv(index.y);\n vec2 uv2 = fetchVertexUv(index.z);\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec4 uvInfo = fetchMatData(ii + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, position, hitFaceNormal, uvInfo.zw);\n } else {\n uv *= uvInfo.zw;\n }\n \n alpha *= sampleMap(diffuseMapIndex, uv).a;\n }\n }\n #endif\n #ifdef NUM_ALPHA_MAPS\n int alphaMapIndex = int(fetchMatData(ii + MAT_ROW_STANDALONE_MAPS).z);\n if (alphaMapIndex >= 0) {\n vec2 uv0 = fetchVertexUv(index.x);\n vec2 uv1 = fetchVertexUv(index.y);\n vec2 uv2 = fetchVertexUv(index.z);\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec4 uvInfo = fetchMatData(ii + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, position, hitFaceNormal, uvInfo.zw);\n } else {\n uv *= uvInfo.zw;\n }\n alpha *= sampleMap(alphaMapIndex, uv).g;\n }\n #endif\n float alphaCutoff = fetchMatData(ii + MAT_ROW_STANDALONE_MAPS).a;\n alpha = resolveMaterialAlpha(\n alpha, int(fetchMatData(ii + MAT_ROW_ALPHA).w), alphaCutoff\n );\n if (hashedSample(0u) > alpha) {\n // Continue after a transparent hit without traversing beyond the light.\n tMax = min(max(lightDistance, 0.0), RAY_MAX_DISTANCE);\n isOccluded = false;\n }\n#endif\n }\n if (isOccluded) {\n return true;\n }\n`,\n glsl`\n if (triangleIndex == currTriangleIndex) {\n continue;\n }\n`,\n 'min(max(lightDistance, 0.0), RAY_MAX_DISTANCE)'\n)}\n return false;\n}\n`\n});\n"]}
@@ -25,7 +25,7 @@ export function createMaterialBufferGlsl(fragments = {}) {
25
25
  main: glsl `
26
26
  ${materialRowsGlsl()}
27
27
  #ifdef HAS_GLTF_ANISOTROPY
28
- vec2 fb(float roughness, float strength) {
28
+ vec2 fl(float roughness, float strength) {
29
29
  if (strength == 0.0) { return vec2(roughness, 0.0); }
30
30
  float u = roughness * roughness;
31
31
  float a = u + (1.0 - u) * strength * strength;
@@ -35,7 +35,7 @@ return vec2(pow((a*a + u*u) * 0.5, 0.25), clamp(1.0 - u/a, 0.0, 1.0));
35
35
 
36
36
  #endif
37
37
 
38
- vec3 mq(vec3 c) {
38
+ vec3 np(vec3 c) {
39
39
  return mix(pow(c * 0.9478672986 + 0.0521327014, vec3(2.4)), c * 0.0773993808, vec3(lessThan(c, vec3(0.04045))));
40
40
  }
41
41
  vec4 fetchMatData(int i) {
@@ -43,7 +43,7 @@ return fetchData(materialBuffer, i, materialBufferColumns);
43
43
  }
44
44
 
45
45
 
46
- float lJ(float alpha, int alphaMode, float alphaCutoff) {
46
+ float mB(float alpha, int alphaMode, float alphaCutoff) {
47
47
  if (alphaMode == ${materialAlphaModeConstants.opaque}) {
48
48
  return 1.0;
49
49
  }
@@ -53,7 +53,7 @@ return alpha >= alphaCutoff ? 1.0 : 0.0;
53
53
  return alpha;
54
54
  }
55
55
 
56
- float yt(int idx) {
56
+ float As(int idx) {
57
57
  return fetchMatData(idx * MAT_DATA_SIZE + MAT_ROW_COLOR).w;
58
58
  }
59
59
 
@@ -64,44 +64,44 @@ return vec2(float(val >> 8), float(val & 0xff) / 255.0);
64
64
  #ifdef NUM_MAPS
65
65
  vec3 decodeMapColor(int index, vec3 c) {
66
66
  if (mapColorLinear[index] > 0.5) { return c; }
67
- return mq(c);
67
+ return np(c);
68
68
  }
69
69
 
70
- vec2 jv(int index) {
70
+ vec2 getMapSize(int index) {
71
71
  return mapInfo[index].xy;
72
72
  }
73
73
 
74
- float lE(int index) {
74
+ float getMapLayer(int index) {
75
75
  return floor(mapInfo[index].z);
76
76
  }
77
77
 
78
- vec2 jV(int index) {
78
+ vec2 getMapOffset(int index) {
79
79
  return vec2(fract(mapInfo[index].z), mapInfo[index].w);
80
80
  }
81
81
 
82
- float fS(float value, float mode) {
82
+ float gi(float value, float mode) {
83
83
  if (mode < 0.5) return fract(value);
84
84
  if (mode < 1.5) return clamp(value, 0.0, 1.0);
85
85
  return 1.0 - abs(1.0 - (value - 2.0 * floor(value * 0.5)));
86
86
  }
87
87
 
88
- vec2 kF(int index, vec2 uv) {
88
+ vec2 jj(int index, vec2 uv) {
89
89
  vec4 transform = mapTransform[index];
90
90
  vec2 value = uv * transform.xy + transform.zw;
91
- return vec2(fS(value.x, mapWrap[index].x), fS(value.y, mapWrap[index].y));
91
+ return vec2(gi(value.x, mapWrap[index].x), gi(value.y, mapWrap[index].y));
92
92
  }
93
93
 
94
- vec2 tK(int index, vec2 uv) {
95
- vec2 rJ = kF(index, uv);
96
- vec2 jn = 1.0 / vec2(textureSize(map, 0).xy);
97
- vec2 dX = jV(index);
98
- vec2 kx = jv(index) + jn;
99
- vec2 po = dX - 0.5 * jn;
100
- vec2 lS = dX + kx - jn;
94
+ vec2 getMapUV(int index, vec2 uv) {
95
+ vec2 sZ = jj(index, uv);
96
+ vec2 jT = 1.0 / vec2(textureSize(map, 0).xy);
97
+ vec2 eg = getMapOffset(index);
98
+ vec2 lf = getMapSize(index) + jT;
99
+ vec2 qy = eg - 0.5 * jT;
100
+ vec2 mM = eg + lf - jT;
101
101
  return clamp(
102
- po + rJ * kx,
103
- dX,
104
- lS
102
+ qy + sZ * lf,
103
+ eg,
104
+ mM
105
105
  );
106
106
  }
107
107
 
@@ -109,42 +109,42 @@ vec2 getMapUvSet(int index, vec2 uv, vec2 uv1) {
109
109
  return mapUvChannel[index] > 0.5 ? uv1 : uv;
110
110
  }
111
111
 
112
- vec4 eN(int index, ivec2 jq, ivec2 size, ivec2 origin, vec2 modes) {
113
- ivec2 p = clamp(jq, ivec2(0), size - 1);
114
- if (modes.x < 0.5) p.x = ((jq.x % size.x) + size.x) % size.x;
115
- if (modes.y < 0.5) p.y = ((jq.y % size.y) + size.y) % size.y;
116
- return texelFetch(map, ivec3(origin + p, int(lE(index))), 0);
112
+ vec4 eX(int index, ivec2 jV, ivec2 size, ivec2 origin, vec2 modes) {
113
+ ivec2 p = clamp(jV, ivec2(0), size - 1);
114
+ if (modes.x < 0.5) p.x = ((jV.x % size.x) + size.x) % size.x;
115
+ if (modes.y < 0.5) p.y = ((jV.y % size.y) + size.y) % size.y;
116
+ return texelFetch(map, ivec3(origin + p, int(getMapLayer(index))), 0);
117
117
  }
118
118
 
119
119
  vec4 sampleMap(int index, vec2 uv) {
120
- ivec2 size = ivec2(round(jv(index) * vec2(textureSize(map, 0).xy) + 1.0));
121
- vec2 cR = kF(index, uv) * vec2(size) - 0.5;
120
+ ivec2 size = ivec2(round(getMapSize(index) * vec2(textureSize(map, 0).xy) + 1.0));
121
+ vec2 texel = jj(index, uv) * vec2(size) - 0.5;
122
122
  vec2 modes = mapWrap[index];
123
- if ((size.x > 1 && modes.x < 0.5 && (cR.x < 0.0 || cR.x > float(size.x - 1))) ||
124
- (size.y > 1 && modes.y < 0.5 && (cR.y < 0.0 || cR.y > float(size.y - 1)))) {
125
- ivec2 base = ivec2(floor(cR));
126
- vec2 weight = fract(cR);
127
- ivec2 origin = ivec2(round(jV(index) * vec2(textureSize(map, 0).xy) - 0.5));
123
+ if ((size.x > 1 && modes.x < 0.5 && (texel.x < 0.0 || texel.x > float(size.x - 1))) ||
124
+ (size.y > 1 && modes.y < 0.5 && (texel.y < 0.0 || texel.y > float(size.y - 1)))) {
125
+ ivec2 base = ivec2(floor(texel));
126
+ vec2 weight = fract(texel);
127
+ ivec2 origin = ivec2(round(getMapOffset(index) * vec2(textureSize(map, 0).xy) - 0.5));
128
128
  return mix(
129
- mix(eN(index, base, size, origin, modes), eN(index, base + ivec2(1, 0), size, origin, modes), weight.x),
130
- mix(eN(index, base + ivec2(0, 1), size, origin, modes), eN(index, base + ivec2(1, 1), size, origin, modes), weight.x), weight.y);
129
+ mix(eX(index, base, size, origin, modes), eX(index, base + ivec2(1, 0), size, origin, modes), weight.x),
130
+ mix(eX(index, base + ivec2(0, 1), size, origin, modes), eX(index, base + ivec2(1, 1), size, origin, modes), weight.x), weight.y);
131
131
  }
132
- return texture(map, vec3(tK(index, uv), lE(index)));
132
+ return texture(map, vec3(getMapUV(index, uv), getMapLayer(index)));
133
133
  }
134
134
  #endif
135
135
 
136
136
 
137
137
  vec2 aL(float roughness, float anisotropy) {
138
138
  float alpha = roughness * roughness;
139
- float pZ = ROUGHNESS_MIN * ROUGHNESS_MIN;
140
- if (anisotropy == 0.0) { return vec2(max(pZ, alpha)); }
141
- float cY = 1.0 - anisotropy;
142
- float tp = alpha * sqrt(2.0 / (1.0 + cY * cY));
143
- return max(vec2(pZ), vec2(tp, cY * tp));
139
+ float rf = ROUGHNESS_MIN * ROUGHNESS_MIN;
140
+ if (anisotropy == 0.0) { return vec2(max(rf, alpha)); }
141
+ float da = 1.0 - anisotropy;
142
+ float uU = alpha * sqrt(2.0 / (1.0 + da * da));
143
+ return max(vec2(rf), vec2(uU, da * uU));
144
144
  }
145
145
 
146
146
  vec4 fetchIns(int i);
147
- vec3 kV(int instanceIndex) {
147
+ vec3 lO(int instanceIndex) {
148
148
  if (instanceIndex < 0) return vec3(1.0);
149
149
  return fetchIns(instanceIndex * ${INSTANCE_VEC4_STRIDE + ''} + 9).rgb;
150
150
  }
@@ -158,62 +158,62 @@ int instanceIndex,
158
158
  vec3 vertexColor
159
159
  ) {
160
160
  int i = materialIndex * MAT_DATA_SIZE;
161
- vec4 pI = fetchMatData(i + MAT_ROW_COLOR);
161
+ vec4 qL = fetchMatData(i + MAT_ROW_COLOR);
162
162
  vec4 roughnessAndNormal = fetchMatData(i + MAT_ROW_ROUGHNESS_NORMAL);
163
- vec4 gm = fetchMatData(i + MAT_ROW_METALLIC_MAPS);
164
- vec4 hF = fetchMatData(i + MAT_ROW_EMISSION);
165
- vec4 gT = fetchMatData(i + MAT_ROW_IOR_TRANSMISSION);
163
+ vec4 gG = fetchMatData(i + MAT_ROW_METALLIC_MAPS);
164
+ vec4 ig = fetchMatData(i + MAT_ROW_EMISSION);
165
+ vec4 hr = fetchMatData(i + MAT_ROW_IOR_TRANSMISSION);
166
166
  vec4 misc = fetchMatData(i + MAT_ROW_MISC);
167
- vec4 oh = fetchMatData(i + MAT_ROW_ALPHA_FILM);
168
- vec4 mi = fetchMatData(i + MAT_ROW_BASE_CONTROLS);
169
- vec4 pP = fetchMatData(i + MAT_ROW_SPECULAR_FUZZ);
167
+ vec4 pg = fetchMatData(i + MAT_ROW_ALPHA_FILM);
168
+ vec4 nd = fetchMatData(i + MAT_ROW_BASE_CONTROLS);
169
+ vec4 qT = fetchMatData(i + MAT_ROW_SPECULAR_FUZZ);
170
170
  vec4 subsurface = fetchMatData(i + MAT_ROW_SUBSURFACE);
171
- vec4 yJ = fetchMatData(i + MAT_ROW_FUZZ);
171
+ vec4 AH = fetchMatData(i + MAT_ROW_FUZZ);
172
172
  vec4 coat = fetchMatData(i + MAT_ROW_COAT);
173
- vec4 mk = fetchMatData(i + MAT_ROW_COAT_CONTROLS);
174
- vec4 nL = fetchMatData(i + MAT_ROW_FILM_DISPERSION);
175
- vec4 og = fetchMatData(i + MAT_ROW_STANDALONE_MAPS);
173
+ vec4 ng = fetchMatData(i + MAT_ROW_COAT_CONTROLS);
174
+ vec4 oJ = fetchMatData(i + MAT_ROW_FILM_DISPERSION);
175
+ vec4 pf = fetchMatData(i + MAT_ROW_STANDALONE_MAPS);
176
176
  int mapAlphaUsage = int(misc.a);
177
177
 
178
- mat.baseColor = pI.rgb;
179
- mat.materialType = int(pI.w);
178
+ mat.baseColor = qL.rgb;
179
+ mat.materialType = int(qL.w);
180
180
  mat.specularRoughness = roughnessAndNormal.x;
181
- mat.baseMetalness = gm.x;
182
- mat.specularAnisotropy = clamp(gm.y, 0.0, 1.0);
183
- mat.emission = hF.rgb;
181
+ mat.baseMetalness = gG.x;
182
+ mat.specularAnisotropy = clamp(gG.y, 0.0, 1.0);
183
+ mat.emission = ig.rgb;
184
184
  mat.inside = false;
185
- mat.specularIor = gT.x;
186
- mat.transmissionWeight = gT.y;
185
+ mat.specularIor = hr.x;
186
+ mat.transmissionWeight = hr.y;
187
187
  #ifdef HAS_MEDIUM
188
- mat.mediumType = int(gT.z);
188
+ mat.mediumType = int(hr.z);
189
189
  #else
190
190
  mat.mediumType = 0;
191
191
  #endif
192
- mat.thinWalled = gT.w > 0.5;
192
+ mat.thinWalled = hr.w > 0.5;
193
193
  mat.bevel = misc.r;
194
194
  mat.transmissionDispersionScale = misc.g;
195
- mat.dispersionAbbeNumber = max(nL.y, 1e-6);
195
+ mat.dispersionAbbeNumber = max(oJ.y, 1e-6);
196
196
  mat.thinFilmThickness = misc.b;
197
- mat.thinFilmIor = oh.b;
198
- mat.thinFilmWeight = clamp(nL.x, 0.0, 1.0);
197
+ mat.thinFilmIor = pg.b;
198
+ mat.thinFilmWeight = clamp(oJ.x, 0.0, 1.0);
199
199
 
200
200
  mat.thinFilmThickness *= 1000.0;
201
- mat.baseWeight = clamp(mi.x, 0.0, 1.0);
202
- mat.diffuseRoughness = clamp(mi.y, 0.0, 1.0);
203
- mat.specularWeight = max(0.0, mi.z);
204
- mat.subsurfaceWeight = clamp(mi.w, 0.0, 1.0);
205
- mat.specularColor = max(pP.rgb, vec3(0.0));
206
- mat.fuzzWeight = clamp(pP.w, 0.0, 1.0);
201
+ mat.baseWeight = clamp(nd.x, 0.0, 1.0);
202
+ mat.diffuseRoughness = clamp(nd.y, 0.0, 1.0);
203
+ mat.specularWeight = max(0.0, nd.z);
204
+ mat.subsurfaceWeight = clamp(nd.w, 0.0, 1.0);
205
+ mat.specularColor = max(qT.rgb, vec3(0.0));
206
+ mat.fuzzWeight = clamp(qT.w, 0.0, 1.0);
207
207
  mat.subsurfaceColor = max(subsurface.rgb, vec3(0.0));
208
208
  mat.transmissionColor = max(fetchMatData(i + MAT_ROW_TRANSMISSION_COLOR).rgb, vec3(0.0));
209
- mat.fuzzColor = max(yJ.rgb, vec3(0.0));
210
- mat.fuzzRoughness = clamp(yJ.w, 0.0, 1.0);
209
+ mat.fuzzColor = max(AH.rgb, vec3(0.0));
210
+ mat.fuzzRoughness = clamp(AH.w, 0.0, 1.0);
211
211
  mat.coatColor = max(coat.rgb, vec3(0.0));
212
212
  mat.coatWeight = clamp(coat.w, 0.0, 1.0);
213
- mat.coatRoughness = clamp(mk.x, ROUGHNESS_MIN, 1.0);
214
- mat.coatAnisotropy = clamp(mk.y, 0.0, 1.0);
215
- mat.coatIor = max(mk.z, 1.0);
216
- mat.coatDarkening = clamp(mk.w, 0.0, 1.0);
213
+ mat.coatRoughness = clamp(ng.x, ROUGHNESS_MIN, 1.0);
214
+ mat.coatAnisotropy = clamp(ng.y, 0.0, 1.0);
215
+ mat.coatIor = max(ng.z, 1.0);
216
+ mat.coatDarkening = clamp(ng.w, 0.0, 1.0);
217
217
 
218
218
  #ifdef HAS_MEDIUM
219
219
  mat.mediumExtinction = max(fetchMatData(i + MAT_ROW_MEDIUM_EXTINCTION).rgb, vec3(0.0));
@@ -224,13 +224,13 @@ mat.mediumType = max(max(mat.mediumExtinction.x, mat.mediumExtinction.y), mat.me
224
224
 
225
225
 
226
226
  #ifdef HAS_ALPHA
227
- mat.alpha = oh.r;
227
+ mat.alpha = pg.r;
228
228
  #else
229
229
  mat.alpha = 1.0;
230
230
  #endif
231
231
 
232
232
  #ifdef NUM_DIFFUSE_MAPS
233
- int diffuseMapIndex = int(gm.z);
233
+ int diffuseMapIndex = int(gG.z);
234
234
  if (diffuseMapIndex >= 0) {
235
235
  vec4 diffuse = sampleMap(
236
236
  diffuseMapIndex, getMapUvSet(diffuseMapIndex, uv, uv1)
@@ -251,21 +251,21 @@ mat.alpha *= diffuse.a;
251
251
 
252
252
  ${simpleTextureSample('alphaMap', 'glsl')}
253
253
 
254
- mat.alpha = lJ(
255
- mat.alpha, int(fetchMatData(i + MAT_ROW_ALPHA).w), og.w
254
+ mat.alpha = mB(
255
+ mat.alpha, int(fetchMatData(i + MAT_ROW_ALPHA).w), pf.w
256
256
  );
257
257
 
258
258
  ${simpleTextureSample('transmissionMap', 'glsl')}
259
259
 
260
260
  #ifdef NUM_METALLIC_ROUGHNESS_MAPS
261
- int metallicRoughnessMapIndex = int(gm.w);
261
+ int metallicRoughnessMapIndex = int(gG.w);
262
262
  if (metallicRoughnessMapIndex >= 0) {
263
- vec4 fO = sampleMap(
263
+ vec4 ga = sampleMap(
264
264
  metallicRoughnessMapIndex,
265
265
  getMapUvSet(metallicRoughnessMapIndex, uv, uv1)
266
266
  );
267
- mat.baseMetalness *= fO.b;
268
- mat.specularRoughness *= fO.g;
267
+ mat.baseMetalness *= ga.b;
268
+ mat.specularRoughness *= ga.g;
269
269
  }
270
270
  #endif
271
271
 
@@ -274,7 +274,7 @@ ${simpleTextureSample('roughnessMap', 'glsl')}
274
274
  ${simpleTextureSample('metalnessMap', 'glsl')}
275
275
 
276
276
  #ifdef NUM_EMISSIVE_MAPS
277
- int emissiveMapIndex = int(hF.w);
277
+ int emissiveMapIndex = int(ig.w);
278
278
  if (emissiveMapIndex >= 0) {
279
279
  vec3 emissive = sampleMap(
280
280
  emissiveMapIndex, getMapUvSet(emissiveMapIndex, uv, uv1)
@@ -284,12 +284,12 @@ mat.emission *= decodeMapColor(emissiveMapIndex, emissive);
284
284
  #endif
285
285
 
286
286
  #ifdef NUM_COAT_WEIGHT_MAPS
287
- int hM = int(fetchMatData(i + MAT_ROW_LAYER_MAPS).x);
288
- if (hM >= 0 && mat.materialType == 0) {
289
- float rs = clamp(coat.w, 0.0, 1.0) * sampleMap(
290
- hM, getMapUvSet(hM, uv, uv1)
287
+ int iu = int(fetchMatData(i + MAT_ROW_LAYER_MAPS).x);
288
+ if (iu >= 0 && mat.materialType == 0) {
289
+ float sK = clamp(coat.w, 0.0, 1.0) * sampleMap(
290
+ iu, getMapUvSet(iu, uv, uv1)
291
291
  ).r;
292
- mat.emission *= mix(vec3(1.0), sqrt(max(coat.rgb, vec3(0.0))), rs);
292
+ mat.emission *= mix(vec3(1.0), sqrt(max(coat.rgb, vec3(0.0))), sK);
293
293
  }
294
294
  #endif
295
295
 
@@ -311,29 +311,29 @@ ${simpleTextureSample('specularWeightMap', 'glsl')}
311
311
 
312
312
  ${simpleTextureSample('specularColorMap', 'glsl')}
313
313
 
314
- vec4 lk = fetchMatData(i + MAT_ROW_DIRECTION_NORMAL);
314
+ vec4 mg = fetchMatData(i + MAT_ROW_DIRECTION_NORMAL);
315
315
  mat.anisotropyDirection = vec2(1.0, 0.0);
316
- mat.anisotropyDirectionEnabled = lk.y != 0.0;
316
+ mat.anisotropyDirectionEnabled = mg.y != 0.0;
317
317
  mat.coatAnisotropyRotation = fetchMatData(i + MAT_ROW_FILM_TEXTURE).x;
318
318
  #ifdef NUM_ANISOTROPY_MAPS
319
- if (lk.x >= 0.0) {
320
- int index = int(lk.x);
321
- vec4 cR = sampleMap(index, getMapUvSet(index, uv, uv1));
322
- mat.specularAnisotropy *= cR.b;
323
- vec2 direction = cR.rg * 2.0 - 1.0;
319
+ if (mg.x >= 0.0) {
320
+ int index = int(mg.x);
321
+ vec4 texel = sampleMap(index, getMapUvSet(index, uv, uv1));
322
+ mat.specularAnisotropy *= texel.b;
323
+ vec2 direction = texel.rg * 2.0 - 1.0;
324
324
  if (dot(direction, direction) > 1e-4) mat.anisotropyDirection = normalize(direction);
325
325
  mat.anisotropyDirectionEnabled = true;
326
326
  }
327
327
  #endif
328
328
  #ifdef HAS_GLTF_ANISOTROPY
329
329
  if (fetchMatData(i + MAT_ROW_FILM_TEXTURE).y > 0.5 && mat.specularAnisotropy > 0.0) {
330
- vec2 tX = fb(clamp(mat.specularRoughness, 0.0, 1.0), mat.specularAnisotropy);
331
- mat.specularRoughness = tX.x;
332
- mat.specularAnisotropy = tX.y;
330
+ vec2 vG = fl(clamp(mat.specularRoughness, 0.0, 1.0), mat.specularAnisotropy);
331
+ mat.specularRoughness = vG.x;
332
+ mat.specularAnisotropy = vG.y;
333
333
  }
334
334
  #endif
335
335
  if (mat.anisotropyDirectionEnabled) {
336
- float theta = lk.y;
336
+ float theta = mg.y;
337
337
  vec2 d = mat.anisotropyDirection;
338
338
  mat.anisotropyDirection = vec2(cos(theta)*d.x - sin(theta)*d.y, sin(theta)*d.x + cos(theta)*d.y);
339
339
  }
@@ -341,12 +341,12 @@ mat.anisotropyDirection = vec2(cos(theta)*d.x - sin(theta)*d.y, sin(theta)*d.x +
341
341
 
342
342
 
343
343
  if (mat.coatWeight > 0.0 && mat.coatRoughness > 0.0) {
344
- float hJ = mat.specularRoughness * mat.specularRoughness;
345
- float hK = mat.coatRoughness * mat.coatRoughness;
344
+ float im = mat.specularRoughness * mat.specularRoughness;
345
+ float iq = mat.coatRoughness * mat.coatRoughness;
346
346
  mat.specularRoughness = mix(mat.specularRoughness,
347
- pow(min(1.0, hJ * hJ + 2.0 * hK * hK), 0.25), mat.coatWeight);
347
+ pow(min(1.0, im * im + 2.0 * iq * iq), 0.25), mat.coatWeight);
348
348
  }
349
- vec3 color = kV(instanceIndex) * vertexColor;
349
+ vec3 color = lO(instanceIndex) * vertexColor;
350
350
  mat.baseColor *= color;
351
351
  if (mat.materialType == UNLIT) mat.emission *= color;
352
352
 
@@ -358,7 +358,7 @@ mat.alphaY = specularAlpha.y;
358
358
  }
359
359
 
360
360
  #if defined(NUM_NORMAL_MAPS)
361
- vec3 oS(int materialIndex, vec2 uv, vec3 normal, vec3 dp1, vec3 dp2, vec2 oM, vec2 oN) {
361
+ vec3 qa(int materialIndex, vec2 uv, vec3 normal, vec3 dp1, vec3 dp2, vec2 pU, vec2 pV) {
362
362
  int i = materialIndex * MAT_DATA_SIZE;
363
363
  vec4 roughnessAndNormal = fetchMatData(i + MAT_ROW_ROUGHNESS_NORMAL);
364
364
  int normalMapIndex = int(roughnessAndNormal.y);
@@ -366,32 +366,32 @@ if (normalMapIndex >= 0) {
366
366
 
367
367
 
368
368
 
369
- vec3 rX = cross(dp2, normal);
370
- vec3 rW = cross(normal, dp1);
371
- vec3 dpdu = rX * oM.x + rW * oN.x;
372
- vec3 tI = rX * oM.y + rW * oN.y;
373
- float dT = max(dot(dpdu, dpdu), dot(tI, tI));
374
- if (dT > 1e-12) {
375
- float tQ = inversesqrt(dT);
376
- dpdu *= tQ;
377
- tI *= tQ;
369
+ vec3 tu = cross(dp2, normal);
370
+ vec3 tq = cross(normal, dp1);
371
+ vec3 dpdu = tu * pU.x + tq * pV.x;
372
+ vec3 vl = tu * pU.y + tq * pV.y;
373
+ float dZ = max(dot(dpdu, dpdu), dot(vl, vl));
374
+ if (dZ > 1e-12) {
375
+ float vw = inversesqrt(dZ);
376
+ dpdu *= vw;
377
+ vl *= vw;
378
378
  }
379
379
  else {
380
380
 
381
381
 
382
382
 
383
- vec3 ob = abs(normal.z) < 0.999
383
+ vec3 pa = abs(normal.z) < 0.999
384
384
  ? vec3(0.0, 0.0, 1.0)
385
385
  : vec3(0.0, 1.0, 0.0);
386
- dpdu = normalize(cross(ob, normal));
387
- tI = cross(normal, dpdu);
386
+ dpdu = normalize(cross(pa, normal));
387
+ vl = cross(normal, dpdu);
388
388
  }
389
389
 
390
390
  vec3 n = 2.0 * sampleMap(normalMapIndex, uv).rgb - 1.0;
391
391
  n.xy *= roughnessAndNormal.zw;
392
392
  n = normalize(n);
393
393
 
394
- mat3 tbn = mat3(dpdu, tI, normal);
394
+ mat3 tbn = mat3(dpdu, vl, normal);
395
395
 
396
396
  return normalize(tbn * n);
397
397
  } else {