@roomle/web-sdk 5.1.0-alpha.4 → 5.1.0-alpha.5

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 (132) hide show
  1. package/lib/{BufferGeometry-Bl5whHAB.mjs → BufferGeometry-CxlpBjLq.mjs} +192 -195
  2. package/lib/BufferGeometry-CxlpBjLq.mjs.map +1 -0
  3. package/lib/ConfiguratorKernel.wasm +0 -0
  4. package/lib/{GLTFExporter-yQ7mMauu.mjs → GLTFExporter-DeNw0qAI.mjs} +86 -80
  5. package/lib/GLTFExporter-DeNw0qAI.mjs.map +1 -0
  6. package/lib/GaussianBlurNode-BR1cKBsX.mjs +65 -0
  7. package/lib/GaussianBlurNode-BR1cKBsX.mjs.map +1 -0
  8. package/lib/{Object3D-BHdngbxB.mjs → Object3D-CALIQdg1.mjs} +142 -59
  9. package/lib/Object3D-CALIQdg1.mjs.map +1 -0
  10. package/lib/{Pass-DLiMLT5k.mjs → Pass-DCljS3Z-.mjs} +4 -4
  11. package/lib/{Pass-DLiMLT5k.mjs.map → Pass-DCljS3Z-.mjs.map} +1 -1
  12. package/lib/{PointLightHelper-CuPSBuDU.mjs → PointLightHelper-C_0CYp7R.mjs} +35 -32
  13. package/lib/PointLightHelper-C_0CYp7R.mjs.map +1 -0
  14. package/lib/RoomleCore.wasm +0 -0
  15. package/lib/RoomleToolsCore.wasm +0 -0
  16. package/lib/{SpotLightHelper-m-Rh8vGU.mjs → SpotLightHelper-UUIHn43T.mjs} +22 -19
  17. package/lib/SpotLightHelper-UUIHn43T.mjs.map +1 -0
  18. package/lib/{USDZExporter-MdkuT226.mjs → USDZExporter-BBNw7Hey.mjs} +6 -3
  19. package/lib/USDZExporter-BBNw7Hey.mjs.map +1 -0
  20. package/lib/{Vector4-C7TlIAyy.mjs → Vector4-BOcWTZJI.mjs} +2 -2
  21. package/lib/Vector4-BOcWTZJI.mjs.map +1 -0
  22. package/lib/{api-Bznmr-xZ.mjs → api-CwEjmjrn.mjs} +2 -2
  23. package/lib/{api-Bznmr-xZ.mjs.map → api-CwEjmjrn.mjs.map} +1 -1
  24. package/lib/{banana-for-scale-DpKXNBt_.mjs → banana-for-scale-Cf41yXTl.mjs} +3 -3
  25. package/lib/{banana-for-scale-DpKXNBt_.mjs.map → banana-for-scale-Cf41yXTl.mjs.map} +1 -1
  26. package/lib/{common-utils-DbL4tku0.mjs → common-utils-OTJQGohe.mjs} +3 -3
  27. package/lib/common-utils-OTJQGohe.mjs.map +1 -0
  28. package/lib/{component-dimensioning-BaUqwqYJ.mjs → component-dimensioning-yPK46Y5o.mjs} +26 -26
  29. package/lib/{component-dimensioning-BaUqwqYJ.mjs.map → component-dimensioning-yPK46Y5o.mjs.map} +1 -1
  30. package/lib/{component-raycast-helper-4i8b4E5B.mjs → component-raycast-helper-CnpnRaFg.mjs} +15 -15
  31. package/lib/{component-raycast-helper-4i8b4E5B.mjs.map → component-raycast-helper-CnpnRaFg.mjs.map} +1 -1
  32. package/lib/{configurator-CDw_c6tB.mjs → configurator-iYlO_buA.mjs} +4 -4
  33. package/lib/{configurator-CDw_c6tB.mjs.map → configurator-iYlO_buA.mjs.map} +1 -1
  34. package/lib/configurator-y7zIaUe_.mjs +2 -0
  35. package/lib/{continuous-drawing-helper-DqHIR_qF.mjs → continuous-drawing-helper-CTfGRTfH.mjs} +3 -3
  36. package/lib/{continuous-drawing-helper-DqHIR_qF.mjs.map → continuous-drawing-helper-CTfGRTfH.mjs.map} +1 -1
  37. package/lib/dimensioning-helper-CQlesi-m.mjs +2 -0
  38. package/lib/{dimensioning-helper-CGPjS2hW.mjs → dimensioning-helper-DSlkLDmx.mjs} +42 -36
  39. package/lib/dimensioning-helper-DSlkLDmx.mjs.map +1 -0
  40. package/lib/{glb-viewer-B-Zr743e.mjs → glb-viewer-AGV-_xKd.mjs} +33 -33
  41. package/lib/{glb-viewer-B-Zr743e.mjs.map → glb-viewer-AGV-_xKd.mjs.map} +1 -1
  42. package/lib/glb-viewer-DSzNR4CI.mjs +2 -0
  43. package/lib/{highlight-coordinator-4gkjde82.mjs → highlight-coordinator-DU6oFunq.mjs} +6 -6
  44. package/lib/{highlight-coordinator-4gkjde82.mjs.map → highlight-coordinator-DU6oFunq.mjs.map} +1 -1
  45. package/lib/{homag-intelligence-D7S7r-Gc.mjs → homag-intelligence-D_yBv0ig.mjs} +3 -3
  46. package/lib/{homag-intelligence-D7S7r-Gc.mjs.map → homag-intelligence-D_yBv0ig.mjs.map} +1 -1
  47. package/lib/{hosek-wilkie-sky-iMar2iw-.mjs → hosek-wilkie-sky-DmTvnxMA.mjs} +33 -33
  48. package/lib/{hosek-wilkie-sky-iMar2iw-.mjs.map → hosek-wilkie-sky-DmTvnxMA.mjs.map} +1 -1
  49. package/lib/{imos-ix-poc-export-helper-CyGqK7nu.mjs → imos-ix-poc-export-helper-BGN97m8W.mjs} +3 -3
  50. package/lib/{imos-ix-poc-export-helper-CyGqK7nu.mjs.map → imos-ix-poc-export-helper-BGN97m8W.mjs.map} +1 -1
  51. package/lib/{kernel-utils-BvatnA7U.mjs → kernel-utils-BYKmP0mf.mjs} +13 -13
  52. package/lib/{kernel-utils-BvatnA7U.mjs.map → kernel-utils-BYKmP0mf.mjs.map} +1 -1
  53. package/lib/{material-viewer-CTsSfTfL.mjs → material-viewer-BuBSXGw6.mjs} +18 -18
  54. package/lib/{material-viewer-CTsSfTfL.mjs.map → material-viewer-BuBSXGw6.mjs.map} +1 -1
  55. package/lib/{packages-BXAZEcKa.mjs → packages-CduZDHYG.mjs} +5 -5
  56. package/lib/{packages-BXAZEcKa.mjs.map → packages-CduZDHYG.mjs.map} +1 -1
  57. package/lib/planner-B-SWR4R8.mjs +2 -0
  58. package/lib/{planner-jvLAnYww.mjs → planner-BuBkFbra.mjs} +3 -3
  59. package/lib/{planner-jvLAnYww.mjs.map → planner-BuBkFbra.mjs.map} +1 -1
  60. package/lib/{plugin-system-CRaC04G5.mjs → plugin-system-CPf99Zkf.mjs} +2 -2
  61. package/lib/{plugin-system-CRaC04G5.mjs.map → plugin-system-CPf99Zkf.mjs.map} +1 -1
  62. package/lib/{render-cache-DCPIQbO1.mjs → render-cache-CPppt7Rd.mjs} +5 -5
  63. package/lib/{render-cache-DCPIQbO1.mjs.map → render-cache-CPppt7Rd.mjs.map} +1 -1
  64. package/lib/{render-order-BPF2wDMw.mjs → render-order-a0QAbB7Q.mjs} +2 -2
  65. package/lib/{render-order-BPF2wDMw.mjs.map → render-order-a0QAbB7Q.mjs.map} +1 -1
  66. package/lib/roomle-headless.d.ts +0 -2
  67. package/lib/roomle-headless.js +14 -14
  68. package/lib/{roomle-renderer-Ato6RMrd.mjs → roomle-renderer-UJINLYxS.mjs} +2 -2
  69. package/lib/{roomle-renderer-Ato6RMrd.mjs.map → roomle-renderer-UJINLYxS.mjs.map} +1 -1
  70. package/lib/{roomle-sdk-CBwhwX_e.mjs → roomle-sdk-CcNdTp_n.mjs} +1844 -1889
  71. package/lib/roomle-sdk-CcNdTp_n.mjs.map +1 -0
  72. package/lib/roomle-sdk.d.ts +0 -2
  73. package/lib/roomle-sdk.js +7 -7
  74. package/lib/{roomle-webgpu-renderer-BfZKcXSz.mjs → roomle-webgpu-renderer-BSvxbopA.mjs} +900 -707
  75. package/lib/roomle-webgpu-renderer-BSvxbopA.mjs.map +1 -0
  76. package/lib/{scene-renderer-BHYZac3H.mjs → scene-renderer--DzrpIl_.mjs} +309 -309
  77. package/lib/{scene-renderer-BHYZac3H.mjs.map → scene-renderer--DzrpIl_.mjs.map} +1 -1
  78. package/lib/{script-loader-CvnG6LgL.mjs → script-loader-D6i0wQ_j.mjs} +2 -2
  79. package/lib/{script-loader-CvnG6LgL.mjs.map → script-loader-D6i0wQ_j.mjs.map} +1 -1
  80. package/lib/{shading-settings-BBhR7KcS.mjs → shading-settings-6v-7O_Sz.mjs} +49 -49
  81. package/lib/{shading-settings-BBhR7KcS.mjs.map → shading-settings-6v-7O_Sz.mjs.map} +1 -1
  82. package/lib/src-6KtBPZXp.mjs +2 -0
  83. package/lib/{src-HhklrVDg.mjs → src-Dg0wYIom.mjs} +150 -150
  84. package/lib/{src-HhklrVDg.mjs.map → src-Dg0wYIom.mjs.map} +1 -1
  85. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/package.json +1 -1
  86. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/ConfiguratorKernel.wasm +0 -0
  87. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/RoomleCore.wasm +0 -0
  88. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/RoomleToolsCore.wasm +0 -0
  89. package/lib/{stats-helper-PndcZCzL.mjs → stats-helper-DYjPPDnz.mjs} +2 -2
  90. package/lib/{stats-helper-PndcZCzL.mjs.map → stats-helper-DYjPPDnz.mjs.map} +1 -1
  91. package/lib/{three.core-0KaTx8dm.mjs → three.core-BTUCraWz.mjs} +976 -884
  92. package/lib/three.core-BTUCraWz.mjs.map +1 -0
  93. package/lib/{three.module-dym6j3lO.mjs → three.module-DUSFrLM6.mjs} +1789 -1739
  94. package/lib/three.module-DUSFrLM6.mjs.map +1 -0
  95. package/lib/three.tsl-De6A-G56.mjs +158 -0
  96. package/lib/three.tsl-De6A-G56.mjs.map +1 -0
  97. package/lib/three.tsl-DtfvggFX.mjs +2 -0
  98. package/lib/three.webgpu-B1OhMci_.mjs +3 -0
  99. package/lib/{three.webgpu-D3nSEIjD.mjs → three.webgpu-wPiwbpFM.mjs} +5806 -4926
  100. package/lib/three.webgpu-wPiwbpFM.mjs.map +1 -0
  101. package/lib/{threejs-utils-v1uOvccg.mjs → threejs-utils-lVSsgAiQ.mjs} +68 -68
  102. package/lib/{threejs-utils-v1uOvccg.mjs.map → threejs-utils-lVSsgAiQ.mjs.map} +1 -1
  103. package/lib/{tools-core-B29U-88K.mjs → tools-core-CRGER_KC.mjs} +3 -3
  104. package/lib/{tools-core-B29U-88K.mjs.map → tools-core-CRGER_KC.mjs.map} +1 -1
  105. package/lib/{webgpu-BHAP6BLI.mjs → webgpu-BxYJfBjz.mjs} +555 -555
  106. package/lib/{webgpu-BHAP6BLI.mjs.map → webgpu-BxYJfBjz.mjs.map} +1 -1
  107. package/package.json +5 -5
  108. package/lib/BufferGeometry-Bl5whHAB.mjs.map +0 -1
  109. package/lib/GLTFExporter-yQ7mMauu.mjs.map +0 -1
  110. package/lib/GaussianBlurNode-DNBEf5-n.mjs +0 -59
  111. package/lib/GaussianBlurNode-DNBEf5-n.mjs.map +0 -1
  112. package/lib/Object3D-BHdngbxB.mjs.map +0 -1
  113. package/lib/PointLightHelper-CuPSBuDU.mjs.map +0 -1
  114. package/lib/SpotLightHelper-m-Rh8vGU.mjs.map +0 -1
  115. package/lib/USDZExporter-MdkuT226.mjs.map +0 -1
  116. package/lib/Vector4-C7TlIAyy.mjs.map +0 -1
  117. package/lib/common-utils-DbL4tku0.mjs.map +0 -1
  118. package/lib/configurator-BYQdWEvf.mjs +0 -2
  119. package/lib/dimensioning-helper-CGPjS2hW.mjs.map +0 -1
  120. package/lib/dimensioning-helper-VndKlIXS.mjs +0 -2
  121. package/lib/glb-viewer-Bd5Xn6Oq.mjs +0 -2
  122. package/lib/planner-DMk3T4ts.mjs +0 -2
  123. package/lib/roomle-sdk-CBwhwX_e.mjs.map +0 -1
  124. package/lib/roomle-webgpu-renderer-BfZKcXSz.mjs.map +0 -1
  125. package/lib/src-Bbq3Hqzn.mjs +0 -2
  126. package/lib/three.core-0KaTx8dm.mjs.map +0 -1
  127. package/lib/three.module-dym6j3lO.mjs.map +0 -1
  128. package/lib/three.tsl-BTc4fg8T.mjs +0 -2
  129. package/lib/three.tsl-Cf0-sCqB.mjs +0 -152
  130. package/lib/three.tsl-Cf0-sCqB.mjs.map +0 -1
  131. package/lib/three.webgpu-ClICiWlK.mjs +0 -3
  132. package/lib/three.webgpu-D3nSEIjD.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"webgpu-BHAP6BLI.mjs","names":["transformStruct","nodeProxyConstructor","transformStruct","rngInit","rand2","rngNextBounce","rngInit","rand2","rngInit","rand2","rngInit","CommonGLSL.util_functions","getTextureHash","rngInit","rand2","intersectionResultStruct","rand1","getTextureHash","rand2"],"sources":["../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/tsl/structs.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/nodes/NodeProxy.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/utils/toObjectBVH.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/utils/packBVHBufferUtils.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/nodes/WGSLTagFnNode.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/tsl/constants.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/shapecastFns/getShapecastFn.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/tsl/fns.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/shapecastFns/getRaycastFirstHitFn.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/shapecastFns/getSampleTrianglePointFn.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/shapecastFns/getClosestPointToPointFn.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/BVHComputeData.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/materials/RenderToScreenMaterial.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/ComputeKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/random.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/structs.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/utils.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/sampling.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/PathTracerMegaKernel.js","../../../../node_modules/three-gpu-pathtracer/src/utils/TextureUtils.js","../../../../node_modules/three-gpu-pathtracer/src/uniforms/EquirectHdrInfoUniform.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/ZeroOutKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/PathTracerBackend.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/MegaKernelPathTracer.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/structs.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/PrimeRayGenerationDispatchKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/RayGenerationKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/RayIntersectionKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/UpdateRayQueueParamsKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/ZeroOutBufferKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/ProcessHitsKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/WaveFrontPathTracer.js","../../../../node_modules/three-gpu-pathtracer/src/shader/common/util_functions.glsl.js","../../../../node_modules/three-gpu-pathtracer/src/utils/CubeToEquirectGenerator.js","../../../../node_modules/three-gpu-pathtracer/src/core/utils/sceneUpdateUtils.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/ggx.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/material.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/AtlasTexture.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/PathtracerBVHComputeData.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/materials/debug/AtlasDebugMaterial.js","../../../../node_modules/three-gpu-pathtracer/src/core/utils/GeometryPreparationUtils.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/materials/PathtracingMaterial.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/materials/GltfCompliantMaterial.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/WebGPUPathTracer.js"],"sourcesContent":["import { StructTypeNode } from 'three/webgpu';\n\n// temporary shim so StructTypeNodes can be passed to storage functions until\n// this is fixed in three.js\nObject.defineProperty( StructTypeNode.prototype, 'layout', {\n\n\tget() {\n\n\t\treturn this;\n\n\t}\n\n} );\nStructTypeNode.prototype.isStruct = true;\n\n//\n\nexport const bvhNodeBoundsStruct = new StructTypeNode( {\n\tmin: 'array<f32, 3>',\n\tmax: 'array<f32, 3>',\n}, 'BVHBoundingBox' );\nbvhNodeBoundsStruct.getLength = () => 6;\n\nexport const bvhNodeStruct = new StructTypeNode( {\n\tbounds: 'BVHBoundingBox',\n\trightChildOrTriangleOffset: 'uint',\n\tsplitAxisOrTriangleCount: 'uint',\n}, 'BVHNode' );\nbvhNodeStruct.getLength = () => bvhNodeBoundsStruct.getLength() + 2;\n\nexport const transformStruct = new StructTypeNode( {\n\tmatrixWorld: 'mat4x4f',\n\tinverseMatrixWorld: 'mat4x4f',\n\tnodeOffset: 'uint',\n\tvisible: 'uint',\n\t_alignment0: 'uint',\n\t_alignment1: 'uint',\n}, 'TransformStruct' );\n\n\n/**\n * WGSL struct node representing a ray with an origin and direction.\n * Used as the input to BVH traversal and intersection functions.\n * @type {StructTypeNode}\n * @section TSL Structs\n */\nexport const rayStruct = new StructTypeNode( {\n\torigin: 'vec3f',\n\tdirection: 'vec3f',\n}, 'Ray' );\n\n/**\n * WGSL struct node describing a ray–triangle intersection result, including barycentric\n * coordinates, world-space normal, hit distance, face side, triangle indices, and the\n * object index within the TLAS.\n * @type {StructTypeNode}\n * @section TSL Structs\n */\nexport const rayIntersectionResultStruct = new StructTypeNode( {\n\tindices: 'vec4u',\n\tnormal: 'vec3f',\n\tdidHit: 'bool',\n\tbarycoord: 'vec3f',\n\tobjectIndex: 'uint',\n\tside: 'float',\n\tdist: 'float',\n}, 'IntersectionResult' );\n\n/**\n * WGSL struct node describing a closest-point query result, including the world-space\n * closest point, squared distance, barycentric coordinates, face normal, side, triangle\n * indices, and the object index within the TLAS.\n *\n * Barycoord convention matches {@link rayIntersectionResultStruct}: `(bary_a, bary_b, bary_c)`\n * where each component is the weight for the corresponding vertex in `faceIndices.xyz`.\n * @type {StructTypeNode}\n * @section TSL Structs\n */\nexport const pointQueryResultStruct = new StructTypeNode( {\n\tfaceIndices: 'vec4u',\n\tclosestPoint: 'vec3f',\n\tfound: 'bool',\n\tbarycoord: 'vec3f',\n\tobjectIndex: 'uint',\n\tfaceNormal: 'vec3f',\n\tside: 'float',\n\tdistanceSq: 'float',\n}, 'PointQueryResult' );\n","import { Node, TSL } from 'three/webgpu';\n\n// three r184 compat: TSL.nodeProxyConstructor only exists from three r185.\n// Recovered from the known-good Jul 21 SDK bundle (webgpu-V2WQRg97.mjs): fall\n// back to a Proxy that forwards to the wrapped node and exposes it via\n// `functionNode` so callable node functions keep working on r184.\nconst nodeProxyConstructor = TSL.nodeProxyConstructor ?? ( ( fn, target ) => new Proxy( fn, {\n\n\tget( obj, prop, receiver ) {\n\n\t\tconst value = Reflect.get( target, prop, receiver );\n\t\treturn value === undefined && prop === 'functionNode' ? target : value;\n\n\t},\n\tset( obj, prop, value ) {\n\n\t\treturn Reflect.set( target, prop, value );\n\n\t},\n\n} ) );\n\n\nclass ProxyCallNode extends Node {\n\n\tstatic get type() {\n\n\t\treturn 'ProxyCallNode';\n\n\t}\n\n\tconstructor( proxyNode, params ) {\n\n\t\tsuper();\n\t\tthis.proxyNode = proxyNode;\n\t\tthis.params = params;\n\n\t}\n\n\tsetup() {\n\n\t\treturn this.proxyNode.proxyNode.call( ...this.params );\n\n\t}\n\n}\n\nexport class NodeProxy {\n\n\tget isNode() {\n\n\t\treturn true;\n\n\t}\n\n\t// getter for the node being proxied to\n\tget proxyNode() {\n\n\t\tconst { proxyObject, proxyProperty } = this;\n\t\tconst properties = proxyProperty.split( '.' );\n\t\tlet value = proxyObject;\n\t\tfor ( let i = 0, l = properties.length; i < l; i ++ ) {\n\n\t\t\tvalue = value[ properties[ i ] ];\n\n\t\t}\n\n\t\tif ( value && 'functionNode' in value ) {\n\n\t\t\treturn value.functionNode;\n\n\t\t} else {\n\n\t\t\treturn value;\n\n\t\t}\n\n\t}\n\n\tconstructor( property, object = null ) {\n\n\t\t// store the proxy property and objects so they can be changed later\n\t\tthis.proxyObject = object;\n\t\tthis.proxyProperty = property;\n\n\t\t// set up a proxy to redirect all calls to the proxied node in order to avoid replicating\n\t\t// expected members for all node types.\n\t\treturn new Proxy( this, {\n\n\t\t\tget( target, property ) {\n\n\t\t\t\tif ( property in target ) {\n\n\t\t\t\t\treturn Reflect.get( target, property );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst node = target.proxyNode;\n\t\t\t\t\tif ( ! node ) {\n\n\t\t\t\t\t\treturn undefined;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst value = Reflect.get( node, property );\n\t\t\t\t\tif ( typeof value === 'function' ) {\n\n\t\t\t\t\t\treturn value.bind( node );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\treturn value;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tset( target, property, value ) {\n\n\t\t\t\tif ( property in target ) {\n\n\t\t\t\t\treturn Reflect.set( target, property, value );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthrow new Error( 'NodeProxy: Cannot set members of proxied nodes.' );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t} );\n\n\t}\n\n}\n\nexport const proxy = ( ...args ) => {\n\n\treturn new NodeProxy( ...args );\n\n};\n\nexport const proxyFn = ( ...args ) => {\n\n\tconst nodeProxy = new NodeProxy( ...args );\n\tconst fn = ( ...params ) => new ProxyCallNode( nodeProxy, params );\n\treturn nodeProxyConstructor( fn, nodeProxy );\n\n};\n","/** @import { Object3D, BufferGeometry } from 'three' */\nimport { Mesh } from 'three/webgpu';\nimport { GeometryBVH } from 'three-mesh-bvh/src/core/GeometryBVH.js';\nimport { ObjectBVH } from 'three-mesh-bvh/src/core/ObjectBVH.js';\nimport { SAH } from 'three-mesh-bvh/src/core/Constants.js';\n\n/**\n * Normalizes the various accepted `bvh` arguments into an {@link ObjectBVH}. A pre-built ObjectBVH\n * is returned as-is; otherwise an Object3D, BufferGeometry, GeometryBVH, or array of those is\n * wrapped into a new ObjectBVH.\n *\n * @private\n * @param {ObjectBVH | Object3D | BufferGeometry | GeometryBVH | Array} bvh\n * @returns {ObjectBVH}\n */\nexport function toObjectBVH( bvh ) {\n\n\tif ( bvh instanceof ObjectBVH ) {\n\n\t\treturn bvh;\n\n\t}\n\n\tif ( ! Array.isArray( bvh ) ) {\n\n\t\tbvh = [ bvh ];\n\n\t}\n\n\tconst objects = bvh.map( item => {\n\n\t\tif ( item.isObject3D ) {\n\n\t\t\treturn item;\n\n\t\t} else if ( item.isBufferGeometry ) {\n\n\t\t\treturn new Mesh( item );\n\n\t\t} else if ( item instanceof GeometryBVH ) {\n\n\t\t\tconst dummy = new Mesh();\n\t\t\tdummy.geometry.boundsTree = item;\n\t\t\treturn dummy;\n\n\t\t}\n\n\t} );\n\n\treturn new ObjectBVH( objects, { strategy: SAH, targetLeafSize: 1 } );\n\n}\n","/** @import { StructTypeNode } from 'three/webgpu' */\n/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { Vector4 } from 'three';\nimport { BYTES_PER_NODE, UINT32_PER_NODE, IS_LEAFNODE_FLAG } from 'three-mesh-bvh/src/core/Constants.js';\n\n// scratch\nconst _def = /* @__PURE__ */ new Vector4();\nconst _vec = /* @__PURE__ */ new Vector4();\n\n// resolve an indirect buffer into a flat triangle index array\nfunction dereferenceIndex( indexAttr, indirectBuffer ) {\n\n\tconst indexArray = indexAttr ? indexAttr.array : null;\n\tconst result = new Uint32Array( indirectBuffer.length * 3 );\n\tfor ( let i = 0, l = indirectBuffer.length; i < l; i ++ ) {\n\n\t\tconst i3 = 3 * i;\n\t\tconst v3 = 3 * indirectBuffer[ i ];\n\t\tfor ( let c = 0; c < 3; c ++ ) {\n\n\t\t\tresult[ i3 + c ] = indexArray ? indexArray[ v3 + c ] : v3 + c;\n\n\t\t}\n\n\t}\n\n\treturn result;\n\n}\n\n/**\n * Copies the packed nodes of a BVH into the shared node buffer, rewriting leaf offsets / counts and\n * tagging leaves as mesh (`0xFFFF`) or TLAS (`0xFF00`) leaves. Returns the write offset of each root.\n *\n * @private\n * @param {Object} bvh\n * @param {number} geometryOffset\n * @param {Array} transformInfo\n * @param {number} nodeWriteOffset\n * @param {ArrayBuffer} target\n * @param {boolean} [tlas=false]\n * @returns {Array<number>}\n */\nexport function appendBVHData( bvh, geometryOffset, transformInfo, nodeWriteOffset, target, tlas = false ) {\n\n\tconst targetU16 = new Uint16Array( target );\n\tconst targetU32 = new Uint32Array( target );\n\tconst targetF32 = new Float32Array( target );\n\n\tconst result = [];\n\tlet tlasOffset = 0;\n\tbvh._roots.forEach( root => {\n\n\t\tconst rootBuffer16 = new Uint16Array( root );\n\t\tconst rootBuffer32 = new Uint32Array( root );\n\t\tresult.push( nodeWriteOffset );\n\t\tfor ( let i = 0, l = root.byteLength / BYTES_PER_NODE; i < l; i ++ ) {\n\n\t\t\tconst r32 = i * UINT32_PER_NODE;\n\t\t\tconst r16 = r32 * 2;\n\t\t\tconst n32 = nodeWriteOffset * UINT32_PER_NODE;\n\t\t\tconst n16 = n32 * 2;\n\n\t\t\t// write bounds\n\t\t\tconst view = new Float32Array( root, i * BYTES_PER_NODE, 6 );\n\t\t\tif ( i === 0 ) {\n\n\t\t\t\t// if we're copying the root then check for cases where there are no primitives and therefore\n\t\t\t\t// be a bounds of [ Infinity, - Infinity ]. Convert this to [ 1, - 1 ] for reliable GPU behavior.\n\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\tconst vMin = view[ i + 0 ];\n\t\t\t\t\tconst vMax = view[ i + 3 ];\n\t\t\t\t\tif ( vMin > vMax ) {\n\n\t\t\t\t\t\ttargetF32[ n32 + i + 0 ] = 1;\n\t\t\t\t\t\ttargetF32[ n32 + i + 3 ] = - 1;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttargetF32[ n32 + i + 0 ] = vMin;\n\t\t\t\t\t\ttargetF32[ n32 + i + 3 ] = vMax;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\ttargetF32.set( view, n32 );\n\n\t\t\t}\n\n\t\t\tconst isLeaf = IS_LEAFNODE_FLAG === rootBuffer16[ r16 + 15 ];\n\t\t\tif ( isLeaf ) {\n\n\t\t\t\tif ( tlas ) {\n\n\t\t\t\t\t// 0xFFFF == mesh leaf, 0xFF00 == TLAS leaf\n\t\t\t\t\ttargetU32[ n32 + 6 ] = tlasOffset;\n\t\t\t\t\ttargetU16[ n16 + 15 ] = 0xFF00;\n\n\t\t\t\t\tconst count = rootBuffer16[ r16 + 14 ];\n\t\t\t\t\t// const offset = rootBuffer32[ r32 + 6 ];\n\n\t\t\t\t\t// each root is expanded into a separate transform so we need to expand\n\t\t\t\t\t// the embedded offsets and counts.\n\t\t\t\t\tlet rootsCount = 0;\n\t\t\t\t\tfor ( let o = 0; o < count; o ++ ) {\n\n\t\t\t\t\t\tconst roots = transformInfo[ tlasOffset ].data.bvh._roots.length;\n\t\t\t\t\t\ttlasOffset += roots;\n\t\t\t\t\t\trootsCount += roots;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetU16[ n16 + 14 ] = rootsCount;\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttargetU32[ n32 + 6 ] = rootBuffer32[ r32 + 6 ] + geometryOffset;\n\t\t\t\t\ttargetU16[ n16 + 14 ] = rootBuffer16[ r16 + 14 ];\n\t\t\t\t\ttargetU16[ n16 + 15 ] = IS_LEAFNODE_FLAG;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\ttargetU32[ n32 + 6 ] = rootBuffer32[ r32 + 6 ];\n\t\t\t\ttargetU32[ n32 + 7 ] = rootBuffer32[ r32 + 7 ];\n\n\t\t\t}\n\n\t\t\tnodeWriteOffset ++;\n\n\t\t}\n\n\t} );\n\n\treturn result;\n\n}\n\n/**\n * Writes the triangle index data for a BVH's geometry into the shared index buffer, rebasing the\n * indices into the packed attribute buffer.\n *\n * @private\n * @param {Object} bvh\n * @param {{start:number,count:number,vertexStart:number}} range\n * @param {number} valueOffset\n * @param {number} writeOffset\n * @param {Uint32Array} target\n */\nexport function appendIndexData( bvh, range, valueOffset, writeOffset, target ) {\n\n\tconst { geometry } = bvh;\n\tconst { start, count, vertexStart } = range;\n\tif ( bvh.indirect ) {\n\n\t\tconst dereferencedIndex = dereferenceIndex( geometry.index, bvh._indirectBuffer );\n\t\tfor ( let i = 0; i < dereferencedIndex.length; i ++ ) {\n\n\t\t\ttarget[ i + writeOffset ] = dereferencedIndex[ i ] - vertexStart + valueOffset;\n\n\t\t}\n\n\t} else if ( geometry.index ) {\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\ttarget[ i + writeOffset ] = geometry.index.getX( i + start ) - vertexStart + valueOffset;\n\n\t\t}\n\n\t} else {\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\ttarget[ i + writeOffset ] = i + start + valueOffset;\n\n\t\t}\n\n\t}\n\n}\n\n/**\n * Writes a BVH's interleaved per-vertex attributes into the shared attribute buffer, filling missing\n * attributes with their defaults and applying bone transforms for skinned meshes.\n *\n * @private\n * @param {Object} bvh\n * @param {{vertexStart:number,vertexCount:number}} range\n * @param {number} writeOffset\n * @param {ArrayBuffer} target\n * @param {StructTypeNode} attributeStruct\n * @param {BVHComputeData} bvhData - Provides per-attribute defaults via `getDefaultAttributeValue`.\n */\nexport function appendGeometryData( bvh, range, writeOffset, target, attributeStruct, bvhData ) {\n\n\t// if \"mesh\" is present then it is assumed to be a SkinnedMeshBVH\n\tconst { geometry, mesh = null } = bvh;\n\tconst { vertexStart, vertexCount } = range;\n\tconst attributesBufferF32 = new Float32Array( target );\n\tconst attrStructLength = attributeStruct.getLength();\n\tattributeStruct.membersLayout.forEach( ( { name }, interleavedOffset ) => {\n\n\t\t// TODO: we should be able to have access to memory layout offsets here via the struct\n\t\t// API but it's not currently available.\n\t\tconst attr = geometry.attributes[ name ];\n\t\tbvhData.getDefaultAttributeValue( name, _def );\n\n\t\tfor ( let i = 0; i < vertexCount; i ++ ) {\n\n\t\t\tif ( attr ) {\n\n\t\t\t\t_vec.fromBufferAttribute( attr, i + vertexStart );\n\n\t\t\t\tswitch ( attr.itemSize ) {\n\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\t_vec.y = _def.y;\n\t\t\t\t\t\t_vec.z = _def.z;\n\t\t\t\t\t\t_vec.w = _def.w;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\t_vec.z = _def.z;\n\t\t\t\t\t\t_vec.w = _def.w;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\t_vec.w = _def.w;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tif ( mesh && ( name === 'position' || name === 'normal' || name === 'tangent' ) ) {\n\n\t\t\t\t\tmesh.applyBoneTransform( i + vertexStart, _vec );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t_vec.copy( _def );\n\n\t\t\t}\n\n\t\t\t_vec.toArray( attributesBufferF32, ( writeOffset + i ) * attrStructLength + interleavedOffset * 4 );\n\n\t\t}\n\n\t} );\n\n}\n","import { CodeNode, FunctionNode, Node, TSL } from 'three/webgpu';\n\n// three r184 compat: TSL.nodeProxyConstructor only exists from three r185.\n// Recovered from the known-good Jul 21 SDK bundle (webgpu-V2WQRg97.mjs): fall\n// back to a Proxy that forwards to the wrapped node and exposes it via\n// `functionNode` so callable node functions keep working on r184.\nconst nodeProxyConstructor = TSL.nodeProxyConstructor ?? ( ( fn, target ) => new Proxy( fn, {\n\n\tget( obj, prop, receiver ) {\n\n\t\tconst value = Reflect.get( target, prop, receiver );\n\t\treturn value === undefined && prop === 'functionNode' ? target : value;\n\n\t},\n\tset( obj, prop, value ) {\n\n\t\treturn Reflect.set( target, prop, value );\n\n\t},\n\n} ) );\n\n\n// minimal node that outputs a raw WGSL expression verbatim when built\nclass LiteralExpression extends Node {\n\n\tconstructor( literal ) {\n\n\t\tsuper();\n\t\tthis.literal = literal;\n\n\t}\n\n\tbuild() {\n\n\t\treturn this.literal;\n\n\t}\n\n}\n\n// wraps a FunctionNode so that build() returns just the function name\nclass PropertyRefNode extends Node {\n\n\tconstructor( node, output = 'property' ) {\n\n\t\tsuper();\n\t\tthis.node = node;\n\t\tthis.output = output;\n\n\t}\n\n\tbuild( builder ) {\n\n\t\treturn this.node.build( builder, this.output );\n\n\t}\n\n}\n\n// returns the node that should be registered as an include for the given arg\n// three r184 compat (roomle patch, recovered from the known-good Jul 21\n// bundle): with the nodeProxyConstructor Proxy fallback, proxied callables are\n// plain functions carrying the wrapped node on `.functionNode` — unwrap them\n// before treating template args as nodes.\nfunction unwrapFunctionNode( arg ) {\n\n\treturn typeof arg === 'function' && arg.functionNode && ! arg.isNode ? arg.functionNode : arg;\n\n}\n\nfunction getIncludeNode( arg ) {\n\n\targ = unwrapFunctionNode( arg );\n\tif ( arg.isNode ) return new PropertyRefNode( arg );\n\treturn null;\n\n}\n\n// extract dependency nodes from template args for include registration\nfunction extractIncludes( args ) {\n\n\tconst includes = [];\n\tfor ( const arg of args ) {\n\n\t\tif ( Array.isArray( arg ) ) {\n\n\t\t\tfor ( const element of arg ) {\n\n\t\t\t\tconst node = getIncludeNode( element );\n\t\t\t\tif ( node ) includes.push( node );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn includes;\n\n}\n\n// normalize args so generate can resolve them uniformly with build():\n// - callable wrappers > PropertyRefNode (emits just the function name)\nfunction normalizeArgs( args ) {\n\n\treturn args.map( arg => {\n\n\t\targ = unwrapFunctionNode( arg );\n\t\tif ( arg && arg.isNode ) {\n\n\t\t\tif ( arg instanceof WGSLTagCodeNode ) {\n\n\t\t\t\t// use a custom flag for this node to inline the output\n\t\t\t\treturn new PropertyRefNode( arg, 'inline' );\n\n\t\t\t} else {\n\n\t\t\t\treturn new PropertyRefNode( arg );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn arg;\n\n\t} );\n\n}\n\n// interleave static tokens with resolved arg values\nfunction assembleTemplate( tokens, args, builder ) {\n\n\tlet code = '';\n\tfor ( let i = 0, l = tokens.length; i < l; i ++ ) {\n\n\t\tcode += tokens[ i ];\n\t\tif ( i < args.length ) {\n\n\t\t\tconst arg = unwrapFunctionNode( args[ i ] );\n\t\t\tif ( Array.isArray( arg ) ) {\n\n\t\t\t\t// include array — no text output\n\n\t\t\t} else if ( typeof arg === 'string' || typeof arg === 'number' ) {\n\n\t\t\t\tcode += String( arg );\n\n\t\t\t} else {\n\n\t\t\t\tcode += arg.build( builder );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn code;\n\n}\n\nexport class WGSLTagFnNode extends FunctionNode {\n\n\tstatic get type() {\n\n\t\treturn 'WGSLTagFnNode';\n\n\t}\n\n\tconstructor( tokens, args, lang = 'wgsl' ) {\n\n\t\tsuper( '', extractIncludes( args ), lang );\n\n\t\tthis.tokens = tokens;\n\t\tthis.args = args;\n\n\t}\n\n\t// assemble the signature from tokens and arg names then parse\n\tgetNodeFunction( builder ) {\n\n\t\tconst { tokens } = this;\n\t\tconst args = normalizeArgs( this.args );\n\n\t\tconst nodeData = builder.getDataFromNode( this );\n\t\tlet nodeFunction = nodeData.nodeFunction;\n\t\tif ( nodeFunction === undefined ) {\n\n\t\t\t// reconstruct the full code with known names for struct args\n\t\t\t// and dummy identifiers for everything else\n\t\t\tlet fullCode = '';\n\t\t\tfor ( let i = 0, l = tokens.length; i < l; i ++ ) {\n\n\t\t\t\tfullCode += tokens[ i ];\n\n\t\t\t\tif ( i < args.length ) {\n\n\t\t\t\t\tconst arg = args[ i ];\n\t\t\t\t\tif ( Array.isArray( arg ) ) {\n\n\t\t\t\t\t\t// include array — no text output\n\n\t\t\t\t\t} else if ( typeof arg === 'string' || typeof arg === 'number' ) {\n\n\t\t\t\t\t\t// literals\n\t\t\t\t\t\tfullCode += String( arg );\n\n\t\t\t\t\t} else if ( arg.isStructLayoutNode ) {\n\n\t\t\t\t\t\t// struct type node\n\t\t\t\t\t\tfullCode += arg.getNodeType( builder );\n\n\t\t\t\t\t} else if ( arg.isStruct ) {\n\n\t\t\t\t\t\t// struct\n\t\t\t\t\t\tfullCode += arg.layout.getNodeType( builder );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tfullCode += '_arg' + i;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// remove comments\n\t\t\tfullCode = fullCode.replace( /\\/\\/.+[\\n\\r]/g, '' );\n\n\t\t\t// parse it so we have the signature defined - we will define the body content after\n\t\t\tnodeFunction = builder.parser.parseFunction( fullCode );\n\t\t\tnodeData.nodeFunction = nodeFunction;\n\n\t\t}\n\n\t\treturn nodeFunction;\n\n\t}\n\n\t// get the code for the function\n\tgenerate( builder, output ) {\n\n\t\tconst result = super.generate( builder, output );\n\t\tconst fullCode = assembleTemplate( this.tokens, normalizeArgs( this.args ), builder );\n\n\t\tconst { type } = this.getNodeFunction( builder );\n\t\tconst nodeCode = builder.getCodeFromNode( this, type );\n\n\t\tnodeCode.code = fullCode.replace( /\\/\\/.+[\\n\\r]/g, '' ).replace( /->\\s*void/, '' ).trim();\n\t\treturn result;\n\n\t}\n\n}\n\nexport class WGSLTagCodeNode extends CodeNode {\n\n\tstatic get type() {\n\n\t\treturn 'WGSLTagCodeNode';\n\n\t}\n\n\tconstructor( tokens, args, lang = 'wgsl' ) {\n\n\t\tsuper( '', extractIncludes( args ), lang );\n\n\t\tthis.tokens = tokens;\n\t\tthis.args = args;\n\n\t}\n\n\tbuild( builder, output ) {\n\n\t\tif ( output === 'inline' ) {\n\n\t\t\treturn assembleTemplate( this.tokens, normalizeArgs( this.args ), builder );\n\n\t\t} else {\n\n\t\t\treturn super.build( builder, output );\n\n\t\t}\n\n\t}\n\n\tgenerate( builder ) {\n\n\t\tsuper.generate( builder );\n\n\t\tconst nodeCode = builder.getCodeFromNode( this, this.getNodeType( builder ) );\n\t\tnodeCode.code = assembleTemplate( this.tokens, normalizeArgs( this.args ), builder );\n\t\treturn nodeCode.code;\n\n\t}\n\n}\n\nconst getFn = functionNode => {\n\n\tconst fn = ( ...params ) => {\n\n\t\t// wrap string parameter values as raw WGSL expressions so they\n\t\t// output verbatim as identifiers like local variable names\n\t\tif ( params.length === 1 && params[ 0 ] && typeof params[ 0 ] === 'object' && ! params[ 0 ].isNode ) {\n\n\t\t\tconst obj = params[ 0 ];\n\t\t\tfor ( const key in obj ) {\n\n\t\t\t\tif ( typeof obj[ key ] === 'string' ) {\n\n\t\t\t\t\tobj[ key ] = new LiteralExpression( obj[ key ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn functionNode.call( ...params );\n\n\t};\n\n\treturn nodeProxyConstructor( fn, functionNode );\n\n};\n\n// template tag literal function version of \"wgslFn\" & \"wgsl\" to generate\n// functions & code snippets respectively\nexport const wgslTagFn = ( tokens, ...args ) => getFn( new WGSLTagFnNode( tokens, args ) );\nexport const wgslTagCode = ( tokens, ...args ) => new WGSLTagCodeNode( tokens, args );\n\n// glsl versions\nexport const glslTagFn = ( tokens, ...args ) => getFn( new WGSLTagFnNode( tokens, args, 'glsl' ) );\nexport const glslTagCode = ( tokens, ...args ) => new WGSLTagCodeNode( tokens, args, 'glsl' );\n","import { uint } from 'three/tsl';\n\nexport const BVH_STACK_DEPTH = uint( 60 );\n","/** @import { StructTypeNode } from 'three/webgpu' */\n/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { wgslTagCode, wgslTagFn } from '../nodes/WGSLTagFnNode.js';\nimport { BVH_STACK_DEPTH } from '../tsl/constants.js';\n\n/**\n * Builds a pair of WGSL shapecast functions (BLAS + TLAS traversal) for a custom shape\n * type. The returned TLAS function signature is:\n * `fn name( shape: ShapeStruct[, result: ptr<function, ResultStruct>] ) -> bool`\n *\n * @private\n * @param {BVHComputeData} bvhData - The compute data whose storage buffers are referenced.\n * @param {Object} options\n * @param {string} [options.name] - Function name. Defaults to a random identifier.\n * @param {StructTypeNode} options.shapeStruct - TSL struct or definition describing the query shape.\n * @param {StructTypeNode|null} [options.resultStruct] - TSL struct for the accumulated result, or null.\n * @param {Function|null} [options.boundsOrderFn] - function node controlling left/right child traversal order.\n * @param {Function} options.intersectsBoundsFn - function node testing the shape against a BVH node's bounds.\n * @param {Function} options.intersectRangeFn - function node testing the shape against a leaf triangle range.\n * @param {Function|null} [options.transformShapeFn] - function node that transforms the shape into object local space.\n * @param {Function|null} [options.transformResultFn] - function node that transforms a hit result back to world space.\n * @param {Function|null} [options.resetShapeFn] - function node called after each BLAS traversal to reset any per-object state set by `transformShapeFn`.\n * @returns {Function} TSL function node for the TLAS traversal.\n */\nexport function getShapecastFn( bvhData, options ) {\n\n\t// TODO: test with and verify use with TSL Fn - both passing them as arguments,\n\t// calling the function from a TSL Fn.\n\t// TODO: revisit the semantics and mental model of \"transformShapeFn\" and \"transformResultFn\".\n\t// Are they \"before\" and \"after\" hooks? Should they include words implying a direction of transform?\n\t// eg \"toLocal\" / \"toWorld\"?\n\tconst {\n\t\tname = `bvh_shapecast_fn_${ Math.random().toString( 36 ).substring( 2, 7 ) }`,\n\t\tshapeStruct,\n\t\tresultStruct = null,\n\n\t\tboundsOrderFn = null,\n\t\tintersectsBoundsFn,\n\t\tintersectRangeFn,\n\t\ttransformShapeFn = null,\n\t\ttransformResultFn = null,\n\t\tresetShapeFn = null,\n\t} = options;\n\n\t// these are proxy nodes, so they can be referenced before the storage buffers exist\n\tconst { nodes, transforms } = bvhData.storage;\n\n\t// handle optional functions\n\tlet transformResultSnippet = '';\n\tif ( transformResultFn ) {\n\n\t\ttransformResultSnippet = wgslTagCode/* wgsl */`${ transformResultFn }( result, i );`;\n\n\t}\n\n\tlet transformShapeSnippet = '';\n\tif ( transformShapeFn ) {\n\n\t\ttransformShapeSnippet = wgslTagCode/* wgsl */`${ transformShapeFn }( &localShape, i );`;\n\n\t}\n\n\tlet resetShapeSnippet = '';\n\tif ( resetShapeFn ) {\n\n\t\tresetShapeSnippet = wgslTagCode/* wgsl */`${ resetShapeFn }( i );`;\n\n\t}\n\n\tlet leftToRightSnippet = '';\n\tif ( boundsOrderFn ) {\n\n\t\tleftToRightSnippet = wgslTagCode/* wgsl */`\n\t\t\tlet leftToRight = ${ boundsOrderFn }( shape, splitAxis, node );\n\t\t\tc1 = select( rightIndex, leftIndex, leftToRight );\n\t\t\tc2 = select( leftIndex, rightIndex, leftToRight );\n\t\t`;\n\n\t}\n\n\tconst resultPtrSnippet = resultStruct ? wgslTagCode/* wgsl */`result: ptr<function, ${ resultStruct }>` : '';\n\tconst resultArg = resultStruct ? 'result' : '';\n\n\tconst getFnBody = leafSnippet => {\n\n\t\t// returns a function with a snippet inserted for the leaf intersection test\n\t\treturn wgslTagCode/* wgsl */`\n\n\t\t\tvar pointer: i32 = 0;\n\t\t\tvar stack: array<u32, ${ BVH_STACK_DEPTH }>;\n\t\t\tstack[ 0 ] = rootNodeIndex;\n\n\t\t\tloop {\n\n\t\t\t\tif ( pointer < 0 || pointer >= i32( ${ BVH_STACK_DEPTH } ) ) {\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tlet nodeIndex = stack[ pointer ];\n\t\t\t\tlet node = ${ nodes }[ nodeIndex ];\n\t\t\t\tpointer = pointer - 1;\n\n\t\t\t\tif ( ${ intersectsBoundsFn }( shape, node.bounds, ${ resultArg } ) == 0u ) {\n\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tlet infoX = node.splitAxisOrTriangleCount;\n\t\t\t\tlet infoY = node.rightChildOrTriangleOffset;\n\t\t\t\tlet isLeaf = ( infoX & 0xffff0000u ) != 0u;\n\n\t\t\t\tif ( isLeaf ) {\n\n\t\t\t\t\tlet count = infoX & 0x0000ffffu;\n\t\t\t\t\tlet offset = infoY;\n\t\t\t\t\t${ leafSnippet }\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet leftIndex = nodeIndex + 1u;\n\t\t\t\t\tlet splitAxis = infoX & 0x0000ffffu;\n\t\t\t\t\tlet rightIndex = nodeIndex + infoY;\n\n\t\t\t\t\tvar c1 = rightIndex;\n\t\t\t\t\tvar c2 = leftIndex;\n\t\t\t\t\t${ leftToRightSnippet }\n\n\t\t\t\t\tpointer = pointer + 1;\n\t\t\t\t\tstack[ pointer ] = c2;\n\n\t\t\t\t\tpointer = pointer + 1;\n\t\t\t\t\tstack[ pointer ] = c1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t`;\n\n\t};\n\n\tconst blasFn = wgslTagFn/* wgsl */`\n\t\t// fn\n\t\tfn ${ name }_blas( shape: ${ shapeStruct }, rootNodeIndex: u32, ${ resultPtrSnippet } ) -> bool {\n\n\t\t\tvar didHit = false;\n\t\t\t${ getFnBody( wgslTagCode/* wgsl */`\n\n\t\t\t\tdidHit = ${ intersectRangeFn }( shape, offset, count, ${ resultArg } ) || didHit;\n\n\t\t\t` ) }\n\n\t\t\treturn didHit;\n\n\t\t}\n\t`;\n\n\tconst tlasFn = wgslTagFn/* wgsl */`\n\t\t// fn\n\t\tfn ${ name }( shape: ${ shapeStruct }, ${ resultPtrSnippet } ) -> bool {\n\n\t\t\tconst rootNodeIndex = 0u;\n\t\t\tvar didHit = false;\n\t\t\t${ getFnBody( wgslTagCode/* wgsl */`\n\n\t\t\t\tfor ( var i = offset; i < offset + count; i ++ ) {\n\n\t\t\t\t\tlet transform = ${ transforms }[ i ];\n\t\t\t\t\tif ( transform.visible == 0u ) {\n\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Transform shape into object local space\n\t\t\t\t\tvar localShape = shape;\n\t\t\t\t\t${ transformShapeSnippet }\n\n\t\t\t\t\tif ( ${ blasFn }( localShape, transform.nodeOffset, ${ resultArg } ) ) {\n\n\t\t\t\t\t\t${ transformResultSnippet }\n\t\t\t\t\t\tdidHit = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t${ resetShapeSnippet }\n\n\t\t\t\t}\n\n\t\t\t` ) }\n\n\t\t\treturn didHit;\n\n\t\t}\n\t`;\n\n\ttlasFn.outputType = resultStruct;\n\ttlasFn.functionName = name;\n\n\treturn tlasFn;\n\n}\n","/** @import { FunctionNode } from 'three/tsl'; */\nimport { wgslTagFn } from '../nodes/WGSLTagFnNode.js';\nimport { rayIntersectionResultStruct, rayStruct } from './structs.js';\n\n/**\n * WGSL function node that finds the closest point on a triangle to `p` and returns the barycoord.\n * @type {FunctionNode}\n * @section TSL Functions\n */\nexport const closestPointToTriangle = wgslTagFn/* wgsl */`\n\t// fn\n\tfn closestPointToTriangle(\n\t\tp: vec3f,\n\t\tv0: vec3f,\n\t\tv1: vec3f,\n\t\tv2: vec3f\n\t) -> vec3f {\n\n\t\tlet v10 = v1 - v0;\n\t\tlet v21 = v2 - v1;\n\t\tlet v02 = v0 - v2;\n\t\tlet p0 = p - v0;\n\t\tlet p1 = p - v1;\n\t\tlet p2 = p - v2;\n\n\t\tlet nor = cross( v10, v02 );\n\t\tlet q = cross( nor, p0 );\n\t\tlet d = 1.0 / dot( nor, nor );\n\t\tvar u = d * dot( q, v02 );\n\t\tvar v = d * dot( q, v10 );\n\t\tvar w = 1.0 - u - v;\n\n\t\tif ( u < 0.0 ) {\n\n\t\t\tw = clamp( dot( p2, v02 ) / dot( v02, v02 ), 0.0, 1.0 );\n\t\t\tu = 0.0;\n\t\t\tv = 1.0 - w;\n\n\t\t} else if ( v < 0.0 ) {\n\n\t\t\tu = clamp( dot( p0, v10 ) / dot( v10, v10 ), 0.0, 1.0 );\n\t\t\tv = 0.0;\n\t\t\tw = 1.0 - u;\n\n\t\t} else if ( w < 0.0 ) {\n\n\t\t\tv = clamp( dot( p1, v21 ) / dot( v21, v21 ), 0.0, 1.0 );\n\t\t\tw = 0.0;\n\t\t\tu = 1.0 - v;\n\n\t\t}\n\n\t\treturn vec3f( w, u, v );\n\n\t}\n`;\n\n/**\n * WGSL function node that tests a ray against a single triangle and returns an\n * {@link rayIntersectionResultStruct} result. Useful when writing a custom `intersectRangeFn`\n * for {@link BVHComputeData#getShapecastFn}.\n * @type {FunctionNode}\n * @section TSL Functions\n */\nexport const intersectRayTriangle = wgslTagFn/* wgsl */ `\n\t// fn\n\tfn intersectRayTriangle( ray: ${ rayStruct }, a: vec3f, b: vec3f, c: vec3f, threshold: f32 ) -> ${ rayIntersectionResultStruct } {\n\n\t\tconst DET_EPSILON = 1e-15;\n\n\t\tvar result: ${ rayIntersectionResultStruct };\n\t\tresult.didHit = false;\n\n\t\tlet edge1 = b - a;\n\t\tlet edge2 = c - a;\n\t\tlet n = cross( edge1, edge2 );\n\n\t\tlet det = - dot( ray.direction, n );\n\t\tif ( abs( det ) < DET_EPSILON ) {\n\n\t\t\treturn result;\n\n\t\t}\n\n\t\tlet invdet = 1.0 / det;\n\n\t\tlet AO = ray.origin - a;\n\t\tlet DAO = cross( AO, ray.direction );\n\n\t\tlet u = dot( edge2, DAO ) * invdet;\n\t\tif ( u < 0.0 || u > 1.0 ) {\n\n\t\t\treturn result;\n\n\t\t}\n\n\t\tlet v = - dot( edge1, DAO ) * invdet;\n\t\tif ( v < 0.0 || u + v > 1.0 ) {\n\n\t\t\treturn result;\n\n\t\t}\n\n\t\tlet t = dot( AO, n ) * invdet;\n\t\tlet w = 1.0 - u - v;\n\t\tif ( t < threshold ) {\n\n\t\t\treturn result;\n\n\t\t}\n\n\t\tresult.didHit = true;\n\t\tresult.barycoord = vec3f( w, u, v );\n\t\tresult.dist = t;\n\t\tresult.side = sign( det );\n\t\tresult.normal = result.side * normalize( n );\n\n\t\treturn result;\n\n\t}\n`;\n\n/**\n * WGSL function node that builds a camera ray (origin + far-plane direction) from an NDC\n * coordinate and an inverse model-view-projection matrix. Works for both perspective and\n * orthographic projections. The returned direction is not normalized and extends to the\n * camera far plane.\n * @type {FunctionNode}\n * @section TSL Functions\n */\nexport const ndcToCameraRay = wgslTagFn/* wgsl */`\n\t// fn\n\tfn ndcToCameraRay( ndc: vec2f, inverseModelViewProjection: mat4x4f ) -> ${ rayStruct } {\n\n\t\tvar homogeneous = vec4f();\n\t\tvar ray: ${ rayStruct };\n\n\t\thomogeneous = inverseModelViewProjection * vec4f( ndc, 0.0, 1.0 );\n\t\tray.origin = homogeneous.xyz / homogeneous.w;\n\n\t\thomogeneous = inverseModelViewProjection * vec4f( ndc, 1.0, 1.0 );\n\t\tray.direction = ( homogeneous.xyz / homogeneous.w ) - ray.origin;\n\n\t\treturn ray;\n\n\t}\n`;\n","/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { float } from 'three/tsl';\nimport { wgslTagFn } from '../nodes/WGSLTagFnNode.js';\nimport { rayStruct, rayIntersectionResultStruct, bvhNodeStruct, bvhNodeBoundsStruct } from '../tsl/structs.js';\nimport { intersectRayTriangle } from '../tsl/fns.js';\n\n/**\n * Builds the `raycastFirstHit` shapecast function: traverses the BVH front to back and returns the\n * closest ray / triangle intersection.\n *\n * @private\n * @param {BVHComputeData} bvhData\n * @returns {Function} TSL function node for the TLAS traversal.\n */\nexport function getRaycastFirstHitFn( bvhData ) {\n\n\t// these are proxy nodes, so they can be referenced before the storage buffers exist\n\tconst { index, attributes, transforms } = bvhData.storage;\n\n\tconst scratchRayScalar = float( 1.0 ).toVar( `bvh_rayScalar_${ Math.random().toString( 36 ).substring( 2, 7 ) }` );\n\n\treturn bvhData.getShapecastFn( {\n\t\tname: 'bvh_RaycastFirstHit',\n\t\tshapeStruct: rayStruct,\n\t\tresultStruct: rayIntersectionResultStruct,\n\n\t\tboundsOrderFn: wgslTagFn/* wgsl */`\n\t\t\tfn getBoundsOrder( ray: ${ rayStruct }, splitAxis: u32, node: ${ bvhNodeStruct } ) -> bool {\n\n\t\t\t\treturn ray.direction[ splitAxis ] >= 0.0;\n\n\t\t\t}\n\t\t`,\n\t\tintersectsBoundsFn: wgslTagFn/* wgsl */`\n\t\t\tfn rayIntersectsBounds( ray: ${ rayStruct }, bounds: ${ bvhNodeBoundsStruct }, result: ptr<function, ${ rayIntersectionResultStruct }> ) -> u32 {\n\n\t\t\t\tlet boundsMin = vec3( bounds.min[0], bounds.min[1], bounds.min[2] );\n\t\t\t\tlet boundsMax = vec3( bounds.max[0], bounds.max[1], bounds.max[2] );\n\n\t\t\t\tlet invDir = 1.0 / ray.direction;\n\t\t\t\tlet tMinPlane = ( boundsMin - ray.origin ) * invDir;\n\t\t\t\tlet tMaxPlane = ( boundsMax - ray.origin ) * invDir;\n\n\t\t\t\tlet tMinHit = vec3f(\n\t\t\t\t\tmin( tMinPlane.x, tMaxPlane.x ),\n\t\t\t\t\tmin( tMinPlane.y, tMaxPlane.y ),\n\t\t\t\t\tmin( tMinPlane.z, tMaxPlane.z )\n\t\t\t\t);\n\n\t\t\t\tlet tMaxHit = vec3f(\n\t\t\t\t\tmax( tMinPlane.x, tMaxPlane.x ),\n\t\t\t\t\tmax( tMinPlane.y, tMaxPlane.y ),\n\t\t\t\t\tmax( tMinPlane.z, tMaxPlane.z )\n\t\t\t\t);\n\n\t\t\t\tlet t0 = max( max( tMinHit.x, tMinHit.y ), tMinHit.z );\n\t\t\t\tlet t1 = min( min( tMaxHit.x, tMaxHit.y ), tMaxHit.z );\n\n\t\t\t\tlet dist = max( t0, 0.0 );\n\t\t\t\tif ( t1 < dist ) {\n\n\t\t\t\t\treturn 0u;\n\n\t\t\t\t} else if ( result.didHit && dist * ${ scratchRayScalar } >= result.dist ) {\n\n\t\t\t\t\treturn 0u;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn 1u;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t`,\n\t\tintersectRangeFn: wgslTagFn/* wgsl */`\n\t\t\tfn intersectRange( ray: ${ rayStruct }, offset: u32, count: u32, result: ptr<function, ${ rayIntersectionResultStruct }> ) -> bool {\n\n\t\t\t\tvar didHit = false;\n\t\t\t\tfor ( var ti = offset; ti < offset + count; ti = ti + 1u ) {\n\n\t\t\t\t\tlet i0 = ${ index }[ ti * 3u ];\n\t\t\t\t\tlet i1 = ${ index }[ ti * 3u + 1u ];\n\t\t\t\t\tlet i2 = ${ index }[ ti * 3u + 2u ];\n\n\t\t\t\t\tlet a = ${ attributes }[ i0 ].position.xyz;\n\t\t\t\t\tlet b = ${ attributes }[ i1 ].position.xyz;\n\t\t\t\t\tlet c = ${ attributes }[ i2 ].position.xyz;\n\n\t\t\t\t\tvar triResult = ${ intersectRayTriangle }( ray, a, b, c, 0.0 );\n\t\t\t\t\ttriResult.dist *= ${ scratchRayScalar };\n\t\t\t\t\tif ( triResult.didHit && ( ! result.didHit || triResult.dist < result.dist ) ) {\n\n\t\t\t\t\t\tresult.didHit = true;\n\t\t\t\t\t\tresult.dist = triResult.dist;\n\t\t\t\t\t\tresult.normal = triResult.normal;\n\t\t\t\t\t\tresult.side = triResult.side;\n\t\t\t\t\t\tresult.barycoord = triResult.barycoord;\n\t\t\t\t\t\tresult.indices = vec4u( i0, i1, i2, ti );\n\n\t\t\t\t\t\tdidHit = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn didHit;\n\n\t\t\t}\n\t\t`,\n\t\ttransformShapeFn: wgslTagFn/* wgsl */`\n\t\t\tfn transformRay( ray: ptr<function, ${ rayStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\tlet toLocal = ${ transforms }[ objectIndex ].inverseMatrixWorld;\n\t\t\t\tray.origin = ( toLocal * vec4f( ray.origin, 1.0 ) ).xyz;\n\t\t\t\tray.direction = ( toLocal * vec4f( ray.direction, 0.0 ) ).xyz;\n\n\t\t\t\tlet len = length( ray.direction );\n\t\t\t\tray.direction /= len;\n\t\t\t\t${ scratchRayScalar } = 1.0 / len;\n\n\t\t\t}\n\t\t`,\n\t\ttransformResultFn: wgslTagFn/* wgsl */`\n\t\t\tfn transformResult( hit: ptr<function, ${ rayIntersectionResultStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\tlet toLocal = ${ transforms }[ objectIndex ].inverseMatrixWorld;\n\t\t\t\thit.normal = normalize( ( transpose( toLocal ) * vec4f( hit.normal, 0.0 ) ).xyz );\n\t\t\t\thit.objectIndex = objectIndex;\n\n\t\t\t}\n\t\t`,\n\t\tresetShapeFn: wgslTagFn/* wgsl */`\n\t\t\tfn resetRayScalar( objectIndex: u32 ) -> void {\n\n\t\t\t\t${ scratchRayScalar } = 1.0;\n\n\t\t\t}\n\t\t`,\n\t} );\n\n}\n","/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { wgslTagFn } from '../nodes/WGSLTagFnNode.js';\n\n/**\n * Builds the `sampleTrianglePoint` function: interpolates the per-vertex attributes of a triangle\n * at the given barycentric coordinate. The body emits one line per attribute, so this must be built\n * after `update` has resolved the attribute struct.\n *\n * @private\n * @param {BVHComputeData} bvhData\n * @returns {Function} TSL function node.\n */\nexport function getSampleTrianglePointFn( bvhData ) {\n\n\tconst { storage, structs } = bvhData;\n\n\tconst interpolateBody = structs\n\t\t.attributes\n\t\t.membersLayout\n\t\t.map( ( { name } ) => {\n\n\t\t\treturn `result.${ name } = a0.${ name } * barycoord.x + a1.${ name } * barycoord.y + a2.${ name } * barycoord.z;`;\n\n\t\t} ).join( '\\n' );\n\n\treturn wgslTagFn/* wgsl */`\n\t\t// fn\n\t\tfn bvh_sampleTrianglePoint( barycoord: vec3f, indices: vec3u ) -> ${ structs.attributes } {\n\n\t\t\tvar result: ${ structs.attributes };\n\t\t\tvar a0 = ${ storage.attributes }[ indices.x ];\n\t\t\tvar a1 = ${ storage.attributes }[ indices.y ];\n\t\t\tvar a2 = ${ storage.attributes }[ indices.z ];\n\t\t\t${ interpolateBody }\n\t\t\treturn result;\n\n\t\t}\n\t`;\n\n}\n","/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { mat4 } from 'three/tsl';\nimport { wgslTagFn } from '../nodes/WGSLTagFnNode.js';\nimport { bvhNodeStruct, bvhNodeBoundsStruct, pointQueryResultStruct } from '../tsl/structs.js';\nimport { closestPointToTriangle } from '../tsl/fns.js';\n\n/**\n * Builds the `closestPointToPoint` shapecast function: finds the closest point on any triangle in\n * the BVH to the given query point.\n *\n * @private\n * @param {BVHComputeData} bvhData\n * @returns {Function} TSL function node for the TLAS traversal.\n */\nexport function getClosestPointToPointFn( bvhData ) {\n\n\t// these are proxy nodes, so they can be referenced before the storage buffers exist\n\tconst { index, attributes, transforms } = bvhData.storage;\n\n\tconst scratchToWorldMat = mat4().toVar( 'bvh_toWorldMat' );\n\n\treturn bvhData.getShapecastFn( {\n\t\tname: 'bvh_ClosestPointToPoint',\n\t\tshapeStruct: 'vec3f',\n\t\tresultStruct: pointQueryResultStruct,\n\n\t\tboundsOrderFn: wgslTagFn/* wgsl */`\n\t\t\tfn cppBoundsOrder( shape: vec3f, splitAxis: u32, node: ${ bvhNodeStruct } ) -> bool {\n\n\t\t\t\tlet toWorld = ${ scratchToWorldMat };\n\n\t\t\t\t// get center\n\t\t\t\tlet bMin = vec3f( node.bounds.min[ 0 ], node.bounds.min[ 1 ], node.bounds.min[ 2 ] );\n\t\t\t\tlet bMax = vec3f( node.bounds.max[ 0 ], node.bounds.max[ 1 ], node.bounds.max[ 2 ] );\n\t\t\t\tlet center = bMin * 0.5 + bMax * 0.5;\n\n\t\t\t\t// determine the order in world space\n\t\t\t\tlet worldCenter = ( toWorld * vec4f( center, 1.0 ) ).xyz;\n\t\t\t\tlet worldAxis = normalize( toWorld[ splitAxis ].xyz );\n\t\t\t\treturn dot( shape - worldCenter, worldAxis ) <= 0.0;\n\n\t\t\t}\n\t\t`,\n\n\t\tintersectsBoundsFn: wgslTagFn/* wgsl */`\n\t\t\tfn cppIntersectsBounds( shape: vec3f, bounds: ${ bvhNodeBoundsStruct }, result: ptr<function, ${ pointQueryResultStruct }> ) -> u32 {\n\n\t\t\t\t// return 1u;\n\t\t\t\t// we need to check this no matter what if the result has not been found yet\n\t\t\t\tif ( ! result.found ) {\n\n\t\t\t\t\treturn 1u;\n\n\t\t\t\t}\n\n\t\t\t\tlet toWorld = ${ scratchToWorldMat };\n\n\t\t\t\t// transform to world space\n\t\t\t\tlet bMin = vec3f( bounds.min[ 0 ], bounds.min[ 1 ], bounds.min[ 2 ] );\n\t\t\t\tlet bMax = vec3f( bounds.max[ 0 ], bounds.max[ 1 ], bounds.max[ 2 ] );\n\t\t\t\tlet center = ( bMin + bMax ) * 0.5;\n\t\t\t\tlet halfExtent = ( bMax - bMin ) * 0.5;\n\t\t\t\tlet worldCenter = ( toWorld * vec4f( center, 1.0 ) ).xyz;\n\t\t\t\tlet worldHalfExtent =\n\t\t\t\t\tabs( toWorld[ 0 ].xyz ) * halfExtent.x +\n\t\t\t\t abs( toWorld[ 1 ].xyz ) * halfExtent.y +\n\t\t\t\t abs( toWorld[ 2 ].xyz ) * halfExtent.z;\n\t\t\t\tlet worldMin = worldCenter - worldHalfExtent;\n\t\t\t\tlet worldMax = worldCenter + worldHalfExtent;\n\n\t\t\t\t// intersect if the distance to the bounds is not bigger than the already found\n\t\t\t\tlet d = shape - clamp( shape, worldMin, worldMax );\n\t\t\t\treturn select( 0u, 1u, dot( d, d ) < result.distanceSq );\n\n\t\t\t}\n\t\t`,\n\n\t\tintersectRangeFn: wgslTagFn /* wgsl */`\n\t\t\tfn cppIntersectsRange( shape: vec3f, offset: u32, count: u32, result: ptr<function, ${ pointQueryResultStruct }> ) -> bool {\n\n\t\t\t\tvar didHit = false;\n\t\t\t\tlet toWorld = ${ scratchToWorldMat };\n\n\t\t\t\tfor ( var i = offset; i < offset + count; i ++ ) {\n\n\t\t\t\t\t// transform the triangle to world space\n\t\t\t\t\tlet i0 = ${ index }[ i * 3u + 0u ];\n\t\t\t\t\tlet i1 = ${ index }[ i * 3u + 1u ];\n\t\t\t\t\tlet i2 = ${ index }[ i * 3u + 2u ];\n\t\t\t\t\tlet a = ( toWorld * vec4f( ${ attributes }[ i0 ].position.xyz, 1.0 ) ).xyz;\n\t\t\t\t\tlet b = ( toWorld * vec4f( ${ attributes }[ i1 ].position.xyz, 1.0 ) ).xyz;\n\t\t\t\t\tlet c = ( toWorld * vec4f( ${ attributes }[ i2 ].position.xyz, 1.0 ) ).xyz;\n\n\t\t\t\t\tlet barycoord = ${ closestPointToTriangle }( shape, a, b, c );\n\t\t\t\t\tlet closestPoint = barycoord.x * a + barycoord.y * b + barycoord.z * c;\n\t\t\t\t\tlet delta = shape - closestPoint;\n\t\t\t\t\tlet distSq = dot( delta, delta );\n\n\t\t\t\t\t// copy the content over\n\t\t\t\t\tif ( ! result.found || distSq < result.distanceSq ) {\n\n\t\t\t\t\t\tlet normal = normalize( cross( a - b, b - c ) );\n\n\t\t\t\t\t\tresult.closestPoint = closestPoint;\n\t\t\t\t\t\tresult.barycoord = barycoord;\n\t\t\t\t\t\tresult.distanceSq = distSq;\n\t\t\t\t\t\tresult.faceNormal = normal;\n\t\t\t\t\t\tresult.side = sign( dot( normal, delta ) );\n\t\t\t\t\t\tresult.faceIndices = vec4u( i0, i1, i2, i );\n\t\t\t\t\t\tresult.found = true;\n\t\t\t\t\t\tdidHit = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn didHit;\n\n\t\t\t}\n\t\t`,\n\n\t\ttransformShapeFn: wgslTagFn/* wgsl */`\n\t\t\tfn cppTransformShape( shape: ptr<function, vec3f>, objectIndex: u32 ) -> void {\n\n\t\t\t\t${ scratchToWorldMat } = ${ transforms }[ objectIndex ].matrixWorld;\n\n\t\t\t}\n\t\t`,\n\n\t\ttransformResultFn: wgslTagFn/* wgsl */`\n\t\t\tfn cppTransformResult( result: ptr<function, ${ pointQueryResultStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\tresult.objectIndex = objectIndex;\n\n\t\t\t}\n\t\t`,\n\t} );\n\n}\n","/** @import { Object3D, BufferGeometry, Vector4 } from 'three' */\nimport { Matrix4 } from 'three';\nimport { StorageBufferAttribute, StructTypeNode } from 'three/webgpu';\nimport { storage } from 'three/tsl';\nimport { MeshBVH } from 'three-mesh-bvh/src/core/MeshBVH.js';\nimport { SkinnedMeshBVH } from 'three-mesh-bvh/src/core/SkinnedMeshBVH.js';\nimport { GeometryBVH } from 'three-mesh-bvh/src/core/GeometryBVH.js';\nimport { ObjectBVH } from 'three-mesh-bvh/src/core/ObjectBVH.js';\nimport { BYTES_PER_NODE } from 'three-mesh-bvh/src/core/Constants.js';\nimport { proxy, proxyFn } from './nodes/NodeProxy.js';\nimport {\n\tbvhNodeStruct,\n\ttransformStruct,\n} from './tsl/structs.js';\nimport { toObjectBVH } from './utils/toObjectBVH.js';\nimport { appendBVHData, appendIndexData, appendGeometryData } from './utils/packBVHBufferUtils.js';\nimport { getShapecastFn } from './shapecastFns/getShapecastFn.js';\nimport { getRaycastFirstHitFn } from './shapecastFns/getRaycastFirstHitFn.js';\nimport { getSampleTrianglePointFn } from './shapecastFns/getSampleTrianglePointFn.js';\nimport { getClosestPointToPointFn } from './shapecastFns/getClosestPointToPointFn.js';\n\n// TODO: add ability to easily update a single matrix / scene rearrangement (partial update)\n// TODO: add material support w/ function to easily update material\n// \t\t- add a callback for writing a property for a geometry to a range\n// TODO: Add support for other geometry types (tris, lines, custom BVHs etc)\n\n// scratch\nconst _matrix = /* @__PURE__ */ new Matrix4();\nconst _inverseMatrix = /* @__PURE__ */ new Matrix4();\n\n// functions\nfunction isObjectVisible( object ) {\n\n\tlet curr = object;\n\twhile ( curr ) {\n\n\t\tif ( curr.visible === false ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tcurr = curr.parent;\n\n\t}\n\n\treturn true;\n\n}\n\nfunction getTotalBVHByteLength( bvh ) {\n\n\treturn bvh._roots.reduce( ( v, root ) => v + root.byteLength, 0 );\n\n}\n\n/**\n * Packs one or more scene objects into GPU-accessible BVH buffers (TLAS + BLAS) for use\n * in WebGPU compute shaders via the Three.js TSL node system. After construction, call\n * {@link BVHComputeData#update} to populate the storage buffers, then reference\n * `this.storage` and `this.fns` in your compute shader nodes.\n *\n * @note This API is unstable and subject to change in future releases.\n *\n * @note This class requires three.js r185 or higher.\n */\nexport class BVHComputeData {\n\n\t/**\n\t * @param {ObjectBVH|Object3D|BufferGeometry|GeometryBVH|Array} bvh\n\t * Scene objects to include, or a pre-built {@link ObjectBVH}. A single item or array of\n\t * Object3D, BufferGeometry, or GeometryBVH instances are all accepted and wrapped\n\t * automatically in an ObjectBVH.\n\t * @param {Object} [options]\n\t * @param {Record<string,string>} [options.attributes={ position: 'vec4f' }]\n\t * WGSL type map for the interleaved per-vertex attribute buffer. Keys are geometry\n\t * attribute names; values are WGSL type strings (e.g. `'vec3f'`, `'vec4f'`).\n\t * @param {boolean} [options.autogenerateBvh=true]\n\t * When true, a {@link MeshBVH} is automatically built for any object that does not\n\t * already have `geometry.boundsTree` set.\n\t */\n\tconstructor( bvh, options = {} ) {\n\n\t\t// convert the bvh argument to an ObjectBVH. Supports an Object3D, BufferGeometry,\n\t\t// GeometryBVH, an array of the above, or a pre-built ObjectBVH.\n\t\tbvh = toObjectBVH( bvh );\n\n\t\tconst {\n\t\t\tattributes = { position: 'vec4f' },\n\t\t\tautogenerateBvh = true,\n\t\t} = options;\n\n\t\tthis._bvhCache = new Map();\n\n\t\tthis.autogenerateBvh = autogenerateBvh;\n\t\tthis.attributes = attributes;\n\t\tthis.bvh = bvh;\n\n\t\t// storage buffers and structs are populated in \"update\"; their members are accessed through\n\t\t// proxy nodes so the functions below can reference them up front and keep working across rebuilds\n\t\tthis.storage = new NodeProxyObject();\n\t\tthis.structs = new NodeProxyObject( { transform: transformStruct } );\n\t\tthis.fns = new NodeProxyObject( {\n\t\t\traycastFirstHit: getRaycastFirstHitFn( this ),\n\t\t\tclosestPointToPoint: getClosestPointToPointFn( this ),\n\t\t\tsampleTrianglePoint: null,\n\t\t}, proxyFn );\n\n\t}\n\n\t/**\n\t * Builds a pair of WGSL shapecast functions (BLAS + TLAS traversal) for a custom shape\n\t * type. The returned TLAS function signature is:\n\t * `fn name( shape: ShapeStruct[, result: ptr<function, ResultStruct>] ) -> bool`\n\t *\n\t * @param {Object} options\n\t * @param {string} [options.name] - Function name. Defaults to a random identifier.\n\t * @param {StructTypeNode} options.shapeStruct - TSL struct or definition describing the query shape.\n\t * @param {StructTypeNode|null} [options.resultStruct] - TSL struct for the accumulated result, or null.\n\t * @param {Function|null} [options.boundsOrderFn] - function node controlling left/right child traversal order.\n\t * @param {Function} options.intersectsBoundsFn - function node testing the shape against a BVH node's bounds.\n\t * @param {Function} options.intersectRangeFn - function node testing the shape against a leaf triangle range.\n\t * @param {Function|null} [options.transformShapeFn] - function node that transforms the shape into object local space.\n\t * @param {Function|null} [options.transformResultFn] - function node that transforms a hit result back to world space.\n\t * @param {Function|null} [options.resetShapeFn] - function node called after each BLAS traversal to reset any per-object state set by `transformShapeFn`.\n\t * @returns {Function} TSL function node for the TLAS traversal.\n\t */\n\tgetShapecastFn( options ) {\n\n\t\treturn getShapecastFn( this, options );\n\n\t}\n\n\t/**\n\t * Rebuilds all GPU storage buffers from the current scene state. Must be called at least\n\t * once before using `this.storage` or `this.fns` in a shader, and again whenever the\n\t * scene topology changes (objects added/removed, geometry modified).\n\t */\n\tupdate() {\n\n\t\t// free any buffers from a previous update before swapping in the new ones\n\t\tthis.dispose();\n\n\t\tconst { attributes, structs, bvh } = this;\n\n\t\t// collect the BVHs\n\t\tconst bvhInfo = [];\n\t\tconst transformInfo = [];\n\n\t\t// accumulate the sizes of the bvh nodes buffer, number of objects, and geometry buffers\n\t\tlet bvhNodesBufferLength = getTotalBVHByteLength( bvh );\n\t\tlet indexBufferLength = 0;\n\t\tlet attributesBufferLength = 0;\n\t\tbvh.primitiveBuffer.forEach( compositeId => {\n\n\t\t\tconst object = bvh.getObjectFromId( compositeId );\n\t\t\tconst instanceId = bvh.getInstanceFromId( compositeId );\n\t\t\tconst range = { start: 0, count: 0, vertexStart: 0, vertexCount: 0 };\n\t\t\tconst primBvh = this.getBVH( object, instanceId, range );\n\n\t\t\tif ( ! primBvh ) {\n\n\t\t\t\tthrow new Error( 'BVHComputeData: BVH not found.' );\n\n\t\t\t}\n\n\t\t\t// if we haven't added this bvh, yet\n\t\t\tif ( ! bvhInfo.find( info => info.bvh === primBvh ) ) {\n\n\t\t\t\t// save the geometry info to write later and increment the buffer sizes\n\t\t\t\tconst info = {\n\t\t\t\t\tindex: bvhInfo.length,\n\t\t\t\t\tbvh: primBvh,\n\t\t\t\t\trange: range,\n\n\t\t\t\t\tbvhNodeOffsets: null,\n\t\t\t\t\tindexBufferOffset: null,\n\n\t\t\t\t};\n\n\t\t\t\t// increase the buffer sizes for bvh and geometry\n\t\t\t\tbvhNodesBufferLength += getTotalBVHByteLength( primBvh );\n\t\t\t\tindexBufferLength += info.range.count;\n\t\t\t\tattributesBufferLength += info.range.vertexCount;\n\t\t\t\tbvhInfo.push( info );\n\n\t\t\t}\n\n\t\t\t// save the index of the bvh associated with this transform\n\t\t\tconst data = bvhInfo.find( info => primBvh === info.bvh );\n\t\t\tprimBvh._roots.forEach( ( root, i ) => {\n\n\t\t\t\ttransformInfo.push( {\n\t\t\t\t\tdata,\n\t\t\t\t\troot: i,\n\t\t\t\t\tobject,\n\t\t\t\t\tinstanceId,\n\t\t\t\t\tcompositeId,\n\t\t\t\t} );\n\n\t\t\t} );\n\n\t\t} );\n\n\t\t//\n\n\t\t// @note These buffer lengths are increased to a minimum size of 2 to avoid TSL converting storage buffers\n\t\t// with length 1 being converted to a scalar value.\n\t\t// TODO: remove this when fixed in three\n\t\tconst transformBufferLength = Math.max( transformInfo.length, 2 );\n\t\tindexBufferLength = Math.max( indexBufferLength, 2 );\n\t\tattributesBufferLength = Math.max( attributesBufferLength, 2 );\n\n\t\t// construct the attribute struct\n\t\tconst attributeStruct = new StructTypeNode( attributes, 'bvh_GeometryStruct' );\n\n\t\t// write the geometry buffer attributes & bvh data\n\t\tlet attributesOffset = 0;\n\t\tlet indexOffset = 0;\n\t\tlet nodeWriteOffset = 0;\n\t\tconst indexBuffer = new Uint32Array( indexBufferLength );\n\t\tconst attributesBuffer = new ArrayBuffer( attributesBufferLength * attributeStruct.getLength() * 4 );\n\t\tconst bvhNodesBuffer = new ArrayBuffer( bvhNodesBufferLength );\n\n\t\t// append TLAS data\n\t\tappendBVHData( bvh, 0, transformInfo, 0, bvhNodesBuffer, true );\n\t\tnodeWriteOffset += getTotalBVHByteLength( bvh ) / BYTES_PER_NODE;\n\t\tbvhInfo.forEach( info => {\n\n\t\t\t// append bvh data\n\t\t\tconst bvhNodeOffsets = appendBVHData( info.bvh, indexOffset / 3, transformInfo, nodeWriteOffset, bvhNodesBuffer, false );\n\t\t\tinfo.bvhNodeOffsets = bvhNodeOffsets;\n\n\t\t\t// append geometry data\n\t\t\tappendIndexData( info.bvh, info.range, attributesOffset, indexOffset, indexBuffer );\n\t\t\tappendGeometryData( info.bvh, info.range, attributesOffset, attributesBuffer, attributeStruct, this );\n\t\t\tinfo.indexBufferOffset = indexOffset;\n\n\t\t\t// step the write offsets forward\n\t\t\tindexOffset += info.range.count;\n\t\t\tattributesOffset += info.range.vertexCount;\n\t\t\tnodeWriteOffset += getTotalBVHByteLength( info.bvh ) / BYTES_PER_NODE;\n\n\t\t} );\n\n\t\t//\n\n\t\t// write the transforms\n\t\tconst transformArrayBuffer = new ArrayBuffer( structs.transform.getLength() * transformBufferLength * 4 );\n\t\ttransformInfo.forEach( ( info, i ) => {\n\n\t\t\t_inverseMatrix.copy( bvh.matrixWorld ).invert();\n\t\t\tthis.writeTransformData( info, _inverseMatrix, i, transformArrayBuffer );\n\n\t\t} );\n\n\t\t//\n\n\t\t// set up the storage buffers\n\t\t// if itemSize for StorageBufferAttribute == arraySize,\n\t\t// then buffer is treated not as array of structs, but as a single struct\n\t\t// And that breaks code. For now itemSize = 1 does not seem to break anything\n\t\tconst bvhNodesStorage = storage( new StorageBufferAttribute( new Uint32Array( bvhNodesBuffer ), 1 ), bvhNodeStruct ).toReadOnly().setName( 'bvh_nodes' );\n\t\tconst transformsBuffer = new StorageBufferAttribute( new Uint32Array( transformArrayBuffer ), 1 );\n\t\tconst transformsStorage = storage( transformsBuffer, structs.transform ).toReadOnly().setName( 'bvh_transforms' );\n\t\tconst indexStorage = storage( new StorageBufferAttribute( indexBuffer, 1 ), 'uint' ).toReadOnly().setName( 'bvh_index' );\n\t\tconst attributesStorage = storage( new StorageBufferAttribute( new Uint32Array( attributesBuffer ), attributeStruct.getLength() ), attributeStruct ).toReadOnly().setName( 'bvh_attributes' );\n\n\t\tthis.storage.transforms = transformsStorage;\n\t\tthis.storage.nodes = bvhNodesStorage;\n\t\tthis.storage.index = indexStorage;\n\t\tthis.storage.attributes = attributesStorage;\n\t\tthis.structs.attributes = attributeStruct;\n\n\t\t// depends on the resolved attribute struct, so it must be built here rather than up front\n\t\tthis.fns.sampleTrianglePoint = getSampleTrianglePointFn( this );\n\n\t\tthis._bvhCache.clear();\n\n\t}\n\n\t/**\n\t * Writes the world/inverse-world matrices, node offset, and visibility flag for one\n\t * transform entry into a raw ArrayBuffer. Override this in a subclass to inject\n\t * additional per-object data (e.g. material index).\n\t *\n\t * @private\n\t * @param {Object3D} info - Transform entry from the internal transform info array.\n\t * @param {Matrix4} premultiplyMatrix - Matrix pre-multiplied onto the object's world matrix (usually the inverse TLAS root matrix).\n\t * @param {number} writeOffset - Index of the transform slot to write into.\n\t * @param {ArrayBuffer} targetBuffer - Destination buffer.\n\t */\n\twriteTransformData( info, premultiplyMatrix, writeOffset, targetBuffer ) {\n\n\t\tconst { structs } = this;\n\t\tconst transformBufferF32 = new Float32Array( targetBuffer );\n\t\tconst transformBufferU32 = new Uint32Array( targetBuffer );\n\n\t\tconst { object, instanceId, root, data } = info;\n\t\tconst { bvhNodeOffsets } = data;\n\t\tif ( object.isInstancedMesh || object.isBatchedMesh ) {\n\n\t\t\tobject.getMatrixAt( instanceId, _matrix );\n\t\t\t_matrix.premultiply( object.matrixWorld );\n\n\t\t} else {\n\n\t\t\t_matrix.copy( object.matrixWorld );\n\n\t\t}\n\n\t\t// write transform\n\t\t_matrix.premultiply( premultiplyMatrix );\n\t\t_matrix.toArray( transformBufferF32, writeOffset * structs.transform.getLength() );\n\n\t\t// write inverse transform\n\t\t_matrix.invert();\n\t\t_matrix.toArray( transformBufferF32, writeOffset * structs.transform.getLength() + 16 );\n\n\t\t// write node offset\n\t\ttransformBufferU32[ writeOffset * structs.transform.getLength() + 32 ] = bvhNodeOffsets[ root ];\n\n\t\tlet visible = isObjectVisible( object );\n\t\tif ( object.isBatchedMesh ) {\n\n\t\t\tvisible = visible && object.getVisibleAt( instanceId );\n\n\t\t}\n\n\t\ttransformBufferU32[ writeOffset * structs.transform.getLength() + 33 ] = visible ? 1 : 0;\n\n\t}\n\n\t/**\n\t * Returns the BVH for a given object/instance, populating `rangeTarget` with the\n\t * corresponding index and vertex ranges within the packed geometry buffers. Override\n\t * to support custom BVH types or caching strategies.\n\t *\n\t * @private\n\t * @param {Object3D} object - The object to generate a BVH for.\n\t * @param {number} instanceId - Instance index (relevant for InstancedMesh / BatchedMesh).\n\t * @param {{start:number,count:number,vertexStart:number,vertexCount:number}} rangeTarget - Populated with the object's geometry range.\n\t * @returns {MeshBVH|SkinnedMeshBVH|null}\n\t */\n\tgetBVH( object, instanceId, rangeTarget ) {\n\n\t\tconst { autogenerateBvh, _bvhCache } = this;\n\n\t\tlet bvh = null;\n\t\tif ( object.boundsTree || object.isSkinnedMesh ) {\n\n\t\t\t// this is a case where a mesh has morph targets and skinned meshes\n\t\t\tconst geometry = object.geometry;\n\t\t\trangeTarget.count = geometry.index ? geometry.index.count : geometry.attributes.position.count;\n\t\t\trangeTarget.vertexCount = geometry.attributes.position.count;\n\t\t\tbvh = object.boundsTree || null;\n\n\t\t\tif ( bvh === null && autogenerateBvh ) {\n\n\t\t\t\tconst id = object.uuid;\n\t\t\t\tbvh = _bvhCache.get( id ) || new SkinnedMeshBVH( object );\n\t\t\t\t_bvhCache.set( id, bvh );\n\n\t\t\t}\n\n\t\t} else if ( object.isBatchedMesh ) {\n\n\t\t\tconst geometryId = object.getGeometryIdAt( instanceId );\n\t\t\tconst range = object.getGeometryRangeAt( geometryId );\n\t\t\tObject.assign( rangeTarget, range );\n\t\t\tbvh = object.boundsTrees[ geometryId ] || null;\n\n\t\t\tif ( bvh === null && autogenerateBvh ) {\n\n\t\t\t\tconst id = `batched_${ object.geometry.uuid }_${ range.start }_${ range.count }`;\n\t\t\t\tbvh = _bvhCache.get( id ) || new MeshBVH( object.geometry, { range: { ...rangeTarget } } );\n\t\t\t\t_bvhCache.set( id, bvh );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst geometry = object.geometry;\n\t\t\trangeTarget.count = geometry.index ? geometry.index.count : geometry.attributes.position.count;\n\t\t\trangeTarget.vertexCount = geometry.attributes.position.count;\n\t\t\tbvh = object.geometry.boundsTree || null;\n\n\t\t\tif ( bvh === null && autogenerateBvh ) {\n\n\t\t\t\tconst id = geometry.uuid;\n\t\t\t\tbvh = _bvhCache.get( id ) || new MeshBVH( geometry );\n\t\t\t\t_bvhCache.set( id, bvh );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn bvh;\n\n\t}\n\n\t/**\n\t * Returns the default vec4 value written to the attribute buffer for vertices that lack\n\t * a given attribute. Override to change per-attribute defaults.\n\t *\n\t * @private\n\t * @param {string} key - Attribute name (e.g. `'position'`, `'normal'`).\n\t * @param {Vector4} target - Receives the default value.\n\t * @returns {Vector4}\n\t */\n\tgetDefaultAttributeValue( key, target ) {\n\n\t\tswitch ( key ) {\n\n\t\t\tcase 'position':\n\t\t\tcase 'color':\n\t\t\t\ttarget.set( 1, 1, 1, 1 );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\ttarget.set( 0, 0, 0, 0 );\n\n\t\t}\n\n\t\treturn target;\n\n\t}\n\n\t/**\n\t * Releases GPU resources held by this instance.\n\t */\n\tdispose() {\n\n\t\tconst { storage } = this;\n\t\tfor ( const key in storage ) {\n\n\t\t\tstorage[ key ].value?.dispose();\n\t\t\tdelete storage[ key ];\n\n\t\t}\n\n\t}\n\n}\n\n\n// A container whose string members are returned as stable proxy nodes. Assigning a member stores\n// the underlying node.\n// TODO: we should automatically infer a proxy node vs fn. Perhaps in r185 we won't need the difference?\nclass NodeProxyObject {\n\n\tconstructor( initialization = {}, createProxy = proxy ) {\n\n\t\tconst proxies = {};\n\n\t\t// the raw backing object holds the underlying nodes and is the proxy target. \"createProxy\"\n\t\t// selects the proxy variant - \"proxy\" for plain nodes, \"proxyFn\" for callable function nodes.\n\t\treturn new Proxy( { ...initialization }, {\n\n\t\t\tget( target, property ) {\n\n\t\t\t\tif ( ! proxies[ property ] ) {\n\n\t\t\t\t\tproxies[ property ] = createProxy( property, target );\n\n\t\t\t\t}\n\n\t\t\t\treturn proxies[ property ];\n\n\t\t\t},\n\n\t\t\tset( target, property, value ) {\n\n\t\t\t\ttarget[ property ] = value;\n\t\t\t\treturn true;\n\n\t\t\t},\n\n\t\t} );\n\n\t}\n\n}\n","import { MeshBasicNodeMaterial, NoToneMapping, StorageTexture } from 'three/webgpu';\nimport { uv, varying, texture, vec4, toneMapping, uniform, wgslFn } from 'three/tsl';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\n// TODO: we could fall back to hardware-based filtering if available but it has to be specifically\n// requested and available on the renderer which we don't have access to immediately. It's possible this\n// can be detected during build time via a custom node to adjust the sample approach used?\nconst sampleTexelFn = wgslFn( /* wgsl */`\n\tfn sampleTexel( tex: texture_2d<f32>, coord: vec2f ) -> vec4f {\n\n\t\t// Manual bilinear filtering using textureLoad to support filterable float32 textures\n\t\t// on all devices\n\t\tlet size = vec2f( textureDimensions( tex, 0 ) );\n\t\tlet pxCoord = coord * size - 0.5;\n\t\tlet px = vec2i( floor( pxCoord ) );\n\t\tlet fr = fract( pxCoord );\n\n\t\t// get the four sibling samples\n\t\tlet s00 = textureLoad( tex, clamp( px, vec2i( 0 ), vec2i( size ) - 1 ), 0 );\n\t\tlet s10 = textureLoad( tex, clamp( px + vec2i( 1, 0 ), vec2i( 0 ), vec2i( size ) - 1 ), 0 );\n\t\tlet s01 = textureLoad( tex, clamp( px + vec2i( 0, 1 ), vec2i( 0 ), vec2i( size ) - 1 ), 0 );\n\t\tlet s11 = textureLoad( tex, clamp( px + vec2i( 1, 1 ), vec2i( 0 ), vec2i( size ) - 1 ), 0 );\n\n\t\t// interpolate on the x axis\n\t\tlet y0 = mix( s00, s10, fr.x );\n\t\tlet y1 = mix( s01, s11, fr.x );\n\n\t\t// then y\n\t\treturn mix( y0, y1, fr.y );\n\n\t}\n` );\n\n// Material to apply tone mapping _before_ applying alpha blending\nexport class RenderToScreenNodeMaterial extends MeshBasicNodeMaterial {\n\n\tget texture() {\n\n\t\treturn this._texNode.value;\n\n\t}\n\n\tset texture( v ) {\n\n\t\tthis._texNode.value = v;\n\n\t}\n\n\tget fromTexture() {\n\n\t\treturn this._fromTexNode.value;\n\n\t}\n\n\tset fromTexture( v ) {\n\n\t\tthis._fromTexNode.value = v;\n\n\t}\n\n\tget toneMapping() {\n\n\t\treturn this._toneMapping.toneMapping;\n\n\t}\n\n\tset toneMapping( v ) {\n\n\t\tthis._toneMapping.setToneMapping( v );\n\n\t}\n\n\tget transition() {\n\n\t\treturn this._transitionUniform.value;\n\n\t}\n\n\tset transition( v ) {\n\n\t\tthis._transitionUniform.value = v;\n\n\t}\n\n\tget exposure() {\n\n\t\treturn this._toneMapping.exposureNode.value;\n\n\t}\n\n\tset exposure( v ) {\n\n\t\tthis._toneMapping.exposureNode.value = v;\n\n\t}\n\n\tconstructor( params ) {\n\n\t\tsuper();\n\n\t\tconst texNode = texture( new StorageTexture() );\n\t\tthis._texNode = texNode;\n\n\t\tconst fromTexNode = texture( new StorageTexture() );\n\t\tthis._fromTexNode = fromTexNode;\n\n\t\tconst texUV = varying( uv() );\n\n\t\tconst transitionUniform = uniform( 1.0 );\n\t\tthis._transitionUniform = transitionUniform;\n\n\t\t// NOTE: varyings cannot be referenced directly and must be passed as arguments\n\t\tconst getFadedColorFn = wgslTagFn/* wgsl */`\n\t\t\tfn fade( uv: vec2f ) -> vec4f {\n\n\t\t\t\tif ( ${ transitionUniform } <= 0.0 ) {\n\n\t\t\t\t\treturn ${ sampleTexelFn }( ${ fromTexNode }, uv );\n\n\t\t\t\t} else if ( ${ transitionUniform } >= 1.0 ) {\n\n\t\t\t\t\treturn ${ sampleTexelFn }( ${ texNode }, uv );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet col0 = ${ sampleTexelFn }( ${ fromTexNode }, uv );\n\t\t\t\t\tlet col1 = ${ sampleTexelFn }( ${ texNode }, uv );\n\t\t\t\t\treturn mix( col0, col1, ${ transitionUniform } );\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t`;\n\n\t\tconst toneMappingNode = toneMapping( NoToneMapping, 1.0, getFadedColorFn( texUV ) );\n\t\tthis._toneMapping = toneMappingNode;\n\n\t\t// apply alpha _after_ applying tone mapping\n\t\t// NOTE: alpha is being multiplied twice here to accommodate some odd blending in three.js\n\t\t// See mrdoob/three.js#33104. It's possible this should be removed or rethought once fixed.\n\t\tthis.transparent = true;\n\t\tthis.colorNode = vec4( toneMappingNode.rgb, toneMappingNode.a );\n\n\t\tthis.setValues( params );\n\n\t}\n\n}\n","export class ComputeKernel {\n\n\tget computeNode() {\n\n\t\treturn this.kernel.computeNode;\n\n\t}\n\n\tget workgroupSize() {\n\n\t\treturn this.kernel.workgroupSize;\n\n\t}\n\n\tset needsUpdate( v ) {\n\n\t\t// TODO: hack to force the kernel to rebuild since \"needsUpdate\" is not respected\n\t\tthis.setWorkgroupSize( ...this.workgroupSize );\n\n\t}\n\n\tconstructor( fn, options = {} ) {\n\n\t\tconst {\n\t\t\tworkgroupSize = [ 64 ],\n\t\t} = options;\n\n\t\t// this.workgroupSize = [ ...workgroupSize ];\n\t\tthis._fn = fn;\n\t\tthis.kernel = null;\n\n\t\tthis.setWorkgroupSize( ...workgroupSize );\n\n\t}\n\n\tdefineUniformAccessors( parameters ) {\n\n\t\tfor ( const key in parameters ) {\n\n\t\t\tif ( key in this ) {\n\n\t\t\t\tthrow new Error( `ComputeNode: Uniform name ${ key } is already defined.` );\n\n\t\t\t}\n\n\t\t\tconst node = parameters[ key ];\n\t\t\tif ( 'value' in node ) {\n\n\t\t\t\tObject.defineProperty( this, key, {\n\t\t\t\t\tget() {\n\n\t\t\t\t\t\treturn parameters[ key ].value;\n\n\t\t\t\t\t},\n\t\t\t\t\tset( v ) {\n\n\t\t\t\t\t\tparameters[ key ].value = v;\n\n\t\t\t\t\t},\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tsetWorkgroupSize( x = 64, y = 1, z = 1 ) {\n\n\t\tthis.kernel = this._fn.computeKernel( [ x, y, z ] );\n\t\treturn this;\n\n\t}\n\n\tgetDispatchSize( tx = 1, ty = 1, tz = 1, target = [] ) {\n\n\t\tconst [ wgx, wgy, wgz ] = this.workgroupSize;\n\t\ttarget.length = 3;\n\t\ttarget[ 0 ] = Math.ceil( tx / wgx );\n\t\ttarget[ 1 ] = Math.ceil( ty / wgy );\n\t\ttarget[ 2 ] = Math.ceil( tz / wgz );\n\t\treturn target;\n\n\t}\n\n}\n","import { uint, float, wgsl, wgslFn } from 'three/tsl';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\n// Alpha test should be the last index as it is summed with triangle index\nexport const RNG_INDEX_RAY_JITTER = 0;\nexport const RNG_INDEX_ENVIRONMENT_SAMPLE = 1;\nexport const RNG_INDEX_SCATTER_TYPE = 2;\nexport const RNG_INDEX_SCATTER_DIRECTION = 3;\nexport const RNG_INDEX_ALPHA_TEST = 4;\n\nexport const pcgStateStruct = wgsl( /* wgsl */`\n\n\tstruct PcgState {\n\t\ts0: vec4u,\n\t\ts1: vec4u,\n\t};\n\n\tvar<private> g_state: PcgState;\n` );\n\nexport const pcgInitFunc = wgslFn( /* wgsl */`\n\tfn pcgInitialize( pixelIndex: u32, pathIndex: u32, bounceIndex: u32 ) -> void {\n\t\tlet pixel = vec2( ( pixelIndex >> 16 ) & 0xFF, pixelIndex & 0xFF );\n\n\t\t//white noise seed\n\t\tg_state.s0 = vec4u( pixel | vec2( bounceIndex << 16 ), pathIndex, pixel.x + pixel.y);\n\n\t\t//blue noise seed\n\t\tg_state.s1 = vec4u(pathIndex, pathIndex*15843, pathIndex*31 + 4566, pathIndex*2345 + 58585);\n\n\t}\n`, [ pcgStateStruct ] );\n\nconst pcg4d = wgslFn( /* wgsl */ `\n\tfn pcg4d(v: ptr<private, vec4u>) -> void {\n\t\t*v = *v * 1664525u + 1013904223u;\n\t\t*v = *v + v.yzxy * v.wxyz;\n\t\t*v = *v ^ (*v >> vec4u(16u));\n\t\t*v = *v + v.yzxy * v.wxyz;\n\t}\n` );\n\nexport const pcgRandFunc = wgslFn( /*wgsl*/`\n\tfn pcgRand( _id: u32 ) -> f32 {\n\t\tpcg4d(&g_state.s0);\n\t\treturn abs( f32( g_state.s0.x ) / f32(0xffffffffu) );\n\t}\n`, [ pcg4d, pcgStateStruct ] );\n\nexport const pcgRand2Func = wgslFn( /*wgsl*/`\n\tfn pcgRand2( _id: u32 ) -> vec2f {\n\t\tpcg4d(&g_state.s0);\n\t\treturn abs( vec2f( g_state.s0.xy ) / f32(0xffffffffu) );\n\t}\n`, [ pcg4d, pcgStateStruct ] );\n\nexport const pcgRand3Func = wgslFn( /*wgsl*/`\n\tfn pcgRand3( _id: u32 ) -> vec3f {\n\t\tpcg4d(&g_state.s0);\n\t\treturn abs( vec3f( g_state.s0.xyz ) / f32(0xffffffffu) );\n\t}\n`, [ pcg4d, pcgStateStruct ] );\n\nexport const pcgRand4Func = wgslFn( /*wgsl*/`\n\tfn pcgRand4( _id: u32 ) -> vec4f {\n\t\tpcg4d(&g_state.s0);\n\t\treturn abs( vec4f( g_state.s0 ) / f32(0xffffffffu) );\n\t}\n`, [ pcg4d, pcgStateStruct ] );\n\nexport const pcgNextBounceFunc = wgslFn( /* wgsl */ 'fn noop() -> void {}' );\n\n// References\n// - https://jcgt.org/published/0009/04/01/\n// - Code from https://www.shadertoy.com/view/WtGyDm\n// Ported from WebGL version at sobol.glsl.js\n\nconst SOBOL_MAX_POINTS = uint( 256 * 256 );\nconst SOBOL_FACTOR = float( 1.0 / 16777216.0 );\n\nconst sobolConstants = wgsl( /* wgsl */ `\n\n\tconst SOBOL_DIRECTIONS_1 = array<u32, 32>(\n\t\t0x80000000u, 0xc0000000u, 0xa0000000u, 0xf0000000u,\n\t\t0x88000000u, 0xcc000000u, 0xaa000000u, 0xff000000u,\n\t\t0x80800000u, 0xc0c00000u, 0xa0a00000u, 0xf0f00000u,\n\t\t0x88880000u, 0xcccc0000u, 0xaaaa0000u, 0xffff0000u,\n\t\t0x80008000u, 0xc000c000u, 0xa000a000u, 0xf000f000u,\n\t\t0x88008800u, 0xcc00cc00u, 0xaa00aa00u, 0xff00ff00u,\n\t\t0x80808080u, 0xc0c0c0c0u, 0xa0a0a0a0u, 0xf0f0f0f0u,\n\t\t0x88888888u, 0xccccccccu, 0xaaaaaaaau, 0xffffffffu\n\t);\n\n\tconst SOBOL_DIRECTIONS_2 = array<u32, 32>(\n\t\t0x80000000u, 0xc0000000u, 0x60000000u, 0x90000000u,\n\t\t0xe8000000u, 0x5c000000u, 0x8e000000u, 0xc5000000u,\n\t\t0x68800000u, 0x9cc00000u, 0xee600000u, 0x55900000u,\n\t\t0x80680000u, 0xc09c0000u, 0x60ee0000u, 0x90550000u,\n\t\t0xe8808000u, 0x5cc0c000u, 0x8e606000u, 0xc5909000u,\n\t\t0x6868e800u, 0x9c9c5c00u, 0xeeee8e00u, 0x5555c500u,\n\t\t0x8000e880u, 0xc0005cc0u, 0x60008e60u, 0x9000c590u,\n\t\t0xe8006868u, 0x5c009c9cu, 0x8e00eeeeu, 0xc5005555u\n\t);\n\n\tconst SOBOL_DIRECTIONS_3 = array<u32, 32>(\n\t\t0x80000000u, 0xc0000000u, 0x20000000u, 0x50000000u,\n\t\t0xf8000000u, 0x74000000u, 0xa2000000u, 0x93000000u,\n\t\t0xd8800000u, 0x25400000u, 0x59e00000u, 0xe6d00000u,\n\t\t0x78080000u, 0xb40c0000u, 0x82020000u, 0xc3050000u,\n\t\t0x208f8000u, 0x51474000u, 0xfbea2000u, 0x75d93000u,\n\t\t0xa0858800u, 0x914e5400u, 0xdbe79e00u, 0x25db6d00u,\n\t\t0x58800080u, 0xe54000c0u, 0x79e00020u, 0xb6d00050u,\n\t\t0x800800f8u, 0xc00c0074u, 0x200200a2u, 0x50050093u\n\t);\n\n\tconst SOBOL_DIRECTIONS_4 = array<u32, 32>(\n\t\t0x80000000u, 0x40000000u, 0x20000000u, 0xb0000000u,\n\t\t0xf8000000u, 0xdc000000u, 0x7a000000u, 0x9d000000u,\n\t\t0x5a800000u, 0x2fc00000u, 0xa1600000u, 0xf0b00000u,\n\t\t0xda880000u, 0x6fc40000u, 0x81620000u, 0x40bb0000u,\n\t\t0x22878000u, 0xb3c9c000u, 0xfb65a000u, 0xddb2d000u,\n\t\t0x78022800u, 0x9c0b3c00u, 0x5a0fb600u, 0x2d0ddb00u,\n\t\t0xa2878080u, 0xf3c9c040u, 0xdb65a020u, 0x6db2d0b0u,\n\t\t0x800228f8u, 0x400b3cdcu, 0x200fb67au, 0xb00ddb9du\n\t);\n\n` );\n\nconst sobolPixelIndex = uint( 0 ).toVar( 'sobolPixelIndex' );\nconst sobolPathIndex = uint( 0 ).toVar( 'sobolPathIndex' );\nconst sobolBounceIndex = uint( 0 ).toVar( 'sobolBounceIndex' );\n\nconst getMaskedSobolFunc = wgslFn( /* wgsl */ `\n\n\tfn getMaskedSobol( index: u32, directions: array<u32, 32> ) -> u32 {\n\n\t\tvar X = 0u;\n\t\tfor ( var bit = 0u; bit < 32u; bit ++ ) {\n\n\t\t\tlet mask = ( index >> bit ) & 1u;\n\t\t\tX ^= mask * directions[ bit ];\n\n\t\t}\n\t\treturn X;\n\n\t}\n\n` );\n\n// functions to generate multi-dimensions variables of the same functions\n// to support 1, 2, 3, and 4 dimensional sobol sampling.\nconst sobolScrambleNodesGenerator = ( dim = 1 ) => {\n\n\tif ( dim <= 0 ) {\n\n\t\treturn;\n\n\t}\n\n\tconst type = dim > 1 ? `vec${dim}u` : 'u32';\n\n\tconst sobolReverseBitsFunc = wgslFn( /* wgsl */ `\n\n\t\t\tfn sobolReverseBits_${type}( in: ${type} ) -> ${type} {\n\n\t\t\t\tvar x = in;\n\t\t\t\tx = ( ( ( x & ${type}( 0xaaaaaaaau ) ) >> ${type}( 1 ) ) | ( ( x & ${type}( 0x55555555u ) ) << ${type}( 1 ) ) );\n\t\t\t\tx = ( ( ( x & ${type}( 0xccccccccu ) ) >> ${type}( 2 ) ) | ( ( x & ${type}( 0x33333333u ) ) << ${type}( 2 ) ) );\n\t\t\t\tx = ( ( ( x & ${type}( 0xf0f0f0f0u ) ) >> ${type}( 4 ) ) | ( ( x & ${type}( 0x0f0f0f0fu ) ) << ${type}( 4 ) ) );\n\t\t\t\tx = ( ( ( x & ${type}( 0xff00ff00u ) ) >> ${type}( 8 ) ) | ( ( x & ${type}( 0x00ff00ffu ) ) << ${type}( 8 ) ) );\n\t\t\t\treturn ( ( x >> ${type}( 16 ) ) | ( x << ${type}( 16 ) ) );\n\n\t\t\t}\n\n\t` );\n\n\tconst sobolHashCombineFunc = wgslFn( /* wgsl */ `\n\n\t\tfn sobolHashCombine_${type}( seed: u32, v: ${type} ) -> ${type} {\n\n\t\t\treturn ${type}( seed ) ^ ( v + ${ type }( ( seed << 6 ) + ( seed >> 2 ) ) );\n\n\t\t}\n\n\t` );\n\n\tconst sobolLaineKarrasPermutationFunc = wgslFn( /* wgsl */ `\n\n\t\tfn sobolLaineKarrasPermutation_${type}( in: ${type}, seed: ${type} ) -> ${type} {\n\n\t\t\tvar x = in;\n\t\t\tx += seed;\n\t\t\tx ^= x * 0x6c50b47cu;\n\t\t\tx ^= x * 0xb82f1e52u;\n\t\t\tx ^= x * 0xc7afe638u;\n\t\t\tx ^= x * 0x8d22f6e6u;\n\t\t\treturn x;\n\n\t\t}\n\n\t` );\n\n\tconst nestedUniformScrambleBase2Func = wgslTagFn/* wgsl */ `\n\n\t\tfn nestedUniformScrambleBase2_${type}( x: ${type}, seed: ${type} ) -> ${type} {\n\n\t\t\tvar res = ${ sobolLaineKarrasPermutationFunc }( x, seed );\n\t\t\tres = ${ sobolReverseBitsFunc }( res );\n\t\t\treturn res;\n\n\t\t}\n\n\t`;\n\n\treturn {\n\t\treverseBits: sobolReverseBitsFunc,\n\t\thashCombine: sobolHashCombineFunc,\n\t\tlkPermutation: sobolLaineKarrasPermutationFunc,\n\t\tscramble: nestedUniformScrambleBase2Func,\n\t};\n\n};\n\n// 0th node is intentionally empty to make access pattern more intuitive:\n// sobolNodes[ i ] are nodes that are needed to sample i-dimensional vectors\n// 1-dimensional vector = f32\nconst sobolNodes = Array.from( { length: 5 }, ( _, i ) => sobolScrambleNodesGenerator( i ) );\n\nexport const generateSobolPointFunc = wgslTagFn`\n ${ [ sobolConstants ] }\n\n\tfn generateSobolPoint( id: u32 ) -> vec4f {\n\n\t\tvar index = id;\n\t\tif ( index >= ${ SOBOL_MAX_POINTS } ) {\n\n\t\t\tindex = index % ${ SOBOL_MAX_POINTS };\n\t\t\t// return vec4( 0.0 );\n\n\t\t}\n\n\t\t// NOTE: this sobol \"direction\" is also available but we can't write out 5 components\n\t\t// uint x = index & 0x00ffffffu;\n\t\tlet x = ${ sobolNodes[ 1 ].reverseBits }( ${ getMaskedSobolFunc }( index, SOBOL_DIRECTIONS_1 ) ) & 0x00ffffffu;\n\t\tlet y = ${ sobolNodes[ 1 ].reverseBits }( ${ getMaskedSobolFunc }( index, SOBOL_DIRECTIONS_2 ) ) & 0x00ffffffu;\n\t\tlet z = ${ sobolNodes[ 1 ].reverseBits }( ${ getMaskedSobolFunc }( index, SOBOL_DIRECTIONS_3 ) ) & 0x00ffffffu;\n\t\tlet w = ${ sobolNodes[ 1 ].reverseBits }( ${ getMaskedSobolFunc }( index, SOBOL_DIRECTIONS_4 ) ) & 0x00ffffffu;\n\n\t\treturn vec4( f32( x ), f32( y ), f32( z ), f32( w ) ) * ${ SOBOL_FACTOR };\n\n\t}\n\n`;\n\nconst sobolHashFunc = wgslFn( /* wgsl */ `\n\n\tfn sobolHash( in: u32 ) -> u32 {\n\n\t\tvar x = in;\n\t\t// finalizer from murmurhash3\n\t\tx ^= x >> 16;\n\t\tx *= 0x85ebca6bu;\n\t\tx ^= x >> 13;\n\t\tx *= 0xc2b2ae35u;\n\t\tx ^= x >> 16;\n\t\treturn x;\n\n\t}\n\n` );\n\nconst sobolGetSeedFunc = wgslTagFn`\n\n\tfn sobolGetSeed( effect: u32 ) -> u32 {\n\n\t\treturn ${ sobolHashFunc }(\n\t\t\t${ sobolNodes[ 1 ].hashCombine }(\n\t\t\t\t${ sobolNodes[ 1 ].hashCombine }(\n\t\t\t\t\t${ sobolHashFunc }( ${ sobolBounceIndex } ),\n\t\t\t\t\t${ sobolPixelIndex }\n\t\t\t\t),\n\t\t\t\teffect\n\t\t\t)\n\t\t);\n\n\t}\n\n`;\n\nconst sobolGenerator = ( dim = 1, sobolPointFunc = generateSobolPointFunc ) => {\n\n\tif ( dim <= 0 ) {\n\n\t\treturn;\n\n\t}\n\n\tconst utype = dim > 1 ? `vec${dim}u` : 'u32';\n\tconst ftype = dim > 1 ? `vec${dim}f` : 'f32';\n\n\tlet components = '.r';\n\tlet combineValues = '1u';\n\tif ( dim === 2 ) {\n\n\t\tcomponents = '.rg';\n\t\tcombineValues = 'vec2( 1u, 2u )';\n\n\t} else if ( dim === 3 ) {\n\n\t\tcomponents = '.rgb';\n\t\tcombineValues = 'vec3( 1u, 2u, 3u )';\n\n\t} else if ( dim === 4 ) {\n\n\t\tcomponents = '';\n\t\tcombineValues = 'vec4( 1u, 2u, 3u, 4u )';\n\n\t}\n\n\treturn wgslTagFn`\n\n\t\tfn sobol${dim}( effect: u32 ) -> ${ftype} {\n\n\t\t\tlet seed = ${sobolGetSeedFunc}( effect );\n\t\t\tlet index = ${sobolPathIndex};\n\n\t\t\tlet shuffle_seed = ${ sobolNodes[ 1 ].hashCombine }( seed, 0u );\n\t\t\tlet shuffled_index = ${ sobolNodes[ 1 ].scramble }( ${ sobolNodes[ 1 ].reverseBits }( index ), shuffle_seed );\n\t\t\tlet sobol_pt = ${ sobolPointFunc }( shuffled_index )${ components };\n\t\t\tvar result = ${ utype }( sobol_pt * 16777216.0 );\n\n\t\t\tlet seed2 = ${ sobolNodes[ dim ].hashCombine }( seed, ${ combineValues } );\n\t\t\tresult = ${ sobolNodes[ dim ].scramble }( result, seed2 );\n\n\t\t\treturn ${ SOBOL_FACTOR } * ${ ftype }( result >> ${utype}( 8 ) );\n\n\t\t}\n\n\t`;\n\n};\n\nexport const sobolRand1Func = sobolGenerator( 1 );\nexport const sobolRand2Func = sobolGenerator( 2 );\nexport const sobolRand3Func = sobolGenerator( 3 );\nexport const sobolRand4Func = sobolGenerator( 4 );\n\nexport const sobolInitFunc = wgslTagFn`\n\n\tfn sobolInit( pixelIndex: u32, pathIndex: u32, bounceIndex: u32 ) -> void {\n\n\t\t${ sobolPixelIndex } = pixelIndex;\n\t\t${ sobolPathIndex } = pathIndex;\n\t\t${ sobolBounceIndex } = bounceIndex;\n\n\t}\n\n`;\n\nexport const sobolNextBounceFunc = wgslTagFn`\n\n\tfn sobolNextBounce() -> void {\n\n\t\t${ sobolBounceIndex }++;\n\n\t}\n\n`;\n\n// PCG definitions\n// export {\n// \tpcgInitFunc as rngInit,\n// \tpcgNextBounceFunc as rngNextBounce,\n// \tpcgRandFunc as rand1,\n// \tpcgRand2Func as rand2,\n// \tpcgRand3Func as rand3,\n// \tpcgRand4Func as rand4,\n// };\n\n// Sobol definitions\nexport {\n\tsobolInitFunc as rngInit,\n\tsobolNextBounceFunc as rngNextBounce,\n\tsobolRand1Func as rand1,\n\tsobolRand2Func as rand2,\n\tsobolRand3Func as rand3,\n\tsobolRand4Func as rand4,\n};\n","import { wgsl } from 'three/tsl';\nimport { StructTypeNode } from 'three/webgpu';\n\n// TODO: Move to node-based constants that are embedded with wgslTagFn\nexport const constants = wgsl( /* wgsl */ `\n\n\tconst PI: f32 = 3.141592653589793;\n\tconst EPSILON: f32 = 1e-5;\n\tconst MIN_ROUGHNESS: f32 = 1e-3;\n\n` );\n\nexport const scatterRecordStruct = new StructTypeNode( {\n\tcolor: 'vec3f',\n\tspecularPdf: 'float',\n\tdirection: 'vec3f',\n\tpdf: 'float',\n}, 'ScatterRecord' );\n\n// NOTE: all \"*Map\" fields are bit-packed integers of texture index & settings:\n// bits 0-23: texture index\n// bits 24-25: wrapS setting\n// bits 26-27: wrapT setting\n// bit 28: filter setting\n// bits 29-30: unused\n// bit 31: negative bit used for indicating unused texture\nexport const materialStruct = new StructTypeNode( {\n\t// offset 0\n\tcolor: 'vec3',\n\tmap: 'int',\n\n\t// offset 4 floats\n\tmetalness: 'float',\n\tmetalnessMap: 'int',\n\n\troughness: 'float',\n\troughnessMap: 'int',\n\n\t// offset 8 floats\n\tior: 'float',\n\ttransmission: 'float',\n\ttransmissionMap: 'int',\n\n\temissiveIntensity: 'float',\n\t// offset 12 floats\n\temissive: 'vec3',\n\temissiveMap: 'int',\n\n\t// offset 16 floats\n\tnormalMap: 'int',\n\tnormalScale: 'vec2',\n\n\t// offset 20 floats\n\tclearcoat: 'float',\n\tclearcoatMap: 'int',\n\tclearcoatNormalMap: 'int',\n\t// offset 24 floats\n\tclearcoatNormalScale: 'vec2',\n\tclearcoatRoughness: 'float',\n\tclearcoatRoughnessMap: 'int',\n\n\t// offset 28 floats\n\tiridescenceMap: 'int',\n\tiridescenceThicknessMap: 'int',\n\tiridescence: 'float',\n\tiridescenceIor: 'float',\n\t// offset 32 floats\n\tiridescenceThicknessMinimum: 'float',\n\tiridescenceThicknessMaximum: 'float',\n\n\t// offset 36 floats\n\tspecularColor: 'vec3',\n\tspecularColorMap: 'int',\n\n\t// offset 40 floats\n\tspecularIntensity: 'float',\n\tspecularIntensityMap: 'int',\n\tthinFilm: 'int', // actually a boolean\n\n\t// offset 44 floats\n\tattenuationColor: 'vec3',\n\tattenuationDistance: 'float',\n\n\t// offset 48 floats\n\talphaMap: 'int',\n\n\tcastShadow: 'int', // actually a boolean\n\topacity: 'float',\n\talphaTest: 'float',\n\n\t// offset 52 floats\n\tside: 'float',\n\tmatte: 'int', // actually a boolean\n\n\tsheen: 'float',\n\t// offset 56 floats\n\tsheenColor: 'vec3',\n\tsheenColorMap: 'int',\n\t// offset 60 floats\n\tsheenRoughness: 'float',\n\tsheenRoughnessMap: 'int',\n\n\t// All those are booleans\n\tvertexColors: 'int',\n\tflatShading: 'int',\n\t// offset 64 floats\n\ttransparent: 'int',\n\tfogVolume: 'int',\n\n\t// offset 68 floats\n\tmapTransform: 'mat3',\n\t// offset 80 floats\n\tmetalnessMapTransform: 'mat3',\n\t// offset 92 floats\n\troughnessMapTransform: 'mat3',\n\t// offset 104 floats\n\ttransmissionMapTransform: 'mat3',\n\t// offset 116 floats\n\temissiveMapTransform: 'mat3',\n\t// offset 128 floats\n\tnormalMapTransform: 'mat3',\n\t// offset 140 floats\n\tclearcoatMapTransform: 'mat3',\n\t// offset 152 floats\n\tclearcoatNormalMapTransform: 'mat3',\n\t// offset 164 floats\n\tclearcoatRoughnessMapTransform: 'mat3',\n\t// offset 176 floats\n\tsheenColorMapTransform: 'mat3',\n\t// offset 188 floats\n\tsheenRoughnessMapTransform: 'mat3',\n\t// offset 200 floats\n\tiridescenceMapTransform: 'mat3',\n\t// offset 212 floats\n\tiridescenceThicknessMapTransform: 'mat3',\n\t// offset 224 floats\n\tspecularColorMapTransform: 'mat3',\n\t// offset 236 floats\n\tspecularIntensityMapTransform: 'mat3',\n\t// offset 248 floats\n\talphaMapTransform: 'mat3',\n\t// total size = 260\n}, 'Material' );\n\nexport const surfaceRecordStruct = new StructTypeNode( {\n\t// surface type\n\tvolumeParticle: 'bool',\n\n\t// geometry\n\tfaceNormal: 'vec3f',\n\tfrontFace: 'bool',\n\tnormal: 'vec3f',\n\tnormalBasis: 'mat3x3f',\n\tnormalInvBasis: 'mat3x3f',\n\n\t// cached properties\n\teta: 'f32',\n\tf0: 'f32',\n\n\t// material\n\troughness: 'f32',\n\tmetalness: 'f32',\n\tcolor: 'vec3f',\n\temission: 'vec3f',\n\n\t// transmission\n\tior: 'f32',\n\ttransmission: 'f32',\n\tthinFilm: 'bool',\n\tattenuationColor: 'vec3f',\n\tattenuationDistance: ' f32',\n\n\t// clearcoat\n\tclearcoatNormal: 'vec3f',\n\tclearcoatBasis: 'mat3x3f',\n\tclearcoatInvBasis: 'mat3x3f',\n\tclearcoat: 'f32',\n\tclearcoatRoughness: 'f32',\n\n\t// sheen\n\tsheen: 'f32',\n\tsheenColor: 'vec3f',\n\tsheenRoughness: 'f32',\n\n\t// iridescence\n\tiridescence: 'f32',\n\tiridescenceIor: 'f32',\n\tiridescenceThickness: 'f32',\n\n\t// specular\n\tspecularColor: 'vec3f',\n\tspecularIntensity: 'f32',\n}, 'SurfaceRecord' );\n\nexport const environmentInfoStruct = new StructTypeNode( {\n\trotation: 'mat3x3f',\n\tintensity: 'float',\n\tblur: 'float',\n}, 'EnvironmentInfo' );\n\nexport const lobeWeightsStruct = new StructTypeNode( {\n\tdiffuse: 'float',\n\tspecular: 'float',\n\ttransmission: 'float',\n\tclearcoat: 'float',\n}, 'LobeWeights' );\n\nexport const bxdfContextStruct = new StructTypeNode( {\n\tNdotV: 'float',\n\tNdotL: 'float',\n\tNdotH: 'float',\n\tVdotH: 'float',\n\n\tVdotNc: 'float',\n\tLdotNc: 'float',\n\tHdotNc: 'float',\n\n}, 'BxDFContext' );\n","import { wgslFn } from 'three/tsl';\nimport { scatterRecordStruct } from './structs.wgsl.js';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\nexport const inverseMat3x3Func = wgslFn( /* wgsl */ `\n\n\tfn inverse(m: mat3x3f) -> mat3x3f {\n\t\tvar adj: mat3x3f;\n\t\tadj[0][0] = (m[1][1] * m[2][2] - m[2][1] * m[1][2]);\n\t\tadj[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n\t\tadj[2][0] = (m[1][0] * m[2][1] - m[2][0] * m[1][1]);\n\t\tadj[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n\t\tadj[1][1] = (m[0][0] * m[2][2] - m[2][0] * m[0][2]);\n\t\tadj[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n\t\tadj[0][2] = (m[0][1] * m[1][2] - m[1][1] * m[0][2]);\n\t\tadj[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n\t\tadj[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]);\n\n\t\tlet det = ( m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])\n\t\t\t- m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])\n\t\t\t+ m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]));\n\n\t\treturn adj * ( 1.0 / det );\n\t}\n\n` );\n\nexport const getBasisFromNormalFunc = wgslFn( /* wgsl */ `\n\n\tfn getBasisFromNormal( normal: vec3f ) -> mat3x3f {\n\n\t\tvar other: vec3f;\n\t\tif ( abs( normal.x ) > 0.5 ) {\n\n\t\t\tother = vec3f( 0.0, 1.0, 0.0 );\n\n\t\t} else {\n\n\t\t\tother = vec3f( 1.0, 0.0, 0.0 );\n\n\t\t}\n\n\t\tlet ortho = normalize( cross( normal, other ) );\n\t\tlet ortho2 = normalize( cross( normal, ortho ) );\n\t\treturn mat3x3f( ortho2, ortho, normal );\n\n\t}\n\n` );\n\nexport const iorToF0Func = wgslFn( /* wgsl */ `\n\n\tfn iorToF0( ior: f32 ) -> f32 {\n\t\treturn pow( ( 1 - ior ) / ( 1 + ior ), 2 );\n\t}\n\n` );\n\nexport const iorToF0GeneralFunc = wgslFn( /* wgsl */ `\n\n\tfn iorToF0General( transmittedIor: f32, incidentIor: f32 ) -> f32 {\n\n\t\treturn pow( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ), 2 );\n\n\t}\n\n` );\n\nexport const iorToF0GeneralVecFunc = wgslFn( /* wgsl */ `\n\n\tfn iorToF0GeneralVec( transmittedIor: vec3f, incidentIor: vec3f ) -> vec3f {\n\n\t\tlet v = ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor );\n\t\treturn v * v;\n\n\t}\n\n` );\n\nexport const fresnel0ToIorFunc = wgslFn( /* wgsl */ `\n\n\tfn fresnel0ToIor( f0: vec3f ) -> vec3f {\n\n\t\tlet sqrtF0 = sqrt( f0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\n\t}\n\n` );\n\nexport const schlickFresnelFunc = wgslFn( /* wgsl */ `\n\n\tfn schlickFresnel( cosine: f32, f0: f32 ) -> f32 {\n\n\t\treturn f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n\t}\n\n` );\n\nexport const schlickFresnelVecFunc = wgslFn( /* wgsl */ `\n\n\tfn schlickFresnelVec( cosine: f32, f0: vec3f, f90: vec3f ) -> vec3f {\n\n\t\treturn f0 + ( f90 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n\t}\n\n` );\n\nexport const totalInternalReflectionFunc = wgslFn( /* wgsl */ `\n\n\tfn totalInternalReflection( cosTheta: f32, eta: f32 ) -> bool {\n\n\t\tlet sinTheta = sqrt( 1.0 - cosTheta * cosTheta );\n\t\treturn eta * sinTheta > 1.0;\n\n\t}\n\n` );\n\nexport const evaluateFresnelFunc = wgslFn( /* wgsl */ `\n\n\tfn evaluateFresnel( cosine: f32, eta: f32, f0: vec3f, f90: vec3f ) -> vec3f {\n\n\t\tif ( totalInternalReflection( cosine, eta ) ) {\n\n\t\t\treturn f90;\n\n\t\t}\n\n\t\treturn f0 + ( f90 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\t}\n\n`, [ totalInternalReflectionFunc ] );\n\nexport const isTerminatingScatterFunc = wgslFn( /* wgsl */ `\n\n\tfn isTerminatingScatter( scatterRec: ScatterRecord ) -> bool {\n\t\treturn scatterRec.pdf <= 0;\n\t}\n\n`, [ scatterRecordStruct ] );\n\nexport const applyWrapFunc = wgslFn( /* wgsl */ `\n\n\tfn applyWrap( v: f32, wrapMode: i32 ) -> f32 {\n\n\t\tvar res = v;\n\t\tif ( wrapMode == 1 ) {\n\n\t\t\t// ClampToEdge\n\t\t\tres = clamp( res, 0.0, 1.0 );\n\n\t\t} else if ( wrapMode == 2 ) {\n\n\t\t\t// MirroredRepeat\n\t\t\tres = 1.0 - abs( 2.0 * fract( res * 0.5 ) - 1.0 );\n\n\t\t} else {\n\n\t\t\t// Repeat\n\t\t\tres = fract( res );\n\n\t\t}\n\n\t\treturn res;\n\n\t}\n\n` );\n\n// Factory: builds sampleTexel bound to the given per-instance textureInfo uniform\n// array node ( must be named \"textureInfo\" ). Called once per scene so a single\n// sampleTexel / textureInfo binding is shared by every caller in a pipeline.\nexport const sampleTexelFunc = ( textureInfoUniform, atlas, atlasSampler ) => wgslTagFn/* wgsl */ `\n\n\tfn sampleTexel( uv: vec2f, packed: i32, lod: f32 ) -> vec4f {\n\n\t\tlet wrapS = ( packed >> 24 ) & 0x3;\n\t\tlet wrapT = ( packed >> 26 ) & 0x3;\n\t\tlet nearest = ( packed >> 28 ) & 0x1;\n\t\tlet texIndex = packed & 0xFFFFFF;\n\n\t\t// look up the texture's rect and page within the atlas. three wraps a\n\t\t// uniformArray in a struct ( textureInfoStruct ) with a \"value\" array member.\n\t\tlet info = ${ textureInfoUniform }[ u32( texIndex ) ];\n\t\tlet offset = vec2f( vec2u( info.x & 0xFFFFu, info.x >> 16u ) );\n\t\tlet size = vec2f( vec2u( info.y & 0xFFFFu, info.y >> 16u ) );\n\t\tlet page = i32( info.z & 0xFFFFu );\n\n\t\t// wrap is applied on the logical uv first, then remapped into the tile\n\t\tlet wrappedUv = vec2f(\n\t\t\t${ applyWrapFunc }( uv.x, wrapS ),\n\t\t\t${ applyWrapFunc }( uv.y, wrapT ),\n\t\t);\n\n\t\tlet pageDim = vec2f( textureDimensions( ${ atlas }, 0 ).xy );\n\n\t\tif ( nearest == 1 ) {\n\n\t\t\tlet tileTexel = clamp( vec2i( wrappedUv * size ), vec2i( 0 ), vec2i( size ) - vec2i( 1 ) );\n\t\t\treturn textureLoad( ${ atlas }, vec2i( offset ) + tileTexel, page, 0 );\n\n\t\t} else {\n\n\t\t\tvar atlasUv = ( offset + wrappedUv * size ) / pageDim;\n\n\t\t\t// clamp to half a texel inside the tile so bilinear taps never bleed into\n\t\t\t// neighboring atlas tiles\n\t\t\tlet minUv = ( offset + vec2f( 0.5 ) ) / pageDim;\n\t\t\tlet maxUv = ( offset + size - vec2f( 0.5 ) ) / pageDim;\n\t\t\tatlasUv = clamp( atlasUv, minUv, maxUv );\n\n\t\t\treturn textureSampleLevel( ${ atlas }, ${ atlasSampler }, atlasUv, page, lod );\n\n\t\t}\n\n\t}\n`;\n\n","import { wgslFn } from 'three/tsl';\nimport { environmentInfoStruct, constants, lobeWeightsStruct } from './structs.wgsl.js';\nimport { evaluateFresnelFunc, iorToF0Func, schlickFresnelFunc } from './utils.wgsl.js';\n\n/*\nwi : incident vector or light vector (pointing toward the light)\nwo : outgoing vector or view vector (pointing towards the camera)\nwh : computed half vector from wo and wi\nVectors above are assumed to be in tangent space. i.e. +z is along macronormal of the surface\neta : Greek character used to denote the \"ratio of ior\"\n*/\n\nexport const sampleSphereFunc = wgslFn( /* wgsl */ `\n\n\tfn sampleSphere( uv: vec2f ) -> vec3f {\n\n\t\tlet u = ( uv.x - 0.5 ) * 2.0;\n\t\tlet t = uv.y * PI * 2.0;\n\t\tlet f = sqrt( 1.0 - u * u );\n\n\t\treturn vec3f( f * cos( t ), f * sin( t ), u );\n\n\t}\n\n`, [ constants ] );\n\n// TODO: Investigate sampling directly in tagent space?\n// See 16.6.1 in https://www.realtimerendering.com/raytracinggems/unofficial_RayTracingGems_v1.9.pdf\nexport const diffuseDirectionFunc = wgslFn( /* wgsl */ `\n\n\tfn diffuseDirection( wo: vec3f, uv: vec2f ) -> vec3f {\n\n\t\tvar lightDirection = sampleSphere( uv );\n\t\tlightDirection.z += 1.0;\n\t\tlightDirection = normalize( lightDirection );\n\n\t\treturn lightDirection;\n\n\t}\n\n`, [ sampleSphereFunc ] );\n\nexport const getLobeWeightsFunc = wgslFn( /* wgsl */ `\n\n\tfn getLobeWeights(wo: vec3f, woClearcoat: vec3f, wh: vec3f, clearcoatIor: f32, surf: SurfaceRecord) -> LobeWeights {\n\n\t\t// TODO: experiment with this; I don't see any usage of normal?\n\t\tlet metalness = surf.metalness;\n\t\tlet transmission = surf.transmission;\n\t\tlet HdotL = dot( wh, wo );\n\t\tlet fEstimate = evaluateFresnel( HdotL, surf.eta, vec3f( surf.f0 ), vec3f( 1.0 ) ).x;\n\n\t\tlet transSpecularProb = mix( max( 0.25, fEstimate ), 1.0, metalness );\n\t\tlet diffSpecularProb = 0.5 + 0.5 * metalness;\n\n\t\tvar weights: LobeWeights;\n\t\tweights.diffuse = ( 1.0 - transmission ) * ( 1.0 - diffSpecularProb );\n\t\tweights.specular = transmission * transSpecularProb + ( 1.0 - transmission ) * diffSpecularProb;\n\n\t\tlet clearcoatF0 = iorToF0( clearcoatIor );\n\t\tlet clearcoatFresnel = schlickFresnel( saturate( woClearcoat.z ), clearcoatF0 );\n\t\tweights.clearcoat = surf.clearcoat * clearcoatFresnel;\n\n\t\tweights.transmission = transmission * ( 1.0 - transSpecularProb );\n\n\t\tlet totalWeight = weights.diffuse + weights.specular;\n\t\tif ( totalWeight > 0 ) {\n\t\t\tweights.diffuse = ( weights.diffuse / totalWeight ) * ( 1 - weights.clearcoat );\n\t\t\tweights.specular = ( weights.specular / totalWeight ) * ( 1 - weights.clearcoat );\n\t\t}\n\t\t// weights.transmission /= totalWeight;\n\n\t\treturn weights;\n\n\t}\n\n`, [ schlickFresnelFunc, iorToF0Func, evaluateFresnelFunc, lobeWeightsStruct, constants ] );\n\nconst equirectDirectionToUvFn = wgslFn( /* wgsl */`\n\n\tfn equirectDirectionToUv(direction: vec3f) -> vec2f {\n\n\t\t// from Spherical.setFromCartesianCoords\n\t\tvar uv = vec2f( atan2( direction.z, direction.x ), acos( direction.y ) );\n\t\tuv /= vec2f( 2.0 * PI, PI );\n\n\t\t// apply adjustments to get values in range [0, 1] and y right side up\n\t\tuv.x += 0.5;\n\t\tuv.y = 1.0 - uv.y;\n\t\treturn uv;\n\n\t}\n\n` );\n\nconst sampleEquirectColorFn = wgslFn( /* wgsl */ `\n\n\tfn sampleEquirectColor( envMap: texture_2d<f32>, envMapSampler: sampler, direction: vec3f ) -> vec4f {\n\n\t\treturn textureSampleLevel( envMap, envMapSampler, equirectDirectionToUv( direction ), 0 );\n\n\t}\n\n`, [ equirectDirectionToUvFn ] );\n\nconst sampleHemisphereFn = wgslFn( /* wgsl */ `\n\n\tfn sampleHemisphere( n: vec3f, uv: vec2f ) -> vec3f {\n\n\t\t// https://www.rorydriscoll.com/2009/01/07/better-sampling/\n\t\t// https://graphics.pixar.com/library/OrthonormalB/paper.pdf\n\t\tlet sign = select( sign( n.z ), 1.0, n.z == 0.0 );\n\t\tlet a = - 1.0 / ( sign + n.z );\n\t\tlet b = n.x * n.y * a;\n\t\tlet b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );\n\t\tlet b2 = vec3( b, sign + n.y * n.y * a, - n.y );\n\n\t\tlet r = sqrt( uv.x );\n\t\tlet theta = 2.0 * PI * uv.y;\n\t\tlet x = r * cos( theta );\n\t\tlet y = r * sin( theta );\n\t\treturn x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;\n\n\t}\n\n`, [ constants ] );\n\nexport const sampleEnvironmentFn = wgslFn( /* wgsl */ `\n\n\tfn sampleEnvironment(\n\t\tenvMap: texture_2d<f32>,\n\t\tenvMapSampler: sampler,\n\t\tenv: EnvironmentInfo,\n\t\tdirection: vec3f,\n\t\tuv: vec2f,\n\t) -> vec4f {\n\n\t\tlet offsetDir = sampleHemisphere( direction, uv ) * 0.5 * env.blur;\n\t\tlet sampleDir = normalize( env.rotation * direction + offsetDir );\n\t\tlet col = sampleEquirectColor( envMap, envMapSampler, sampleDir );\n\n\t\treturn vec4f( env.intensity * col.rgb, col.a );\n\n\t}\n\n`, [ sampleEquirectColorFn, sampleHemisphereFn, environmentInfoStruct ] );\n\nexport const weightedAlphaBlendFn = wgslFn( /* wgsl */`\n\n\tfn weightedAlphaBlend( prevColor: vec4f, newColor: vec4f, weight: f32 ) -> vec4f {\n\n\t\tlet invWeight = 1.0 - weight;\n\t\tlet totalAlpha = prevColor.a * invWeight + newColor.a * weight;\n\t\tvar blendedColor = vec4f( 0 );\n\t\tif ( totalAlpha != 0.0 ) {\n\n\t\t\tlet prevContrib = prevColor.rgb * invWeight * prevColor.a / totalAlpha;\n\t\t\tlet resContrib = newColor.rgb * weight * newColor.a / totalAlpha;\n\t\t\tblendedColor = vec4f( prevContrib + resContrib, totalAlpha );\n\n\t\t}\n\n\t\treturn blendedColor;\n\n\t}\n\n` );\n","import { DataTexture, Matrix3, Matrix4, Vector2, StorageTexture } from 'three/webgpu';\nimport { ComputeKernel } from './ComputeKernel.js';\nimport { texture, sampler, uniform, globalId, textureStore } from 'three/tsl';\nimport { rngInit, rngNextBounce, rand2, RNG_INDEX_RAY_JITTER, RNG_INDEX_ENVIRONMENT_SAMPLE } from '../nodes/random.wgsl.js';\nimport { sampleEnvironmentFn, weightedAlphaBlendFn } from '../nodes/sampling.wgsl.js';\nimport { ndcToCameraRay, proxy, proxyFn, wgslTagFn } from '../lib/three-mesh-bvh/index.js';\nimport { isTerminatingScatterFunc } from '../nodes/utils.wgsl.js';\n\nexport class PathTracerMegaKernel extends ComputeKernel {\n\n\tconstructor( ) {\n\n\t\tconst params = {\n\t\t\tbvhData: { value: null },\n\t\t\tmaterial: { value: null },\n\n\t\t\tprevOutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadOnly(),\n\t\t\toutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toWriteOnly(),\n\t\t\tsampleCountTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadWrite(),\n\n\t\t\toffset: uniform( new Vector2() ),\n\t\t\ttileSize: uniform( new Vector2() ),\n\t\t\tseed: uniform( 0 ),\n\t\t\tbounces: uniform( 5 ),\n\n\t\t\t// transforms\n\t\t\tinverseProjectionMatrix: uniform( new Matrix4() ),\n\t\t\tcameraToModelMatrix: uniform( new Matrix4() ),\n\n\t\t\t// environment\n\t\t\tenvMap: texture( new DataTexture() ),\n\t\t\tenvMapSampler: sampler( new DataTexture() ),\n\t\t\tenvMapRotation: uniform( new Matrix3() ),\n\t\t\tenvMapIntensity: uniform( 1 ),\n\n\t\t\tbackground: texture( new DataTexture() ),\n\t\t\tbackgroundSampler: sampler( new DataTexture() ),\n\t\t\tbackgroundRotation: uniform( new Matrix3() ),\n\t\t\tbackgroundIntensity: uniform( 1 ),\n\t\t\tbackgroundBlurriness: uniform( 0 ),\n\n\t\t\ttextures: texture( new DataTexture() ),\n\t\t\ttextureSampler: sampler( new DataTexture() ),\n\n\t\t\t// compute variables\n\t\t\tglobalId: globalId,\n\t\t};\n\n\t\tconst raycastOutput = proxy( 'bvhData.value.fns.raycastFirstHit.outputType', params );\n\t\tconst raycastFirstHitFn = proxyFn( 'bvhData.value.fns.raycastFirstHit', params );\n\t\tconst sampleTrianglePointFn = proxyFn( 'bvhData.value.fns.sampleTrianglePoint', params );\n\t\tconst getSurfaceRecordFn = proxyFn( 'bvhData.value.fns.getSurfaceRecord', params );\n\t\tconst bsdfSampleFn = proxyFn( 'material.value.bsdfSample', params );\n\n\t\tconst shader = wgslTagFn/* wgsl */`\n\n\t\t\tfn compute(\n\n\t\t\t\t// indices and target\n\t\t\t\tglobalId: vec3u,\n\n\t\t\t\t// tiles\n\t\t\t\toffset: vec2u,\n\t\t\t\ttileSize: vec2u,\n\n\t\t\t\t// settings\n\t\t\t\tinverseProjectionMatrix: mat4x4f,\n\t\t\t\tcameraToModelMatrix: mat4x4f,\n\t\t\t\tseed: u32,\n\t\t\t\tbounces: u32,\n\n\t\t\t\t// environment\n\t\t\t\tenvMap: texture_2d<f32>,\n\t\t\t\tenvMapSampler: sampler,\n\t\t\t\tenvMapRotation: mat3x3f,\n\t\t\t\tenvMapIntensity: f32,\n\n\t\t\t\tbackground: texture_2d<f32>,\n\t\t\t\tbackgroundSampler: sampler,\n\t\t\t\tbackgroundRotation: mat3x3f,\n\t\t\t\tbackgroundIntensity: f32,\n\t\t\t\tbackgroundBlurriness: f32,\n\n\t\t\t) -> void {\n\n\t\t\t\tlet transforms = &${ proxy( 'bvhData.value.storage.transforms', params ) };\n\t\t\t\tlet materials = &${ proxy( 'bvhData.value.storage.materials', params ) };\n\n\t\t\t\tlet envInfo = EnvironmentInfo(\n\t\t\t\t\tenvMapRotation,\n\t\t\t\t\tenvMapIntensity,\n\t\t\t\t\t0.0 // blur,\n\t\t\t\t);\n\n\t\t\t\tlet backgroundInfo = EnvironmentInfo(\n\t\t\t\t\tbackgroundRotation,\n\t\t\t\t\tbackgroundIntensity,\n\t\t\t\t\tbackgroundBlurriness,\n\t\t\t\t);\n\n\t\t\t\t// make sure we don't bleed over the edge of our tile\n\t\t\t\tif ( globalId.x >= tileSize.x || globalId.y >= tileSize.y ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// to screen coordinates\n\t\t\t\tlet indexUV = offset + globalId.xy;\n\t\t\t\tlet targetDimensions = textureDimensions( ${ params.outputTarget } );\n\t\t\t\tif ( indexUV.x >= targetDimensions.x || indexUV.y >= targetDimensions.y ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tlet uv = vec2f( indexUV ) / vec2f( targetDimensions );\n\t\t\t\tlet ndc = uv * 2.0 - vec2f( 1.0 );\n\n\t\t\t\tlet pixelIndex = ( indexUV.x << 16 ) | indexUV.y;\n\t\t\t\t${ rngInit }( pixelIndex, seed, 0 );\n\n\t\t\t\t// scene ray\n\t\t\t\tvar jitter = 2.0 * ${ rand2 }( ${ RNG_INDEX_RAY_JITTER } ) / vec2f( targetDimensions.xy );\n\t\t\t\tvar ray = ${ ndcToCameraRay }( ndc + jitter, cameraToModelMatrix * inverseProjectionMatrix );\n\t\t\t\tray.direction = normalize( ray.direction );\n\n\t\t\t\tvar resultColor = vec4f( 0, 0, 0, 1 );\n\t\t\t\tvar throughputColor = vec3f( 1.0 );\n\n\t\t\t\tfor ( var bounce = 0u; bounce < bounces; bounce ++ ) {\n\n\t\t\t\t\tvar hitResult: ${ raycastOutput };\n\t\t\t\t\tif ( ${ raycastFirstHitFn }( ray, &hitResult ) ) {\n\n\t\t\t\t\t\tlet object = transforms[ hitResult.objectIndex ];\n\t\t\t\t\t\tvar material = materials[ object.materialIndex ];\n\n\t\t\t\t\t\t// apply per-object colors\n\t\t\t\t\t\tmaterial.color *= object.color.rgb;\n\t\t\t\t\t\tmaterial.opacity *= object.color.a;\n\n\t\t\t\t\t\tvar vertexData = ${ sampleTrianglePointFn }( hitResult.barycoord, hitResult.indices.xyz );\n\t\t\t\t\t\tvertexData.normal = normalize( transpose( object.inverseMatrixWorld ) * vertexData.normal );\n\t\t\t\t\t\tvertexData.position = object.matrixWorld * vertexData.position;\n\n\t\t\t\t\t\tlet surface = ${ getSurfaceRecordFn }( material, vertexData, hitResult.side, hitResult.normal );\n\n\t\t\t\t\t\tresultColor += vec4f( throughputColor * surface.emission, 0.0 );\n\n\t\t\t\t\t\tlet scatterRec = ${ bsdfSampleFn }( - ray.direction, surface );\n\n\t\t\t\t\t\tif ( ${ isTerminatingScatterFunc }( scatterRec ) ) {\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthroughputColor *= scatterRec.color;\n\t\t\t\t\t\tthroughputColor /= scatterRec.pdf;\n\n\t\t\t\t\t\t// TODO: Investigate offsetting this position to not self-intersect multiple times\n\t\t\t\t\t\t// Adding + scatterRec.direction * 1e-1 seems to fix almost all the fireflies\n\t\t\t\t\t\t// However that seems like a very large distance to offset\n\t\t\t\t\t\tray.origin = vertexData.position.xyz;\n\t\t\t\t\t\tray.direction = scatterRec.direction;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tlet rng = ${ rand2 }( ${ RNG_INDEX_ENVIRONMENT_SAMPLE } );\n\t\t\t\t\t\tif ( bounce > 0u ) {\n\n\t\t\t\t\t\t\tresultColor += ${ sampleEnvironmentFn }( envMap, envMapSampler, envInfo, ray.direction, rng ) * vec4f( throughputColor, 0.0 );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tresultColor = ${ sampleEnvironmentFn }( background, backgroundSampler, backgroundInfo, ray.direction, rng );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t${ rngNextBounce }();\n\n\t\t\t\t}\n\n\t\t\t\tlet sampleCount = textureLoad( ${ params.sampleCountTarget }, indexUV ).r + 1;\n\t\t\t\tlet prevColor = textureLoad( ${ params.prevOutputTarget }, indexUV );\n\t\t\t\tlet blendedColor = ${ weightedAlphaBlendFn }( prevColor, resultColor, 1.0 / f32( sampleCount ) );\n\t\t\t\ttextureStore( ${ params.sampleCountTarget }, indexUV, vec4( sampleCount ) );\n\t\t\t\ttextureStore( ${ params.outputTarget }, indexUV, blendedColor );\n\n\t\t\t}`;\n\n\t\tsuper( shader( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { DataUtils } from 'three';\n\n\nexport function toHalfFloatArray( f32Array ) {\n\n\tconst f16Array = new Uint16Array( f32Array.length );\n\tfor ( let i = 0, n = f32Array.length; i < n; ++ i ) {\n\n\t\tf16Array[ i ] = DataUtils.toHalfFloat( f32Array[ i ] );\n\n\t}\n\n\treturn f16Array;\n\n}\n","import { DataTexture, RedFormat, LinearFilter, DataUtils, HalfFloatType, Source, RepeatWrapping, RGBAFormat, FloatType, ClampToEdgeWrapping } from 'three';\nimport { toHalfFloatArray } from '../utils/TextureUtils.js';\n\nfunction binarySearchFindClosestIndexOf( array, targetValue, offset = 0, count = array.length ) {\n\n\tlet lower = offset;\n\tlet upper = offset + count - 1;\n\n\twhile ( lower < upper ) {\n\n\t\t// calculate the midpoint for this iteration using a bitwise shift right operator to save 1 floating point multiplication\n\t\t// and 1 truncation from the double tilde operator to improve performance\n\t\t// this results in much better performance over using standard \"~ ~ ( (lower + upper) ) / 2\" to calculate the midpoint\n\t\tconst mid = ( lower + upper ) >> 1;\n\n\t\t// check if the middle array value is above or below the target and shift\n\t\t// which half of the array we're looking at\n\t\tif ( array[ mid ] < targetValue ) {\n\n\t\t\tlower = mid + 1;\n\n\t\t} else {\n\n\t\t\tupper = mid;\n\n\t\t}\n\n\t}\n\n\treturn lower - offset;\n\n}\n\nfunction colorToLuminance( r, g, b ) {\n\n\t// https://en.wikipedia.org/wiki/Relative_luminance\n\treturn 0.2126 * r + 0.7152 * g + 0.0722 * b;\n\n}\n\n// ensures the data is all floating point values and flipY is false\nfunction preprocessEnvMap( envMap, targetType = HalfFloatType ) {\n\n\tconst map = envMap.clone();\n\tmap.source = new Source( { ...map.image } );\n\tconst { width, height, data } = map.image;\n\n\t// TODO: is there a simple way to avoid cloning and adjusting the env map data here?\n\t// convert the data from half float uint 16 arrays to float arrays for cdf computation\n\tlet newData = data;\n\tif ( map.type !== targetType ) {\n\n\t\tif ( targetType === HalfFloatType ) {\n\n\t\t\tnewData = new Uint16Array( data.length );\n\n\t\t} else {\n\n\t\t\tnewData = new Float32Array( data.length );\n\n\t\t}\n\n\t\tlet maxIntValue;\n\t\tif ( data instanceof Int8Array || data instanceof Int16Array || data instanceof Int32Array ) {\n\n\t\t\tmaxIntValue = 2 ** ( 8 * data.BYTES_PER_ELEMENT - 1 ) - 1;\n\n\t\t} else {\n\n\t\t\tmaxIntValue = 2 ** ( 8 * data.BYTES_PER_ELEMENT ) - 1;\n\n\t\t}\n\n\t\tfor ( let i = 0, l = data.length; i < l; i ++ ) {\n\n\t\t\tlet v = data[ i ];\n\t\t\tif ( map.type === HalfFloatType ) {\n\n\t\t\t\tv = DataUtils.fromHalfFloat( data[ i ] );\n\n\t\t\t}\n\n\t\t\tif ( map.type !== FloatType && map.type !== HalfFloatType ) {\n\n\t\t\t\tv /= maxIntValue;\n\n\t\t\t}\n\n\t\t\tif ( targetType === HalfFloatType ) {\n\n\t\t\t\tnewData[ i ] = DataUtils.toHalfFloat( v );\n\n\t\t\t}\n\n\t\t}\n\n\t\tmap.image.data = newData;\n\t\tmap.type = targetType;\n\n\t}\n\n\t// remove any y flipping for cdf computation\n\tif ( map.flipY ) {\n\n\t\tconst ogData = newData;\n\t\tnewData = newData.slice();\n\t\tfor ( let y = 0; y < height; y ++ ) {\n\n\t\t\tfor ( let x = 0; x < width; x ++ ) {\n\n\t\t\t\tconst newY = height - y - 1;\n\t\t\t\tconst ogIndex = 4 * ( y * width + x );\n\t\t\t\tconst newIndex = 4 * ( newY * width + x );\n\n\t\t\t\tnewData[ newIndex + 0 ] = ogData[ ogIndex + 0 ];\n\t\t\t\tnewData[ newIndex + 1 ] = ogData[ ogIndex + 1 ];\n\t\t\t\tnewData[ newIndex + 2 ] = ogData[ ogIndex + 2 ];\n\t\t\t\tnewData[ newIndex + 3 ] = ogData[ ogIndex + 3 ];\n\n\t\t\t}\n\n\t\t}\n\n\t\tmap.flipY = false;\n\t\tmap.image.data = newData;\n\n\t}\n\n\treturn map;\n\n}\n\nexport class EquirectHdrInfoUniform {\n\n\tconstructor() {\n\n\t\t// Default to a white texture and associated weights so we don't\n\t\t// just render black initially.\n\t\tconst blackTex = new DataTexture( toHalfFloatArray( new Float32Array( [ 0, 0, 0, 0 ] ) ), 1, 1 );\n\t\tblackTex.type = HalfFloatType;\n\t\tblackTex.format = RGBAFormat;\n\t\tblackTex.minFilter = LinearFilter;\n\t\tblackTex.magFilter = LinearFilter;\n\t\tblackTex.wrapS = RepeatWrapping;\n\t\tblackTex.wrapT = RepeatWrapping;\n\t\tblackTex.generateMipmaps = false;\n\t\tblackTex.needsUpdate = true;\n\n\t\t// Stores a map of [0, 1] value -> cumulative importance row & pdf\n\t\t// used to sampling a random value to a relevant row to sample from\n\t\tconst marginalWeights = new DataTexture( toHalfFloatArray( new Float32Array( [ 0, 1 ] ) ), 1, 2 );\n\t\tmarginalWeights.type = HalfFloatType;\n\t\tmarginalWeights.format = RedFormat;\n\t\tmarginalWeights.minFilter = LinearFilter;\n\t\tmarginalWeights.magFilter = LinearFilter;\n\t\tmarginalWeights.generateMipmaps = false;\n\t\tmarginalWeights.needsUpdate = true;\n\n\t\t// Stores a map of [0, 1] value -> cumulative importance column & pdf\n\t\t// used to sampling a random value to a relevant pixel to sample from\n\t\tconst conditionalWeights = new DataTexture( toHalfFloatArray( new Float32Array( [ 0, 0, 1, 1 ] ) ), 2, 2 );\n\t\tconditionalWeights.type = HalfFloatType;\n\t\tconditionalWeights.format = RedFormat;\n\t\tconditionalWeights.minFilter = LinearFilter;\n\t\tconditionalWeights.magFilter = LinearFilter;\n\t\tconditionalWeights.generateMipmaps = false;\n\t\tconditionalWeights.needsUpdate = true;\n\n\t\tthis.map = blackTex;\n\t\tthis.marginalWeights = marginalWeights;\n\t\tthis.conditionalWeights = conditionalWeights;\n\t\tthis.totalSum = 0;\n\n\t\t// TODO: Add support for float or half float types here. We need to pass this into\n\t\t// the preprocess function and ensure our CDF and MDF textures are appropriately sized\n\t\t// Ideally we wouldn't upscale a bit depth if we didn't need to.\n\t\t// this.type = HalfFloatType;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.marginalWeights.dispose();\n\t\tthis.conditionalWeights.dispose();\n\t\tthis.map.dispose();\n\n\t}\n\n\tupdateFrom( hdr ) {\n\n\t\t// https://github.com/knightcrawler25/GLSL-PathTracer/blob/3c6fd9b6b3da47cd50c527eeb45845eef06c55c3/src/loaders/hdrloader.cpp\n\t\t// https://pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Sampling_Light_Sources#InfiniteAreaLights\n\t\tconst map = preprocessEnvMap( hdr );\n\t\tmap.wrapS = RepeatWrapping;\n\t\tmap.wrapT = ClampToEdgeWrapping;\n\n\t\tconst { width, height, data } = map.image;\n\n\t\t// \"conditional\" = \"pixel relative to row pixels sum\"\n\t\t// \"marginal\" = \"row relative to row sum\"\n\n\t\t// track the importance of any given pixel in the image by tracking its weight relative to other pixels in the image\n\t\tconst pdfConditional = new Float32Array( width * height );\n\t\tconst cdfConditional = new Float32Array( width * height );\n\n\t\tconst pdfMarginal = new Float32Array( height );\n\t\tconst cdfMarginal = new Float32Array( height );\n\n\t\tlet totalSumValue = 0.0;\n\t\tlet cumulativeWeightMarginal = 0.0;\n\t\tfor ( let y = 0; y < height; y ++ ) {\n\n\t\t\tlet cumulativeRowWeight = 0.0;\n\t\t\tfor ( let x = 0; x < width; x ++ ) {\n\n\t\t\t\tconst i = y * width + x;\n\t\t\t\tconst r = DataUtils.fromHalfFloat( data[ 4 * i + 0 ] );\n\t\t\t\tconst g = DataUtils.fromHalfFloat( data[ 4 * i + 1 ] );\n\t\t\t\tconst b = DataUtils.fromHalfFloat( data[ 4 * i + 2 ] );\n\n\t\t\t\t// the probability of the pixel being selected in this row is the\n\t\t\t\t// scale of the luminance relative to the rest of the pixels.\n\t\t\t\t// TODO: this should also account for the solid angle of the pixel when sampling\n\t\t\t\tconst weight = colorToLuminance( r, g, b );\n\t\t\t\tcumulativeRowWeight += weight;\n\t\t\t\ttotalSumValue += weight;\n\n\t\t\t\tpdfConditional[ i ] = weight;\n\t\t\t\tcdfConditional[ i ] = cumulativeRowWeight;\n\n\t\t\t}\n\n\t\t\t// can happen if the row is all black\n\t\t\tif ( cumulativeRowWeight !== 0 ) {\n\n\t\t\t\t// scale the pdf and cdf to [0.0, 1.0]\n\t\t\t\tfor ( let i = y * width, l = y * width + width; i < l; i ++ ) {\n\n\t\t\t\t\tpdfConditional[ i ] /= cumulativeRowWeight;\n\t\t\t\t\tcdfConditional[ i ] /= cumulativeRowWeight;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tcumulativeWeightMarginal += cumulativeRowWeight;\n\n\t\t\t// compute the marginal pdf and cdf along the height of the map.\n\t\t\tpdfMarginal[ y ] = cumulativeRowWeight;\n\t\t\tcdfMarginal[ y ] = cumulativeWeightMarginal;\n\n\t\t}\n\n\t\t// can happen if the texture is all black\n\t\tif ( cumulativeWeightMarginal !== 0 ) {\n\n\t\t\t// scale the marginal pdf and cdf to [0.0, 1.0]\n\t\t\tfor ( let i = 0, l = pdfMarginal.length; i < l; i ++ ) {\n\n\t\t\t\tpdfMarginal[ i ] /= cumulativeWeightMarginal;\n\t\t\t\tcdfMarginal[ i ] /= cumulativeWeightMarginal;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// compute a sorted index of distributions and the probabilities along them for both\n\t\t// the marginal and conditional data. These will be used to sample with a random number\n\t\t// to retrieve a uv value to sample in the environment map.\n\t\t// These values continually increase so it's okay to interpolate between them.\n\t\tconst marginalDataArray = new Uint16Array( height );\n\t\tconst conditionalDataArray = new Uint16Array( width * height );\n\n\t\t// we add a half texel offset so we're sampling the center of the pixel\n\t\tfor ( let i = 0; i < height; i ++ ) {\n\n\t\t\tconst dist = ( i + 1 ) / height;\n\t\t\tconst row = binarySearchFindClosestIndexOf( cdfMarginal, dist );\n\n\t\t\tmarginalDataArray[ i ] = DataUtils.toHalfFloat( ( row + 0.5 ) / height );\n\n\t\t}\n\n\t\tfor ( let y = 0; y < height; y ++ ) {\n\n\t\t\tfor ( let x = 0; x < width; x ++ ) {\n\n\t\t\t\tconst i = y * width + x;\n\t\t\t\tconst dist = ( x + 1 ) / width;\n\t\t\t\tconst col = binarySearchFindClosestIndexOf( cdfConditional, dist, y * width, width );\n\n\t\t\t\tconditionalDataArray[ i ] = DataUtils.toHalfFloat( ( col + 0.5 ) / width );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.dispose();\n\n\t\tconst { marginalWeights, conditionalWeights } = this;\n\t\tmarginalWeights.image = { width: height, height: 1, data: marginalDataArray };\n\t\tmarginalWeights.needsUpdate = true;\n\n\t\tconditionalWeights.image = { width, height, data: conditionalDataArray };\n\t\tconditionalWeights.needsUpdate = true;\n\n\t\tthis.totalSum = totalSumValue;\n\t\tthis.map = map;\n\n\t}\n\n}\n","import { StorageTexture } from 'three/webgpu';\nimport { ComputeKernel } from './ComputeKernel.js';\nimport { textureStore, globalId } from 'three/tsl';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\nexport class ZeroOutKernel extends ComputeKernel {\n\n\tconstructor() {\n\n\t\tconst params = {\n\t\t\tglobalId: globalId,\n\t\t\toutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toWriteOnly(),\n\t\t};\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\t\t\tfn compute( globalId: vec3u ) -> void {\n\n\t\t\t\ttextureStore( ${ params.outputTarget }, globalId.xy, vec4( 0, 0, 0, 1 ) );\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( {\n\t\t\ttarget: params.outputTarget,\n\t\t} );\n\n\t}\n\n}\n","import { ColorManagement, FloatType, RGBAFormat } from 'three';\nimport { RedIntegerFormat, StorageTexture, UnsignedIntType } from 'three/webgpu';\nimport { ZeroOutKernel } from './compute/ZeroOutKernel.js';\n\nexport class PathTracerBackend {\n\n\tconstructor( renderer ) {\n\n\t\tthis.renderer = renderer;\n\t\tthis.camera = null;\n\t\tthis.samples = 0;\n\t\tthis.bounces = 7;\n\t\tthis.lowResMode = false;\n\n\t\tthis._renderTask = null;\n\n\t\tthis.outputTarget = new StorageTexture( 1, 1, );\n\t\tthis.outputTarget.format = RGBAFormat;\n\t\tthis.outputTarget.type = FloatType;\n\t\tthis.outputTarget.colorSpace = ColorManagement.workingColorSpace;\n\t\tthis.outputTarget.name = 'Output #0';\n\t\tthis.outputTarget.generateMipmaps = false;\n\n\t\tthis.prevOutputTarget = new StorageTexture( 1, 1, );\n\t\tthis.prevOutputTarget.format = RGBAFormat;\n\t\tthis.prevOutputTarget.type = FloatType;\n\t\tthis.prevOutputTarget.colorSpace = ColorManagement.workingColorSpace;\n\t\tthis.prevOutputTarget.name = 'Output #1';\n\t\tthis.prevOutputTarget.generateMipmaps = false;\n\n\t\tthis.sampleCountTarget = new StorageTexture( 1, 1, );\n\t\tthis.sampleCountTarget.format = RedIntegerFormat;\n\t\tthis.sampleCountTarget.type = UnsignedIntType;\n\t\tthis.sampleCountTarget.name = 'Sample Count';\n\t\tthis.sampleCountTarget.generateMipmaps = false;\n\n\t\tthis.sampleCountClearKernel = new ZeroOutKernel().setWorkgroupSize( 8, 8, 1 );\n\t\tthis.outputTargetClearKernel = new ZeroOutKernel().setWorkgroupSize( 8, 8, 1 );\n\n\t}\n\n\tsetCamera( camera ) {\n\n\t\tthis.camera = camera;\n\t\tthis.reset();\n\n\t}\n\n\tsetBVHData( data ) {\n\n\t}\n\n\tsetTextures( textures ) {\n\n\t}\n\n\tsetMaterial( material ) {\n\n\t}\n\n\tsetEnvironment(\n\t\tenvMap,\n\t\tenvMapIntensity,\n\t\tenvMapRotation,\n\n\t\tbackground,\n\t\tbackgroundIntensity,\n\t\tbackgroundRotation,\n\t\tbackgroundBlurriness,\n\t) {\n\n\t}\n\n\tsetSize( w, h ) {\n\n\t\tw = Math.ceil( w );\n\t\th = Math.ceil( h );\n\n\t\tconst { width, height } = this.outputTarget;\n\t\tif ( width === w && height === h ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tthis.outputTarget.dispose();\n\t\tthis.prevOutputTarget.dispose();\n\t\tthis.sampleCountTarget.dispose();\n\n\t\tthis.outputTarget = this.outputTarget.clone();\n\t\tthis.prevOutputTarget = this.outputTarget.clone();\n\t\tthis.sampleCountTarget = this.sampleCountTarget.clone();\n\n\t\tthis.outputTarget.setSize( w, h );\n\t\tthis.prevOutputTarget.setSize( w, h );\n\t\tthis.sampleCountTarget.setSize( w, h );\n\n\t\tthis.reset();\n\t\treturn true;\n\n\t}\n\n\tgetSize( target ) {\n\n\t\tconst { width, height } = this.outputTarget;\n\t\ttarget.x = width;\n\t\ttarget.y = height;\n\n\t\treturn target;\n\n\t}\n\n\tupdate() {\n\n\t\tconst { camera, renderer } = this;\n\t\tif ( ! camera || ! renderer.initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( ! this._renderTask ) {\n\n\t\t\tthis._renderTask = this.createRenderTask();\n\n\t\t}\n\n\t\tthis._renderTask.next();\n\n\t}\n\n\t*createRenderTask() {\n\n\t}\n\n\treset() {\n\n\t\tconst {\n\t\t\trenderer,\n\t\t\toutputTargetClearKernel,\n\t\t\tsampleCountClearKernel,\n\n\t\t\toutputTarget,\n\t\t\tprevOutputTarget,\n\t\t\tsampleCountTarget,\n\t\t} = this;\n\n\t\tif ( ! renderer.initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst { width, height } = outputTarget;\n\t\tconst dispatchSize = outputTargetClearKernel.getDispatchSize( width, height );\n\n\t\toutputTargetClearKernel.target = outputTarget;\n\t\trenderer.compute( outputTargetClearKernel.kernel, dispatchSize );\n\n\t\toutputTargetClearKernel.target = prevOutputTarget;\n\t\trenderer.compute( outputTargetClearKernel.kernel, dispatchSize );\n\n\t\tsampleCountClearKernel.target = sampleCountTarget;\n\t\trenderer.compute( sampleCountClearKernel.kernel, dispatchSize );\n\n\t\tthis.samples = 0;\n\t\tthis._renderTask = null;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.outputTarget.dispose();\n\t\tthis.prevOutputTarget.dispose();\n\t\tthis.sampleCountTarget.dispose();\n\n\t\tthis._renderTask = null;\n\n\t}\n\n}\n","import { Matrix4, Vector2 } from 'three/webgpu';\nimport { PathTracerMegaKernel } from './compute/PathTracerMegaKernel.js';\nimport { EquirectHdrInfoUniform } from '../uniforms/EquirectHdrInfoUniform.js';\nimport { PathTracerBackend } from './PathTracerBackend.js';\n\nexport class MegaKernelPathTracer extends PathTracerBackend {\n\n\tconstructor( renderer ) {\n\n\t\tsuper( renderer );\n\n\t\t// options\n\t\tthis.tiles = new Vector2( 2, 2 );\n\t\tthis.envInfo = new EquirectHdrInfoUniform();\n\t\tthis.samples = 0;\n\n\t\t// kernels\n\t\tthis.kernel = new PathTracerMegaKernel( ).setWorkgroupSize( 8, 8, 1 );\n\n\t}\n\n\tsetBVHData( bvhData ) {\n\n\t\tthis.kernel.bvhData = bvhData;\n\t\tthis.kernel.needsUpdate = true;\n\t\tthis.reset();\n\n\t}\n\n\tsetMaterial( material ) {\n\n\t\tthis.kernel.material = material.getData();\n\t\tthis.kernel.needsUpdate = true;\n\t\tthis.reset();\n\n\t}\n\n\tsetEnvironment(\n\t\tenvMap,\n\t\tenvMapIntensity,\n\t\tenvMapRotation,\n\n\t\tbackground,\n\t\tbackgroundIntensity,\n\t\tbackgroundRotation,\n\t\tbackgroundBlurriness,\n\t) {\n\n\t\tconst { kernel } = this;\n\n\t\tif ( kernel.background.isTexture ) {\n\n\t\t\tkernel.background.dispose();\n\n\t\t}\n\n\t\tif ( envMap !== null ) {\n\n\t\t\tthis.envInfo.updateFrom( envMap );\n\t\t\tkernel.envMap = this.envInfo.map;\n\t\t\tkernel.kernel.computeNode.parameters.envMapSampler.node.value = this.envInfo.map;\n\n\t\t}\n\n\t\tconst rotationMatrix = new Matrix4().makeRotationFromEuler( envMapRotation ).invert();\n\t\tkernel.envMapRotation.setFromMatrix4( rotationMatrix );\n\t\tkernel.envMapIntensity = envMapIntensity;\n\n\t\tkernel.background = background;\n\t\tkernel.kernel.computeNode.parameters.backgroundSampler.node.value = background;\n\t\trotationMatrix.makeRotationFromEuler( backgroundRotation ).invert();\n\t\tkernel.backgroundRotation.setFromMatrix4( rotationMatrix );\n\t\tkernel.backgroundIntensity = backgroundIntensity;\n\t\tkernel.backgroundBlurriness = backgroundBlurriness;\n\n\t}\n\n\tsetTiles( tiles ) {\n\n\t\tthis.tiles.copy( tiles );\n\n\t}\n\n\t*createRenderTask() {\n\n\t\tconst {\n\t\t\trenderer,\n\t\t\tcamera,\n\t\t\tkernel,\n\t\t\tbounces,\n\n\t\t\ttiles,\n\t\t\toutputTarget,\n\t\t\tsampleCountTarget,\n\t\t\tlowResMode,\n\t\t} = this;\n\n\t\tcamera.updateMatrixWorld();\n\n\t\t// init parameters\n\t\tkernel.outputTarget = outputTarget;\n\t\tkernel.sampleCountTarget = sampleCountTarget;\n\n\t\tkernel.bounces = bounces;\n\t\tkernel.inverseProjectionMatrix.copy( camera.projectionMatrixInverse );\n\t\tkernel.cameraToModelMatrix.copy( camera.matrixWorld );\n\n\t\twhile ( true ) {\n\n\t\t\tconst tileSize = kernel.tileSize;\n\t\t\tif ( lowResMode ) {\n\n\t\t\t\tthis.getSize( tileSize );\n\n\t\t\t} else {\n\n\t\t\t\tthis.getSize( tileSize ).divide( tiles ).ceil();\n\n\t\t\t}\n\n\t\t\tconst dispatchSize = kernel.getDispatchSize( tileSize.x, tileSize.y );\n\t\t\tkernel.seed += 1;\n\n\t\t\t// Swap targets to support devices without <rgba32float, read_write> textures\n\t\t\t// Copy latest data to a new outputTarget to keep the appearance\n\t\t\trenderer.copyTextureToTexture( this.outputTarget, this.prevOutputTarget );\n\t\t\t[ this.outputTarget, this.prevOutputTarget ] = [ this.prevOutputTarget, this.outputTarget ];\n\t\t\tkernel.prevOutputTarget = this.prevOutputTarget;\n\t\t\tkernel.outputTarget = this.outputTarget;\n\n\t\t\tfor ( let x = 0; x < tiles.x; x ++ ) {\n\n\t\t\t\tfor ( let y = 0; y < tiles.y; y ++ ) {\n\n\t\t\t\t\tkernel.offset.set( x, y ).multiply( tileSize );\n\t\t\t\t\trenderer.compute( kernel.kernel, dispatchSize );\n\t\t\t\t\tyield;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.samples ++;\n\n\t\t}\n\n\t}\n\n\tdispose() {\n\n\t\tsuper.dispose();\n\n\t\t// TODO: dispose of all buffers\n\t\tthis.envInfo.dispose();\n\n\t}\n\n}\n","import { StructTypeNode } from 'three/webgpu';\n\nexport const queuedRayStruct = new StructTypeNode( {\n\n\torigin: 'vec3f',\n\tseed: 'uint',\n\n\tdirection: 'vec3f',\n\t_alignment0: 'uint',\n\n\tthroughputColor: 'vec3f',\n\tcurrentBounce: 'uint',\n\n\tpixel: 'vec2u',\n\n\tresultColor: 'vec4f',\n\n}, 'QueuedRay' );\n\nexport const queuedHitStruct = new StructTypeNode( {\n\n\tindices: 'vec3u',\n\tseed: 'uint',\n\n\tbarycoord: 'vec2f',\n\tpixel_x: 'uint',\n\tpixel_y: 'uint',\n\n\tview: 'vec3f',\n\tcurrentBounce: 'uint',\n\n\tthroughputColor: 'vec3f',\n\tobjectIndex: 'uint',\n\n\tnormal: 'vec3f',\n\tside: 'float',\n\n\tresultColor: 'vec4f',\n\n}, 'QueuedHit' );\n","import { Vector2, Vector3 } from 'three';\nimport { IndirectStorageBufferAttribute } from 'three/webgpu';\nimport { uniform, storage } from 'three/tsl';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { queuedRayStruct } from './structs.js';\nimport { wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\n\nexport class PrimeRayGenerationDispatchKernel extends ComputeKernel {\n\n\tconstructor() {\n\n\t\tconst params = {\n\t\t\trayWorkGroupSize: uniform( new Vector3() ),\n\n\t\t\ttileSize: uniform( new Vector2() ),\n\t\t\ttileCount: uniform( new Vector2() ),\n\t\t\ttileOffset: uniform( 1 ),\n\n\t\t\trayQueue: storage( new IndirectStorageBufferAttribute( 1, queuedRayStruct.getLength() ), queuedRayStruct ).toReadOnly(),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ),\n\n\t\t\toutputTileIndex: storage( new IndirectStorageBufferAttribute( 2, 1 ), 'u32' ).setName( 'outputTileIndex' ),\n\t\t\toutputDispatch: storage( new IndirectStorageBufferAttribute( 3, 1 ), 'u32' ).setName( 'outputDispatch' ),\n\t\t};\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\t\t\tfn compute(\n\t\t\t\trayWorkGroupSize: vec3u,\n\n\t\t\t\ttileSize: vec2u,\n\t\t\t\ttileCount: vec2u,\n\t\t\t\ttileOffset: u32,\n\t\t\t) -> void {\n\n\t\t\t\tlet rayQueue = &${ params.rayQueue };\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\n\t\t\t\tlet outputTileIndex = &${ params.outputTileIndex };\n\t\t\t\tlet outputDispatch = &${ params.outputDispatch };\n\n\t\t\t\t// reset hit queue size from previous iteration\n\t\t\t\tqueueSizes[ 2 ] = 0u;\n\t\t\t\tqueueSizes[ 3 ] = 0u;\n\n\t\t\t\t// keep the queue index small\n\t\t\t let queueCapacity = arrayLength( rayQueue );\n\t\t\t\tif ( queueSizes[ 0 ] >= queueCapacity ) {\n\n\t\t\t\t\t// uint division results in a floored value\n\t\t\t\t\tlet offset = queueSizes[ 0 ] / queueCapacity;\n\t\t\t\t\tqueueSizes[ 0 ] = queueSizes[ 0 ] - queueCapacity * offset;\n\t\t\t\t\tqueueSizes[ 1 ] = queueSizes[ 1 ] - queueCapacity * offset;\n\n\t\t\t\t}\n\n\t\t\t\t// calculate the amount of elements in the queue\n\t\t\t var queueSize = queueSizes[ 1 ] - queueSizes[ 0 ];\n\n\t\t\t\t// calculate the overhead of space in the queue and how much space we need to run a new tile\n\t\t\t\tlet overhead = queueCapacity - queueSize;\n\t\t\t\tlet requiredSpace = tileSize.x * tileSize.y;\n\n\t\t\t\tif ( overhead >= requiredSpace ) {\n\n\t\t\t\t\t// calculate the necessary dispatch size to cover the tile\n\t\t\t\t\toutputDispatch[ 0 ] = u32( ceil( f32( tileSize.x ) / f32( rayWorkGroupSize.x ) ) );\n\t\t\t\t\toutputDispatch[ 1 ] = u32( ceil( f32( tileSize.y ) / f32( rayWorkGroupSize.y ) ) );\n\t\t\t\t\toutputDispatch[ 2 ] = 1;\n\n\t\t\t\t\t// calculate the tile index to generate rays for\n\t\t\t\t\tlet totalTiles = tileCount.x * tileCount.y;\n\t\t\t\t\tlet currentIndex = outputTileIndex[ 1 ] * tileCount.x + outputTileIndex[ 0 ];\n\t\t\t\t\tlet nextIndex = ( currentIndex + tileOffset ) % totalTiles;\n\n\t\t\t\t\toutputTileIndex[ 0 ] = nextIndex % tileCount.x;\n\t\t\t\t\toutputTileIndex[ 1 ] = nextIndex / tileCount.x;\n\n\t\t\t\t} else {\n\n\t\t\t\t\toutputDispatch[ 0 ] = 0;\n\t\t\t\t\toutputDispatch[ 1 ] = 0;\n\t\t\t\t\toutputDispatch[ 2 ] = 0;\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { Vector2, Matrix4 } from 'three';\nimport { IndirectStorageBufferAttribute, StorageTexture } from 'three/webgpu';\nimport { uniform, storage, globalId, textureStore } from 'three/tsl';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { rngInit, rand2, RNG_INDEX_RAY_JITTER } from '../../nodes/random.wgsl.js';\nimport { queuedRayStruct } from './structs.js';\nimport { ndcToCameraRay, wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\n\nexport class RayGenerationKernel extends ComputeKernel {\n\n\tconstructor( ) {\n\n\t\tconst params = {\n\t\t\tcameraToModelMatrix: uniform( new Matrix4() ),\n\t\t\tinverseProjectionMatrix: uniform( new Matrix4() ),\n\n\t\t\tseed: uniform( 0 ),\n\n\t\t\ttileIndexBuffer: storage( new IndirectStorageBufferAttribute( 2, 1 ), 'u32' ),\n\t\t\ttileSize: uniform( new Vector2() ),\n\n\t\t\trayQueue: storage( new IndirectStorageBufferAttribute( 1, queuedRayStruct.getLength() ), queuedRayStruct ),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ).toAtomic(),\n\n\t\t\tsampleCountTarget: textureStore( new StorageTexture() ).toReadWrite(),\n\n\t\t\tglobalId: globalId,\n\t\t};\n\n\t\tconst fn = wgslTagFn /* wgsl */`\n\t\t\tfn compute(\n\t\t\t\tcameraToModelMatrix: mat4x4f,\n\t\t\t\tinverseProjectionMatrix: mat4x4f,\n\n\t\t\t\tseed: u32,\n\t\t\t\ttileSize: vec2u,\n\n\t\t\t\tglobalId: vec3u\n\t\t\t) -> void {\n\n\t\t\t\tlet rayQueue = &${ params.rayQueue };\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\t\t\t\tlet tileIndexBuffer = &${ params.tileIndexBuffer };\n\n\t\t\t\t// don't overstep the edge of the tile\n\t\t\t\tif ( globalId.x >= tileSize.x || globalId.y >= tileSize.y ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// calculate the pixel index and ensure we are not generating rays outside the texture bounds\n\t\t\t\tlet offset = vec2( tileIndexBuffer[ 0 ] * tileSize.x, tileIndexBuffer[ 1 ] * tileSize.y );\n\t\t\t\tlet indexUV = offset + globalId.xy;\n\t\t\t\tlet targetDimensions = textureDimensions( ${ params.sampleCountTarget } );\n\t\t\t\tif ( indexUV.x >= targetDimensions.x || indexUV.y >= targetDimensions.y ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// calculate the screen uv\n\t\t\t\tlet uv = vec2f( indexUV ) / vec2f( targetDimensions );\n\t\t\t\tlet ndc = uv * 2.0 - vec2f( 1.0 );\n\n\t\t\t\t// check whether ray is already active (added on the queue) and skip it if it is\n\t\t\t\tlet ACTIVE_FLAG = 0xF0000000u;\n\t\t\t\tlet combinedField = textureLoad( ${ params.sampleCountTarget }, indexUV ).r;\n\t\t\t\tlet isActive = ( ACTIVE_FLAG & combinedField ) != 0;\n\t\t\t\tlet samples = ( ( ~ ACTIVE_FLAG ) & combinedField );\n\n\t\t\t\tif ( isActive ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// get the ray index\n\t\t\t\tlet queueCapacity = arrayLength( rayQueue );\n\t\t\t\tlet index = atomicAdd( &queueSizes[ 1 ], 1 ) % queueCapacity;\n\n\t\t\t\tlet pixelIndex = ( indexUV.x << 16 ) | indexUV.y;\n\t\t\t\t${ rngInit }( pixelIndex, seed, 0 );\n\n\t\t\t\t// write the ray data\n\t\t\t\tvar jitter = 2.0 * ${ rand2 }( ${ RNG_INDEX_RAY_JITTER } ) / vec2f( targetDimensions.xy );\n\t\t\t\tvar ray = ${ ndcToCameraRay }( ndc + jitter, cameraToModelMatrix * inverseProjectionMatrix );\n\t\t\t\tray.direction = normalize( ray.direction );\n\n\t\t\t\trayQueue[ index ].origin = ray.origin;\n\t\t\t\trayQueue[ index ].direction = ray.direction;\n\t\t\t\trayQueue[ index ].pixel = indexUV;\n\t\t\t\trayQueue[ index ].throughputColor = vec3f( 1.0 );\n\t\t\t\trayQueue[ index ].currentBounce = 0;\n\t\t\t\trayQueue[ index ].resultColor = vec4f( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\trayQueue[ index ].seed = seed;\n\n\t\t\t\t// write the active params\n\t\t\t\ttextureStore( ${ params.sampleCountTarget }, indexUV, vec4( ACTIVE_FLAG | samples ) );\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { DataTexture, Matrix3, IndirectStorageBufferAttribute, StorageTexture } from 'three/webgpu';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { uniform, texture, sampler, storage, textureStore, globalId } from 'three/tsl';\nimport { rngInit, rand2, RNG_INDEX_ENVIRONMENT_SAMPLE } from '../../nodes/random.wgsl.js';\nimport { queuedRayStruct, queuedHitStruct } from './structs.js';\nimport { proxy, wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\nimport { sampleEnvironmentFn, weightedAlphaBlendFn } from '../../nodes/sampling.wgsl.js';\n\nexport class RayIntersectionKernel extends ComputeKernel {\n\n\tconstructor( ) {\n\n\t\tconst params = {\n\t\t\tbvhData: { value: null },\n\n\t\t\tprevOutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadOnly(),\n\t\t\toutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toWriteOnly(),\n\t\t\tsampleCountTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadWrite(),\n\n\t\t\t// rays\n\t\t\trayQueue: storage( new IndirectStorageBufferAttribute( 1, queuedRayStruct.getLength() ), queuedRayStruct ).toReadOnly(),\n\t\t\thitQueue: storage( new IndirectStorageBufferAttribute( 1, queuedHitStruct.getLength() ), queuedHitStruct ),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ).toAtomic(),\n\n\t\t\t// environment\n\t\t\tenvMap: texture( new DataTexture() ),\n\t\t\tenvMapSampler: sampler( new DataTexture() ),\n\t\t\tenvMapRotation: uniform( new Matrix3() ),\n\t\t\tenvMapIntensity: uniform( 1 ),\n\n\t\t\tbackground: texture( new DataTexture() ),\n\t\t\tbackgroundSampler: sampler( new DataTexture() ),\n\t\t\tbackgroundRotation: uniform( new Matrix3() ),\n\t\t\tbackgroundIntensity: uniform( 1 ),\n\t\t\tbackgroundBlurriness: uniform( 0 ),\n\n\t\t\tglobalId: globalId,\n\t\t};\n\n\t\tconst raycastOutput = proxy( 'bvhData.value.fns.raycastFirstHit.outputType', params );\n\t\tconst raycastFirstHitFn = proxy( 'bvhData.value.fns.raycastFirstHit', params );\n\n\t\tconst fn = wgslTagFn /* wgsl */`\n\n\t\t\tfn compute(\n\t\t\t\t// environment\n\t\t\t\tenvMap: texture_2d<f32>,\n\t\t\t\tenvMapSampler: sampler,\n\t\t\t\tenvMapRotation: mat3x3f,\n\t\t\t\tenvMapIntensity: f32,\n\n\t\t\t\tbackground: texture_2d<f32>,\n\t\t\t\tbackgroundSampler: sampler,\n\t\t\t\tbackgroundRotation: mat3x3f,\n\t\t\t\tbackgroundIntensity: f32,\n\t\t\t\tbackgroundBlurriness: f32,\n\n\t\t\t\tglobalId: vec3u\n\t\t\t) -> void {\n\n\t\t\t\tlet rayQueue = &${ params.rayQueue };\n\t\t\t\tlet hitQueue = &${ params.hitQueue };\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\n\t\t\t\tlet envInfo = EnvironmentInfo(\n\t\t\t\t\tenvMapRotation,\n\t\t\t\t\tenvMapIntensity,\n\t\t\t\t\t0.0 // blur,\n\t\t\t\t);\n\n\t\t\t\tlet backgroundInfo = EnvironmentInfo(\n\t\t\t\t\tbackgroundRotation,\n\t\t\t\t\tbackgroundIntensity,\n\t\t\t\t\tbackgroundBlurriness,\n\t\t\t\t);\n\n\t\t\t\t// skip any rays invocations beyond the ray count\n\t\t\t\tlet queueCapacity = arrayLength( rayQueue );\n\t\t\t\tlet rayIndex = ( globalId.x + atomicLoad( &queueSizes[ 0 ] ) );\n\t\t\t\tif ( rayIndex >= atomicLoad( &queueSizes[ 1 ] ) ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// get the ray info\n\t\t\t\tlet ACTIVE_FLAG = 0xF0000000u;\n\t\t\t\tlet input = rayQueue[ rayIndex % queueCapacity ];\n\t\t\t\tlet indexUV = input.pixel;\n\n\t\t\t\tlet pixelIndex = ( indexUV.x << 16 ) | indexUV.y;\n\t\t\t\t${ rngInit }( pixelIndex, input.seed, input.currentBounce );\n\n\t\t\t\t// run intersection\n\t\t\t\tlet ray = Ray( input.origin, input.direction );\n\t\t\t\tvar hitResult: ${ raycastOutput };\n\t\t\t\tif ( ${ raycastFirstHitFn }( ray, &hitResult ) ) {\n\n\t\t\t\t\t// TODO: we process all of these materials immediately to push to the ray queue\n\t\t\t\t\tlet index = atomicAdd( &queueSizes[ 3 ], 1 );\n\t\t\t\t\thitQueue[ index ].view = - input.direction;\n\t\t\t\t\thitQueue[ index ].indices = hitResult.indices.xyz;\n\t\t\t\t\thitQueue[ index ].barycoord = hitResult.barycoord.xy;\n\t\t\t\t\thitQueue[ index ].normal = hitResult.normal.xyz;\n\t\t\t\t\thitQueue[ index ].side = hitResult.side;\n\t\t\t\t\thitQueue[ index ].pixel_x = indexUV.x;\n\t\t\t\t\thitQueue[ index ].pixel_y = indexUV.y;\n\t\t\t\t\thitQueue[ index ].objectIndex = hitResult.objectIndex;\n\t\t\t\t\thitQueue[ index ].throughputColor = input.throughputColor;\n\t\t\t\t\thitQueue[ index ].currentBounce = input.currentBounce;\n\t\t\t\t\thitQueue[ index ].resultColor = input.resultColor;\n\t\t\t\t\thitQueue[ index ].seed = input.seed;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet rng = ${ rand2 }( ${ RNG_INDEX_ENVIRONMENT_SAMPLE } );\n\t\t\t\t\tvar resultColor = input.resultColor;\n\t\t\t\t\tif ( input.currentBounce > 0u ) {\n\n\t\t\t\t\t\tresultColor += ${ sampleEnvironmentFn }( envMap, envMapSampler, envInfo, input.direction, rng ) * vec4f( input.throughputColor, 0.0 );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tresultColor = ${ sampleEnvironmentFn }( background, backgroundSampler, backgroundInfo, input.direction, rng );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet sampleCount = ( textureLoad( ${ params.sampleCountTarget }, indexUV ).r & ( ~ ACTIVE_FLAG ) ) + 1;\n\t\t\t\t\tlet prevColor = textureLoad( ${ params.prevOutputTarget }, indexUV );\n\t\t\t\t\tlet blendedColor = ${ weightedAlphaBlendFn }( prevColor, resultColor, 1.0 / f32( sampleCount ) );\n\t\t\t\t\ttextureStore( ${ params.sampleCountTarget }, indexUV, vec4( sampleCount ) );\n\t\t\t\t\ttextureStore( ${ params.outputTarget }, indexUV, blendedColor );\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { IndirectStorageBufferAttribute } from 'three/webgpu';\nimport { uniform, storage } from 'three/tsl';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\n\nexport class UpdateRayQueueParamsKernel extends ComputeKernel {\n\n\tconstructor() {\n\n\t\tconst params = {\n\t\t\tprocessed: uniform( 0 ),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ),\n\t\t};\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\t\t\tfn compute( processed: u32 ) -> void {\n\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\t\t\t var queueSize = queueSizes[ 1 ] - queueSizes[ 0 ];\n\t\t\t\tif ( processed > queueSize ) {\n\n\t\t\t\t\tqueueSizes[ 0 ] = queueSizes[ 1 ];\n\n\t\t\t\t} else {\n\n\t\t\t\t\tqueueSizes[ 0 ] = queueSizes[ 0 ] + processed;\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { IndirectStorageBufferAttribute } from 'three/webgpu';\nimport { ComputeKernel } from './ComputeKernel.js';\nimport { storage, globalId } from 'three/tsl';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\nexport class ZeroOutBufferKernel extends ComputeKernel {\n\n\tconstructor( options = {} ) {\n\n\t\tconst {\n\t\t\ttype = 'u32',\n\t\t} = options;\n\n\t\tconst params = {\n\t\t\tglobalId: globalId,\n\t\t\toutputTarget: storage( new IndirectStorageBufferAttribute( 1, 1 ), type ),\n\t\t};\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\t\t\tfn compute( globalId: vec3u ) -> void {\n\n\t\t\t\t${ params.outputTarget }[ globalId.x ] = 0;\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( {\n\t\t\ttarget: params.outputTarget,\n\t\t} );\n\n\t}\n\n}\n","import { IndirectStorageBufferAttribute, StorageTexture, DataTexture } from 'three/webgpu';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { uniform, storage, textureStore, globalId, texture, sampler } from 'three/tsl';\nimport { queuedRayStruct, queuedHitStruct } from './structs.js';\nimport { proxy, proxyFn, wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\nimport { weightedAlphaBlendFn } from '../../nodes/sampling.wgsl.js';\nimport { isTerminatingScatterFunc } from '../../nodes/utils.wgsl.js';\nimport { rngInit } from '../../nodes/random.wgsl.js';\n\nexport class ProcessHitsKernel extends ComputeKernel {\n\n\tconstructor( ) {\n\n\t\tconst params = {\n\t\t\tbvhData: { value: null },\n\t\t\tmaterial: { value: null },\n\n\t\t\tprevOutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadOnly(),\n\t\t\toutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toWriteOnly(),\n\t\t\tsampleCountTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadWrite(),\n\n\t\t\t// settings\n\t\t\tsmoothNormals: uniform( 1 ),\n\t\t\tbounces: uniform( 1 ),\n\n\t\t\t// rays\n\t\t\trayQueue: storage( new IndirectStorageBufferAttribute( 1, queuedRayStruct.getLength() ), queuedRayStruct ),\n\t\t\thitQueue: storage( new IndirectStorageBufferAttribute( 1, queuedHitStruct.getLength() ), queuedHitStruct ),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ).toAtomic(),\n\n\t\t\ttextures: texture( new DataTexture() ),\n\t\t\ttextureSampler: sampler( new DataTexture() ),\n\n\t\t\tglobalId: globalId,\n\t\t};\n\n\t\tconst sampleTrianglePointFn = proxyFn( 'bvhData.value.fns.sampleTrianglePoint', params );\n\t\tconst getSurfaceRecordFn = proxyFn( 'bvhData.value.fns.getSurfaceRecord', params );\n\t\tconst bsdfSampleFn = proxyFn( 'material.value.bsdfSample', params );\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\n\t\t\tfn compute(\n\t\t\t\t// settings\n\t\t\t\tsmoothNormals: u32,\n\t\t\t\tbounces: u32,\n\n\t\t\t\tglobalId: vec3u\n\t\t\t) -> void {\n\n\t\t\t\tlet rayQueue = &${ params.rayQueue };\n\t\t\t\tlet hitQueue = &${ params.hitQueue };\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\n\t\t\t\tlet materials = &${ proxy( 'bvhData.value.storage.materials', params ) };\n\t\t\t\tlet transforms = &${ proxy( 'bvhData.value.storage.transforms', params ) };\n\n\t\t\t\t// skip any rays invocations beyond the ray count\n\t\t\t\tlet hitQueueCapacity = arrayLength( hitQueue );\n\t\t\t\tlet hitIndex = ( globalId.x + atomicLoad( &queueSizes[ 2 ] ) );\n\t\t\t\tif ( hitIndex >= atomicLoad( &queueSizes[ 3 ] ) ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// get the ray info\n\t\t\t\tlet ACTIVE_FLAG = 0xF0000000u;\n\t\t\t\tlet input = hitQueue[ hitIndex ];\n\t\t\t\tlet indexUV = vec2u( input.pixel_x, input.pixel_y );\n\n\t\t\t\tlet pixelIndex = ( indexUV.x << 16 ) | indexUV.y;\n\t\t\t\t${ rngInit }( pixelIndex, input.seed, input.currentBounce );\n\n\t\t\t\tlet object = transforms[ input.objectIndex ];\n\t\t\t\tvar material = materials[ object.materialIndex ];\n\n\t\t\t\t// apply per-object colors\n\t\t\t\tmaterial.color *= object.color.rgb;\n\t\t\t\tmaterial.opacity *= object.color.a;\n\n\t\t\t\tlet barycoord = vec3( input.barycoord, 1.0 - input.barycoord.x - input.barycoord.y );\n\t\t\t\tvar vertexData = ${ sampleTrianglePointFn }( barycoord, input.indices.xyz );\n\t\t\t\tvertexData.normal = normalize( transpose( object.inverseMatrixWorld ) * vertexData.normal );\n\t\t\t\tvertexData.position = object.matrixWorld * vertexData.position;\n\n\t\t\t\tlet surface = ${ getSurfaceRecordFn }( material, vertexData, input.side, input.normal );\n\n\t\t\t\tlet scatterRec = ${ bsdfSampleFn }( input.view, surface );\n\n\t\t\t\tlet resultColor = input.resultColor + vec4f( input.throughputColor * surface.emission, 0.0 );\n\n\t\t\t\tlet isTerminated = input.currentBounce >= bounces || ${ isTerminatingScatterFunc }( scatterRec );\n\n\t\t\t\tif ( isTerminated ) {\n\n\t\t\t\t\t// terminate ray, write color\n\t\t\t\t\tlet sampleCount = ( textureLoad( ${ params.sampleCountTarget }, indexUV ).r & ( ~ ACTIVE_FLAG ) ) + 1;\n\t\t\t\t\tlet prevColor = textureLoad( ${ params.prevOutputTarget }, indexUV );\n\t\t\t\t\tlet blendedColor = ${ weightedAlphaBlendFn }( prevColor, resultColor, 1.0 / f32( sampleCount ) );\n\t\t\t\t\ttextureStore( ${ params.sampleCountTarget }, indexUV, vec4( sampleCount ) );\n\t\t\t\t\ttextureStore( ${ params.outputTarget }, indexUV, blendedColor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet rayQueueCapacity = arrayLength( rayQueue );\n\t\t\t\t\tlet index = atomicAdd( &queueSizes[ 1 ], 1 ) % rayQueueCapacity;\n\t\t\t\t\trayQueue[ index ].origin = vertexData.position.xyz;\n\t\t\t\t\trayQueue[ index ].direction = scatterRec.direction;\n\t\t\t\t\trayQueue[ index ].pixel = indexUV;\n\t\t\t\t\trayQueue[ index ].throughputColor = input.throughputColor * scatterRec.color / scatterRec.pdf;\n\t\t\t\t\trayQueue[ index ].currentBounce = input.currentBounce + 1;\n\t\t\t\t\trayQueue[ index ].resultColor = resultColor;\n\t\t\t\t\trayQueue[ index ].seed = input.seed;\n\n\t\t\t\t}\n\n\t\t\t}`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { Matrix4, IndirectStorageBufferAttribute, Vector2 } from 'three/webgpu';\nimport { PrimeRayGenerationDispatchKernel } from './compute/wavefront/PrimeRayGenerationDispatchKernel.js';\nimport { RayGenerationKernel } from './compute/wavefront/RayGenerationKernel.js';\nimport { RayIntersectionKernel } from './compute/wavefront/RayIntersectionKernel.js';\nimport { UpdateRayQueueParamsKernel } from './compute/wavefront/UpdateRayQueueParamsKernel.js';\nimport { ZeroOutBufferKernel } from './compute/ZeroOutBufferKernel.js';\nimport { ProcessHitsKernel } from './compute/wavefront/ProcessHitsKernel.js';\nimport { EquirectHdrInfoUniform } from '../uniforms/EquirectHdrInfoUniform.js';\nimport { queuedHitStruct, queuedRayStruct } from './compute/wavefront/structs.js';\nimport { PathTracerBackend } from './PathTracerBackend.js';\n\n// set the buffers to the max possible size supported by default (128MB)\n// TODO: this can be increased based on platform.\nconst RAYS_TO_PROCESS = 250000;\nconst MAX_BUFFER_SIZE = 134217728;\nconst MAX_RAY_COUNT = Math.floor( MAX_BUFFER_SIZE / ( queuedRayStruct.getLength() * 4 ) );\nconst MAX_HIT_COUNT = Math.floor( MAX_BUFFER_SIZE / ( queuedHitStruct.getLength() * 4 ) );\n\nexport class WaveFrontPathTracer extends PathTracerBackend {\n\n\tconstructor( renderer ) {\n\n\t\tsuper( renderer );\n\n\t\t// options\n\t\tthis.tiles = new Vector2( 3, 3 );\n\t\tthis.envInfo = new EquirectHdrInfoUniform();\n\n\t\t// queues\n\t\tthis.rayQueue = new IndirectStorageBufferAttribute( MAX_RAY_COUNT, queuedRayStruct.getLength() );\n\t\tthis.rayQueue.name = 'Ray Queue';\n\n\t\tthis.hitQueue = new IndirectStorageBufferAttribute( MAX_HIT_COUNT, queuedHitStruct.getLength() );\n\t\tthis.hitQueue.name = 'Hit Queue';\n\n\t\t// [0] ray head, [1] ray count, [2] hit head, [3] hit count\n\t\tthis.queueSizes = new IndirectStorageBufferAttribute( 4, 1 );\n\t\tthis.queueSizes.name = 'Queue Sizes';\n\n\t\t// dispatches\n\t\tthis.tileIndexBuffer = new IndirectStorageBufferAttribute( 2, 1 );\n\t\tthis.rayGenerationDispatch = new IndirectStorageBufferAttribute( 3, 1 );\n\t\tthis.hitProcessDispatch = new IndirectStorageBufferAttribute( 3, 1 );\n\n\t\t// kernels\n\t\tthis.primeRayGenerationDispatchKernel = new PrimeRayGenerationDispatchKernel().setWorkgroupSize( 1, 1, 1 );\n\t\tthis.enqueueRaysKernel = new RayGenerationKernel( ).setWorkgroupSize( 8, 8, 1 );\n\t\tthis.rayIntersectionKernel = new RayIntersectionKernel( ).setWorkgroupSize( 64, 1, 1 );\n\t\tthis.updateRayQueueParamsKernel = new UpdateRayQueueParamsKernel().setWorkgroupSize( 1, 1, 1 );\n\t\tthis.hitProcessKernel = new ProcessHitsKernel( ).setWorkgroupSize( 64, 1, 1 );\n\n\t\t// clear kernels\n\t\tthis.zeroDispatchKernel = new ZeroOutBufferKernel().setWorkgroupSize( 1, 1, 1 );\n\n\t\t// later\n\t\tthis.volumeKernel = null;\n\t\tthis.lightConnectionKernel = null;\n\n\t}\n\n\tsetBVHData( bvhData ) {\n\n\t\tthis.rayIntersectionKernel.bvhData = bvhData;\n\t\tthis.rayIntersectionKernel.needsUpdate = true;\n\n\t\tthis.hitProcessKernel.bvhData = bvhData;\n\t\tthis.hitProcessKernel.needsUpdate = true;\n\n\t\tthis.reset();\n\n\t}\n\n\tsetMaterial( material ) {\n\n\t\tthis.hitProcessKernel.material = material.getData();\n\t\tthis.hitProcessKernel.needsUpdate = true;\n\t\tthis.reset();\n\n\t}\n\n\tsetEnvironment(\n\t\tenvMap,\n\t\tenvMapIntensity,\n\t\tenvMapRotation,\n\n\t\tbackground,\n\t\tbackgroundIntensity,\n\t\tbackgroundRotation,\n\t\tbackgroundBlurriness,\n\t) {\n\n\t\tconst kernel = this.rayIntersectionKernel;\n\n\t\tif ( kernel.background.isTexture ) {\n\n\t\t\tkernel.background.dispose();\n\n\t\t}\n\n\t\tif ( envMap !== null ) {\n\n\t\t\tthis.envInfo.updateFrom( envMap );\n\t\t\tkernel.envMap = this.envInfo.map;\n\t\t\tkernel.kernel.computeNode.parameters.envMapSampler.node.value = this.envInfo.map;\n\n\t\t}\n\n\t\tconst rotationMatrix = new Matrix4().makeRotationFromEuler( envMapRotation ).invert();\n\t\tkernel.envMapRotation.setFromMatrix4( rotationMatrix );\n\t\tkernel.envMapIntensity = envMapIntensity;\n\n\t\tkernel.background = background;\n\t\tkernel.kernel.computeNode.parameters.backgroundSampler.node.value = background;\n\t\trotationMatrix.makeRotationFromEuler( backgroundRotation ).invert();\n\t\tkernel.backgroundRotation.setFromMatrix4( rotationMatrix );\n\t\tkernel.backgroundIntensity = backgroundIntensity;\n\t\tkernel.backgroundBlurriness = backgroundBlurriness;\n\n\t}\n\n\tsetTiles( tiles ) {\n\n\t\tthis.tiles.copy( tiles );\n\n\t}\n\n\tgetTileSize( target ) {\n\n\t\tthis.getSize( target ).divide( this.tiles ).ceil();\n\n\t\treturn target;\n\n\t}\n\n\tdispose() {\n\n\t\tsuper.dispose();\n\n\t\t// TODO: dispose of all buffers\n\t\tthis.envInfo.dispose();\n\n\t}\n\n\treset() {\n\n\t\tconst {\n\t\t\trenderer,\n\n\t\t\tsampleCountClearKernel,\n\t\t\tzeroDispatchKernel,\n\n\t\t\tsampleCountTarget,\n\n\t\t\thitProcessDispatch,\n\t\t\trayGenerationDispatch,\n\t\t\tqueueSizes,\n\t\t\ttileIndexBuffer,\n\t\t} = this;\n\n\t\tif ( ! renderer.initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tsuper.reset();\n\n\t\tthis.enqueueRaysKernel.seed = 0;\n\n\t\tconst { width, height } = sampleCountTarget;\n\t\tconst dispatchSize = sampleCountClearKernel.getDispatchSize( width, height );\n\n\t\t// clear buffers\n\t\tsampleCountClearKernel.target = sampleCountTarget;\n\t\trenderer.compute( sampleCountClearKernel.kernel, dispatchSize );\n\n\t\t// clear queues\n\t\t// TODO: why do we need to se the work group size here?\n\t\tzeroDispatchKernel.target = queueSizes;\n\t\trenderer.compute( zeroDispatchKernel.kernel, [ queueSizes.count ] );\n\n\t\t// clear dispatch sizes\n\t\tzeroDispatchKernel.target = hitProcessDispatch;\n\t\trenderer.compute( zeroDispatchKernel.kernel, [ hitProcessDispatch.count ] );\n\n\t\tzeroDispatchKernel.target = rayGenerationDispatch;\n\t\trenderer.compute( zeroDispatchKernel.kernel, [ rayGenerationDispatch.count ] );\n\n\t\tzeroDispatchKernel.target = tileIndexBuffer;\n\t\trenderer.compute( zeroDispatchKernel.kernel, [ tileIndexBuffer.count ] );\n\n\t}\n\n\t*createRenderTask() {\n\n\t\tconst {\n\t\t\trenderer,\n\t\t\tcamera,\n\t\t\tbounces,\n\n\t\t\ttiles,\n\t\t\tsampleCountTarget,\n\n\t\t\trayQueue,\n\t\t\thitQueue,\n\t\t\tqueueSizes,\n\t\t\trayGenerationDispatch,\n\t\t\t// hitProcessDispatch,\n\t\t\ttileIndexBuffer,\n\n\t\t\tprimeRayGenerationDispatchKernel,\n\t\t\tenqueueRaysKernel,\n\t\t\trayIntersectionKernel,\n\t\t\tupdateRayQueueParamsKernel,\n\t\t\thitProcessKernel,\n\n\t\t\tlowResMode\n\t\t} = this;\n\n\t\tcamera.updateMatrixWorld();\n\n\t\tprimeRayGenerationDispatchKernel.tileOffset = 0;\n\n\t\tconst tileSize = new Vector2();\n\t\tconst samplesPerIteration = RAYS_TO_PROCESS / ( sampleCountTarget.width * sampleCountTarget.height * bounces );\n\t\tconst iter = lowResMode ? 5 : 1;\n\t\tlet samples = 0;\n\n\t\twhile ( true ) {\n\n\t\t\tfor ( let i = 0; i < iter; i ++ ) {\n\n\t\t\t\tthis.getTileSize( tileSize );\n\n\t\t\t\t// Swap targets to support devices without <rgba32float, read_write> textures\n\t\t\t\t// Copy latest data to a new outputTarget to keep the appearance\n\t\t\t\trenderer.copyTextureToTexture( this.outputTarget, this.prevOutputTarget );\n\t\t\t\t[ this.outputTarget, this.prevOutputTarget ] = [ this.prevOutputTarget, this.outputTarget ];\n\t\t\t\trayIntersectionKernel.prevOutputTarget = this.prevOutputTarget;\n\t\t\t\trayIntersectionKernel.outputTarget = this.outputTarget;\n\t\t\t\thitProcessKernel.prevOutputTarget = this.prevOutputTarget;\n\t\t\t\thitProcessKernel.outputTarget = this.outputTarget;\n\n\t\t\t\t// Step 1: Top up the ray queue\n\t\t\t\t// set up the ray prime kernel\n\t\t\t\tprimeRayGenerationDispatchKernel.rayWorkGroupSize.set( 8, 8, 1 );\n\t\t\t\tprimeRayGenerationDispatchKernel.tileCount.copy( tiles );\n\t\t\t\tprimeRayGenerationDispatchKernel.tileSize.copy( tileSize );\n\t\t\t\tprimeRayGenerationDispatchKernel.rayQueue = rayQueue;\n\t\t\t\tprimeRayGenerationDispatchKernel.queueSizes = queueSizes;\n\t\t\t\tprimeRayGenerationDispatchKernel.outputTileIndex = tileIndexBuffer;\n\t\t\t\tprimeRayGenerationDispatchKernel.outputDispatch = rayGenerationDispatch;\n\n\t\t\t\t// set up the ray generation kernel\n\t\t\t\tenqueueRaysKernel.seed ++;\n\t\t\t\tenqueueRaysKernel.cameraToModelMatrix.copy( camera.matrixWorld );\n\t\t\t\tenqueueRaysKernel.inverseProjectionMatrix.copy( camera.projectionMatrixInverse );\n\t\t\t\tenqueueRaysKernel.tileIndexBuffer = tileIndexBuffer;\n\t\t\t\tenqueueRaysKernel.tileSize.copy( tileSize );\n\t\t\t\tenqueueRaysKernel.rayQueue = rayQueue;\n\t\t\t\tenqueueRaysKernel.queueSizes = queueSizes;\n\t\t\t\tenqueueRaysKernel.sampleCountTarget = sampleCountTarget;\n\n\t\t\t\tfor ( let i = 0; i < tiles.x * tiles.y; i ++ ) {\n\n\t\t\t\t\t// TODO: skip rays that have converged, have reach max samples\n\t\t\t\t\trenderer.compute( primeRayGenerationDispatchKernel.kernel, [ 1, 1, 1 ] );\n\t\t\t\t\trenderer.compute( enqueueRaysKernel.kernel, rayGenerationDispatch );\n\t\t\t\t\tprimeRayGenerationDispatchKernel.tileOffset = 1;\n\n\t\t\t\t}\n\n\t\t\t\t// Step 2: run intersections, add color for terminated rays, add material handling to a dedicated queue\n\t\t\t\t// TODO: setting dispatch size to 10000 is causing failures / missed rays\n\t\t\t\tconst intersectDispatch = rayIntersectionKernel.getDispatchSize( RAYS_TO_PROCESS, 1, 1 );\n\t\t\t\trayIntersectionKernel.sampleCountTarget = sampleCountTarget;\n\t\t\t\trayIntersectionKernel.rayQueue = rayQueue;\n\t\t\t\trayIntersectionKernel.queueSizes = queueSizes;\n\t\t\t\trayIntersectionKernel.hitQueue = hitQueue;\n\t\t\t\trenderer.compute( rayIntersectionKernel.kernel, intersectDispatch );\n\n\t\t\t\t// mark the rays as consumed\n\t\t\t\tconst processed = intersectDispatch[ 0 ] * rayIntersectionKernel.workgroupSize[ 0 ];\n\t\t\t\tupdateRayQueueParamsKernel.processed = processed;\n\t\t\t\tupdateRayQueueParamsKernel.queueSizes = queueSizes;\n\t\t\t\trenderer.compute( updateRayQueueParamsKernel.kernel, [ 1, 1, 1 ] );\n\n\t\t\t\t// TODO: we should use an indirect dispatch here to only kick off the number of threads\n\t\t\t\t// as needed to iterate over all the fields\n\t\t\t\t// Step 3: attenuate ray color, scatter, run russian roulette\n\t\t\t\thitProcessKernel.sampleCountTarget = sampleCountTarget;\n\t\t\t\thitProcessKernel.bounces = bounces;\n\t\t\t\thitProcessKernel.rayQueue = rayQueue;\n\t\t\t\thitProcessKernel.queueSizes = queueSizes;\n\t\t\t\thitProcessKernel.hitQueue = hitQueue;\n\t\t\t\trenderer.compute( hitProcessKernel.kernel, hitProcessKernel.getDispatchSize( processed, 1, 1 ) );\n\t\t\t\t// Note: hit queue size ([2] and [3]) is reset at the top of the next iteration by PrimeRayGenerationDispatchKernel\n\n\t\t\t\t// Step 4: connect to lights\n\t\t\t\t// TODO\n\n\t\t\t\t// Future\n\t\t\t\t// - track variance to skip rays\n\t\t\t\t// - switch to rays pushing themselves onto the queue when terminating to avoid tiles once enough pixels have completed\n\t\t\t\t// - separate \"volume\" step?\n\t\t\t\t// - allow for simultaneous writes by queue pixel writes, sorting, and blending them in a single thread\n\n\t\t\t\tsamples += samplesPerIteration;\n\t\t\t\tthis.samples = Math.floor( samples );\n\n\t\t\t}\n\n\t\t\tyield;\n\n\t\t}\n\n\t}\n\n}\n","export const util_functions = /* glsl */`\n\n\t// TODO: possibly this should be renamed something related to material or path tracing logic\n\n\t#ifndef RAY_OFFSET\n\t#define RAY_OFFSET 1e-4\n\t#endif\n\n\t// adjust the hit point by the surface normal by a factor of some offset and the\n\t// maximum component-wise value of the current point to accommodate floating point\n\t// error as values increase.\n\tvec3 stepRayOrigin( vec3 rayOrigin, vec3 rayDirection, vec3 offset, float dist ) {\n\n\t\tvec3 point = rayOrigin + rayDirection * dist;\n\t\tvec3 absPoint = abs( point );\n\t\tfloat maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );\n\t\treturn point + offset * ( maxPoint + 1.0 ) * RAY_OFFSET;\n\n\t}\n\n\t// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation\n\tvec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {\n\n\t\tvec3 ot = - log( attColor ) / attDist;\n\t\treturn exp( - ot * dist );\n\n\t}\n\n\tvec3 getHalfVector( vec3 wi, vec3 wo, float eta ) {\n\n\t\t// get the half vector - assuming if the light incident vector is on the other side\n\t\t// of the that it's transmissive.\n\t\tvec3 h;\n\t\tif ( wi.z > 0.0 ) {\n\n\t\t\th = normalize( wi + wo );\n\n\t\t} else {\n\n\t\t\t// Scale by the ior ratio to retrieve the appropriate half vector\n\t\t\t// From Section 2.2 on computing the transmission half vector:\n\t\t\t// https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf\n\t\t\th = normalize( wi + wo * eta );\n\n\t\t}\n\n\t\th *= sign( h.z );\n\t\treturn h;\n\n\t}\n\n\tvec3 getHalfVector( vec3 a, vec3 b ) {\n\n\t\treturn normalize( a + b );\n\n\t}\n\n\t// The discrepancy between interpolated surface normal and geometry normal can cause issues when a ray\n\t// is cast that is on the top side of the geometry normal plane but below the surface normal plane. If\n\t// we find a ray like that we ignore it to avoid artifacts.\n\t// This function returns if the direction is on the same side of both planes.\n\tbool isDirectionValid( vec3 direction, vec3 surfaceNormal, vec3 geometryNormal ) {\n\n\t\tbool aboveSurfaceNormal = dot( direction, surfaceNormal ) > 0.0;\n\t\tbool aboveGeometryNormal = dot( direction, geometryNormal ) > 0.0;\n\t\treturn aboveSurfaceNormal == aboveGeometryNormal;\n\n\t}\n\n\t// ray sampling x and z are swapped to align with expected background view\n\tvec2 equirectDirectionToUv( vec3 direction ) {\n\n\t\t// from Spherical.setFromCartesianCoords\n\t\tvec2 uv = vec2( atan( direction.z, direction.x ), acos( direction.y ) );\n\t\tuv /= vec2( 2.0 * PI, PI );\n\n\t\t// apply adjustments to get values in range [0, 1] and y right side up\n\t\tuv.x += 0.5;\n\t\tuv.y = 1.0 - uv.y;\n\t\treturn uv;\n\n\t}\n\n\tvec3 equirectUvToDirection( vec2 uv ) {\n\n\t\t// undo above adjustments\n\t\tuv.x -= 0.5;\n\t\tuv.y = 1.0 - uv.y;\n\n\t\t// from Vector3.setFromSphericalCoords\n\t\tfloat theta = uv.x * 2.0 * PI;\n\t\tfloat phi = uv.y * PI;\n\n\t\tfloat sinPhi = sin( phi );\n\n\t\treturn vec3( sinPhi * cos( theta ), cos( phi ), sinPhi * sin( theta ) );\n\n\t}\n\n\t// power heuristic for multiple importance sampling\n\tfloat misHeuristic( float a, float b ) {\n\n\t\tfloat aa = a * a;\n\t\tfloat bb = b * b;\n\t\treturn aa / ( aa + bb );\n\n\t}\n\n\t// tentFilter from Peter Shirley's 'Realistic Ray Tracing (2nd Edition)' book, pg. 60\n\t// erichlof/THREE.js-PathTracing-Renderer/\n\tfloat tentFilter( float x ) {\n\n\t\treturn x < 0.5 ? sqrt( 2.0 * x ) - 1.0 : 1.0 - sqrt( 2.0 - ( 2.0 * x ) );\n\n\t}\n`;\n","import {\n\tDataTexture,\n\tDataUtils,\n\tEquirectangularReflectionMapping,\n\tFloatType,\n\tHalfFloatType,\n\tLinearFilter,\n\tLinearMipMapLinearFilter,\n\tRGBAFormat,\n\tRepeatWrapping,\n\tShaderMaterial,\n\tWebGLRenderTarget,\n} from 'three';\nimport { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';\nimport * as CommonGLSL from '../shader/common/index.js';\n\nclass CubeToEquirectMaterial extends ShaderMaterial {\n\n\tconstructor() {\n\n\t\tsuper( {\n\n\t\t\tuniforms: {\n\n\t\t\t\tenvMap: { value: null },\n\t\t\t\tflipEnvMap: { value: - 1 },\n\n\t\t\t},\n\n\t\t\tvertexShader: /* glsl */`\n\t\t\t\tvarying vec2 vUv;\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvUv = uv;\n\t\t\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t\t\t}`,\n\n\t\t\tfragmentShader: /* glsl */`\n\t\t\t\t#define ENVMAP_TYPE_CUBE_UV\n\n\t\t\t\tuniform samplerCube envMap;\n\t\t\t\tuniform float flipEnvMap;\n\t\t\t\tvarying vec2 vUv;\n\n\t\t\t\t#include <common>\n\t\t\t\t#include <cube_uv_reflection_fragment>\n\n\t\t\t\t${ CommonGLSL.util_functions }\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 rayDirection = equirectUvToDirection( vUv );\n\t\t\t\t\trayDirection.x *= flipEnvMap;\n\t\t\t\t\tgl_FragColor = textureCube( envMap, rayDirection );\n\n\t\t\t\t}`\n\t\t} );\n\n\t\tthis.depthWrite = false;\n\t\tthis.depthTest = false;\n\n\t}\n\n}\n\nexport class CubeToEquirectGenerator {\n\n\tconstructor( renderer ) {\n\n\t\tthis._renderer = renderer;\n\t\tthis._quad = new FullScreenQuad( new CubeToEquirectMaterial() );\n\n\t}\n\n\tgenerate( source, width = null, height = null ) {\n\n\t\tif ( ! source.isCubeTexture ) {\n\n\t\t\tthrow new Error( 'CubeToEquirectMaterial: Source can only be cube textures.' );\n\n\t\t}\n\n\t\tconst image = source.images[ 0 ];\n\t\tconst renderer = this._renderer;\n\t\tconst quad = this._quad;\n\n\t\t// determine the dimensions if not provided\n\t\tif ( width === null ) {\n\n\t\t\twidth = 4 * image.height;\n\n\t\t}\n\n\t\tif ( height === null ) {\n\n\t\t\theight = 2 * image.height;\n\n\t\t}\n\n\t\tconst target = new WebGLRenderTarget( width, height, {\n\t\t\ttype: FloatType,\n\t\t\tcolorSpace: image.colorSpace,\n\t\t} );\n\n\t\t// prep the cube map data\n\t\tconst imageHeight = image.height;\n\t\tconst maxMip = Math.log2( imageHeight ) - 2;\n\t\tconst texelHeight = 1.0 / imageHeight;\n\t\tconst texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );\n\n\t\tquad.material.defines.CUBEUV_MAX_MIP = `${ maxMip }.0`;\n\t\tquad.material.defines.CUBEUV_TEXEL_WIDTH = texelWidth;\n\t\tquad.material.defines.CUBEUV_TEXEL_HEIGHT = texelHeight;\n\t\tquad.material.uniforms.envMap.value = source;\n\t\tquad.material.uniforms.flipEnvMap.value = source.isRenderTargetTexture ? 1 : - 1;\n\t\tquad.material.needsUpdate = true;\n\n\t\t// save state and render the contents\n\t\tconst currentTarget = renderer.getRenderTarget();\n\t\tconst currentAutoClear = renderer.autoClear;\n\t\trenderer.autoClear = true;\n\t\trenderer.setRenderTarget( target );\n\t\tquad.render( renderer );\n\t\trenderer.setRenderTarget( currentTarget );\n\t\trenderer.autoClear = currentAutoClear;\n\n\t\t// read the data back\n\t\tconst buffer = new Uint16Array( width * height * 4 );\n\t\tconst readBuffer = new Float32Array( width * height * 4 );\n\t\trenderer.readRenderTargetPixels( target, 0, 0, width, height, readBuffer );\n\t\ttarget.dispose();\n\n\t\tfor ( let i = 0, l = readBuffer.length; i < l; i ++ ) {\n\n\t\t\tbuffer[ i ] = DataUtils.toHalfFloat( readBuffer[ i ] );\n\n\t\t}\n\n\t\t// produce the data texture\n\t\tconst result = new DataTexture( buffer, width, height, RGBAFormat, HalfFloatType );\n\t\tresult.minFilter = LinearMipMapLinearFilter;\n\t\tresult.magFilter = LinearFilter;\n\t\tresult.wrapS = RepeatWrapping;\n\t\tresult.wrapT = RepeatWrapping;\n\t\tresult.mapping = EquirectangularReflectionMapping;\n\t\tresult.needsUpdate = true;\n\n\t\treturn result;\n\n\t}\n\n\tdispose() {\n\n\t\tthis._quad.dispose();\n\n\t}\n\n}\n","function uuidSort( a, b ) {\n\n\tif ( a.uuid < b.uuid ) return 1;\n\tif ( a.uuid > b.uuid ) return - 1;\n\treturn 0;\n\n}\n\n// we must hash the texture to determine uniqueness using the encoding, as well, because the\n// when rendering each texture to the texture array they must have a consistent color space.\nexport function getTextureHash( t ) {\n\n\treturn `${ t.source.uuid }:${ t.colorSpace }`;\n\n}\n\n// reduce the set of textures to just those with a unique source while retaining\n// the order of the textures.\nfunction reduceTexturesToUniqueSources( textures ) {\n\n\tconst sourceSet = new Set();\n\tconst result = [];\n\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\tconst tex = textures[ i ];\n\t\tconst hash = getTextureHash( tex );\n\t\tif ( ! sourceSet.has( hash ) ) {\n\n\t\t\tsourceSet.add( hash );\n\t\t\tresult.push( tex );\n\n\t\t}\n\n\t}\n\n\treturn result;\n\n}\n\nexport function getIesTextures( lights ) {\n\n\tconst textures = lights.map( l => l.iesMap || null ).filter( t => t );\n\tconst textureSet = new Set( textures );\n\treturn Array.from( textureSet ).sort( uuidSort );\n\n}\n\nexport function getTextures( materials ) {\n\n\tconst textureSet = new Set();\n\tfor ( let i = 0, l = materials.length; i < l; i ++ ) {\n\n\t\tconst material = materials[ i ];\n\t\tfor ( const key in material ) {\n\n\t\t\tconst value = material[ key ];\n\t\t\tif ( value && value.isTexture ) {\n\n\t\t\t\ttextureSet.add( value );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tconst textureArray = Array.from( textureSet );\n\treturn reduceTexturesToUniqueSources( textureArray ).sort( uuidSort );\n\n}\n\nexport function getLights( scene ) {\n\n\tconst lights = [];\n\tscene.traverse( c => {\n\n\t\tif ( c.visible ) {\n\n\t\t\tif (\n\t\t\t\tc.isRectAreaLight ||\n\t\t\t\tc.isSpotLight ||\n\t\t\t\tc.isPointLight ||\n\t\t\t\tc.isDirectionalLight\n\t\t\t) {\n\n\t\t\t\tlights.push( c );\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\treturn lights.sort( uuidSort );\n\n}\n","import { wgslFn } from 'three/tsl';\nimport { constants } from './structs.wgsl.js';\n\n// See sampling.wgsl for vector shorthand explanations\n// The GGX functions provide sampling and distribution information for normals as output so\n// in order to get probability of scatter direction the half vector must be computed and provided.\n// [0] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf\n// [1] https://hal.archives-ouvertes.fr/hal-01509746/document\n// [2] http://jcgt.org/published/0007/04/01/\n// [4] http://jcgt.org/published/0003/02/03/\n// [5] https://seblagarde.wordpress.com/wp-content/uploads/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf\n// trowbridge-reitz === GGX === GTR\nexport const ggxDirectionFunc = wgslFn( /* wgsl */ `\n\n\tfn ggxDirection( incidentDir: vec3f, alpha: vec2f, uv: vec2f ) -> vec3f {\n\n\t\t// Implementation from reference [1]\n\t\t// stretch view\n\t\tlet V = normalize( vec3f( alpha * incidentDir.xy, incidentDir.z ) );\n\n\t\t// orthonormal basis\n\t\tvar T1: vec3f;\n\t\tif ( V.z < 0.9999 ) {\n\t\t\tT1 = normalize( cross( V, vec3( 0.0, 0.0, 1.0 ) ) );\n\t\t} else {\n\t\t\tT1 = vec3( 1.0, 0.0, 0.0 );\n\t\t}\n\n\t\tlet T2 = cross( T1, V );\n\n\t\t// sample point with polar coordinates (r, phi)\n\t\tlet a = 1.0 / ( 1.0 + V.z );\n\t\tlet r = sqrt( uv.x );\n\t\tvar phi: f32;\n\t\tif ( uv.y < a ) {\n\t\t\tphi = uv.y / a * PI;\n\t\t} else {\n\t\t\tphi = PI + ( uv.y - a ) / ( 1.0 - a ) * PI;\n\t\t}\n\t\tlet P1 = r * cos( phi );\n\t\tvar P2 = r * sin( phi );\n\t\tif ( uv.y >= a ) {\n\t\t\tP2 *= V.z;\n\t\t}\n\n\t\t// compute normal\n\t\tvar N = P1 * T1 + P2 * T2 + V * sqrt( max( 0.0, 1.0 - P1 * P1 - P2 * P2 ) );\n\n\t\t// unstretch\n\t\tN = normalize( vec3( alpha * N.xy, max( 0.0, N.z ) ) );\n\n\t\treturn N;\n\n\t}\n\n`, [ constants ] );\n\n// Below are PDF and related functions for use in a Monte Carlo path tracer\n// as specified in Appendix B of the following paper\n// See equation (34) from reference [0]\nexport const ggxLamdaFunc = wgslFn( /* wgsl */ `\n\n\tfn ggxLamda( theta: f32, alpha: f32 ) -> f32 {\n\n\t\tlet tanTheta = tan( theta );\n\t\tlet tanTheta2 = tanTheta * tanTheta;\n\t\tlet alpha2 = alpha * alpha;\n\n\t\tlet numerator = - 1.0 + sqrt( 1.0 + alpha2 * tanTheta2 );\n\t\treturn numerator / 2.0;\n\n\t}\n\n` );\n\n// Based on equation (34) from reference [0]\nexport const ggxShadowMaskG1Func = wgslFn( /* wgsl */ `\n\n\tfn ggxShadowMaskG1( cosTheta: f32, alpha: f32 ) -> f32 {\n\n\t\tlet a2 = alpha * alpha;\n\t\tlet cosTheta2 = cosTheta * cosTheta;\n\t\tlet denom = cosTheta + sqrt( cosTheta2 * ( 1 - a2 ) + a2 );\n\t\treturn 2.0 * cosTheta / denom;\n\n\t}\n\n`, [ ggxLamdaFunc ] );\n\n// See listing 2 from reference [5]\nexport const ggxSmithVisibilityFunc = wgslFn( /* wgsl */ `\n\n\tfn ggxSmithVisibility( NdotV: f32, NdotL: f32, alpha: f32 ) -> f32 {\n\n\t\t// Original formulation of G_SmithGGX Correlated\n\t\t// lambda_v = ( -1 + sqrt ( alphaG2 * (1 - NdotL2 ) / NdotL2 + 1)) * 0.5 f;\n\t\t// lambda_l = ( -1 + sqrt ( alphaG2 * (1 - NdotV2 ) / NdotV2 + 1)) * 0.5 f;\n\t\t// G_SmithGGXCorrelated = 1 / (1 + lambda_v + lambda_l );\n\t\t// V_SmithGGXCorrelated = G_SmithGGXCorrelated / (4.0 f * NdotL * NdotV );\n\n\t\t// This is an optimized version\n\t\tlet alpha2 = alpha * alpha;\n\t\t// Caution: the \"NdotL *\" and \"NdotV *\" are explicitely inversed , this is not a mistake.\n\t\tlet Lambda_GGXV = NdotL * sqrt (( - NdotV * alpha2 + NdotV ) * NdotV + alpha2 );\n\t\tlet Lambda_GGXL = NdotV * sqrt (( - NdotL * alpha2 + NdotL ) * NdotL + alpha2 );\n\n\t\treturn 0.5 / ( Lambda_GGXV + Lambda_GGXL );\n\n\t}\n\n`, [ ggxLamdaFunc ] );\n\n\n// See listing 2 from reference [5]\nexport const ggxDistributionFunc = wgslFn( /* wgsl */ `\n\tfn ggxDistribution( NdotH: f32, alpha: f32 ) -> f32 {\n\n\t\tlet a2 = max( alpha * alpha, EPSILON );\n\t\tlet denom = NdotH * NdotH * ( a2 - 1 ) + 1;\n\n\t\treturn ( a2 / ( PI * denom * denom ) );\n\n\t}\n`, );\n\n// ggxPDF, divided by the Jacobian of reflection operation\n// See equation (17) from [2]\n// Note: HdotV cancel out bc its guaranteed to be > 0\nexport const ggxReflectionAdjustedPDFFunc = wgslFn( /* wgsl */ `\n\tfn ggxReflectionAdjustedPDF( NdotV: f32, NdotH: f32, alpha: f32 ) -> f32 {\n\n\t\tlet D = ggxDistribution( NdotH, alpha );\n\t\tlet G1 = ggxShadowMaskG1( NdotV, alpha );\n\n\t\treturn D * G1 / ( 4 * NdotV );\n\n\t}\n`, [ ggxDistributionFunc, ggxShadowMaskG1Func ] );\n","import { wgslFn, mat3 } from 'three/tsl';\nimport {\n\tinverseMat3x3Func,\n\tgetBasisFromNormalFunc,\n\tiorToF0Func,\n\tschlickFresnelFunc,\n\tschlickFresnelVecFunc,\n\tiorToF0GeneralFunc,\n\tfresnel0ToIorFunc,\n\tiorToF0GeneralVecFunc,\n} from './utils.wgsl.js';\nimport {\n\tggxSmithVisibilityFunc,\n\tggxDistributionFunc,\n\tggxDirectionFunc,\n\tggxReflectionAdjustedPDFFunc,\n} from './ggx.wgsl.js';\nimport { constants, surfaceRecordStruct } from './structs.wgsl.js';\nimport { rngInit, rand2, RNG_INDEX_SCATTER_DIRECTION } from './random.wgsl.js';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\n// Builds getSurfaceRecord using the given per-instance sampleTexel\nexport const getSurfaceRecordFunc = sampleTexel => wgslFn( /* wgsl */ `\n\n\tfn getSurfaceRecord(\n\t\tmaterial: Material,\n\t\tvertexData: bvh_GeometryStruct,\n\t\tside: f32,\n\t\tfaceNormal: vec3f,\n\t) -> SurfaceRecord {\n\t\tlet uv = vertexData.uv.xy;\n\n\t\tvar normal = faceNormal * side;\n\t\tif ( material.flatShading == 0 ) {\n\n\t\t\tnormal = vertexData.normal.xyz;\n\n\t\t}\n\t\tnormal = normalize( normal );\n\t\tlet baseNormal = normal;\n\n\t\tif ( material.normalMap != -1 ) {\n\n\t\t\t// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate\n\t\t\t// resulting in NaNs and slow path tracing.\n\t\t\tif ( length( vertexData.tangent.xyz ) > 0.0 && vertexData.tangent.w != 0.0 ) {\n\n\t\t\t\tlet tangent = normalize( vertexData.tangent.xyz );\n\t\t\t\tlet bitangent = normalize( cross( baseNormal, tangent ) * vertexData.tangent.w );\n\t\t\t\tlet vTBN = mat3x3f( tangent, bitangent, baseNormal );\n\n\t\t\t\tlet uvPrime = material.normalMapTransform * vec3( uv, 1.0 );\n\t\t\t\tvar texNormal = sampleTexel( uvPrime.xy, material.normalMap, 0 ).xyz;\n\t\t\t\ttexNormal = texNormal * 2.0 - 1.0;\n\t\t\t\ttexNormal = texNormal * vec3f( material.normalScale, 1.0 );\n\t\t\t\tnormal = normalize( vTBN * texNormal );\n\n\t\t\t}\n\n\t\t}\n\n\t\tnormal *= side;\n\n\t\tvar albedo = vec4( material.color, material.opacity );\n\n\t\tif ( material.vertexColors == 1 ) {\n\n\t\t\tlet vertexColor = vertexData.color.xyz;\n\t\t\talbedo *= vec4f( vertexColor, 1.0 );\n\n\t\t}\n\n\t\tif ( material.map != -1 ) {\n\n\t\t\tlet uvPrime = material.mapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.map, 0 );\n\t\t\talbedo *= vec4f( texColor.rgb, 1.0 );\n\n\t\t}\n\n\t\tvar roughness = material.roughness;\n\t\tif ( material.roughnessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.roughnessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.roughnessMap, 0 );\n\t\t\troughness *= texColor.g;\n\n\t\t}\n\n\t\tvar metalness = material.metalness;\n\t\tif ( material.metalnessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.metalnessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.metalnessMap, 0 );\n\t\t\tmetalness *= texColor.b;\n\n\t\t}\n\n\t\tvar emission = material.emissiveIntensity * material.emissive;\n\t\tif ( material.emissiveMap != -1 ) {\n\n\t\t\tlet uvPrime = material.emissiveMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.emissiveMap, 0 );\n\t\t\temission *= texColor.rgb;\n\n\t\t}\n\n\t\tvar transmission = material.transmission;\n\t\tif ( material.transmissionMap != -1 ) {\n\n\t\t\tlet uvPrime = material.transmissionMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.transmissionMap, 0 );\n\t\t\ttransmission *= texColor.r;\n\n\t\t}\n\n\t\tvar clearcoat = material.clearcoat;\n\t\tif ( material.clearcoatMap != -1 ) {\n\n\t\t\tlet uvPrime = material.clearcoatMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.clearcoatMap, 0 );\n\t\t\tclearcoat *= texColor.r;\n\n\t\t}\n\n\t\tvar clearcoatRoughness = material.clearcoatRoughness;\n\t\tif ( material.clearcoatRoughnessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.clearcoatRoughnessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.clearcoatRoughnessMap, 0 );\n\t\t\tclearcoatRoughness *= texColor.g;\n\n\t\t}\n\n\t\tvar clearcoatNormal = baseNormal;\n\t\tif ( material.clearcoatNormalMap != -1 ) {\n\n\t\t\t// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate\n\t\t\t// resulting in NaNs and slow path tracing.\n\t\t\tif ( length( vertexData.tangent.xyz ) > 0.0 && vertexData.tangent.w != 0.0 ) {\n\n\t\t\t\tlet tangent = normalize( vertexData.tangent.xyz );\n\t\t\t\tlet bitangent = normalize( cross( baseNormal, tangent ) * vertexData.tangent.w );\n\t\t\t\tlet vTBN = mat3x3f( tangent, bitangent, baseNormal );\n\n\t\t\t\tlet uvPrime = material.clearcoatNormalMapTransform * vec3( uv, 1.0 );\n\t\t\t\tvar texNormal = sampleTexel( uvPrime.xy, material.clearcoatNormalMap, 0 ).xyz;\n\t\t\t\ttexNormal = texNormal * 2.0 - 1.0;\n\t\t\t\ttexNormal = texNormal * vec3f( material.clearcoatNormalScale, 1.0 );\n\t\t\t\tclearcoatNormal = normalize( vTBN * texNormal );\n\n\t\t\t}\n\n\t\t}\n\t\tclearcoatNormal *= side;\n\n\t\tvar sheenColor = material.sheenColor;\n\t\tif ( material.sheenColorMap != -1 ) {\n\n\t\t\tlet uvPrime = material.sheenColorMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.sheenColorMap, 0 );\n\t\t\tsheenColor *= texColor.rgb;\n\n\t\t}\n\n\t\tvar sheenRoughness = material.sheenRoughness;\n\t\tif ( material.sheenRoughnessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.sheenRoughnessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.sheenRoughnessMap, 0 );\n\t\t\tsheenRoughness *= texColor.r;\n\n\t\t}\n\n\t\tvar iridescence = material.iridescence;\n\t\tif ( material.iridescenceMap != -1 ) {\n\n\t\t\tlet uvPrime = material.iridescenceMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.iridescenceMap, 0 );\n\t\t\tiridescence *= texColor.r;\n\n\t\t}\n\n\t\tvar iridescenceThickness = material.iridescenceThicknessMaximum;\n\t\tif ( material.iridescenceThicknessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.iridescenceThicknessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.iridescenceThicknessMap, 0 );\n\n\t\t\tiridescenceThickness = mix(\n\t\t\t\tmaterial.iridescenceThicknessMinimum,\n\t\t\t\tmaterial.iridescenceThicknessMaximum,\n\t\t\t\ttexColor.g,\n\t\t\t);\n\n\t\t}\n\n\t\tvar specularColor = material.specularColor;\n\t\tif ( material.specularColorMap != -1 ) {\n\n\t\t\tlet uvPrime = material.specularColorMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.specularColorMap, 0 );\n\t\t\tspecularColor *= texColor.rgb;\n\n\t\t}\n\n\t\tvar specularIntensity = material.specularIntensity;\n\t\tif ( material.specularIntensityMap != -1 ) {\n\n\t\t\tlet uvPrime = material.specularIntensityMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.specularIntensityMap, 0 );\n\t\t\tspecularIntensity *= texColor.r;\n\n\t\t}\n\n\t\tvar surf: SurfaceRecord;\n\n\t\tsurf.volumeParticle = false;\n\t\tsurf.faceNormal = faceNormal;\n\t\tsurf.normal = normal;\n\n\t\tsurf.metalness = metalness;\n\t\tsurf.color = albedo.rgb;\n\t\tsurf.emission = emission;\n\n\t\tsurf.ior = material.ior;\n\t\tsurf.transmission = transmission;\n\t\tsurf.thinFilm = material.thinFilm == 1;\n\t\tsurf.attenuationColor = material.attenuationColor;\n\t\tsurf.attenuationDistance = material.attenuationDistance;\n\n\t\tsurf.clearcoatNormal = clearcoatNormal;\n\t\tsurf.clearcoat = clearcoat;\n\n\t\tsurf.iridescence = iridescence;\n\t\tsurf.iridescenceIor = material.iridescenceIor;\n\t\tsurf.iridescenceThickness = iridescenceThickness;\n\n\t\tsurf.specularColor = specularColor;\n\t\tsurf.specularIntensity = specularIntensity;\n\n\t\tsurf.roughness = clamp( roughness, MIN_ROUGHNESS, 1.0 );\n\t\tsurf.clearcoatRoughness = clamp( clearcoatRoughness, MIN_ROUGHNESS, 1.0 );\n\t\tsurf.sheenRoughness = clamp( sheenRoughness, MIN_ROUGHNESS, 1.0 );\n\n\t\t// frontFace is used to determine transmissive properties and PDF. If no transmission is used\n\t\t// then we can just always assume this is a front face.\n\t\tsurf.frontFace = side == 1.0 || transmission == 0.0;\n\t\tif ( material.thinFilm == 1 || surf.frontFace ) {\n\t\t\tsurf.eta = 1.0 / material.ior;\n\t\t} else {\n\t\t\tsurf.eta = material.ior;\n\t\t}\n\t\tsurf.f0 = iorToF0( surf.eta );\n\n\t\t// get the normal frames\n\t\tsurf.normalBasis = getBasisFromNormal( surf.normal );\n\t\tsurf.normalInvBasis = inverse( surf.normalBasis );\n\n\t\tsurf.clearcoatBasis = getBasisFromNormal( surf.clearcoatNormal );\n\t\tsurf.clearcoatInvBasis = inverse( surf.clearcoatBasis );\n\n\t\treturn surf;\n\t}\n\n`, [\n\tinverseMat3x3Func,\n\tiorToF0Func,\n\tgetBasisFromNormalFunc,\n\tsampleTexel,\n\tsurfaceRecordStruct,\n\tconstants,\n] );\n\n/*\n *\n * N \t\t\t : Macronormal of the surface\n * V ( wo ) : View direction\n * L ( wi ) : Light direction\n * H ( wh ) : Halfvector between V and L, micronormal of the surface in ggx\n * f0 : Amount of light reflected when looking at a surface head on - \"fresnel 0\"\n * f90 : Amount of light reflected at grazing angles\n *\n */\n\n// Disney Diffuse BRDF without subsurface approximation\nexport const diffuseBrdfFunc = wgslFn( /* wgsl */ `\n\n\tfn diffuseBrdf( NdotV: f32, NdotL: f32, VdotH: f32, surf: SurfaceRecord ) -> vec3f {\n\n\t\t// https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf\n\t\t// See equation (4)\n\n\t\tlet fl = schlickFresnel( NdotL, 0.0 );\n\t\tlet fv = schlickFresnel( NdotV, 0.0 );\n\n\t\tlet alpha = surf.roughness * surf.roughness;\n\t\tlet bias = mix( 0.0, 0.5, alpha ) - 1;\n\t\tlet energyFactor = mix( 1.0, 1.0 / 1.51, alpha );\n\n\t\tlet rr = 2.0 * alpha * VdotH * VdotH;\n\t\tlet retro = rr * ( fl + fv + fl * fv * ( rr + 2.0 * bias ) );\n\t\tlet fresnel = ( 1.0 + bias * fl ) * ( 1.0f + bias * fv );\n\n\t\t// TODO: subsurface approx?\n\n\t\treturn energyFactor * ( surf.color / PI ) * ( retro + fresnel );\n\n\t}\n\n`, [ constants, schlickFresnelFunc, surfaceRecordStruct ] );\n\nexport const specularBrdfFunc = wgslFn( /* wgsl */ `\n\n\tfn specularBrdf( NdotL: f32, NdotV: f32, NdotH: f32, alpha: f32 ) -> vec3f {\n\n\t\tlet Vis = ggxSmithVisibility( NdotV, NdotL, alpha );\n\t\tlet D = ggxDistribution( NdotH, alpha );\n\n\t\treturn vec3f( D * Vis );\n\n\t}\n\n`, [ ggxSmithVisibilityFunc, ggxDistributionFunc ] );\n\nexport const fresnelMixFunc = wgslFn( /* wgsl */ `\n\n\tfn fresnelMix( VdotH: f32, ior: f32, base: vec3f, layer: vec3f ) -> vec3f {\n\n\t\tlet f0 = iorToF0( ior );\n \tlet F = schlickFresnel( abs( VdotH ), f0 );\n\n \treturn base + F * layer;\n\n\t}\n\n`, [ schlickFresnelFunc, iorToF0Func ] );\n\nconst XYZ_TO_REC709 = mat3(\n\t3.2404542, - 0.9692660, 0.0556434,\n\t- 1.5371385, 1.8760108, - 0.2040259,\n\t- 0.4985314, 0.0415560, 1.0572252,\n);\n\nconst evalSensitivityFunc = wgslTagFn/* wgsl */`\n\n\tfn evalSensitivity( OPD: f32, shift: vec3f ) -> vec3f {\n\n\t\tlet phase = 2.0 * ${ Math.PI } * OPD * 1.0e-9;\n\t\tconst val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13);\n\t\tconst pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06);\n\t\tconst _var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09);\n\n\t\tvar xyz = val * sqrt(2.0 * ${ Math.PI } * _var) * cos(pos * phase + shift) * exp(-phase * phase * _var);\n\t\txyz.x += 9.7470e-14 * sqrt(2.0 * ${ Math.PI } * 4.5282e+09) * cos(2.2399e+06 * phase + shift.x) * exp(-4.5282e+09 * phase * phase);\n\t\txyz /= 1.0685e-7;\n\n\t\tlet rgb = ${ XYZ_TO_REC709 } * xyz;\n\t\treturn rgb;\n\n\t}\n\n`;\n\n// Reference: Belcour/Barla, 2017\n// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html\n// This is a simplified model that ignores light polarization and uses fresnel approximation\nexport const iridescentFresnelFunc = wgslFn( /* wgsl */ `\n\n\tfn iridescentFresnel(\n\t\tcosTheta1: f32, baseF0: vec3f, iridescenceIor: f32,\n\t\toutsideIor: f32, iridescenceThickness: f32,\n\t) -> vec3f {\n\n\t\tlet sinTheta2Sq = pow( outsideIor / iridescenceIor, 2.0 ) * ( 1.0 - pow( cosTheta1, 2.0 ) );\n\t\tlet cosTheta2Sq = 1.0 - sinTheta2Sq;\n\n\t\t// Handle total internal reflection\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\n\t\t\treturn vec3( 1.0 );\n\n\t\t}\n\n\t\tlet cosTheta2 = sqrt( cosTheta2Sq );\n\n\t\t// First interface: air -> iridescent thin film\n\t\tlet R0 = iorToF0General( iridescenceIor, outsideIor );\n\t\tlet R12 = schlickFresnel( cosTheta1, R0 );\n\t\tlet R21 = R12;\n\t\tlet T121 = 1.0 - R12;\n\t\tlet phi12 = select( 0.0, PI, iridescenceIor < outsideIor );\n\t\tlet phi21 = PI - phi12;\n\n\t\t// Second interface: iridescent thin film -> base material\n\t\tlet baseIor = fresnel0ToIor( baseF0 + 0.0001 ); // guard against 1.0\n\t\tlet R1 = iorToF0GeneralVec( baseIor, vec3( iridescenceIor ) );\n\t\tlet R23 = schlickFresnelVec( cosTheta2, R1, vec3( 1.0 ) );\n\t\tlet phi23 = select( vec3( 0.0 ), vec3( PI ), baseIor < vec3( iridescenceIor ) );\n\n\t\t// Phase shift\n\t\tlet OPD = 2.0 * iridescenceIor * iridescenceThickness * cosTheta2;\n\t\tlet phi = vec3( phi21 ) + phi23;\n\n\t\t// Analytical integration\n\t\t// Compound terms\n\t\tlet R123 = clamp( R12 * R23, vec3( 1e-5 ), vec3( 0.9999 ) );\n\t\tlet r123 = sqrt( R123 );\n\t\tlet Rs = T121 * T121 * R23 / ( vec3( 1.0 ) - R123 );\n\n\t\t// Reflectance term for m = 0 (DC term amplitude)\n\t\tlet C0 = R12 + Rs;\n\t\tvar I = C0;\n\n\t\t// Reflectance term for m > 0 (pairs of diracs)\n\t\tvar Cm = Rs - T121;\n\t\tfor (var m = 1; m <= 2; m += 1) {\n\n\t\t\tCm *= r123;\n\t\t\tlet Sm = 2.0 * evalSensitivity( f32( m ) * OPD, f32( m ) * phi );\n\t\t\tI += Cm * Sm;\n\n\t\t}\n\n\t\treturn max( I, vec3(0.0) );\n\n\t}\n\n`, [ iorToF0GeneralFunc, iorToF0GeneralVecFunc, schlickFresnelFunc, fresnel0ToIorFunc, evalSensitivityFunc ] );\n\nconst rgbMixFunc = wgslFn( /* wgsl */ `\n\n\tfn rgbMix( base: vec3f, specular: vec3f, rgbAlpha: vec3f ) -> vec3f {\n\n\t\tlet alphaMax = max( max( rgbAlpha.x, rgbAlpha.y ), rgbAlpha.z );\n\t\treturn ( 1 - alphaMax ) * base + rgbAlpha * specular;\n\n\t}\n\n` );\n\nexport const iridescentDielectricLayerFunc = wgslFn( /* wgsl */ `\n\n\tfn iridescentDielectricLayer(\n\t\tdielectricBase: vec3f, base: vec3f, specular: vec3f, HdotL: f32,\n\t\toutsideIor: f32, baseIor: f32, iridescenceIor: f32, thickness: f32, strength: f32,\n\t) -> vec3f {\n\n\t\tlet baseF0 = vec3( iorToF0( baseIor ) );\n\n\t\tlet iridescentF = iridescentFresnel( HdotL, baseF0, iridescenceIor, outsideIor, thickness );\n\n\t\treturn mix( dielectricBase, rgbMix( base, specular, iridescentF ), strength );\n\n\t}\n\n`, [ iorToF0Func, iridescentFresnelFunc, rgbMixFunc ] );\n\nexport const iridescentConductorLayerFunc = wgslFn( /* wgsl */ `\n\n\tfn iridescentConductorLayer(\n\t\tmetalBase: vec3f, specular: vec3f, baseF0: vec3f, HdotL: f32,\n\t\toutsideIor: f32, iridescenceIor: f32, thickness: f32, strength: f32,\n\t) -> vec3f {\n\n\t\tlet iridescenceF = iridescentFresnel( HdotL, baseF0, iridescenceIor, outsideIor, thickness );\n\n\t\treturn mix( metalBase, specular * iridescenceF, strength );\n\n\t}\n\n`, [ iridescentFresnelFunc ] );\n\nexport const conductorFresnelFunc = ( turquinTexture ) => wgslFn( /* wgsl */ `\n\n\tfn conductorFresnel( NdotV: f32, VdotH: f32, f0: vec3f, bsdf: vec3f, alpha: f32 ) -> vec3f {\n\n\t let ss = bsdf * schlickFresnelVec( abs( VdotH ), f0, vec3f( 1 ) );\n\n\t\tlet uv = vec2( NdotV, sqrt( alpha ) );\n\t\tlet energySs = max( textureSampleLevel( turquinTexture, turquinTexture_sampler, uv, 0 ).r, 1e-5 );\n\n\t\treturn ss * ( 1.0 + f0 * ( 1.0 - energySs ) / energySs );\n\n\t}\n\n`, [ schlickFresnelVecFunc, turquinTexture ] );\n\nexport const fresnelCoatFunc = wgslFn( /* wgsl */ `\n\n\tfn fresnelCoat( VdotNc: f32, ior: f32, base: vec3f, layer: vec3f, weight: f32 ) -> vec3f {\n\n\t\tlet f0 = iorToF0( ior );\n\t\tlet F = schlickFresnel( abs( VdotNc ), f0 );\n\n\t\treturn mix( base, layer, weight * F );\n\n\t}\n\n`, [ iorToF0Func, schlickFresnelFunc ] );\n\n// GGX Multibounce compensation using Turquin's method\n\nexport const albedoIntegralMetallic = wgslTagFn/* wgsl */ `\n\n\tfn albedo(\n\t\ttexture: texture_storage_2d<r16float, write>,\n\n\t\tglobalId: vec3u,\n\t) -> void {\n\n\t\tconst INTEGRATION_SAMPLES = ( 1 << 20 );\n\t\tlet pixelIndex = ( globalId.x << 16 ) | globalId.y;\n\t\t${ rngInit }( pixelIndex, 0, 0 );\n\n\t\tlet dimensions = textureDimensions( texture ).xy;\n\t\tlet uv = ( vec2f( globalId.xy ) + vec2f( 0.5 ) ) / vec2f( dimensions );\n\n\t\tlet cosThetaO = uv.x;\n\t\tlet roughness = uv.y;\n\n\t\tlet alpha = roughness * roughness;\n\n\t\tlet wo = vec3( sqrt( 1 - cosThetaO * cosThetaO ), 0 , cosThetaO );\n\n\t\tvar result = 0.0;\n\t\tfor ( var i = 0; i < INTEGRATION_SAMPLES; i++ ) {\n\n\t\t\tlet wh = ${ ggxDirectionFunc }( wo, vec2( alpha ), ${ rand2 }(${ RNG_INDEX_SCATTER_DIRECTION }) );\n\t\t\tvar wi = - reflect( wo, wh );\n\n\t\t\tlet NdotV = max( wo.z, EPSILON );\n\t\t\tlet NdotL = saturate( wi.z );\n\t\t\tlet NdotH = saturate( wh.z );\n\n\t\t\tlet specular = ${ specularBrdfFunc }( NdotL, NdotV, NdotH, alpha );\n\t\t\tlet pdf = ${ ggxReflectionAdjustedPDFFunc }( NdotV, NdotH, alpha );\n\n\t\t\tvar weight = 0.0;\n\t\t\tif ( pdf != 0.0 ) {\n\t\t\t\tweight = 1 / pdf;\n\t\t\t}\n\n\t\t\tresult += specular.x * NdotL * weight;\n\n\t\t}\n\n\t\tresult /= f32( INTEGRATION_SAMPLES );\n\n\t\ttextureStore( texture, globalId.xy, vec4( result ) );\n\n\t}\n\n`;\n","import {\n\tMeshBasicMaterial,\n\tRenderTarget,\n\tNoToneMapping,\n\tQuadMesh,\n\tNoBlending,\n\tColor,\n\tVector4,\n} from 'three/webgpu';\n\nconst MAX_TEXTURE_SIZE = 4096;\nconst _prevClearColor = new Color();\n\nfunction getTextureHash( texture ) {\n\n\treturn `${ texture.source.uuid }:${ texture.source.version }`;\n\n}\n\n// TODO: consider adding a \"waste map\"\n// TODO: consider using \"best fit\"\n\n// Skyline rectangle packing (bottom-left, no waste map).\n// A \"skyline\" is an array of contiguous segments { x, y, width } that always\n// spans [ 0, pageWidth ] and describes the upper contour of placed rectangles.\n// Each rect is placed where its top edge is lowest ( leftmost on ties ).\n//\n// Reference: Jukka Jylänki, \"A Thousand Ways to Pack the Bin - A Practical\n// Approach to Two-Dimensional Rectangle Bin Packing\" (2010), the Skyline\n// Bottom-Left (SkylineBL) heuristic. See also Sean Barrett's stb_rect_pack.h:\n// https://github.com/nothings/stb/blob/master/stb_rect_pack.h\n\n// Resting y for a w-wide rect whose left edge sits at nodes[ i ].x. The rect\n// bridges every segment it spans and rests on the tallest of them. Returns -1\n// if it would run off the right edge.\nfunction skylineFit( nodes, i, w, pageWidth ) {\n\n\tconst x = nodes[ i ].x;\n\tif ( x + w > pageWidth ) {\n\n\t\treturn - 1;\n\n\t}\n\n\tlet widthLeft = w;\n\tlet y = 0;\n\tlet j = i;\n\twhile ( widthLeft > 0 ) {\n\n\t\t// defensive: the skyline should always cover the full page width\n\t\tif ( j >= nodes.length ) {\n\n\t\t\treturn - 1;\n\n\t\t}\n\n\t\ty = Math.max( y, nodes[ j ].y );\n\t\twidthLeft -= nodes[ j ].width;\n\t\tj ++;\n\n\t}\n\n\treturn y;\n\n}\n\n// Patch the skyline after placing a rect spanning [ x, x + w ] with top edge y.\n// The left edge x always aligns to an existing segment boundary, so only the\n// right edge can split a segment. Mutates nodes in place.\nfunction addSkylineNode( nodes, x, y, w ) {\n\n\tconst right = x + w;\n\tconst result = [];\n\tlet inserted = false;\n\n\tfor ( let i = 0; i < nodes.length; i ++ ) {\n\n\t\tconst node = nodes[ i ];\n\t\tconst nodeRight = node.x + node.width;\n\n\t\tif ( nodeRight <= x ) {\n\n\t\t\t// entirely left of the new node\n\t\t\tresult.push( node );\n\n\t\t} else if ( node.x >= right ) {\n\n\t\t\t// entirely right of the new node\n\t\t\tif ( ! inserted ) {\n\n\t\t\t\tresult.push( { x, y, width: w } );\n\t\t\t\tinserted = true;\n\n\t\t\t}\n\n\t\t\tresult.push( node );\n\n\t\t} else {\n\n\t\t\t// overlapped by the new node\n\t\t\tif ( ! inserted ) {\n\n\t\t\t\tresult.push( { x, y, width: w } );\n\t\t\t\tinserted = true;\n\n\t\t\t}\n\n\t\t\t// keep any right-side remainder at its original height\n\t\t\tif ( nodeRight > right ) {\n\n\t\t\t\tresult.push( { x: right, y: node.y, width: nodeRight - right } );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tif ( ! inserted ) {\n\n\t\tresult.push( { x, y, width: w } );\n\n\t}\n\n\t// merge adjacent segments of equal height and write back into nodes\n\tnodes.length = 0;\n\tfor ( let i = 0; i < result.length; i ++ ) {\n\n\t\tconst node = result[ i ];\n\t\tconst last = nodes[ nodes.length - 1 ];\n\t\tif ( last && last.y === node.y && last.x + last.width === node.x ) {\n\n\t\t\tlast.width += node.width;\n\n\t\t} else {\n\n\t\t\tnodes.push( node );\n\n\t\t}\n\n\t}\n\n}\n\n// Try to place a w x h rect into a single page's skyline. Returns the chosen\n// { x, y } or null if it does not fit.\nfunction skylineInsert( nodes, w, h, pageWidth, pageHeight ) {\n\n\tlet bestY = Infinity;\n\tlet bestX = 0;\n\tlet bestIndex = - 1;\n\n\tfor ( let i = 0; i < nodes.length; i ++ ) {\n\n\t\tconst y = skylineFit( nodes, i, w, pageWidth );\n\t\tif ( y >= 0 && y + h <= pageHeight && y < bestY ) {\n\n\t\t\tbestY = y;\n\t\t\tbestX = nodes[ i ].x;\n\t\t\tbestIndex = i;\n\n\t\t}\n\n\t}\n\n\tif ( bestIndex === - 1 ) {\n\n\t\treturn null;\n\n\t}\n\n\taddSkylineNode( nodes, bestX, bestY + h, w );\n\treturn { x: bestX, y: bestY };\n\n}\n\n// Packs a set of textures into one or more atlas pages and exposes both the\n// packed texture and a Uint32Array of per-texture info ( atlas bounds + page )\n// suitable for upload as a uniform array.\nexport class AtlasTexture {\n\n\tget width() {\n\n\t\treturn this.renderTarget.width;\n\n\t}\n\n\tget height() {\n\n\t\treturn this.renderTarget.height;\n\n\t}\n\n\tget pageCount() {\n\n\t\treturn this.renderTarget.depth;\n\n\t}\n\n\tget texture() {\n\n\t\treturn this.renderTarget.texture;\n\n\t}\n\n\tconstructor( options = {} ) {\n\n\t\t// RenderTarget already defaults to RGBA8, linear filtering, clamp wrapping\n\t\t// and no mipmaps, so we only specify the array-target-specific options here.\n\t\tthis.renderTarget = new RenderTarget( 1, 1, {\n\t\t\tdepthBuffer: false,\n\t\t\tdepth: 1,\n\t\t\t...options,\n\t\t} );\n\t\tthis.texture.isArrayTexture = true;\n\n\t\t// per-texture packed info ( one Vector4 each ): see _buildTextureInfo\n\t\tthis.textureInfo = [ new Vector4() ];\n\n\t\tthis.hashes = [];\n\t\tthis.quadMesh = new QuadMesh( new MeshBasicMaterial() );\n\t\tthis.quadMesh.material.blending = NoBlending;\n\n\t}\n\n\tsetTextures( renderer, textures ) {\n\n\t\t// nothing to do if the set of textures is unchanged\n\t\tif ( this._hashesMatch( textures ) ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// calculate the maximum dimension of the atlas\n\t\tlet maxDim = textures.reduce( ( v, t ) => Math.max( v, t.width, t.height ), 1 );\n\t\tmaxDim = Math.min( MAX_TEXTURE_SIZE, maxDim );\n\n\t\tconst width = maxDim;\n\t\tconst height = maxDim;\n\n\t\t// full repack of every texture\n\t\tconst { renderTarget } = this;\n\t\tconst { placements, pageCount } = this._packTextures( textures, width, height );\n\n\t\t// RenderTarget.setSize resets isArrayTexture to \"image.depth > 1\" so\n\t\t// we reset it here.\n\t\trenderTarget.setSize( width, height, pageCount );\n\t\tthis.texture.isArrayTexture = true;\n\n\t\tthis._buildTextureInfo( placements );\n\t\tthis._renderTextures( renderer, textures, placements );\n\n\t\t// rebuild hashes and the texture -> index lookup\n\t\tconst hashes = new Array( textures.length );\n\t\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\t\tconst hash = getTextureHash( textures[ i ] );\n\t\t\thashes[ i ] = hash;\n\n\t\t}\n\n\t\tthis.hashes = hashes;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.renderTarget.dispose();\n\t\tthis.quadMesh.material.dispose();\n\n\t}\n\n\t_hashesMatch( textures ) {\n\n\t\tconst hashes = this.hashes;\n\t\tif ( hashes.length !== textures.length ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\t\tif ( hashes[ i ] !== getTextureHash( textures[ i ] ) ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\t_packTextures( textures, width, height ) {\n\n\t\t// use each texture's native size, clamped so it can physically fit a page\n\t\t// ( anything larger is downsampled into its rect during the blit )\n\t\tconst items = [];\n\t\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\t\tconst texture = textures[ i ];\n\t\t\titems.push( {\n\t\t\t\tindex: i,\n\t\t\t\tw: Math.min( texture.width, width ),\n\t\t\t\th: Math.min( texture.height, height ),\n\t\t\t} );\n\n\t\t}\n\n\t\t// place taller rects first for tighter skyline occupancy\n\t\tconst order = items.sort( ( a, b ) => b.h - a.h );\n\n\t\tconst placements = new Array( textures.length );\n\t\tconst pages = [];\n\n\t\tfor ( let k = 0, l = order.length; k < l; k ++ ) {\n\n\t\t\tconst item = order[ k ];\n\t\t\tlet placed = null;\n\t\t\tlet page = - 1;\n\n\t\t\t// try to fit into an existing page\n\t\t\tfor ( let p = 0; p < pages.length; p ++ ) {\n\n\t\t\t\tplaced = skylineInsert( pages[ p ], item.w, item.h, width, height );\n\t\t\t\tif ( placed ) {\n\n\t\t\t\t\tpage = p;\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// otherwise open a new page\n\t\t\tif ( ! placed ) {\n\n\t\t\t\tconst skyline = [ { x: 0, y: 0, width: width } ];\n\t\t\t\tplaced = skylineInsert( skyline, item.w, item.h, width, height );\n\t\t\t\tpages.push( skyline );\n\t\t\t\tpage = pages.length - 1;\n\n\t\t\t}\n\n\t\t\tplacements[ item.index ] = { x: placed.x, y: placed.y, w: item.w, h: item.h, page };\n\n\t\t}\n\n\t\treturn { placements, pageCount: Math.max( pages.length, 1 ) };\n\n\t}\n\n\t_buildTextureInfo( placements ) {\n\n\t\tconst info = this.textureInfo;\n\t\tinfo.length = 0;\n\t\tfor ( let i = 0, l = placements.length; i < l; i ++ ) {\n\n\t\t\t// offsetX and Y in pixels (16 bits + 16 bits)\n\t\t\t// width and height in pixels (16 bit + 16 bits)\n\t\t\t// page + reserved (16 bits)\n\t\t\t// reserved\n\t\t\tconst { x, y, w, h, page } = placements[ i ];\n\t\t\tconst v = new Vector4();\n\t\t\tv.x = ( x & 0xFFFF ) | ( ( y & 0xFFFF ) << 16 );\n\t\t\tv.y = ( w & 0xFFFF ) | ( ( h & 0xFFFF ) << 16 );\n\t\t\tv.z = page & 0xFFFF;\n\t\t\tv.w = 0;\n\t\t\tinfo.push( v );\n\n\t\t}\n\n\t\tif ( info.length === 0 ) {\n\n\t\t\tinfo.push( new Vector4( 0, 0, 0, 0 ) );\n\n\t\t}\n\n\t}\n\n\t_renderTextures( renderer, textures, placements ) {\n\n\t\tconst { quadMesh, renderTarget, width, height } = this;\n\n\t\t// Save previous renderer state\n\t\tconst prevRenderTarget = renderer.getRenderTarget();\n\t\tconst prevToneMapping = renderer.toneMapping;\n\t\tconst prevAutoClear = renderer.autoClear;\n\t\tconst prevScissorTest = renderer.getScissorTest();\n\t\tconst prevClearAlpha = renderer.getClearAlpha();\n\t\trenderer.getClearColor( _prevClearColor );\n\n\t\t// blit each tile into its sub-rect without clearing the rest of the page\n\t\trenderer.toneMapping = NoToneMapping;\n\t\trenderer.autoClear = false;\n\t\trenderer.setScissorTest( true );\n\t\trenderer.setClearColor( 0, 0 );\n\n\t\t// clear the pages\n\t\tfor ( let i = 0, l = renderTarget.depth; i < l; i ++ ) {\n\n\t\t\trenderTarget.viewport.set( 0, 0, width, height );\n\t\t\trenderTarget.scissor.set( 0, 0, width, height );\n\t\t\trenderer.setRenderTarget( renderTarget, i );\n\t\t\trenderer.clear();\n\n\t\t}\n\n\t\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\t\tconst { x, y, w, h, page } = placements[ i ];\n\n\t\t\t// Clone the source so we get an independent texture handle\n\t\t\tconst texture = textures[ i ].clone();\n\t\t\ttexture.matrixAutoUpdate = false;\n\t\t\ttexture.matrix.identity();\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\tquadMesh.material.map = texture;\n\n\t\t\t// three.js uses the render target viewport / scissor\n\t\t\trenderTarget.viewport.set( x, y, w, h );\n\t\t\trenderTarget.scissor.set( x, y, w, h );\n\t\t\trenderer.setRenderTarget( renderTarget, page );\n\t\t\tquadMesh.render( renderer );\n\n\t\t\ttexture.dispose();\n\n\t\t}\n\n\t\t// restore the render target's full-size viewport/scissor and the renderer\n\t\trenderTarget.viewport.set( 0, 0, width, height );\n\t\trenderTarget.scissor.set( 0, 0, width, height );\n\t\tquadMesh.material.map = null;\n\t\trenderer.setClearColor( _prevClearColor, prevClearAlpha );\n\t\trenderer.setScissorTest( prevScissorTest );\n\t\trenderer.autoClear = prevAutoClear;\n\t\trenderer.setRenderTarget( prevRenderTarget );\n\t\trenderer.toneMapping = prevToneMapping;\n\n\t}\n\n}\n","import { BackSide, FrontSide, DoubleSide, BufferAttribute, BufferGeometry, StorageBufferAttribute, StructTypeNode, Vector4, SkinnedMesh, StructNode, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, NearestFilter } from 'three/webgpu';\nimport { BVHComputeData, intersectRayTriangle, bvhNodeBoundsStruct, bvhNodeStruct, rayStruct, rayIntersectionResultStruct as intersectionResultStruct, wgslTagFn } from '../lib/three-mesh-bvh/index.js';\nimport { storage, float, sampler, texture, uniformArray } from 'three/tsl';\nimport { SkinnedMeshBVH, MeshBVH, SAH } from 'three-mesh-bvh';\nimport { materialStruct } from './structs.wgsl.js';\nimport { getTextureHash } from '../../core/utils/sceneUpdateUtils.js';\nimport { rand1, RNG_INDEX_ALPHA_TEST } from './random.wgsl.js';\nimport { sampleTexelFunc } from './utils.wgsl.js';\nimport { getSurfaceRecordFunc } from './material.wgsl.js';\nimport { AtlasTexture } from '../AtlasTexture.js';\n\nconst _colorVec = new Vector4();\nconst transformStruct = new StructTypeNode( {\n\tmatrixWorld: 'mat4x4f',\n\tinverseMatrixWorld: 'mat4x4f',\n\tnodeOffset: 'uint',\n\tvisible: 'uint',\n\tmaterialIndex: 'uint',\n\t_alignment0: 'uint',\n\tcolor: 'vec4f',\n}, 'TransformStruct' );\n\n// Pathtracer-specific version of the BVHComputeData tht includes material mapping, property structs\nexport class PathtracerBVHComputeData extends BVHComputeData {\n\n\tconstructor( bvh, options = {} ) {\n\n\t\t// TODO: once supported we should use the appropriately-sized member sizes\n\t\tsuper( bvh, {\n\t\t\tattributes: {\n\t\t\t\tposition: 'vec4f',\n\t\t\t\tnormal: 'vec4f',\n\t\t\t\ttangent: 'vec4f',\n\t\t\t\tcolor: 'vec4f',\n\t\t\t\tuv: 'vec4f',\n\t\t\t},\n\t\t\t...options,\n\t\t} );\n\n\t\tthis.structs.transform = transformStruct;\n\t\tthis.structs.material = materialStruct;\n\t\tthis.storage.materials = null;\n\t\tthis.materials = [];\n\t\tthis.bvhMap = new Map();\n\t\tthis.textureAtlas = new AtlasTexture();\n\n\t}\n\n\tuseTransparencyRaycastFn() {\n\n\t\tconst { textureAtlas, storage, structs, fns } = this;\n\t\tconst textures = textureAtlas.texture;\n\t\tconst textureInfo = uniformArray( textureAtlas.textureInfo, 'uvec4' );\n\n\t\t// build the single sampleTexel bound to this instance's textureInfo node\n\t\tconst sampleTexel = sampleTexelFunc( textureInfo, texture( textures ), sampler( textures ) );\n\n\t\t// getSurfaceRecord shares the same sampleTexel, so the surface shading and\n\t\t// the transparency raycast resolve to one textureInfo binding per pipeline\n\t\tfns.getSurfaceRecord = getSurfaceRecordFunc( sampleTexel );\n\n\t\t// raycast first hit\n\t\tconst currentMaterial = new StructNode( structs.material ).toVar( 'bvh_material' );\n\t\tconst scratchRayScalar = float( 1.0 ).toVar( 'bvh_rayScalar' );\n\t\tconst baseOpacityScalar = float( 1.0 ).toVar( 'bvh_baseOpacity' );\n\n\t\tfns.raycastFirstHit = this.getShapecastFn( {\n\t\t\tname: 'raycastFirstHit',\n\t\t\tshapeStruct: rayStruct,\n\t\t\tresultStruct: intersectionResultStruct,\n\n\t\t\tboundsOrderFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn getBoundsOrder( ray: ${ rayStruct }, splitAxis: u32, node: ${ bvhNodeStruct } ) -> bool {\n\n\t\t\t\t\treturn ray.direction[ splitAxis ] >= 0.0;\n\n\t\t\t\t}\n\t\t\t`,\n\t\t\tintersectsBoundsFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn rayIntersectsBounds( ray: ${ rayStruct }, bounds: ${ bvhNodeBoundsStruct }, result: ptr<function, ${ intersectionResultStruct }> ) -> u32 {\n\n\t\t\t\t\t// early-out if our object is completely transparent\n\t\t\t\t\tif ( ${ baseOpacityScalar } == 0.0 ) {\n\n\t\t\t\t\t\treturn 0u;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet boundsMin = vec3( bounds.min[0], bounds.min[1], bounds.min[2] );\n\t\t\t\t\tlet boundsMax = vec3( bounds.max[0], bounds.max[1], bounds.max[2] );\n\n\t\t\t\t\tlet invDir = 1.0 / ray.direction;\n\t\t\t\t\tlet tMinPlane = ( boundsMin - ray.origin ) * invDir;\n\t\t\t\t\tlet tMaxPlane = ( boundsMax - ray.origin ) * invDir;\n\n\t\t\t\t\tlet tMinHit = min( tMinPlane, tMaxPlane );\n\t\t\t\t\tlet tMaxHit = max( tMinPlane, tMaxPlane );\n\n\t\t\t\t\tlet t0 = max( max( tMinHit.x, tMinHit.y ), tMinHit.z );\n\t\t\t\t\tlet t1 = min( min( tMaxHit.x, tMaxHit.y ), tMaxHit.z );\n\n\t\t\t\t\tlet dist = max( t0, 0.0 );\n\t\t\t\t\tif ( t1 < dist ) {\n\n\t\t\t\t\t\treturn 0u;\n\n\t\t\t\t\t} else if ( result.didHit && dist * ${ scratchRayScalar } >= result.dist ) {\n\n\t\t\t\t\t\treturn 0u;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\treturn 1u;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t`,\n\t\t\tintersectRangeFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn intersectRange( ray: ${ rayStruct }, offset: u32, count: u32, result: ptr<function, ${ intersectionResultStruct }> ) -> bool {\n\n\t\t\t\t\tvar didHit = false;\n\t\t\t\t\tfor ( var ti = offset; ti < offset + count; ti = ti + 1u ) {\n\n\t\t\t\t\t\tlet i0 = ${ storage.index }[ ti * 3u ];\n\t\t\t\t\t\tlet i1 = ${ storage.index }[ ti * 3u + 1u ];\n\t\t\t\t\t\tlet i2 = ${ storage.index }[ ti * 3u + 2u ];\n\n\t\t\t\t\t\tlet a = ${ storage.attributes }[ i0 ].position.xyz;\n\t\t\t\t\t\tlet b = ${ storage.attributes }[ i1 ].position.xyz;\n\t\t\t\t\t\tlet c = ${ storage.attributes }[ i2 ].position.xyz;\n\n\t\t\t\t\t\tvar triResult = ${ intersectRayTriangle }( ray, a, b, c, 1e-5 );\n\t\t\t\t\t\ttriResult.dist *= ${ scratchRayScalar };\n\t\t\t\t\t\tif ( triResult.didHit && ( ! result.didHit || triResult.dist < result.dist ) ) {\n\n\t\t\t\t\t\t\tlet material = ${ currentMaterial };\n\n\t\t\t\t\t\t\t// TODO: if material is a transmissive volume we may need to assume double-sidedness\n\t\t\t\t\t\t\tif ( material.side != 0 && triResult.side != material.side ) {\n\n\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( material.transparent != 0 || material.alphaTest > 0.0 ) {\n\n\t\t\t\t\t\t\t\tvar opacity = ${ baseOpacityScalar };\n\n\t\t\t\t\t\t\t\t// account for alpha component of albedo map\n\t\t\t\t\t\t\t\tif ( material.map != - 1 ) {\n\n\t\t\t\t\t\t\t\t\tlet barycoord = triResult.barycoord;\n\t\t\t\t\t\t\t\t\tlet a = ${ storage.attributes }[ i0 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet b = ${ storage.attributes }[ i1 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet c = ${ storage.attributes }[ i2 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet uv = barycoord.x * a + barycoord.y * b + barycoord.z * c;\n\t\t\t\t\t\t\t\t\tlet uvPrime = material.mapTransform * vec3f( uv, 1 );\n\n\t\t\t\t\t\t\t\t\topacity *= ${ sampleTexel }( uvPrime.xy, material.map, 0 ).a;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// account for green component of alpha map\n\t\t\t\t\t\t\t\tif ( material.alphaMap != - 1 ) {\n\n\t\t\t\t\t\t\t\t\tlet barycoord = triResult.barycoord;\n\t\t\t\t\t\t\t\t\tlet a = ${ storage.attributes }[ i0 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet b = ${ storage.attributes }[ i1 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet c = ${ storage.attributes }[ i2 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet uv = barycoord.x * a + barycoord.y * b + barycoord.z * c;\n\t\t\t\t\t\t\t\t\tlet uvPrime = material.alphaMapTransform * vec3f( uv, 1 );\n\n\t\t\t\t\t\t\t\t\topacity *= ${ sampleTexel }( uvPrime.xy, material.alphaMap, 0 ).g;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif ( material.transparent != 0 && opacity < ${ rand1 }( ${ RNG_INDEX_ALPHA_TEST } + ti ) ) {\n\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif ( opacity < material.alphaTest ) {\n\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tresult.didHit = true;\n\t\t\t\t\t\t\tresult.dist = triResult.dist;\n\t\t\t\t\t\t\tresult.normal = triResult.normal;\n\t\t\t\t\t\t\tresult.side = triResult.side;\n\t\t\t\t\t\t\tresult.barycoord = triResult.barycoord;\n\t\t\t\t\t\t\tresult.indices = vec4u( i0, i1, i2, ti );\n\n\t\t\t\t\t\t\tdidHit = true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn didHit;\n\n\t\t\t\t}\n\t\t\t`,\n\t\t\ttransformShapeFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn transformRay( ray: ptr<function, ${ rayStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\t\tlet toLocal = ${ storage.transforms }[ objectIndex ].inverseMatrixWorld;\n\t\t\t\t\tray.origin = ( toLocal * vec4f( ray.origin, 1.0 ) ).xyz;\n\t\t\t\t\tray.direction = ( toLocal * vec4f( ray.direction, 0.0 ) ).xyz;\n\n\t\t\t\t\tlet len = length( ray.direction );\n\t\t\t\t\tray.direction /= len;\n\t\t\t\t\t${ scratchRayScalar } = 1.0 / len;\n\n\t\t\t\t\tlet object = ${ storage.transforms }[ objectIndex ];\n\t\t\t\t\t${ currentMaterial } = ${ storage.materials }[ object.materialIndex ];\n\t\t\t\t\tif ( ${ currentMaterial }.transparent == 1 ) {\n\n\t\t\t\t\t\t${ baseOpacityScalar } = ${ currentMaterial }.opacity * object.color.a;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t${ baseOpacityScalar } = 1.0;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t`,\n\t\t\ttransformResultFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn transformResult( hit: ptr<function, ${ intersectionResultStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\t\tlet toLocal = ${ storage.transforms }[ objectIndex ].inverseMatrixWorld;\n\t\t\t\t\thit.normal = normalize( ( transpose( toLocal ) * vec4f( hit.normal, 0.0 ) ).xyz );\n\t\t\t\t\thit.objectIndex = objectIndex;\n\n\t\t\t\t}\n\t\t\t`,\n\t\t} );\n\n\t}\n\n\tupdate() {\n\n\t\tsuper.update();\n\n\t\t// build material storage\n\t\tconst { materials, structs } = this;\n\n\t\tconst { materialData, textures } = this.writeMaterialsBuffer( materials );\n\n\t\tthis.textures = textures;\n\n\t\tconst materialAttribute = new StorageBufferAttribute( materialData, structs.material.getLength() );\n\t\tconst materialStorage = storage( materialAttribute, structs.material ).toReadOnly().setName( 'bvh_materials' );\n\t\tthis.storage.materials = materialStorage;\n\n\t\tthis.bvhMap.clear();\n\t\tthis.materials.length = 0;\n\t\tthis.useTransparencyRaycastFn();\n\n\t}\n\n\twriteMaterialsBuffer( materials ) {\n\n\t\tfunction encodeTextureWrap( wrap ) {\n\n\t\t\tswitch ( wrap ) {\n\n\t\t\t\tcase RepeatWrapping:\n\t\t\t\t\treturn 0;\n\t\t\t\tcase ClampToEdgeWrapping:\n\t\t\t\t\treturn 1;\n\t\t\t\tcase MirroredRepeatWrapping:\n\t\t\t\t\treturn 2;\n\t\t\t\tdefault:\n\t\t\t\t\treturn 0;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getTexture( material, key ) {\n\n\t\t\tif ( key in material && material[ key ] ) {\n\n\t\t\t\tconst texture = material[ key ];\n\t\t\t\tconst hash = getTextureHash( texture );\n\n\t\t\t\tif ( ! textureLookUp.has( hash ) ) {\n\n\t\t\t\t\ttextureLookUp.set( hash, textureLookUp.size );\n\t\t\t\t\ttextures.push( texture );\n\n\t\t\t\t}\n\n\t\t\t\tconst idx = textureLookUp.get( hash );\n\t\t\t\tconst wrapS = encodeTextureWrap( texture.wrapS );\n\t\t\t\tconst wrapT = encodeTextureWrap( texture.wrapT );\n\t\t\t\tconst nearest = texture.magFilter === NearestFilter ? 1 : 0;\n\t\t\t\treturn ( nearest << 28 ) | ( wrapT << 26 ) | ( wrapS << 24 ) | idx;\n\n\t\t\t} else {\n\n\t\t\t\treturn - 1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getField( material, key, def ) {\n\n\t\t\treturn key in material ? material[ key ] : def;\n\n\t\t}\n\n\t\tfunction writeTextureMatrixToArray( material, textureKey, array, offset ) {\n\n\t\t\tconst texture = material[ textureKey ] && material[ textureKey ].isTexture ? material[ textureKey ] : null;\n\n\t\t\t// check if texture exists\n\t\t\tif ( texture ) {\n\n\t\t\t\tif ( texture.matrixAutoUpdate ) {\n\n\t\t\t\t\ttexture.updateMatrix();\n\n\t\t\t\t}\n\n\t\t\t\tconst elements = texture.matrix.elements;\n\n\t\t\t\t// Both wgsl struct and elements should be in column-major format\n\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\tarray[ offset + 4 * i + 0 ] = elements[ 3 * i + 0 ];\n\t\t\t\t\tarray[ offset + 4 * i + 1 ] = elements[ 3 * i + 1 ];\n\t\t\t\t\tarray[ offset + 4 * i + 2 ] = elements[ 3 * i + 2 ];\n\t\t\t\t\tarray[ offset + 4 * i + 3 ] = 0; // padding float\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn 12;\n\n\t\t}\n\n\t\tlet index = 0;\n\n\t\t// Collect and index the list of textures based on shareable source\n\t\tconst textureLookUp = new Map();\n\t\tconst textures = [];\n\n\t\t// NOTE: make the minimum material buffer length 2 in order to avoid TSL converting it to a scalar\n\t\t// TODO: remove this when fixed in three\n\t\tconst materialBufferLength = Math.max( materials.length, 2 );\n\t\tconst floatArray = new Float32Array( materialBufferLength * this.structs.material.getLength() );\n\t\tconst intArray = new Int32Array( floatArray.buffer );\n\n\t\t// TODO: make features work\n\t\t// features.reset();\n\t\tfor ( let i = 0, l = materials.length; i < l; i ++ ) {\n\n\t\t\tconst m = materials[ i ];\n\n\t\t\t// if ( m.isFogVolumeMaterial ) {\n\t\t\t//\n\t\t\t// \t// features.setUsed( 'FOG' );\n\t\t\t//\n\t\t\t// \tfor ( let j = 0; j < MATERIAL_STRIDE; j ++ ) {\n\t\t\t//\n\t\t\t// \t\tfloatArray[ index + j ] = 0;\n\t\t\t//\n\t\t\t// \t}\n\t\t\t//\n\t\t\t// \t// sample 0 .rgb\n\t\t\t// \tfloatArray[ index + 0 * 4 + 0 ] = m.color.r;\n\t\t\t// \tfloatArray[ index + 0 * 4 + 1 ] = m.color.g;\n\t\t\t// \tfloatArray[ index + 0 * 4 + 2 ] = m.color.b;\n\t\t\t//\n\t\t\t// \t// sample 2 .a\n\t\t\t// \tfloatArray[ index + 2 * 4 + 3 ] = getField( m, 'emissiveIntensity', 0.0 );\n\t\t\t//\n\t\t\t// \t// sample 3 .rgb\n\t\t\t// \tfloatArray[ index + 3 * 4 + 0 ] = m.emissive.r;\n\t\t\t// \tfloatArray[ index + 3 * 4 + 1 ] = m.emissive.g;\n\t\t\t// \tfloatArray[ index + 3 * 4 + 2 ] = m.emissive.b;\n\t\t\t//\n\t\t\t// \t// sample 13 .g\n\t\t\t// \t// reusing opacity field\n\t\t\t// \tfloatArray[ index + 13 * 4 + 1 ] = m.density;\n\t\t\t//\n\t\t\t// \t// side\n\t\t\t// \tfloatArray[ index + 13 * 4 + 3 ] = 0.0;\n\t\t\t//\n\t\t\t// \t// sample 14 .b\n\t\t\t// \tfloatArray[ index + 14 * 4 + 2 ] = 1 << 2;\n\t\t\t//\n\t\t\t// \tindex += MATERIAL_STRIDE;\n\t\t\t// \tcontinue;\n\t\t\t//\n\t\t\t// }\n\n\t\t\t// color - offset 0\n\t\t\tfloatArray[ index ++ ] = m.color.r;\n\t\t\tfloatArray[ index ++ ] = m.color.g;\n\t\t\tfloatArray[ index ++ ] = m.color.b;\n\t\t\tintArray[ index ++ ] = getTexture( m, 'map' );\n\n\t\t\t// metalness & roughness - offset 4\n\t\t\tfloatArray[ index ++ ] = getField( m, 'metalness', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'metalnessMap' );\n\t\t\tfloatArray[ index ++ ] = getField( m, 'roughness', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'roughnessMap' );\n\n\t\t\t// transmission & emissiveIntensity - offset 8\n\t\t\t// three.js assumes a default f0 of 0.04 if no ior is provided which equates to an ior of 1.5\n\t\t\tfloatArray[ index ++ ] = getField( m, 'ior', 1.5 );\n\t\t\tfloatArray[ index ++ ] = getField( m, 'transmission', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'transmissionMap' );\n\t\t\tfloatArray[ index ++ ] = getField( m, 'emissiveIntensity', 0.0 );\n\n\t\t\t// emission - offset 12\n\t\t\tif ( 'emissive' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.emissive.r;\n\t\t\t\tfloatArray[ index ++ ] = m.emissive.g;\n\t\t\t\tfloatArray[ index ++ ] = m.emissive.b;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\n\t\t\t}\n\n\t\t\tintArray[ index ++ ] = getTexture( m, 'emissiveMap' );\n\n\t\t\t// normals - offset 16\n\t\t\tintArray[ index ++ ] = getTexture( m, 'normalMap' );\n\t\t\tindex ++; // because of vec2 alignment\n\t\t\tif ( 'normalScale' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.normalScale.x;\n\t\t\t\tfloatArray[ index ++ ] = m.normalScale.y;\n\n \t\t\t} else {\n\n \t\t\t\tfloatArray[ index ++ ] = 1;\n \t\t\t\tfloatArray[ index ++ ] = 1;\n\n \t\t\t}\n\n\t\t\t// clearcoat - offset 20\n\t\t\tfloatArray[ index ++ ] = getField( m, 'clearcoat', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'clearcoatMap' );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'clearcoatNormalMap' );\n\t\t\tindex ++; // because of vec2 alignment\n\n\t\t\t// offset 24\n\t\t\tif ( 'clearcoatNormalScale' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.clearcoatNormalScale.x;\n\t\t\t\tfloatArray[ index ++ ] = m.clearcoatNormalScale.y;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 1;\n\t\t\t\tfloatArray[ index ++ ] = 1;\n\n\t\t\t}\n\n\t\t\tfloatArray[ index ++ ] = getField( m, 'clearcoatRoughness', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'clearcoatRoughnessMap' );\n\n\t\t\t// iridescence - offset 28\n\t\t\tintArray[ index ++ ] = getTexture( m, 'iridescenceMap' );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'iridescenceThicknessMap' );\n\n\t\t\tfloatArray[ index ++ ] = getField( m, 'iridescence', 0.0 );\n\t\t\tfloatArray[ index ++ ] = getField( m, 'iridescenceIOR', 1.3 );\n\n\t\t\t// offset 32\n\t\t\tconst iridescenceThicknessRange = getField( m, 'iridescenceThicknessRange', [ 100, 400 ] );\n\t\t\tfloatArray[ index ++ ] = iridescenceThicknessRange[ 0 ];\n\t\t\tfloatArray[ index ++ ] = iridescenceThicknessRange[ 1 ];\n\t\t\t// vec3f alignment requirements\n\t\t\tindex ++;\n\t\t\tindex ++;\n\n\t\t\t// specular color - offset 36\n\t\t\tif ( 'specularColor' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.specularColor.r;\n\t\t\t\tfloatArray[ index ++ ] = m.specularColor.g;\n\t\t\t\tfloatArray[ index ++ ] = m.specularColor.b;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\n\t\t\t}\n\n\t\t\tintArray[ index ++ ] = getTexture( m, 'specularColorMap' );\n\n\t\t\t// specular intensity - offset 40\n\t\t\tfloatArray[ index ++ ] = getField( m, 'specularIntensity', 1.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'specularIntensityMap' );\n\n\t\t\t// isThinFilm\n\t\t\tconst isThinFilm = getField( m, 'thickness', 0.0 ) === 0.0 && getField( m, 'attenuationDistance', Infinity ) === Infinity;\n\t\t\tintArray[ index ++ ] = Number( isThinFilm );\n\t\t\tindex ++;\n\n\t\t\t// attenuation - offset 44\n\t\t\tif ( 'attenuationColor' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.attenuationColor.r;\n\t\t\t\tfloatArray[ index ++ ] = m.attenuationColor.g;\n\t\t\t\tfloatArray[ index ++ ] = m.attenuationColor.b;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\n\t\t\t}\n\n\t\t\tfloatArray[ index ++ ] = getField( m, 'attenuationDistance', Infinity );\n\n\t\t\t// alphaMap - offset 48\n\t\t\tintArray[ index ++ ] = getTexture( m, 'alphaMap' );\n\t\t\tintArray[ index ++ ] = Number( getField( m, 'castShadow', true ) ); // shadow\n\t\t\tfloatArray[ index ++ ] = m.opacity;\n\t\t\tfloatArray[ index ++ ] = m.alphaTest;\n\n\t\t\t// side & matte - offset 52\n\t\t\tif ( ! isThinFilm && m.transmission > 0.0 ) {\n\n\t\t\t\tfloatArray[ index ++ ] = 0;\n\n\t\t\t} else {\n\n\t\t\t\tswitch ( m.side ) {\n\n\t\t\t\t\tcase FrontSide:\n\t\t\t\t\t\tfloatArray[ index ++ ] = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BackSide:\n\t\t\t\t\t\tfloatArray[ index ++ ] = - 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DoubleSide:\n\t\t\t\t\t\tfloatArray[ index ++ ] = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tintArray[ index ++ ] = Number( getField( m, 'matte', false ) ); // matte\n\t\t\tfloatArray[ index ++ ] = getField( m, 'sheen', 0.0 );\n\t\t\tindex ++; // vec3 alignment requirements\n\n\t\t\t// sheenColor - offset 56\n\t\t\tif ( 'sheenColor' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.sheenColor.r;\n\t\t\t\tfloatArray[ index ++ ] = m.sheenColor.g;\n\t\t\t\tfloatArray[ index ++ ] = m.sheenColor.b;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\n\t\t\t}\n\n\t\t\tintArray[ index ++ ] = getTexture( m, 'sheenColorMap' );\n\n\t\t\t// sheenRoughness, flags - offset 60\n\t\t\tfloatArray[ index ++ ] = getField( m, 'sheenRoughness', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'sheenRoughnessMap' );\n\n\t\t\tintArray[ index ++ ] = Number( m.vertexColors );\n\t\t\tintArray[ index ++ ] = Number( m.flatShading );\n\n\t\t\t// transparent, fogVolume - offset 64\n\t\t\tintArray[ index ++ ] = Number( m.transparent );\n\t\t\tintArray[ index ++ ] = 0;\n\t\t\tindex ++;\n\t\t\tindex ++;\n\n\t\t\t// map transform - offset 68\n\t\t\tindex += writeTextureMatrixToArray( m, 'map', floatArray, index );\n\n\t\t\t// metalnessMap transform - offset 80\n\t\t\tindex += writeTextureMatrixToArray( m, 'metalnessMap', floatArray, index );\n\n\t\t\t// roughnessMap transform - offset 92\n\t\t\tindex += writeTextureMatrixToArray( m, 'roughnessMap', floatArray, index );\n\n\t\t\t// transmissionMap transform - offset 104\n\t\t\tindex += writeTextureMatrixToArray( m, 'transmissionMap', floatArray, index );\n\n\t\t\t// emissiveMap transform - offset 116\n\t\t\tindex += writeTextureMatrixToArray( m, 'emissiveMap', floatArray, index );\n\n\t\t\t// normalMap transform - offset 128\n\t\t\tindex += writeTextureMatrixToArray( m, 'normalMap', floatArray, index );\n\n\t\t\t// clearcoatMap transform - offset 140\n\t\t\tindex += writeTextureMatrixToArray( m, 'clearcoatMap', floatArray, index );\n\n\t\t\t// clearcoatNormalMap transform - offset 152\n\t\t\tindex += writeTextureMatrixToArray( m, 'clearcoatNormalMap', floatArray, index );\n\n\t\t\t// clearcoatRoughnessMap transform - offset 164\n\t\t\tindex += writeTextureMatrixToArray( m, 'clearcoatRoughnessMap', floatArray, index );\n\n\t\t\t// sheenColorMap transform - offset 176\n\t\t\tindex += writeTextureMatrixToArray( m, 'sheenColorMap', floatArray, index );\n\n\t\t\t// sheenRoughnessMap transform - offset 188\n\t\t\tindex += writeTextureMatrixToArray( m, 'sheenRoughnessMap', floatArray, index );\n\n\t\t\t// iridescenceMap transform - offset 200\n\t\t\tindex += writeTextureMatrixToArray( m, 'iridescenceMap', floatArray, index );\n\n\t\t\t// iridescenceThicknessMap transform - offset 212\n\t\t\tindex += writeTextureMatrixToArray( m, 'iridescenceThicknessMap', floatArray, index );\n\n\t\t\t// specularColorMap transform - offset 224\n\t\t\tindex += writeTextureMatrixToArray( m, 'specularColorMap', floatArray, index );\n\n\t\t\t// specularIntensityMap transform - offset 236\n\t\t\tindex += writeTextureMatrixToArray( m, 'specularIntensityMap', floatArray, index );\n\n\t\t\t// alphaMap transform - offset 248\n\t\t\tindex += writeTextureMatrixToArray( m, 'alphaMap', floatArray, index );\n\n\t\t}\n\n\t\treturn { materialData: floatArray, textures };\n\n\t}\n\n\twriteTransformData( info, premultiplyMatrix, writeOffset, targetBuffer ) {\n\n\t\tsuper.writeTransformData( info, premultiplyMatrix, writeOffset, targetBuffer );\n\n\t\t// write material data to the transforms\n\t\tconst { materials } = this;\n\t\tconst { object, instanceId, root } = info;\n\n\t\t// get the material associated with the bvh group\n\t\tlet material = object.material;\n\t\tif ( Array.isArray( material ) ) {\n\n\t\t\tconst { materialIndex } = object.geometry.groups[ root ];\n\t\t\tmaterial = material[ materialIndex ];\n\n\t\t}\n\n\t\t// save the index\n\t\tlet index = materials.indexOf( material );\n\t\tif ( index === - 1 ) {\n\n\t\t\tindex = materials.length;\n\t\t\tmaterials.push( material );\n\n\t\t}\n\n\t\tconst transformBufferU32 = new Uint32Array( targetBuffer );\n\t\ttransformBufferU32[ writeOffset * transformStruct.getLength() + 34 ] = index;\n\n\t\t// write color\n\t\t// TODO: note that both BatchedMesh and InstancedMesh \"getColorAt\" functions throw\n\t\t// if colors have not been defined.\n\t\tif ( object.isInstancedMesh && object.instanceColor ) {\n\n\t\t\tobject.getColorAt( instanceId, _colorVec );\n\t\t\t_colorVec.w = 1.0;\n\n\t\t} else if ( object.isBatchedMesh && object._colorsTexture ) {\n\n\t\t\tobject.getColorAt( instanceId, _colorVec );\n\n\t\t} else {\n\n\t\t\t_colorVec.setScalar( 1 );\n\n\t\t}\n\n\t\tconst transformBufferF32 = new Float32Array( targetBuffer );\n\t\t_colorVec.toArray( transformBufferF32, writeOffset * transformStruct.getLength() + 36 );\n\n\t}\n\n\tgetBVH( object, instanceId, rangeTarget ) {\n\n\t\tconst { bvhMap } = this;\n\t\tconst bvh = super.getBVH( object, instanceId, rangeTarget );\n\t\tif ( bvhMap.has( bvh ) ) {\n\n\t\t\tconst data = bvhMap.get( bvh );\n\t\t\tObject.assign( rangeTarget, data.range );\n\n\t\t\t// make sure the mesh and bvh are updated if it's being reused across updates\n\t\t\tif ( bvh !== data.bvh && bvh instanceof SkinnedMeshBVH ) {\n\n\t\t\t\tconst sourceMesh = bvh.mesh;\n\t\t\t\tconst clonedMesh = data.bvh.mesh;\n\t\t\t\tclonedMesh.matrixWorld\n\t\t\t\t\t.copy( sourceMesh.matrixWorld )\n\t\t\t\t\t.decompose( clonedMesh.position, clonedMesh.quaternion, clonedMesh.scale );\n\n\t\t\t\tbvh.refit();\n\n\t\t\t}\n\n\t\t\treturn data.bvh;\n\n\t\t} else if ( bvh.indirect ) {\n\n\t\t\t// \"indirect\" bvhs are not supported since they cannot be unpacked in a way tht will allow for coherent material indices\n\t\t\tconst proxyGeometry = new BufferGeometry();\n\t\t\tproxyGeometry.attributes = bvh.geometry.attributes;\n\n\t\t\tlet array;\n\t\t\tif ( bvh.geometry.index ) {\n\n\t\t\t\tarray = bvh.geometry.index.array.slice( rangeTarget.start, rangeTarget.count + rangeTarget.start );\n\n\t\t\t} else {\n\n\t\t\t\tconst { start, count } = rangeTarget;\n\t\t\t\tarray = new Uint32Array( count );\n\t\t\t\tfor ( let i = 0, l = rangeTarget.count; i < l; i ++ ) {\n\n\t\t\t\t\tarray[ i ] = start + i;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tproxyGeometry.index = new BufferAttribute( array, 1 );\n\t\t\trangeTarget.start = 0;\n\n\t\t\tlet newBVH;\n\t\t\tif ( bvh instanceof SkinnedMeshBVH ) {\n\n\t\t\t\tconst sourceMesh = bvh.mesh;\n\t\t\t\tconst clonedMesh = new SkinnedMesh( proxyGeometry );\n\t\t\t\tclonedMesh.copy( sourceMesh );\n\t\t\t\tclonedMesh.matrixWorld\n\t\t\t\t\t.copy( sourceMesh.matrixWorld )\n\t\t\t\t\t.decompose( clonedMesh.position, clonedMesh.quaternion, clonedMesh.scale );\n\n\t\t\t\tnewBVH = new SkinnedMeshBVH( clonedMesh, { strategy: SAH, maxLeafSize: 5 } );\n\n\t\t\t} else {\n\n\t\t\t\tnewBVH = new MeshBVH( proxyGeometry, { strategy: SAH, maxLeafSize: 5 } );\n\n\t\t\t}\n\n\t\t\tbvhMap.set( bvh, { bvh: newBVH, range: { ...rangeTarget } } );\n\t\t\treturn newBVH;\n\n\t\t} else {\n\n\t\t\treturn bvh;\n\n\t\t}\n\n\t}\n\n}\n","import { MeshBasicNodeMaterial, DataTexture, NoBlending } from 'three/webgpu';\nimport { uv, varying, texture, uniform, wgslFn } from 'three/tsl';\n\nexport class AtlasDebugMaterial extends MeshBasicNodeMaterial {\n\n\tset texture( v ) {\n\n\t\tthis._texNode.value = v;\n\n\t}\n\n\tset layer( v ) {\n\n\t\tthis._layerUniform.value = v;\n\n\t}\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.blending = NoBlending;\n\n\t\tthis._texNode = texture( new DataTexture() );\n\t\tthis._layerUniform = uniform( 0 );\n\n\t\t// Shows one layer of the atlas array texture.\n\t\tthis.colorNode = wgslFn( /* wgsl */ `\n\t\t\tfn atlasDebug( tex: texture_2d_array<f32>, coord: vec2f, layer: f32 ) -> vec4f {\n\n\t\t\t\t// flip y so texel origin shows at the top-left\n\t\t\t\tlet dims = vec2f( textureDimensions( tex, 0 ).xy );\n\t\t\t\tlet texel = vec2i( vec2f( coord.x, 1.0 - coord.y ) * dims );\n\t\t\t\treturn textureLoad( tex, texel, i32( layer ), 0 );\n\n\t\t\t}\n\t\t` )( this._texNode, varying( uv() ), this._layerUniform );\n\n\t}\n\n}\n","import { BufferAttribute } from 'three';\n\nexport function updateMaterialIndexAttribute( geometry, materials, allMaterials ) {\n\n\tconst indexAttr = geometry.index;\n\tconst posAttr = geometry.attributes.position;\n\tconst vertCount = posAttr.count;\n\tconst totalCount = indexAttr ? indexAttr.count : vertCount;\n\tlet groups = geometry.groups;\n\tif ( groups.length === 0 ) {\n\n\t\tgroups = [ { count: totalCount, start: 0, materialIndex: 0 } ];\n\n\t}\n\n\tlet materialIndexAttribute = geometry.getAttribute( 'materialIndex' );\n\tif ( ! materialIndexAttribute || materialIndexAttribute.count !== vertCount ) {\n\n\t\t// use an array with the minimum precision required to store all material id references.\n\t\tlet array;\n\t\tif ( allMaterials.length <= 255 ) {\n\n\t\t\tarray = new Uint8Array( vertCount );\n\n\t\t} else {\n\n\t\t\tarray = new Uint16Array( vertCount );\n\n\t\t}\n\n\t\tmaterialIndexAttribute = new BufferAttribute( array, 1, false );\n\t\tgeometry.deleteAttribute( 'materialIndex' );\n\t\tgeometry.setAttribute( 'materialIndex', materialIndexAttribute );\n\n\t}\n\n\tconst materialArray = materialIndexAttribute.array;\n\tfor ( let i = 0; i < groups.length; i ++ ) {\n\n\t\tconst group = groups[ i ];\n\t\tconst start = group.start;\n\t\tconst count = group.count;\n\t\tconst endCount = Math.min( count, totalCount - start );\n\n\t\tconst mat = Array.isArray( materials ) ? materials[ group.materialIndex ] : materials;\n\t\tconst materialIndex = allMaterials.indexOf( mat );\n\n\t\tfor ( let j = 0; j < endCount; j ++ ) {\n\n\t\t\tlet index = start + j;\n\t\t\tif ( indexAttr ) {\n\n\t\t\t\tindex = indexAttr.getX( index );\n\n\t\t\t}\n\n\t\t\tmaterialArray[ index ] = materialIndex;\n\n\t\t}\n\n\t}\n\n}\n\nexport function setCommonAttributes( geometry, attributes ) {\n\n\tif ( ! geometry.index ) {\n\n\t\t// TODO: compute a typed array\n\t\tconst indexCount = geometry.attributes.position.count;\n\t\tconst array = new Array( indexCount );\n\t\tfor ( let i = 0; i < indexCount; i ++ ) {\n\n\t\t\tarray[ i ] = i;\n\n\t\t}\n\n\t\tgeometry.setIndex( array );\n\n\t}\n\n\tif ( ! geometry.attributes.normal && ( attributes && attributes.includes( 'normal' ) ) ) {\n\n\t\tgeometry.computeVertexNormals();\n\n\t}\n\n\tif ( ! geometry.attributes.uv && ( attributes && attributes.includes( 'uv' ) ) ) {\n\n\t\tconst vertCount = geometry.attributes.position.count;\n\t\tgeometry.setAttribute( 'uv', new BufferAttribute( new Float32Array( vertCount * 2 ), 2, false ) );\n\n\t}\n\n\tif ( ! geometry.attributes.uv2 && ( attributes && attributes.includes( 'uv2' ) ) ) {\n\n\t\tconst vertCount = geometry.attributes.position.count;\n\t\tgeometry.setAttribute( 'uv2', new BufferAttribute( new Float32Array( vertCount * 2 ), 2, false ) );\n\n\t}\n\n\tif ( ! geometry.attributes.tangent && ( attributes && attributes.includes( 'tangent' ) ) ) {\n\n\t\t// compute tangents requires a uv and normal buffer\n\t\tif ( geometry.attributes.uv && geometry.attributes.normal ) {\n\n\t\t\tgeometry.computeTangents();\n\n\t\t} else {\n\n\t\t\tconst vertCount = geometry.attributes.position.count;\n\t\t\tgeometry.setAttribute( 'tangent', new BufferAttribute( new Float32Array( vertCount * 4 ), 4, false ) );\n\n\t\t}\n\n\t}\n\n\tif ( ! geometry.attributes.color && ( attributes && attributes.includes( 'color' ) ) ) {\n\n\t\tconst vertCount = geometry.attributes.position.count;\n\t\tconst array = new Float32Array( vertCount * 4 );\n\t\tarray.fill( 1.0 );\n\t\tgeometry.setAttribute( 'color', new BufferAttribute( array, 4 ) );\n\n\t}\n\n}\n","import { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\nimport { rand2, RNG_INDEX_SCATTER_DIRECTION } from '../nodes/random.wgsl.js';\nimport { diffuseDirectionFunc } from '../nodes/sampling.wgsl.js';\n\n/**\n * Defines a material sampled by the pathtracer\n */\nexport class PathtracingMaterial {\n\n\t/**\n\t *\n\t * Called once per material\n\t * Adds ability to initialize state\n\t *\n\t */\n\tinit( /* renderer */ ) {\n\n\t}\n\n\t/**\n\t *\n\t * Must return a bsdf sampling function node with signature\n\t * ( worldView: vec3f, surface: Surface ) -> ScatterRecord\n\t *\n\t */\n\tgetBsdfNode() {\n\n\t\treturn wgslTagFn`\n\n\t\t\tfn bsdfSample( worldWo: vec3f, surf: SurfaceRecord ) -> ScatterRecord {\n\n\t\t\t\tvar record: ScatterRecord;\n\n\t\t\t\tlet wo = normalize( surf.normalInvBasis * worldWo );\n\t\t\t\tlet wi = ${ diffuseDirectionFunc }( wo, ${ rand2 }( ${ RNG_INDEX_SCATTER_DIRECTION } ) );\n\t\t\t\trecord.color = surf.color * max( wi.z, 0.0 );\n\t\t\t\trecord.pdf = max( wi.z, 0.0 ) / PI;\n\t\t\t\trecord.direction = normalize( surf.normalBasis * wi );\n\n\t\t\t\treturn record;\n\n\t\t\t}\n\n\t\t`;\n\n\t}\n\n\tgetData() {\n\n\t\treturn {\n\n\t\t\tbsdfSample: this.getBsdfNode(),\n\n\t\t};\n\n\t}\n\n}\n","import { texture, textureStore, globalId, float } from 'three/tsl';\nimport { StorageTexture, RedFormat, LinearFilter, TextureLoader, HalfFloatType } from 'three/webgpu';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\nimport { PathtracingMaterial } from './PathtracingMaterial';\nimport { specularBrdfFunc, diffuseBrdfFunc, fresnelMixFunc, conductorFresnelFunc, albedoIntegralMetallic, fresnelCoatFunc, iridescentDielectricLayerFunc, iridescentConductorLayerFunc } from '../nodes/material.wgsl.js';\nimport { diffuseDirectionFunc, getLobeWeightsFunc } from '../nodes/sampling.wgsl.js';\nimport { ggxDirectionFunc, ggxReflectionAdjustedPDFFunc } from '../nodes/ggx.wgsl.js';\nimport { bxdfContextStruct, scatterRecordStruct, surfaceRecordStruct } from '../nodes/structs.wgsl.js';\nimport { rand1, rand2, RNG_INDEX_SCATTER_DIRECTION, RNG_INDEX_SCATTER_TYPE } from '../nodes/random.wgsl.js';\nimport { ComputeKernel } from '../compute/ComputeKernel';\n\nconst TURQUIN_METAL_URL = new URL( '../../textures/turquinMetal.png', import.meta.url ).toString();\nconst TURQUIN_METAL_TEXTURE = await new TextureLoader().loadAsync( TURQUIN_METAL_URL );\n\nconst CLEARCOAT_IOR = float( 1.5 );\nconst MIN_INCIDENT_COS = float( 1e-3 );\n\nexport class GltfCompliantMaterial extends PathtracingMaterial {\n\n\tconstructor( options = {} ) {\n\n\t\tsuper();\n\n\t\tconst {\n\t\t\tspecularBrdf = specularBrdfFunc,\n\t\t\tdiffuseBrdf = diffuseBrdfFunc,\n\t\t\tfresnelMix = fresnelMixFunc,\n\t\t\tconductorFresnel = conductorFresnelFunc,\n\t\t\tfresnelCoat = fresnelCoatFunc,\n\t\t\tiridescentDielectricLayer = iridescentDielectricLayerFunc,\n\t\t\tiridescentConductorLayer = iridescentConductorLayerFunc,\n\t\t\tcalculateTurquinTexture = false,\n\t\t} = options;\n\n\t\tif ( calculateTurquinTexture ) {\n\n\t\t\tthis.turquinTexture = new StorageTexture( 32, 32 );\n\t\t\tthis.turquinTexture.type = HalfFloatType;\n\n\t\t} else {\n\n\t\t\tthis.turquinTexture = TURQUIN_METAL_TEXTURE;\n\t\t\tthis.turquinTexture.flipY = false;\n\n\t\t}\n\n\t\tthis.turquinTexture.format = RedFormat;\n\t\tthis.turquinTexture.minFilter = LinearFilter;\n\t\tthis.turquinTexture.magFilter = LinearFilter;\n\n\t\tconst turquinNode = texture( this.turquinTexture ).setName( 'turquinTexture' );\n\n\t\tthis.specularBrdf = specularBrdf;\n\t\tthis.diffuseBrdf = diffuseBrdf;\n\t\tthis.fresnelMix = fresnelMix;\n\t\tthis.conductorFresnel = conductorFresnel( turquinNode );\n\t\tthis.fresnelCoat = fresnelCoat;\n\t\tthis.iridescentDielectricLayer = iridescentDielectricLayer;\n\t\tthis.iridescentConductorLayer = iridescentConductorLayer;\n\t\tthis.calculateTurquinTexture = calculateTurquinTexture;\n\n\t}\n\n\tinit( renderer ) {\n\n\t\tif ( ! this.calculateTurquinTexture ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst turquinParams = {\n\t\t\ttexture: textureStore( this.turquinTexture ).toWriteOnly(),\n\t\t\tglobalId,\n\t\t};\n\t\tconst turquinKernel = new ComputeKernel( albedoIntegralMetallic( turquinParams ), { workgroupSize: [ 16, 16, 1 ] } );\n\n\t\trenderer.compute( turquinKernel.kernel, [ 2, 2, 1 ] );\n\n\t}\n\n\tgetBsdfNode() {\n\n\t\tconst bsdfEvalFunc = wgslTagFn/* wgsl */`\n\n\t\t\tfn bsdfEval( ctx: ${ bxdfContextStruct }, surf: ${ surfaceRecordStruct } ) -> vec3f {\n\n\t\t\t\tlet alpha = surf.roughness * surf.roughness;\n\n\t\t\t\tlet specular = ${ this.specularBrdf }( ctx.NdotL, ctx.NdotV, ctx.NdotH, alpha );\n\t\t\t\tlet diffuse = ${ this.diffuseBrdf }( ctx.NdotV, ctx.NdotL, ctx.VdotH, surf );\n\t\t\t\tlet dielectricBase = ${ this.fresnelMix }( ctx.VdotH, surf.ior, diffuse, specular );\n\n\t\t\t\tlet dielectric = ${ this.iridescentDielectricLayer }(\n\t\t\t\t\tdielectricBase, diffuse, specular, ctx.VdotH, /* outsideIor */ 1.0,\n\t\t\t\t\tsurf.ior, surf.iridescenceIor, surf.iridescenceThickness, surf.iridescence\n\t\t\t\t);\n\n\t\t\t\tlet metallicBase = ${ this.conductorFresnel }( ctx.NdotV, ctx.VdotH, surf.color, specular, alpha );\n\n\t\t\t\tlet metallic = ${ this.iridescentConductorLayer }(\n\t\t\t\t\tmetallicBase, specular, surf.color, ctx.VdotH, /* outsideIor */ 1.0,\n\t\t\t\t\tsurf.iridescenceIor, surf.iridescenceThickness, surf.iridescence\n\t\t\t\t);\n\n\t\t\t\tlet material = mix( dielectric, metallic, surf.metalness );\n\n\t\t\t\tlet clearcoatAlpha = surf.clearcoatRoughness * surf.clearcoatRoughness;\n\t\t\t\tlet clearcoat = ${ this.specularBrdf }( ctx.LdotNc, ctx.VdotNc, ctx.HdotNc, clearcoatAlpha );\n\n\t\t\t\tlet coatedMaterial = ${ this.fresnelCoat }( ctx.VdotNc, ${ CLEARCOAT_IOR }, material, clearcoat, surf.clearcoat );\n\n\t\t\t\treturn coatedMaterial;\n\n\t\t\t}\n\n\t\t`;\n\n\t\treturn wgslTagFn/* wgsl */`\n\n\t\t\tfn bsdfSample( worldWo: vec3f, surf: ${ surfaceRecordStruct } ) -> ${ scatterRecordStruct } {\n\n\t\t\t\tvar result: ${ scatterRecordStruct };\n\t\t\t\tresult.pdf = 0.0;\n\n\t\t\t\tlet alpha = surf.roughness * surf.roughness;\n\t\t\t\tlet clearcoatAlpha = surf.clearcoatRoughness * surf.clearcoatRoughness;\n\n\t\t\t\tlet normalBasis = surf.normalBasis;\n\t\t\t\tlet invBasis = surf.normalInvBasis;\n\t\t\t\tlet clearcoatBasis = surf.clearcoatBasis;\n\t\t\t\tlet invClearcoatBasis = surf.clearcoatInvBasis;\n\n\t\t\t\tlet wo = normalize( invBasis * worldWo );\n\t\t\t\tlet woClearcoat = normalize( invClearcoatBasis * worldWo );\n\n\t\t\t\t// TODO: handle such intersections better;\n\t\t\t\t// Sometimes .z < 0.0 on a pretty round surface e.g. sphere\n\t\t\t\t// Disabling this condition leads to more fireflies on ClearCoatCarPaint example\n\t\t\t\t// This could also be fixed by offsetting rays by 1e-1\n\t\t\t\t// Also, this will be an invalid condition when transmission is implemented\n\t\t\t\tif ( wo.z < 0.0 || woClearcoat.z < 0.0 ) {\n\n\t\t\t\t\treturn result;\n\n\t\t\t\t}\n\n\t\t\t\tlet weights = ${ getLobeWeightsFunc }( wo, woClearcoat, vec3( 0, 0, 1 ), ${ CLEARCOAT_IOR }, surf );\n\n\t\t\t\tvar cdf: vec4f;\n\t\t\t\tcdf.x = weights.diffuse;\n\t\t\t\tcdf.y = weights.specular + cdf.x;\n\t\t\t\tcdf.z = weights.clearcoat + cdf.y;\n\t\t\t\tcdf.w = 0; // weights.transmission + cdf.z;\n\n\t\t\t\tlet r = ${ rand1 }( ${ RNG_INDEX_SCATTER_TYPE } ) * cdf.z;\n\n\t\t\t\tlet directionUV = ${ rand2 }( ${ RNG_INDEX_SCATTER_DIRECTION } );\n\t\t\t\tvar wi: vec3f;\n\t\t\t\tvar wiClearcoat: vec3f;\n\t\t\t\tvar wh: vec3f;\n\t\t\t\tvar whClearcoat: vec3f;\n\n\t\t\t\tif ( r <= cdf.x ) { // diffuse\n\n\t\t\t\t\twi = ${ diffuseDirectionFunc }( wo, directionUV );\n\t\t\t\t\twh = normalize( wi + wo );\n\n\t\t\t\t\twiClearcoat = normalize( invClearcoatBasis * normalBasis * wi );\n\t\t\t\t\twhClearcoat = normalize( invClearcoatBasis * normalBasis * wh );\n\n\t\t\t\t} else if ( r <= cdf.y ) { // specular\n\n\t\t\t\t\twh = ${ ggxDirectionFunc }( wo, vec2( alpha ), directionUV );\n\t\t\t\t\twi = - normalize( reflect( wo, wh ) );\n\n\t\t\t\t\twiClearcoat = normalize( invClearcoatBasis * normalBasis * wi );\n\t\t\t\t\twhClearcoat = normalize( invClearcoatBasis * normalBasis * wh );\n\n\t\t\t\t} else if ( r <= cdf.z ) { // clearcoat\n\n\t\t\t\t\twhClearcoat = ${ ggxDirectionFunc }( woClearcoat, vec2( clearcoatAlpha ), directionUV );\n\t\t\t\t\twiClearcoat = - normalize( reflect( woClearcoat, whClearcoat ) );\n\n\t\t\t\t\twi = normalize( invBasis * clearcoatBasis * wiClearcoat );\n\t\t\t\t\twh = normalize( invBasis * clearcoatBasis * whClearcoat );\n\n\t\t\t\t} else if ( r <= cdf.w ) { // transmission / refraction\n\n\t\t\t\t\t// NOT IMPLEMENTED\n\n\t\t\t\t}\n\n\t\t\t\tvar ctx: ${ bxdfContextStruct };\n\t\t\t\tctx.NdotV = max( wo.z, ${ MIN_INCIDENT_COS } );\n\t\t\t\tctx.NdotL = max( wi.z, ${ MIN_INCIDENT_COS } );\n\t\t\t\tctx.NdotH = saturate( wh.z );\n\t\t\t\tctx.VdotH = saturate( dot( wo, wh ) );\n\n\t\t\t\tctx.VdotNc = max( woClearcoat.z, ${ MIN_INCIDENT_COS } );\n\t\t\t\tctx.LdotNc = max( wiClearcoat.z, ${ MIN_INCIDENT_COS } );\n\t\t\t\tctx.HdotNc = saturate( whClearcoat.z );\n\n\t\t\t\tif ( weights.diffuse > 0.0 ) {\n\n\t\t\t\t\tresult.pdf += weights.diffuse * max( wi.z, 0.0 ) / PI;\n\n\t\t\t\t}\n\n\t\t\t\tif ( weights.specular > 0.0 && wi.z > 0.0 ) {\n\n\t\t\t\t\tresult.pdf += weights.specular * ${ ggxReflectionAdjustedPDFFunc }( ctx.NdotV, ctx.NdotH, alpha );\n\n\t\t\t\t}\n\n\t\t\t\tif ( weights.clearcoat > 0.0 && wiClearcoat.z > 0.0 ) {\n\n\t\t\t\t\tresult.pdf += weights.clearcoat * ${ ggxReflectionAdjustedPDFFunc }( ctx.VdotNc, ctx.HdotNc, clearcoatAlpha );\n\n\t\t\t\t}\n\n\t\t\t\tresult.color = ${ bsdfEvalFunc }( ctx, surf );\n\t\t\t\tresult.color *= max( 0.0, wi.z );\n\t\t\t\tresult.direction = normalize( normalBasis * wi );\n\n\t\t\t\treturn result;\n\n\t\t\t}\n\n\t\t`;\n\n\t}\n\n}\n","import { DataTexture, LinearFilter, Vector2, Scene, PerspectiveCamera, Color, NoToneMapping, FloatType, Timer, StorageTexture } from 'three/webgpu';\nimport { SkinnedMeshBVH, MeshBVH, SAH } from 'three-mesh-bvh';\nimport { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';\nimport { RenderToScreenNodeMaterial } from './materials/RenderToScreenMaterial.js';\nimport { MegaKernelPathTracer } from './MegaKernelPathTracer.js';\nimport { WaveFrontPathTracer } from './WaveFrontPathTracer.js';\nimport { CubeToEquirectGenerator } from '../utils/CubeToEquirectGenerator.js';\nimport { PathtracerBVHComputeData } from './nodes/PathtracerBVHComputeData.js';\nimport { AtlasDebugMaterial } from './materials/debug/AtlasDebugMaterial.js';\nimport { setCommonAttributes } from '../core/utils/GeometryPreparationUtils.js';\nimport { GltfCompliantMaterial } from './materials/GltfCompliantMaterial.js';\n\nconst _resolution = new Vector2();\nconst _color = new Color();\n\nexport class WebGPUPathTracer {\n\n\tget bounces() {\n\n\t\treturn this._pathTracer.bounces;\n\n\t}\n\n\tset bounces( v ) {\n\n\t\tthis._pathTracer.bounces = v;\n\t\tthis._pathTracer.reset();\n\n\t}\n\n\tget samples() {\n\n\t\treturn this._pathTracer.samples;\n\n\t}\n\n\tget fadeState() {\n\n\t\treturn this._fadeState;\n\n\t}\n\n\tget textureAtlas() {\n\n\t\treturn this._bvhData.textureAtlas;\n\n\t}\n\n\tuseMegakernel( value ) {\n\n\t\tthis._pathTracer.dispose();\n\t\tthis._pathTracer = value ? new MegaKernelPathTracer( this._renderer ) : new WaveFrontPathTracer( this._renderer );\n\t\tthis._pathTracer.setBVHData( this._bvhData );\n\t\tthis._pathTracer.setMaterial( this.material );\n\t\tthis.setCamera( this.camera );\n\t\tthis.updateEnvironment();\n\n\t}\n\n\tconstructor( renderer ) {\n\n\t\t// members\n\t\tthis._renderer = renderer;\n\t\tthis._timer = new Timer();\n\n\t\tthis._envColorTexture = new DataTexture( );\n\t\tthis._envColorTexture.image.data = new Uint8Array( [ 255, 255, 255, 255 ] );\n\t\tthis._envColorTexture.needsUpdate = true;\n\t\tthis._envColorTexture.minFilter = LinearFilter;\n\t\tthis._envColorTexture.magFilter = LinearFilter;\n\n\t\tthis._backgroundColorTexture = new DataTexture( );\n\t\tthis._backgroundColorTexture.image.data = new Uint8Array( [ 255, 255, 255, 255 ] );\n\t\tthis._backgroundColorTexture.needsUpdate = true;\n\t\tthis._backgroundColorTexture.minFilter = LinearFilter;\n\t\tthis._backgroundColorTexture.magFilter = LinearFilter;\n\n\t\tthis._resetTime = - 1;\n\t\tthis._fadeState = 0;\n\t\tthis._size = new Vector2();\n\t\tthis._blitQuad = new FullScreenQuad( new RenderToScreenNodeMaterial() );\n\n\t\t// avoid mipmap gen on copy, not always supported with float type\n\t\tthis._lowResTarget = new StorageTexture( 1, 1 );\n\t\tthis._lowResTarget.type = FloatType;\n\t\tthis._lowResTarget.generateMipmaps = false;\n\n\t\t// options\n\t\tthis.minSamples = 1;\n\t\tthis.renderDelay = 500;\n\t\tthis.fadeDuration = 500;\n\t\tthis.dynamicLowRes = true;\n\t\tthis.lowResScale = 0.2;\n\t\tthis.renderScale = 1;\n\t\tthis.synchronizeRenderSize = true;\n\t\tthis.generateMissingAttributes = true;\n\t\tthis.commonAttributes = [ 'normal', 'uv', 'tangent', 'color' ];\n\n\t\tthis.material = new GltfCompliantMaterial();\n\t\tthis._pathTracer = new MegaKernelPathTracer( renderer );\n\n\t\t// initialize the scene so it doesn't fail\n\t\tthis.setScene( new Scene(), new PerspectiveCamera() );\n\n\t}\n\n\tsetScene( scene, camera ) {\n\n\t\tscene.updateMatrixWorld( true );\n\t\tcamera.updateMatrixWorld();\n\n\t\t// Build BVH for each mesh geometry\n\t\tscene.traverse( child => {\n\n\t\t\tif ( this.generateMissingAttributes && child.geometry?.isBufferGeometry ) {\n\n\t\t\t\tsetCommonAttributes( child.geometry, this.commonAttributes );\n\n\t\t\t}\n\n\t\t\tif ( child.isSkinnedMesh ) {\n\n\t\t\t\tif ( ! child.boundsTree ) {\n\n\t\t\t\t\tchild.boundsTree = new SkinnedMeshBVH( child, { strategy: SAH, maxLeafSize: 5, indirect: true } );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tchild.boundsTree.refit();\n\n\t\t\t\t}\n\n\t\t\t} else if ( child.isMesh ) {\n\n\t\t\t\tif ( ! child.geometry.boundsTree ) {\n\n\t\t\t\t\tchild.geometry.boundsTree = new MeshBVH( child.geometry, { strategy: SAH, maxLeafSize: 5 } );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} );\n\n\t\t// Build TLAS and compute functions\n\t\tconst bvhData = new PathtracerBVHComputeData( scene );\n\t\tbvhData.update();\n\t\tbvhData.textureAtlas.setTextures( this._renderer, bvhData.textures );\n\n\t\tthis.scene = scene;\n\t\tthis._bvhData = bvhData;\n\t\tthis._pathTracer.setBVHData( bvhData );\n\t\tthis.setCamera( camera );\n\t\tthis.updateEnvironment();\n\n\t}\n\n\tgetMaterial() {\n\n\t\treturn this.material;\n\n\t}\n\n\tsetMaterial( material ) {\n\n\t\tthis.material = material;\n\t\tthis._pathTracer.setMaterial( material );\n\n\t}\n\n\t// TODO: support async generation of ObjectBVH\n\tsetSceneAsync( ...args ) {\n\n\t\tthis.setScene( ...args );\n\n\t}\n\n\tsetCamera( camera ) {\n\n\t\tthis.camera = camera;\n\t\tthis.updateCamera();\n\n\t}\n\n\tupdateCamera() {\n\n\t\tconst camera = this.camera;\n\t\tcamera.updateMatrixWorld();\n\n\t\tthis._pathTracer.setCamera( camera );\n\t\tthis.reset();\n\n\t}\n\n\tupdateEnvironment() {\n\n\t\tconst {\n\t\t\t_renderer,\n\t\t\t_pathTracer,\n\t\t\tscene,\n\t\t\t_envColorTexture,\n\t\t\t_backgroundColorTexture,\n\t\t} = this;\n\n\t\tconst environment = convertToTexture( _renderer, scene.environment || _color.set( 0 ), _envColorTexture );\n\t\tconst background = convertToTexture( _renderer, scene.background, _backgroundColorTexture );\n\n\t\t_pathTracer.setEnvironment(\n\t\t\tenvironment,\n\t\t\tscene.environmentIntensity,\n\t\t\tscene.environmentRotation,\n\n\t\t\tbackground,\n\t\t\tscene.backgroundIntensity,\n\t\t\tscene.backgroundRotation,\n\t\t\tscene.backgroundBlurriness,\n\t\t);\n\n\t}\n\n\tsetSize( x, y ) {\n\n\t\tif ( this._size.x !== x || this._size.y !== y ) {\n\n\t\t\tthis._size.set( x, y );\n\t\t\tthis.reset();\n\n\t\t}\n\n\t}\n\n\treset() {\n\n\t\tthis._pathTracer.reset();\n\t\tthis._resetTime = 0;\n\t\tthis._fadeState = 0;\n\n\t}\n\n\trenderSample() {\n\n\t\tconst renderer = this._renderer;\n\t\tconst size = this._size;\n\t\tconst blitQuad = this._blitQuad;\n\t\tconst pathTracer = this._pathTracer;\n\t\tconst lowResTarget = this._lowResTarget;\n\t\tconst timer = this._timer;\n\t\tconst {\n\t\t\trenderDelay,\n\t\t\tdynamicLowRes,\n\t\t\tsynchronizeRenderSize,\n\t\t\trenderScale,\n\t\t\tlowResScale,\n\t\t\tminSamples,\n\t\t} = this;\n\n\t\ttimer.update();\n\n\t\tif ( ! this._renderer._initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( ! this.material.initialized ) {\n\n\t\t\tthis.material.init( renderer );\n\t\t\tthis.material.initialized = true;\n\n\t\t}\n\n\t\tconst delta = 1000 * timer.getDelta();\n\t\tthis._resetTime += delta;\n\n\t\tconst originalToneMapping = renderer.toneMapping;\n\t\tconst originalExposure = renderer.toneMappingExposure;\n\t\tconst originalTarget = renderer.getRenderTarget();\n\t\tconst originalAutoClear = renderer.autoClear;\n\t\trenderer.toneMapping = NoToneMapping;\n\t\trenderer.toneMappingExposure = 1.0;\n\n\t\t// handle canvas-size auto synchronization\n\t\tif ( synchronizeRenderSize ) {\n\n\t\t\trenderer.getDrawingBufferSize( _resolution );\n\t\t\tconst w = Math.floor( renderScale * _resolution.x );\n\t\t\tconst h = Math.floor( renderScale * _resolution.y );\n\t\t\tthis.setSize( w, h );\n\n\t\t}\n\n\t\t// check if we should be in low res mode and calculate the target size\n\t\tlet { width, height } = size;\n\t\tconst lowResMode = this._resetTime < renderDelay;\n\t\tif ( lowResMode ) {\n\n\t\t\twidth = Math.ceil( lowResScale * width );\n\t\t\theight = Math.ceil( lowResScale * height );\n\n\t\t}\n\n\t\t// set the size if necessary\n\t\tpathTracer.getSize( _resolution );\n\n\t\tconst resized = _resolution.x !== width || _resolution.y !== height;\n\t\tif ( resized ) {\n\n\t\t\tif ( ! lowResMode && dynamicLowRes ) {\n\n\t\t\t\t// copy the low reset content if we're transitioning to the full\n\t\t\t\t// resolution view so we can fade to it\n\t\t\t\tlowResTarget.setSize( Math.ceil( lowResScale * width ), Math.ceil( lowResScale * height ) );\n\t\t\t\trenderer.copyTextureToTexture( pathTracer.outputTarget, lowResTarget );\n\n\t\t\t}\n\n\t\t\tpathTracer.setSize( width, height );\n\n\t\t}\n\n\t\tif ( ! lowResMode && pathTracer.samples >= minSamples ) {\n\n\t\t\tthis._fadeState += delta / this.fadeDuration;\n\t\t\tthis._fadeState = Math.min( 1.0, this._fadeState );\n\n\t\t}\n\n\n\t\t// update the samples\n\t\tif ( ! lowResMode || ( lowResMode && dynamicLowRes ) ) {\n\n\t\t\tpathTracer.lowResMode = lowResMode;\n\t\t\tpathTracer.update();\n\n\t\t}\n\n\n\t\t// render the content to the canvas\n\t\tconst opacity = ( lowResMode && dynamicLowRes ? 1.0 : this._fadeState );\n\n\t\trenderer.autoClear = dynamicLowRes ? true : opacity === 1.0;\n\t\tblitQuad.material.transition = dynamicLowRes ? opacity : 1.0;\n\t\tblitQuad.material.opacity = dynamicLowRes ? 1.0 : opacity;\n\t\tblitQuad.material.fromTexture = lowResTarget;\n\t\tblitQuad.material.texture = pathTracer.outputTarget;\n\t\tblitQuad.material.toneMapping = originalToneMapping;\n\t\tblitQuad.material.toneMappingExposure = originalExposure;\n\t\tblitQuad.render( renderer );\n\n\t\t// reset the renderer\n\t\trenderer.autoClear = originalAutoClear;\n\t\trenderer.toneMapping = originalToneMapping;\n\t\trenderer.toneMappingExposure = originalExposure;\n\t\trenderer.setRenderTarget( originalTarget );\n\n\t}\n\n\trenderTextureAtlas( layer = 0 ) {\n\n\t\tconst renderer = this._renderer;\n\t\tif ( ! renderer._initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( ! this._atlasDebugQuad ) {\n\n\t\t\tthis._atlasDebugQuad = new FullScreenQuad( new AtlasDebugMaterial() );\n\n\t\t}\n\n\t\tconst quad = this._atlasDebugQuad;\n\t\tquad.material.texture = this.textureAtlas.texture;\n\t\tquad.material.layer = layer;\n\t\trenderer.setRenderTarget( null );\n\t\tquad.render( renderer );\n\n\t}\n\n\tdispose() {\n\n\t\tthis._pathTracer.dispose();\n\t\tthis._blitQuad.dispose();\n\t\tthis._lowResTarget.dispose();\n\t\tthis._envColorTexture.dispose();\n\t\tthis._backgroundColorTexture.dispose();\n\t\tthis._atlasDebugQuad?.dispose();\n\n\t}\n\n\tasync getDetailedSampleCount() {\n\n\t\tconst sampleCountTarget = this._pathTracer.sampleCountTarget;\n\t\tconst { width, height } = sampleCountTarget;\n\t\tconst renderer = this._renderer;\n\n\t\t// Create a stub \"render target\" with just textures field to read from the storage texture\n\t\tconst targetStub = { textures: [ sampleCountTarget ] };\n\n\t\tconst buffer = await renderer.readRenderTargetPixelsAsync( targetStub, 0, 0, width, height );\n\t\tconst uintBuffer = new Uint32Array( buffer.buffer );\n\n\t\t// copyTexture requires a multiple of 256 bytes for texelsPerRow\n\t\t// Hence a multiple of 64 u32 per row\n\t\tconst texelsPerRow = Math.ceil( width / 64 ) * 64;\n\n\t\t// Sum up all sample counts and divide by pixel count to get average samples per pixel\n\t\tlet totalSamples = 0;\n\t\tlet minSamples = Number.MAX_VALUE;\n\t\tlet maxSamples = - Number.MAX_VALUE;\n\t\tfor ( let i = 0, l = uintBuffer.length; i < l; i ++ ) {\n\n\t\t\t// Skip padding\n\t\t\tif ( i % texelsPerRow >= width ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\t// Each entry contains sample count in lower bits and active flag in high bit\n\t\t\t// Mask out the active flag (0xF0000000) to get just the sample count\n\t\t\tconst samples = uintBuffer[ i ] & 0x0FFFFFFF;\n\n\t\t\ttotalSamples += samples;\n\t\t\tminSamples = Math.min( minSamples, samples );\n\t\t\tmaxSamples = Math.max( maxSamples, samples );\n\n\t\t}\n\n\t\treturn {\n\t\t\tmin: minSamples,\n\t\t\tmax: maxSamples,\n\t\t\tavg: Math.floor( totalSamples / ( width * height ) ),\n\t\t};\n\n\n\t}\n\n\t// Returns time since last reset in ms\n\tgetRenderTime() {\n\n\t\treturn this._resetTime;\n\n\t}\n\n}\n\nfunction convertToTexture( renderer, value, colorTexture ) {\n\n\tif ( ! value ) {\n\n\t\tconst clearAlpha = renderer.getClearAlpha();\n\t\trenderer.getClearColor( _color );\n\n\t\tcolorTexture.image.data[ 0 ] = _color.r * 255;\n\t\tcolorTexture.image.data[ 1 ] = _color.g * 255;\n\t\tcolorTexture.image.data[ 2 ] = _color.b * 255;\n\t\tcolorTexture.image.data[ 3 ] = clearAlpha * 255;\n\n\t\tcolorTexture.needsUpdate = true;\n\t\tvalue = colorTexture;\n\n\t} else if ( value.isColor ) {\n\n\t\tcolorTexture.image.data[ 0 ] = value.r * 255;\n\t\tcolorTexture.image.data[ 1 ] = value.g * 255;\n\t\tcolorTexture.image.data[ 2 ] = value.b * 255;\n\t\tcolorTexture.image.data[ 3 ] = 255;\n\t\tcolorTexture.needsUpdate = true;\n\t\tvalue = colorTexture;\n\n\t} else if ( value?.isCubeTexture ) {\n\n\t\tvalue = new CubeToEquirectGenerator( renderer ).generate( value );\n\n\t}\n\n\treturn value;\n\n}\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"mappings":"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"}
1
+ {"version":3,"file":"webgpu-BxYJfBjz.mjs","names":["transformStruct","nodeProxyConstructor","transformStruct","rngInit","rand2","rngNextBounce","rngInit","rand2","rngInit","rand2","rngInit","CommonGLSL.util_functions","getTextureHash","rngInit","rand2","intersectionResultStruct","rand1","getTextureHash","rand2"],"sources":["../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/tsl/structs.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/nodes/NodeProxy.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/utils/toObjectBVH.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/utils/packBVHBufferUtils.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/nodes/WGSLTagFnNode.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/tsl/constants.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/shapecastFns/getShapecastFn.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/tsl/fns.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/shapecastFns/getRaycastFirstHitFn.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/shapecastFns/getSampleTrianglePointFn.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/shapecastFns/getClosestPointToPointFn.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/lib/three-mesh-bvh/BVHComputeData.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/materials/RenderToScreenMaterial.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/ComputeKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/random.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/structs.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/utils.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/sampling.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/PathTracerMegaKernel.js","../../../../node_modules/three-gpu-pathtracer/src/utils/TextureUtils.js","../../../../node_modules/three-gpu-pathtracer/src/uniforms/EquirectHdrInfoUniform.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/ZeroOutKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/PathTracerBackend.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/MegaKernelPathTracer.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/structs.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/PrimeRayGenerationDispatchKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/RayGenerationKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/RayIntersectionKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/UpdateRayQueueParamsKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/ZeroOutBufferKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/compute/wavefront/ProcessHitsKernel.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/WaveFrontPathTracer.js","../../../../node_modules/three-gpu-pathtracer/src/shader/common/util_functions.glsl.js","../../../../node_modules/three-gpu-pathtracer/src/utils/CubeToEquirectGenerator.js","../../../../node_modules/three-gpu-pathtracer/src/core/utils/sceneUpdateUtils.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/ggx.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/material.wgsl.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/AtlasTexture.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/nodes/PathtracerBVHComputeData.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/materials/debug/AtlasDebugMaterial.js","../../../../node_modules/three-gpu-pathtracer/src/core/utils/GeometryPreparationUtils.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/materials/PathtracingMaterial.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/materials/GltfCompliantMaterial.js","../../../../node_modules/three-gpu-pathtracer/src/webgpu/WebGPUPathTracer.js"],"sourcesContent":["import { StructTypeNode } from 'three/webgpu';\n\n// temporary shim so StructTypeNodes can be passed to storage functions until\n// this is fixed in three.js\nObject.defineProperty( StructTypeNode.prototype, 'layout', {\n\n\tget() {\n\n\t\treturn this;\n\n\t}\n\n} );\nStructTypeNode.prototype.isStruct = true;\n\n//\n\nexport const bvhNodeBoundsStruct = new StructTypeNode( {\n\tmin: 'array<f32, 3>',\n\tmax: 'array<f32, 3>',\n}, 'BVHBoundingBox' );\nbvhNodeBoundsStruct.getLength = () => 6;\n\nexport const bvhNodeStruct = new StructTypeNode( {\n\tbounds: 'BVHBoundingBox',\n\trightChildOrTriangleOffset: 'uint',\n\tsplitAxisOrTriangleCount: 'uint',\n}, 'BVHNode' );\nbvhNodeStruct.getLength = () => bvhNodeBoundsStruct.getLength() + 2;\n\nexport const transformStruct = new StructTypeNode( {\n\tmatrixWorld: 'mat4x4f',\n\tinverseMatrixWorld: 'mat4x4f',\n\tnodeOffset: 'uint',\n\tvisible: 'uint',\n\t_alignment0: 'uint',\n\t_alignment1: 'uint',\n}, 'TransformStruct' );\n\n\n/**\n * WGSL struct node representing a ray with an origin and direction.\n * Used as the input to BVH traversal and intersection functions.\n * @type {StructTypeNode}\n * @section TSL Structs\n */\nexport const rayStruct = new StructTypeNode( {\n\torigin: 'vec3f',\n\tdirection: 'vec3f',\n}, 'Ray' );\n\n/**\n * WGSL struct node describing a ray–triangle intersection result, including barycentric\n * coordinates, world-space normal, hit distance, face side, triangle indices, and the\n * object index within the TLAS.\n * @type {StructTypeNode}\n * @section TSL Structs\n */\nexport const rayIntersectionResultStruct = new StructTypeNode( {\n\tindices: 'vec4u',\n\tnormal: 'vec3f',\n\tdidHit: 'bool',\n\tbarycoord: 'vec3f',\n\tobjectIndex: 'uint',\n\tside: 'float',\n\tdist: 'float',\n}, 'IntersectionResult' );\n\n/**\n * WGSL struct node describing a closest-point query result, including the world-space\n * closest point, squared distance, barycentric coordinates, face normal, side, triangle\n * indices, and the object index within the TLAS.\n *\n * Barycoord convention matches {@link rayIntersectionResultStruct}: `(bary_a, bary_b, bary_c)`\n * where each component is the weight for the corresponding vertex in `faceIndices.xyz`.\n * @type {StructTypeNode}\n * @section TSL Structs\n */\nexport const pointQueryResultStruct = new StructTypeNode( {\n\tfaceIndices: 'vec4u',\n\tclosestPoint: 'vec3f',\n\tfound: 'bool',\n\tbarycoord: 'vec3f',\n\tobjectIndex: 'uint',\n\tfaceNormal: 'vec3f',\n\tside: 'float',\n\tdistanceSq: 'float',\n}, 'PointQueryResult' );\n","import { Node, TSL } from 'three/webgpu';\n\n// three r184 compat: TSL.nodeProxyConstructor only exists from three r185.\n// Recovered from the known-good Jul 21 SDK bundle (webgpu-V2WQRg97.mjs): fall\n// back to a Proxy that forwards to the wrapped node and exposes it via\n// `functionNode` so callable node functions keep working on r184.\nconst nodeProxyConstructor = TSL.nodeProxyConstructor ?? ( ( fn, target ) => new Proxy( fn, {\n\n\tget( obj, prop, receiver ) {\n\n\t\tconst value = Reflect.get( target, prop, receiver );\n\t\treturn value === undefined && prop === 'functionNode' ? target : value;\n\n\t},\n\tset( obj, prop, value ) {\n\n\t\treturn Reflect.set( target, prop, value );\n\n\t},\n\n} ) );\n\n\nclass ProxyCallNode extends Node {\n\n\tstatic get type() {\n\n\t\treturn 'ProxyCallNode';\n\n\t}\n\n\tconstructor( proxyNode, params ) {\n\n\t\tsuper();\n\t\tthis.proxyNode = proxyNode;\n\t\tthis.params = params;\n\n\t}\n\n\tsetup() {\n\n\t\treturn this.proxyNode.proxyNode.call( ...this.params );\n\n\t}\n\n}\n\nexport class NodeProxy {\n\n\tget isNode() {\n\n\t\treturn true;\n\n\t}\n\n\t// getter for the node being proxied to\n\tget proxyNode() {\n\n\t\tconst { proxyObject, proxyProperty } = this;\n\t\tconst properties = proxyProperty.split( '.' );\n\t\tlet value = proxyObject;\n\t\tfor ( let i = 0, l = properties.length; i < l; i ++ ) {\n\n\t\t\tvalue = value[ properties[ i ] ];\n\n\t\t}\n\n\t\tif ( value && 'functionNode' in value ) {\n\n\t\t\treturn value.functionNode;\n\n\t\t} else {\n\n\t\t\treturn value;\n\n\t\t}\n\n\t}\n\n\tconstructor( property, object = null ) {\n\n\t\t// store the proxy property and objects so they can be changed later\n\t\tthis.proxyObject = object;\n\t\tthis.proxyProperty = property;\n\n\t\t// set up a proxy to redirect all calls to the proxied node in order to avoid replicating\n\t\t// expected members for all node types.\n\t\treturn new Proxy( this, {\n\n\t\t\tget( target, property ) {\n\n\t\t\t\tif ( property in target ) {\n\n\t\t\t\t\treturn Reflect.get( target, property );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst node = target.proxyNode;\n\t\t\t\t\tif ( ! node ) {\n\n\t\t\t\t\t\treturn undefined;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst value = Reflect.get( node, property );\n\t\t\t\t\tif ( typeof value === 'function' ) {\n\n\t\t\t\t\t\treturn value.bind( node );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\treturn value;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tset( target, property, value ) {\n\n\t\t\t\tif ( property in target ) {\n\n\t\t\t\t\treturn Reflect.set( target, property, value );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthrow new Error( 'NodeProxy: Cannot set members of proxied nodes.' );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t} );\n\n\t}\n\n}\n\nexport const proxy = ( ...args ) => {\n\n\treturn new NodeProxy( ...args );\n\n};\n\nexport const proxyFn = ( ...args ) => {\n\n\tconst nodeProxy = new NodeProxy( ...args );\n\tconst fn = ( ...params ) => new ProxyCallNode( nodeProxy, params );\n\treturn nodeProxyConstructor( fn, nodeProxy );\n\n};\n","/** @import { Object3D, BufferGeometry } from 'three' */\nimport { Mesh } from 'three/webgpu';\nimport { GeometryBVH } from 'three-mesh-bvh/src/core/GeometryBVH.js';\nimport { ObjectBVH } from 'three-mesh-bvh/src/core/ObjectBVH.js';\nimport { SAH } from 'three-mesh-bvh/src/core/Constants.js';\n\n/**\n * Normalizes the various accepted `bvh` arguments into an {@link ObjectBVH}. A pre-built ObjectBVH\n * is returned as-is; otherwise an Object3D, BufferGeometry, GeometryBVH, or array of those is\n * wrapped into a new ObjectBVH.\n *\n * @private\n * @param {ObjectBVH | Object3D | BufferGeometry | GeometryBVH | Array} bvh\n * @returns {ObjectBVH}\n */\nexport function toObjectBVH( bvh ) {\n\n\tif ( bvh instanceof ObjectBVH ) {\n\n\t\treturn bvh;\n\n\t}\n\n\tif ( ! Array.isArray( bvh ) ) {\n\n\t\tbvh = [ bvh ];\n\n\t}\n\n\tconst objects = bvh.map( item => {\n\n\t\tif ( item.isObject3D ) {\n\n\t\t\treturn item;\n\n\t\t} else if ( item.isBufferGeometry ) {\n\n\t\t\treturn new Mesh( item );\n\n\t\t} else if ( item instanceof GeometryBVH ) {\n\n\t\t\tconst dummy = new Mesh();\n\t\t\tdummy.geometry.boundsTree = item;\n\t\t\treturn dummy;\n\n\t\t}\n\n\t} );\n\n\treturn new ObjectBVH( objects, { strategy: SAH, targetLeafSize: 1 } );\n\n}\n","/** @import { StructTypeNode } from 'three/webgpu' */\n/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { Vector4 } from 'three';\nimport { BYTES_PER_NODE, UINT32_PER_NODE, IS_LEAFNODE_FLAG } from 'three-mesh-bvh/src/core/Constants.js';\n\n// scratch\nconst _def = /* @__PURE__ */ new Vector4();\nconst _vec = /* @__PURE__ */ new Vector4();\n\n// resolve an indirect buffer into a flat triangle index array\nfunction dereferenceIndex( indexAttr, indirectBuffer ) {\n\n\tconst indexArray = indexAttr ? indexAttr.array : null;\n\tconst result = new Uint32Array( indirectBuffer.length * 3 );\n\tfor ( let i = 0, l = indirectBuffer.length; i < l; i ++ ) {\n\n\t\tconst i3 = 3 * i;\n\t\tconst v3 = 3 * indirectBuffer[ i ];\n\t\tfor ( let c = 0; c < 3; c ++ ) {\n\n\t\t\tresult[ i3 + c ] = indexArray ? indexArray[ v3 + c ] : v3 + c;\n\n\t\t}\n\n\t}\n\n\treturn result;\n\n}\n\n/**\n * Copies the packed nodes of a BVH into the shared node buffer, rewriting leaf offsets / counts and\n * tagging leaves as mesh (`0xFFFF`) or TLAS (`0xFF00`) leaves. Returns the write offset of each root.\n *\n * @private\n * @param {Object} bvh\n * @param {number} geometryOffset\n * @param {Array} transformInfo\n * @param {number} nodeWriteOffset\n * @param {ArrayBuffer} target\n * @param {boolean} [tlas=false]\n * @returns {Array<number>}\n */\nexport function appendBVHData( bvh, geometryOffset, transformInfo, nodeWriteOffset, target, tlas = false ) {\n\n\tconst targetU16 = new Uint16Array( target );\n\tconst targetU32 = new Uint32Array( target );\n\tconst targetF32 = new Float32Array( target );\n\n\tconst result = [];\n\tlet tlasOffset = 0;\n\tbvh._roots.forEach( root => {\n\n\t\tconst rootBuffer16 = new Uint16Array( root );\n\t\tconst rootBuffer32 = new Uint32Array( root );\n\t\tresult.push( nodeWriteOffset );\n\t\tfor ( let i = 0, l = root.byteLength / BYTES_PER_NODE; i < l; i ++ ) {\n\n\t\t\tconst r32 = i * UINT32_PER_NODE;\n\t\t\tconst r16 = r32 * 2;\n\t\t\tconst n32 = nodeWriteOffset * UINT32_PER_NODE;\n\t\t\tconst n16 = n32 * 2;\n\n\t\t\t// write bounds\n\t\t\tconst view = new Float32Array( root, i * BYTES_PER_NODE, 6 );\n\t\t\tif ( i === 0 ) {\n\n\t\t\t\t// if we're copying the root then check for cases where there are no primitives and therefore\n\t\t\t\t// be a bounds of [ Infinity, - Infinity ]. Convert this to [ 1, - 1 ] for reliable GPU behavior.\n\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\tconst vMin = view[ i + 0 ];\n\t\t\t\t\tconst vMax = view[ i + 3 ];\n\t\t\t\t\tif ( vMin > vMax ) {\n\n\t\t\t\t\t\ttargetF32[ n32 + i + 0 ] = 1;\n\t\t\t\t\t\ttargetF32[ n32 + i + 3 ] = - 1;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttargetF32[ n32 + i + 0 ] = vMin;\n\t\t\t\t\t\ttargetF32[ n32 + i + 3 ] = vMax;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\ttargetF32.set( view, n32 );\n\n\t\t\t}\n\n\t\t\tconst isLeaf = IS_LEAFNODE_FLAG === rootBuffer16[ r16 + 15 ];\n\t\t\tif ( isLeaf ) {\n\n\t\t\t\tif ( tlas ) {\n\n\t\t\t\t\t// 0xFFFF == mesh leaf, 0xFF00 == TLAS leaf\n\t\t\t\t\ttargetU32[ n32 + 6 ] = tlasOffset;\n\t\t\t\t\ttargetU16[ n16 + 15 ] = 0xFF00;\n\n\t\t\t\t\tconst count = rootBuffer16[ r16 + 14 ];\n\t\t\t\t\t// const offset = rootBuffer32[ r32 + 6 ];\n\n\t\t\t\t\t// each root is expanded into a separate transform so we need to expand\n\t\t\t\t\t// the embedded offsets and counts.\n\t\t\t\t\tlet rootsCount = 0;\n\t\t\t\t\tfor ( let o = 0; o < count; o ++ ) {\n\n\t\t\t\t\t\tconst roots = transformInfo[ tlasOffset ].data.bvh._roots.length;\n\t\t\t\t\t\ttlasOffset += roots;\n\t\t\t\t\t\trootsCount += roots;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetU16[ n16 + 14 ] = rootsCount;\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttargetU32[ n32 + 6 ] = rootBuffer32[ r32 + 6 ] + geometryOffset;\n\t\t\t\t\ttargetU16[ n16 + 14 ] = rootBuffer16[ r16 + 14 ];\n\t\t\t\t\ttargetU16[ n16 + 15 ] = IS_LEAFNODE_FLAG;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\ttargetU32[ n32 + 6 ] = rootBuffer32[ r32 + 6 ];\n\t\t\t\ttargetU32[ n32 + 7 ] = rootBuffer32[ r32 + 7 ];\n\n\t\t\t}\n\n\t\t\tnodeWriteOffset ++;\n\n\t\t}\n\n\t} );\n\n\treturn result;\n\n}\n\n/**\n * Writes the triangle index data for a BVH's geometry into the shared index buffer, rebasing the\n * indices into the packed attribute buffer.\n *\n * @private\n * @param {Object} bvh\n * @param {{start:number,count:number,vertexStart:number}} range\n * @param {number} valueOffset\n * @param {number} writeOffset\n * @param {Uint32Array} target\n */\nexport function appendIndexData( bvh, range, valueOffset, writeOffset, target ) {\n\n\tconst { geometry } = bvh;\n\tconst { start, count, vertexStart } = range;\n\tif ( bvh.indirect ) {\n\n\t\tconst dereferencedIndex = dereferenceIndex( geometry.index, bvh._indirectBuffer );\n\t\tfor ( let i = 0; i < dereferencedIndex.length; i ++ ) {\n\n\t\t\ttarget[ i + writeOffset ] = dereferencedIndex[ i ] - vertexStart + valueOffset;\n\n\t\t}\n\n\t} else if ( geometry.index ) {\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\ttarget[ i + writeOffset ] = geometry.index.getX( i + start ) - vertexStart + valueOffset;\n\n\t\t}\n\n\t} else {\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\ttarget[ i + writeOffset ] = i + start + valueOffset;\n\n\t\t}\n\n\t}\n\n}\n\n/**\n * Writes a BVH's interleaved per-vertex attributes into the shared attribute buffer, filling missing\n * attributes with their defaults and applying bone transforms for skinned meshes.\n *\n * @private\n * @param {Object} bvh\n * @param {{vertexStart:number,vertexCount:number}} range\n * @param {number} writeOffset\n * @param {ArrayBuffer} target\n * @param {StructTypeNode} attributeStruct\n * @param {BVHComputeData} bvhData - Provides per-attribute defaults via `getDefaultAttributeValue`.\n */\nexport function appendGeometryData( bvh, range, writeOffset, target, attributeStruct, bvhData ) {\n\n\t// if \"mesh\" is present then it is assumed to be a SkinnedMeshBVH\n\tconst { geometry, mesh = null } = bvh;\n\tconst { vertexStart, vertexCount } = range;\n\tconst attributesBufferF32 = new Float32Array( target );\n\tconst attrStructLength = attributeStruct.getLength();\n\tattributeStruct.membersLayout.forEach( ( { name }, interleavedOffset ) => {\n\n\t\t// TODO: we should be able to have access to memory layout offsets here via the struct\n\t\t// API but it's not currently available.\n\t\tconst attr = geometry.attributes[ name ];\n\t\tbvhData.getDefaultAttributeValue( name, _def );\n\n\t\tfor ( let i = 0; i < vertexCount; i ++ ) {\n\n\t\t\tif ( attr ) {\n\n\t\t\t\t_vec.fromBufferAttribute( attr, i + vertexStart );\n\n\t\t\t\tswitch ( attr.itemSize ) {\n\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\t_vec.y = _def.y;\n\t\t\t\t\t\t_vec.z = _def.z;\n\t\t\t\t\t\t_vec.w = _def.w;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\t_vec.z = _def.z;\n\t\t\t\t\t\t_vec.w = _def.w;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\t_vec.w = _def.w;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tif ( mesh && ( name === 'position' || name === 'normal' || name === 'tangent' ) ) {\n\n\t\t\t\t\tmesh.applyBoneTransform( i + vertexStart, _vec );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t_vec.copy( _def );\n\n\t\t\t}\n\n\t\t\t_vec.toArray( attributesBufferF32, ( writeOffset + i ) * attrStructLength + interleavedOffset * 4 );\n\n\t\t}\n\n\t} );\n\n}\n","import { CodeNode, FunctionNode, Node, TSL } from 'three/webgpu';\n\n// three r184 compat: TSL.nodeProxyConstructor only exists from three r185.\n// Recovered from the known-good Jul 21 SDK bundle (webgpu-V2WQRg97.mjs): fall\n// back to a Proxy that forwards to the wrapped node and exposes it via\n// `functionNode` so callable node functions keep working on r184.\nconst nodeProxyConstructor = TSL.nodeProxyConstructor ?? ( ( fn, target ) => new Proxy( fn, {\n\n\tget( obj, prop, receiver ) {\n\n\t\tconst value = Reflect.get( target, prop, receiver );\n\t\treturn value === undefined && prop === 'functionNode' ? target : value;\n\n\t},\n\tset( obj, prop, value ) {\n\n\t\treturn Reflect.set( target, prop, value );\n\n\t},\n\n} ) );\n\n\n// minimal node that outputs a raw WGSL expression verbatim when built\nclass LiteralExpression extends Node {\n\n\tconstructor( literal ) {\n\n\t\tsuper();\n\t\tthis.literal = literal;\n\n\t}\n\n\tbuild() {\n\n\t\treturn this.literal;\n\n\t}\n\n}\n\n// wraps a FunctionNode so that build() returns just the function name\nclass PropertyRefNode extends Node {\n\n\tconstructor( node, output = 'property' ) {\n\n\t\tsuper();\n\t\tthis.node = node;\n\t\tthis.output = output;\n\n\t}\n\n\tbuild( builder ) {\n\n\t\treturn this.node.build( builder, this.output );\n\n\t}\n\n}\n\n// returns the node that should be registered as an include for the given arg\n// three r184 compat (roomle patch, recovered from the known-good Jul 21\n// bundle): with the nodeProxyConstructor Proxy fallback, proxied callables are\n// plain functions carrying the wrapped node on `.functionNode` — unwrap them\n// before treating template args as nodes.\nfunction unwrapFunctionNode( arg ) {\n\n\treturn typeof arg === 'function' && arg.functionNode && ! arg.isNode ? arg.functionNode : arg;\n\n}\n\nfunction getIncludeNode( arg ) {\n\n\targ = unwrapFunctionNode( arg );\n\tif ( arg.isNode ) return new PropertyRefNode( arg );\n\treturn null;\n\n}\n\n// extract dependency nodes from template args for include registration\nfunction extractIncludes( args ) {\n\n\tconst includes = [];\n\tfor ( const arg of args ) {\n\n\t\tif ( Array.isArray( arg ) ) {\n\n\t\t\tfor ( const element of arg ) {\n\n\t\t\t\tconst node = getIncludeNode( element );\n\t\t\t\tif ( node ) includes.push( node );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn includes;\n\n}\n\n// normalize args so generate can resolve them uniformly with build():\n// - callable wrappers > PropertyRefNode (emits just the function name)\nfunction normalizeArgs( args ) {\n\n\treturn args.map( arg => {\n\n\t\targ = unwrapFunctionNode( arg );\n\t\tif ( arg && arg.isNode ) {\n\n\t\t\tif ( arg instanceof WGSLTagCodeNode ) {\n\n\t\t\t\t// use a custom flag for this node to inline the output\n\t\t\t\treturn new PropertyRefNode( arg, 'inline' );\n\n\t\t\t} else {\n\n\t\t\t\treturn new PropertyRefNode( arg );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn arg;\n\n\t} );\n\n}\n\n// interleave static tokens with resolved arg values\nfunction assembleTemplate( tokens, args, builder ) {\n\n\tlet code = '';\n\tfor ( let i = 0, l = tokens.length; i < l; i ++ ) {\n\n\t\tcode += tokens[ i ];\n\t\tif ( i < args.length ) {\n\n\t\t\tconst arg = unwrapFunctionNode( args[ i ] );\n\t\t\tif ( Array.isArray( arg ) ) {\n\n\t\t\t\t// include array — no text output\n\n\t\t\t} else if ( typeof arg === 'string' || typeof arg === 'number' ) {\n\n\t\t\t\tcode += String( arg );\n\n\t\t\t} else {\n\n\t\t\t\tcode += arg.build( builder );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn code;\n\n}\n\nexport class WGSLTagFnNode extends FunctionNode {\n\n\tstatic get type() {\n\n\t\treturn 'WGSLTagFnNode';\n\n\t}\n\n\tconstructor( tokens, args, lang = 'wgsl' ) {\n\n\t\tsuper( '', extractIncludes( args ), lang );\n\n\t\tthis.tokens = tokens;\n\t\tthis.args = args;\n\n\t}\n\n\t// assemble the signature from tokens and arg names then parse\n\tgetNodeFunction( builder ) {\n\n\t\tconst { tokens } = this;\n\t\tconst args = normalizeArgs( this.args );\n\n\t\tconst nodeData = builder.getDataFromNode( this );\n\t\tlet nodeFunction = nodeData.nodeFunction;\n\t\tif ( nodeFunction === undefined ) {\n\n\t\t\t// reconstruct the full code with known names for struct args\n\t\t\t// and dummy identifiers for everything else\n\t\t\tlet fullCode = '';\n\t\t\tfor ( let i = 0, l = tokens.length; i < l; i ++ ) {\n\n\t\t\t\tfullCode += tokens[ i ];\n\n\t\t\t\tif ( i < args.length ) {\n\n\t\t\t\t\tconst arg = args[ i ];\n\t\t\t\t\tif ( Array.isArray( arg ) ) {\n\n\t\t\t\t\t\t// include array — no text output\n\n\t\t\t\t\t} else if ( typeof arg === 'string' || typeof arg === 'number' ) {\n\n\t\t\t\t\t\t// literals\n\t\t\t\t\t\tfullCode += String( arg );\n\n\t\t\t\t\t} else if ( arg.isStructLayoutNode ) {\n\n\t\t\t\t\t\t// struct type node\n\t\t\t\t\t\tfullCode += arg.getNodeType( builder );\n\n\t\t\t\t\t} else if ( arg.isStruct ) {\n\n\t\t\t\t\t\t// struct\n\t\t\t\t\t\tfullCode += arg.layout.getNodeType( builder );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tfullCode += '_arg' + i;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// remove comments\n\t\t\tfullCode = fullCode.replace( /\\/\\/.+[\\n\\r]/g, '' );\n\n\t\t\t// parse it so we have the signature defined - we will define the body content after\n\t\t\tnodeFunction = builder.parser.parseFunction( fullCode );\n\t\t\tnodeData.nodeFunction = nodeFunction;\n\n\t\t}\n\n\t\treturn nodeFunction;\n\n\t}\n\n\t// get the code for the function\n\tgenerate( builder, output ) {\n\n\t\tconst result = super.generate( builder, output );\n\t\tconst fullCode = assembleTemplate( this.tokens, normalizeArgs( this.args ), builder );\n\n\t\tconst { type } = this.getNodeFunction( builder );\n\t\tconst nodeCode = builder.getCodeFromNode( this, type );\n\n\t\tnodeCode.code = fullCode.replace( /\\/\\/.+[\\n\\r]/g, '' ).replace( /->\\s*void/, '' ).trim();\n\t\treturn result;\n\n\t}\n\n}\n\nexport class WGSLTagCodeNode extends CodeNode {\n\n\tstatic get type() {\n\n\t\treturn 'WGSLTagCodeNode';\n\n\t}\n\n\tconstructor( tokens, args, lang = 'wgsl' ) {\n\n\t\tsuper( '', extractIncludes( args ), lang );\n\n\t\tthis.tokens = tokens;\n\t\tthis.args = args;\n\n\t}\n\n\tbuild( builder, output ) {\n\n\t\tif ( output === 'inline' ) {\n\n\t\t\treturn assembleTemplate( this.tokens, normalizeArgs( this.args ), builder );\n\n\t\t} else {\n\n\t\t\treturn super.build( builder, output );\n\n\t\t}\n\n\t}\n\n\tgenerate( builder ) {\n\n\t\tsuper.generate( builder );\n\n\t\tconst nodeCode = builder.getCodeFromNode( this, this.getNodeType( builder ) );\n\t\tnodeCode.code = assembleTemplate( this.tokens, normalizeArgs( this.args ), builder );\n\t\treturn nodeCode.code;\n\n\t}\n\n}\n\nconst getFn = functionNode => {\n\n\tconst fn = ( ...params ) => {\n\n\t\t// wrap string parameter values as raw WGSL expressions so they\n\t\t// output verbatim as identifiers like local variable names\n\t\tif ( params.length === 1 && params[ 0 ] && typeof params[ 0 ] === 'object' && ! params[ 0 ].isNode ) {\n\n\t\t\tconst obj = params[ 0 ];\n\t\t\tfor ( const key in obj ) {\n\n\t\t\t\tif ( typeof obj[ key ] === 'string' ) {\n\n\t\t\t\t\tobj[ key ] = new LiteralExpression( obj[ key ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn functionNode.call( ...params );\n\n\t};\n\n\treturn nodeProxyConstructor( fn, functionNode );\n\n};\n\n// template tag literal function version of \"wgslFn\" & \"wgsl\" to generate\n// functions & code snippets respectively\nexport const wgslTagFn = ( tokens, ...args ) => getFn( new WGSLTagFnNode( tokens, args ) );\nexport const wgslTagCode = ( tokens, ...args ) => new WGSLTagCodeNode( tokens, args );\n\n// glsl versions\nexport const glslTagFn = ( tokens, ...args ) => getFn( new WGSLTagFnNode( tokens, args, 'glsl' ) );\nexport const glslTagCode = ( tokens, ...args ) => new WGSLTagCodeNode( tokens, args, 'glsl' );\n","import { uint } from 'three/tsl';\n\nexport const BVH_STACK_DEPTH = uint( 60 );\n","/** @import { StructTypeNode } from 'three/webgpu' */\n/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { wgslTagCode, wgslTagFn } from '../nodes/WGSLTagFnNode.js';\nimport { BVH_STACK_DEPTH } from '../tsl/constants.js';\n\n/**\n * Builds a pair of WGSL shapecast functions (BLAS + TLAS traversal) for a custom shape\n * type. The returned TLAS function signature is:\n * `fn name( shape: ShapeStruct[, result: ptr<function, ResultStruct>] ) -> bool`\n *\n * @private\n * @param {BVHComputeData} bvhData - The compute data whose storage buffers are referenced.\n * @param {Object} options\n * @param {string} [options.name] - Function name. Defaults to a random identifier.\n * @param {StructTypeNode} options.shapeStruct - TSL struct or definition describing the query shape.\n * @param {StructTypeNode|null} [options.resultStruct] - TSL struct for the accumulated result, or null.\n * @param {Function|null} [options.boundsOrderFn] - function node controlling left/right child traversal order.\n * @param {Function} options.intersectsBoundsFn - function node testing the shape against a BVH node's bounds.\n * @param {Function} options.intersectRangeFn - function node testing the shape against a leaf triangle range.\n * @param {Function|null} [options.transformShapeFn] - function node that transforms the shape into object local space.\n * @param {Function|null} [options.transformResultFn] - function node that transforms a hit result back to world space.\n * @param {Function|null} [options.resetShapeFn] - function node called after each BLAS traversal to reset any per-object state set by `transformShapeFn`.\n * @returns {Function} TSL function node for the TLAS traversal.\n */\nexport function getShapecastFn( bvhData, options ) {\n\n\t// TODO: test with and verify use with TSL Fn - both passing them as arguments,\n\t// calling the function from a TSL Fn.\n\t// TODO: revisit the semantics and mental model of \"transformShapeFn\" and \"transformResultFn\".\n\t// Are they \"before\" and \"after\" hooks? Should they include words implying a direction of transform?\n\t// eg \"toLocal\" / \"toWorld\"?\n\tconst {\n\t\tname = `bvh_shapecast_fn_${ Math.random().toString( 36 ).substring( 2, 7 ) }`,\n\t\tshapeStruct,\n\t\tresultStruct = null,\n\n\t\tboundsOrderFn = null,\n\t\tintersectsBoundsFn,\n\t\tintersectRangeFn,\n\t\ttransformShapeFn = null,\n\t\ttransformResultFn = null,\n\t\tresetShapeFn = null,\n\t} = options;\n\n\t// these are proxy nodes, so they can be referenced before the storage buffers exist\n\tconst { nodes, transforms } = bvhData.storage;\n\n\t// handle optional functions\n\tlet transformResultSnippet = '';\n\tif ( transformResultFn ) {\n\n\t\ttransformResultSnippet = wgslTagCode/* wgsl */`${ transformResultFn }( result, i );`;\n\n\t}\n\n\tlet transformShapeSnippet = '';\n\tif ( transformShapeFn ) {\n\n\t\ttransformShapeSnippet = wgslTagCode/* wgsl */`${ transformShapeFn }( &localShape, i );`;\n\n\t}\n\n\tlet resetShapeSnippet = '';\n\tif ( resetShapeFn ) {\n\n\t\tresetShapeSnippet = wgslTagCode/* wgsl */`${ resetShapeFn }( i );`;\n\n\t}\n\n\tlet leftToRightSnippet = '';\n\tif ( boundsOrderFn ) {\n\n\t\tleftToRightSnippet = wgslTagCode/* wgsl */`\n\t\t\tlet leftToRight = ${ boundsOrderFn }( shape, splitAxis, node );\n\t\t\tc1 = select( rightIndex, leftIndex, leftToRight );\n\t\t\tc2 = select( leftIndex, rightIndex, leftToRight );\n\t\t`;\n\n\t}\n\n\tconst resultPtrSnippet = resultStruct ? wgslTagCode/* wgsl */`result: ptr<function, ${ resultStruct }>` : '';\n\tconst resultArg = resultStruct ? 'result' : '';\n\n\tconst getFnBody = leafSnippet => {\n\n\t\t// returns a function with a snippet inserted for the leaf intersection test\n\t\treturn wgslTagCode/* wgsl */`\n\n\t\t\tvar pointer: i32 = 0;\n\t\t\tvar stack: array<u32, ${ BVH_STACK_DEPTH }>;\n\t\t\tstack[ 0 ] = rootNodeIndex;\n\n\t\t\tloop {\n\n\t\t\t\tif ( pointer < 0 || pointer >= i32( ${ BVH_STACK_DEPTH } ) ) {\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tlet nodeIndex = stack[ pointer ];\n\t\t\t\tlet node = ${ nodes }[ nodeIndex ];\n\t\t\t\tpointer = pointer - 1;\n\n\t\t\t\tif ( ${ intersectsBoundsFn }( shape, node.bounds, ${ resultArg } ) == 0u ) {\n\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tlet infoX = node.splitAxisOrTriangleCount;\n\t\t\t\tlet infoY = node.rightChildOrTriangleOffset;\n\t\t\t\tlet isLeaf = ( infoX & 0xffff0000u ) != 0u;\n\n\t\t\t\tif ( isLeaf ) {\n\n\t\t\t\t\tlet count = infoX & 0x0000ffffu;\n\t\t\t\t\tlet offset = infoY;\n\t\t\t\t\t${ leafSnippet }\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet leftIndex = nodeIndex + 1u;\n\t\t\t\t\tlet splitAxis = infoX & 0x0000ffffu;\n\t\t\t\t\tlet rightIndex = nodeIndex + infoY;\n\n\t\t\t\t\tvar c1 = rightIndex;\n\t\t\t\t\tvar c2 = leftIndex;\n\t\t\t\t\t${ leftToRightSnippet }\n\n\t\t\t\t\tpointer = pointer + 1;\n\t\t\t\t\tstack[ pointer ] = c2;\n\n\t\t\t\t\tpointer = pointer + 1;\n\t\t\t\t\tstack[ pointer ] = c1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t`;\n\n\t};\n\n\tconst blasFn = wgslTagFn/* wgsl */`\n\t\t// fn\n\t\tfn ${ name }_blas( shape: ${ shapeStruct }, rootNodeIndex: u32, ${ resultPtrSnippet } ) -> bool {\n\n\t\t\tvar didHit = false;\n\t\t\t${ getFnBody( wgslTagCode/* wgsl */`\n\n\t\t\t\tdidHit = ${ intersectRangeFn }( shape, offset, count, ${ resultArg } ) || didHit;\n\n\t\t\t` ) }\n\n\t\t\treturn didHit;\n\n\t\t}\n\t`;\n\n\tconst tlasFn = wgslTagFn/* wgsl */`\n\t\t// fn\n\t\tfn ${ name }( shape: ${ shapeStruct }, ${ resultPtrSnippet } ) -> bool {\n\n\t\t\tconst rootNodeIndex = 0u;\n\t\t\tvar didHit = false;\n\t\t\t${ getFnBody( wgslTagCode/* wgsl */`\n\n\t\t\t\tfor ( var i = offset; i < offset + count; i ++ ) {\n\n\t\t\t\t\tlet transform = ${ transforms }[ i ];\n\t\t\t\t\tif ( transform.visible == 0u ) {\n\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Transform shape into object local space\n\t\t\t\t\tvar localShape = shape;\n\t\t\t\t\t${ transformShapeSnippet }\n\n\t\t\t\t\tif ( ${ blasFn }( localShape, transform.nodeOffset, ${ resultArg } ) ) {\n\n\t\t\t\t\t\t${ transformResultSnippet }\n\t\t\t\t\t\tdidHit = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t${ resetShapeSnippet }\n\n\t\t\t\t}\n\n\t\t\t` ) }\n\n\t\t\treturn didHit;\n\n\t\t}\n\t`;\n\n\ttlasFn.outputType = resultStruct;\n\ttlasFn.functionName = name;\n\n\treturn tlasFn;\n\n}\n","/** @import { FunctionNode } from 'three/tsl'; */\nimport { wgslTagFn } from '../nodes/WGSLTagFnNode.js';\nimport { rayIntersectionResultStruct, rayStruct } from './structs.js';\n\n/**\n * WGSL function node that finds the closest point on a triangle to `p` and returns the barycoord.\n * @type {FunctionNode}\n * @section TSL Functions\n */\nexport const closestPointToTriangle = wgslTagFn/* wgsl */`\n\t// fn\n\tfn closestPointToTriangle(\n\t\tp: vec3f,\n\t\tv0: vec3f,\n\t\tv1: vec3f,\n\t\tv2: vec3f\n\t) -> vec3f {\n\n\t\tlet v10 = v1 - v0;\n\t\tlet v21 = v2 - v1;\n\t\tlet v02 = v0 - v2;\n\t\tlet p0 = p - v0;\n\t\tlet p1 = p - v1;\n\t\tlet p2 = p - v2;\n\n\t\tlet nor = cross( v10, v02 );\n\t\tlet q = cross( nor, p0 );\n\t\tlet d = 1.0 / dot( nor, nor );\n\t\tvar u = d * dot( q, v02 );\n\t\tvar v = d * dot( q, v10 );\n\t\tvar w = 1.0 - u - v;\n\n\t\tif ( u < 0.0 ) {\n\n\t\t\tw = clamp( dot( p2, v02 ) / dot( v02, v02 ), 0.0, 1.0 );\n\t\t\tu = 0.0;\n\t\t\tv = 1.0 - w;\n\n\t\t} else if ( v < 0.0 ) {\n\n\t\t\tu = clamp( dot( p0, v10 ) / dot( v10, v10 ), 0.0, 1.0 );\n\t\t\tv = 0.0;\n\t\t\tw = 1.0 - u;\n\n\t\t} else if ( w < 0.0 ) {\n\n\t\t\tv = clamp( dot( p1, v21 ) / dot( v21, v21 ), 0.0, 1.0 );\n\t\t\tw = 0.0;\n\t\t\tu = 1.0 - v;\n\n\t\t}\n\n\t\treturn vec3f( w, u, v );\n\n\t}\n`;\n\n/**\n * WGSL function node that tests a ray against a single triangle and returns an\n * {@link rayIntersectionResultStruct} result. Useful when writing a custom `intersectRangeFn`\n * for {@link BVHComputeData#getShapecastFn}.\n * @type {FunctionNode}\n * @section TSL Functions\n */\nexport const intersectRayTriangle = wgslTagFn/* wgsl */ `\n\t// fn\n\tfn intersectRayTriangle( ray: ${ rayStruct }, a: vec3f, b: vec3f, c: vec3f, threshold: f32 ) -> ${ rayIntersectionResultStruct } {\n\n\t\tconst DET_EPSILON = 1e-15;\n\n\t\tvar result: ${ rayIntersectionResultStruct };\n\t\tresult.didHit = false;\n\n\t\tlet edge1 = b - a;\n\t\tlet edge2 = c - a;\n\t\tlet n = cross( edge1, edge2 );\n\n\t\tlet det = - dot( ray.direction, n );\n\t\tif ( abs( det ) < DET_EPSILON ) {\n\n\t\t\treturn result;\n\n\t\t}\n\n\t\tlet invdet = 1.0 / det;\n\n\t\tlet AO = ray.origin - a;\n\t\tlet DAO = cross( AO, ray.direction );\n\n\t\tlet u = dot( edge2, DAO ) * invdet;\n\t\tif ( u < 0.0 || u > 1.0 ) {\n\n\t\t\treturn result;\n\n\t\t}\n\n\t\tlet v = - dot( edge1, DAO ) * invdet;\n\t\tif ( v < 0.0 || u + v > 1.0 ) {\n\n\t\t\treturn result;\n\n\t\t}\n\n\t\tlet t = dot( AO, n ) * invdet;\n\t\tlet w = 1.0 - u - v;\n\t\tif ( t < threshold ) {\n\n\t\t\treturn result;\n\n\t\t}\n\n\t\tresult.didHit = true;\n\t\tresult.barycoord = vec3f( w, u, v );\n\t\tresult.dist = t;\n\t\tresult.side = sign( det );\n\t\tresult.normal = result.side * normalize( n );\n\n\t\treturn result;\n\n\t}\n`;\n\n/**\n * WGSL function node that builds a camera ray (origin + far-plane direction) from an NDC\n * coordinate and an inverse model-view-projection matrix. Works for both perspective and\n * orthographic projections. The returned direction is not normalized and extends to the\n * camera far plane.\n * @type {FunctionNode}\n * @section TSL Functions\n */\nexport const ndcToCameraRay = wgslTagFn/* wgsl */`\n\t// fn\n\tfn ndcToCameraRay( ndc: vec2f, inverseModelViewProjection: mat4x4f ) -> ${ rayStruct } {\n\n\t\tvar homogeneous = vec4f();\n\t\tvar ray: ${ rayStruct };\n\n\t\thomogeneous = inverseModelViewProjection * vec4f( ndc, 0.0, 1.0 );\n\t\tray.origin = homogeneous.xyz / homogeneous.w;\n\n\t\thomogeneous = inverseModelViewProjection * vec4f( ndc, 1.0, 1.0 );\n\t\tray.direction = ( homogeneous.xyz / homogeneous.w ) - ray.origin;\n\n\t\treturn ray;\n\n\t}\n`;\n","/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { float } from 'three/tsl';\nimport { wgslTagFn } from '../nodes/WGSLTagFnNode.js';\nimport { rayStruct, rayIntersectionResultStruct, bvhNodeStruct, bvhNodeBoundsStruct } from '../tsl/structs.js';\nimport { intersectRayTriangle } from '../tsl/fns.js';\n\n/**\n * Builds the `raycastFirstHit` shapecast function: traverses the BVH front to back and returns the\n * closest ray / triangle intersection.\n *\n * @private\n * @param {BVHComputeData} bvhData\n * @returns {Function} TSL function node for the TLAS traversal.\n */\nexport function getRaycastFirstHitFn( bvhData ) {\n\n\t// these are proxy nodes, so they can be referenced before the storage buffers exist\n\tconst { index, attributes, transforms } = bvhData.storage;\n\n\tconst scratchRayScalar = float( 1.0 ).toVar( `bvh_rayScalar_${ Math.random().toString( 36 ).substring( 2, 7 ) }` );\n\n\treturn bvhData.getShapecastFn( {\n\t\tname: 'bvh_RaycastFirstHit',\n\t\tshapeStruct: rayStruct,\n\t\tresultStruct: rayIntersectionResultStruct,\n\n\t\tboundsOrderFn: wgslTagFn/* wgsl */`\n\t\t\tfn getBoundsOrder( ray: ${ rayStruct }, splitAxis: u32, node: ${ bvhNodeStruct } ) -> bool {\n\n\t\t\t\treturn ray.direction[ splitAxis ] >= 0.0;\n\n\t\t\t}\n\t\t`,\n\t\tintersectsBoundsFn: wgslTagFn/* wgsl */`\n\t\t\tfn rayIntersectsBounds( ray: ${ rayStruct }, bounds: ${ bvhNodeBoundsStruct }, result: ptr<function, ${ rayIntersectionResultStruct }> ) -> u32 {\n\n\t\t\t\tlet boundsMin = vec3( bounds.min[0], bounds.min[1], bounds.min[2] );\n\t\t\t\tlet boundsMax = vec3( bounds.max[0], bounds.max[1], bounds.max[2] );\n\n\t\t\t\tlet invDir = 1.0 / ray.direction;\n\t\t\t\tlet tMinPlane = ( boundsMin - ray.origin ) * invDir;\n\t\t\t\tlet tMaxPlane = ( boundsMax - ray.origin ) * invDir;\n\n\t\t\t\tlet tMinHit = vec3f(\n\t\t\t\t\tmin( tMinPlane.x, tMaxPlane.x ),\n\t\t\t\t\tmin( tMinPlane.y, tMaxPlane.y ),\n\t\t\t\t\tmin( tMinPlane.z, tMaxPlane.z )\n\t\t\t\t);\n\n\t\t\t\tlet tMaxHit = vec3f(\n\t\t\t\t\tmax( tMinPlane.x, tMaxPlane.x ),\n\t\t\t\t\tmax( tMinPlane.y, tMaxPlane.y ),\n\t\t\t\t\tmax( tMinPlane.z, tMaxPlane.z )\n\t\t\t\t);\n\n\t\t\t\tlet t0 = max( max( tMinHit.x, tMinHit.y ), tMinHit.z );\n\t\t\t\tlet t1 = min( min( tMaxHit.x, tMaxHit.y ), tMaxHit.z );\n\n\t\t\t\tlet dist = max( t0, 0.0 );\n\t\t\t\tif ( t1 < dist ) {\n\n\t\t\t\t\treturn 0u;\n\n\t\t\t\t} else if ( result.didHit && dist * ${ scratchRayScalar } >= result.dist ) {\n\n\t\t\t\t\treturn 0u;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn 1u;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t`,\n\t\tintersectRangeFn: wgslTagFn/* wgsl */`\n\t\t\tfn intersectRange( ray: ${ rayStruct }, offset: u32, count: u32, result: ptr<function, ${ rayIntersectionResultStruct }> ) -> bool {\n\n\t\t\t\tvar didHit = false;\n\t\t\t\tfor ( var ti = offset; ti < offset + count; ti = ti + 1u ) {\n\n\t\t\t\t\tlet i0 = ${ index }[ ti * 3u ];\n\t\t\t\t\tlet i1 = ${ index }[ ti * 3u + 1u ];\n\t\t\t\t\tlet i2 = ${ index }[ ti * 3u + 2u ];\n\n\t\t\t\t\tlet a = ${ attributes }[ i0 ].position.xyz;\n\t\t\t\t\tlet b = ${ attributes }[ i1 ].position.xyz;\n\t\t\t\t\tlet c = ${ attributes }[ i2 ].position.xyz;\n\n\t\t\t\t\tvar triResult = ${ intersectRayTriangle }( ray, a, b, c, 0.0 );\n\t\t\t\t\ttriResult.dist *= ${ scratchRayScalar };\n\t\t\t\t\tif ( triResult.didHit && ( ! result.didHit || triResult.dist < result.dist ) ) {\n\n\t\t\t\t\t\tresult.didHit = true;\n\t\t\t\t\t\tresult.dist = triResult.dist;\n\t\t\t\t\t\tresult.normal = triResult.normal;\n\t\t\t\t\t\tresult.side = triResult.side;\n\t\t\t\t\t\tresult.barycoord = triResult.barycoord;\n\t\t\t\t\t\tresult.indices = vec4u( i0, i1, i2, ti );\n\n\t\t\t\t\t\tdidHit = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn didHit;\n\n\t\t\t}\n\t\t`,\n\t\ttransformShapeFn: wgslTagFn/* wgsl */`\n\t\t\tfn transformRay( ray: ptr<function, ${ rayStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\tlet toLocal = ${ transforms }[ objectIndex ].inverseMatrixWorld;\n\t\t\t\tray.origin = ( toLocal * vec4f( ray.origin, 1.0 ) ).xyz;\n\t\t\t\tray.direction = ( toLocal * vec4f( ray.direction, 0.0 ) ).xyz;\n\n\t\t\t\tlet len = length( ray.direction );\n\t\t\t\tray.direction /= len;\n\t\t\t\t${ scratchRayScalar } = 1.0 / len;\n\n\t\t\t}\n\t\t`,\n\t\ttransformResultFn: wgslTagFn/* wgsl */`\n\t\t\tfn transformResult( hit: ptr<function, ${ rayIntersectionResultStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\tlet toLocal = ${ transforms }[ objectIndex ].inverseMatrixWorld;\n\t\t\t\thit.normal = normalize( ( transpose( toLocal ) * vec4f( hit.normal, 0.0 ) ).xyz );\n\t\t\t\thit.objectIndex = objectIndex;\n\n\t\t\t}\n\t\t`,\n\t\tresetShapeFn: wgslTagFn/* wgsl */`\n\t\t\tfn resetRayScalar( objectIndex: u32 ) -> void {\n\n\t\t\t\t${ scratchRayScalar } = 1.0;\n\n\t\t\t}\n\t\t`,\n\t} );\n\n}\n","/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { wgslTagFn } from '../nodes/WGSLTagFnNode.js';\n\n/**\n * Builds the `sampleTrianglePoint` function: interpolates the per-vertex attributes of a triangle\n * at the given barycentric coordinate. The body emits one line per attribute, so this must be built\n * after `update` has resolved the attribute struct.\n *\n * @private\n * @param {BVHComputeData} bvhData\n * @returns {Function} TSL function node.\n */\nexport function getSampleTrianglePointFn( bvhData ) {\n\n\tconst { storage, structs } = bvhData;\n\n\tconst interpolateBody = structs\n\t\t.attributes\n\t\t.membersLayout\n\t\t.map( ( { name } ) => {\n\n\t\t\treturn `result.${ name } = a0.${ name } * barycoord.x + a1.${ name } * barycoord.y + a2.${ name } * barycoord.z;`;\n\n\t\t} ).join( '\\n' );\n\n\treturn wgslTagFn/* wgsl */`\n\t\t// fn\n\t\tfn bvh_sampleTrianglePoint( barycoord: vec3f, indices: vec3u ) -> ${ structs.attributes } {\n\n\t\t\tvar result: ${ structs.attributes };\n\t\t\tvar a0 = ${ storage.attributes }[ indices.x ];\n\t\t\tvar a1 = ${ storage.attributes }[ indices.y ];\n\t\t\tvar a2 = ${ storage.attributes }[ indices.z ];\n\t\t\t${ interpolateBody }\n\t\t\treturn result;\n\n\t\t}\n\t`;\n\n}\n","/** @import { BVHComputeData } from '../BVHComputeData.js' */\nimport { mat4 } from 'three/tsl';\nimport { wgslTagFn } from '../nodes/WGSLTagFnNode.js';\nimport { bvhNodeStruct, bvhNodeBoundsStruct, pointQueryResultStruct } from '../tsl/structs.js';\nimport { closestPointToTriangle } from '../tsl/fns.js';\n\n/**\n * Builds the `closestPointToPoint` shapecast function: finds the closest point on any triangle in\n * the BVH to the given query point.\n *\n * @private\n * @param {BVHComputeData} bvhData\n * @returns {Function} TSL function node for the TLAS traversal.\n */\nexport function getClosestPointToPointFn( bvhData ) {\n\n\t// these are proxy nodes, so they can be referenced before the storage buffers exist\n\tconst { index, attributes, transforms } = bvhData.storage;\n\n\tconst scratchToWorldMat = mat4().toVar( 'bvh_toWorldMat' );\n\n\treturn bvhData.getShapecastFn( {\n\t\tname: 'bvh_ClosestPointToPoint',\n\t\tshapeStruct: 'vec3f',\n\t\tresultStruct: pointQueryResultStruct,\n\n\t\tboundsOrderFn: wgslTagFn/* wgsl */`\n\t\t\tfn cppBoundsOrder( shape: vec3f, splitAxis: u32, node: ${ bvhNodeStruct } ) -> bool {\n\n\t\t\t\tlet toWorld = ${ scratchToWorldMat };\n\n\t\t\t\t// get center\n\t\t\t\tlet bMin = vec3f( node.bounds.min[ 0 ], node.bounds.min[ 1 ], node.bounds.min[ 2 ] );\n\t\t\t\tlet bMax = vec3f( node.bounds.max[ 0 ], node.bounds.max[ 1 ], node.bounds.max[ 2 ] );\n\t\t\t\tlet center = bMin * 0.5 + bMax * 0.5;\n\n\t\t\t\t// determine the order in world space\n\t\t\t\tlet worldCenter = ( toWorld * vec4f( center, 1.0 ) ).xyz;\n\t\t\t\tlet worldAxis = normalize( toWorld[ splitAxis ].xyz );\n\t\t\t\treturn dot( shape - worldCenter, worldAxis ) <= 0.0;\n\n\t\t\t}\n\t\t`,\n\n\t\tintersectsBoundsFn: wgslTagFn/* wgsl */`\n\t\t\tfn cppIntersectsBounds( shape: vec3f, bounds: ${ bvhNodeBoundsStruct }, result: ptr<function, ${ pointQueryResultStruct }> ) -> u32 {\n\n\t\t\t\t// return 1u;\n\t\t\t\t// we need to check this no matter what if the result has not been found yet\n\t\t\t\tif ( ! result.found ) {\n\n\t\t\t\t\treturn 1u;\n\n\t\t\t\t}\n\n\t\t\t\tlet toWorld = ${ scratchToWorldMat };\n\n\t\t\t\t// transform to world space\n\t\t\t\tlet bMin = vec3f( bounds.min[ 0 ], bounds.min[ 1 ], bounds.min[ 2 ] );\n\t\t\t\tlet bMax = vec3f( bounds.max[ 0 ], bounds.max[ 1 ], bounds.max[ 2 ] );\n\t\t\t\tlet center = ( bMin + bMax ) * 0.5;\n\t\t\t\tlet halfExtent = ( bMax - bMin ) * 0.5;\n\t\t\t\tlet worldCenter = ( toWorld * vec4f( center, 1.0 ) ).xyz;\n\t\t\t\tlet worldHalfExtent =\n\t\t\t\t\tabs( toWorld[ 0 ].xyz ) * halfExtent.x +\n\t\t\t\t abs( toWorld[ 1 ].xyz ) * halfExtent.y +\n\t\t\t\t abs( toWorld[ 2 ].xyz ) * halfExtent.z;\n\t\t\t\tlet worldMin = worldCenter - worldHalfExtent;\n\t\t\t\tlet worldMax = worldCenter + worldHalfExtent;\n\n\t\t\t\t// intersect if the distance to the bounds is not bigger than the already found\n\t\t\t\tlet d = shape - clamp( shape, worldMin, worldMax );\n\t\t\t\treturn select( 0u, 1u, dot( d, d ) < result.distanceSq );\n\n\t\t\t}\n\t\t`,\n\n\t\tintersectRangeFn: wgslTagFn /* wgsl */`\n\t\t\tfn cppIntersectsRange( shape: vec3f, offset: u32, count: u32, result: ptr<function, ${ pointQueryResultStruct }> ) -> bool {\n\n\t\t\t\tvar didHit = false;\n\t\t\t\tlet toWorld = ${ scratchToWorldMat };\n\n\t\t\t\tfor ( var i = offset; i < offset + count; i ++ ) {\n\n\t\t\t\t\t// transform the triangle to world space\n\t\t\t\t\tlet i0 = ${ index }[ i * 3u + 0u ];\n\t\t\t\t\tlet i1 = ${ index }[ i * 3u + 1u ];\n\t\t\t\t\tlet i2 = ${ index }[ i * 3u + 2u ];\n\t\t\t\t\tlet a = ( toWorld * vec4f( ${ attributes }[ i0 ].position.xyz, 1.0 ) ).xyz;\n\t\t\t\t\tlet b = ( toWorld * vec4f( ${ attributes }[ i1 ].position.xyz, 1.0 ) ).xyz;\n\t\t\t\t\tlet c = ( toWorld * vec4f( ${ attributes }[ i2 ].position.xyz, 1.0 ) ).xyz;\n\n\t\t\t\t\tlet barycoord = ${ closestPointToTriangle }( shape, a, b, c );\n\t\t\t\t\tlet closestPoint = barycoord.x * a + barycoord.y * b + barycoord.z * c;\n\t\t\t\t\tlet delta = shape - closestPoint;\n\t\t\t\t\tlet distSq = dot( delta, delta );\n\n\t\t\t\t\t// copy the content over\n\t\t\t\t\tif ( ! result.found || distSq < result.distanceSq ) {\n\n\t\t\t\t\t\tlet normal = normalize( cross( a - b, b - c ) );\n\n\t\t\t\t\t\tresult.closestPoint = closestPoint;\n\t\t\t\t\t\tresult.barycoord = barycoord;\n\t\t\t\t\t\tresult.distanceSq = distSq;\n\t\t\t\t\t\tresult.faceNormal = normal;\n\t\t\t\t\t\tresult.side = sign( dot( normal, delta ) );\n\t\t\t\t\t\tresult.faceIndices = vec4u( i0, i1, i2, i );\n\t\t\t\t\t\tresult.found = true;\n\t\t\t\t\t\tdidHit = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn didHit;\n\n\t\t\t}\n\t\t`,\n\n\t\ttransformShapeFn: wgslTagFn/* wgsl */`\n\t\t\tfn cppTransformShape( shape: ptr<function, vec3f>, objectIndex: u32 ) -> void {\n\n\t\t\t\t${ scratchToWorldMat } = ${ transforms }[ objectIndex ].matrixWorld;\n\n\t\t\t}\n\t\t`,\n\n\t\ttransformResultFn: wgslTagFn/* wgsl */`\n\t\t\tfn cppTransformResult( result: ptr<function, ${ pointQueryResultStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\tresult.objectIndex = objectIndex;\n\n\t\t\t}\n\t\t`,\n\t} );\n\n}\n","/** @import { Object3D, BufferGeometry, Vector4 } from 'three' */\nimport { Matrix4 } from 'three';\nimport { StorageBufferAttribute, StructTypeNode } from 'three/webgpu';\nimport { storage } from 'three/tsl';\nimport { MeshBVH } from 'three-mesh-bvh/src/core/MeshBVH.js';\nimport { SkinnedMeshBVH } from 'three-mesh-bvh/src/core/SkinnedMeshBVH.js';\nimport { GeometryBVH } from 'three-mesh-bvh/src/core/GeometryBVH.js';\nimport { ObjectBVH } from 'three-mesh-bvh/src/core/ObjectBVH.js';\nimport { BYTES_PER_NODE } from 'three-mesh-bvh/src/core/Constants.js';\nimport { proxy, proxyFn } from './nodes/NodeProxy.js';\nimport {\n\tbvhNodeStruct,\n\ttransformStruct,\n} from './tsl/structs.js';\nimport { toObjectBVH } from './utils/toObjectBVH.js';\nimport { appendBVHData, appendIndexData, appendGeometryData } from './utils/packBVHBufferUtils.js';\nimport { getShapecastFn } from './shapecastFns/getShapecastFn.js';\nimport { getRaycastFirstHitFn } from './shapecastFns/getRaycastFirstHitFn.js';\nimport { getSampleTrianglePointFn } from './shapecastFns/getSampleTrianglePointFn.js';\nimport { getClosestPointToPointFn } from './shapecastFns/getClosestPointToPointFn.js';\n\n// TODO: add ability to easily update a single matrix / scene rearrangement (partial update)\n// TODO: add material support w/ function to easily update material\n// \t\t- add a callback for writing a property for a geometry to a range\n// TODO: Add support for other geometry types (tris, lines, custom BVHs etc)\n\n// scratch\nconst _matrix = /* @__PURE__ */ new Matrix4();\nconst _inverseMatrix = /* @__PURE__ */ new Matrix4();\n\n// functions\nfunction isObjectVisible( object ) {\n\n\tlet curr = object;\n\twhile ( curr ) {\n\n\t\tif ( curr.visible === false ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tcurr = curr.parent;\n\n\t}\n\n\treturn true;\n\n}\n\nfunction getTotalBVHByteLength( bvh ) {\n\n\treturn bvh._roots.reduce( ( v, root ) => v + root.byteLength, 0 );\n\n}\n\n/**\n * Packs one or more scene objects into GPU-accessible BVH buffers (TLAS + BLAS) for use\n * in WebGPU compute shaders via the Three.js TSL node system. After construction, call\n * {@link BVHComputeData#update} to populate the storage buffers, then reference\n * `this.storage` and `this.fns` in your compute shader nodes.\n *\n * @note This API is unstable and subject to change in future releases.\n *\n * @note This class requires three.js r185 or higher.\n */\nexport class BVHComputeData {\n\n\t/**\n\t * @param {ObjectBVH|Object3D|BufferGeometry|GeometryBVH|Array} bvh\n\t * Scene objects to include, or a pre-built {@link ObjectBVH}. A single item or array of\n\t * Object3D, BufferGeometry, or GeometryBVH instances are all accepted and wrapped\n\t * automatically in an ObjectBVH.\n\t * @param {Object} [options]\n\t * @param {Record<string,string>} [options.attributes={ position: 'vec4f' }]\n\t * WGSL type map for the interleaved per-vertex attribute buffer. Keys are geometry\n\t * attribute names; values are WGSL type strings (e.g. `'vec3f'`, `'vec4f'`).\n\t * @param {boolean} [options.autogenerateBvh=true]\n\t * When true, a {@link MeshBVH} is automatically built for any object that does not\n\t * already have `geometry.boundsTree` set.\n\t */\n\tconstructor( bvh, options = {} ) {\n\n\t\t// convert the bvh argument to an ObjectBVH. Supports an Object3D, BufferGeometry,\n\t\t// GeometryBVH, an array of the above, or a pre-built ObjectBVH.\n\t\tbvh = toObjectBVH( bvh );\n\n\t\tconst {\n\t\t\tattributes = { position: 'vec4f' },\n\t\t\tautogenerateBvh = true,\n\t\t} = options;\n\n\t\tthis._bvhCache = new Map();\n\n\t\tthis.autogenerateBvh = autogenerateBvh;\n\t\tthis.attributes = attributes;\n\t\tthis.bvh = bvh;\n\n\t\t// storage buffers and structs are populated in \"update\"; their members are accessed through\n\t\t// proxy nodes so the functions below can reference them up front and keep working across rebuilds\n\t\tthis.storage = new NodeProxyObject();\n\t\tthis.structs = new NodeProxyObject( { transform: transformStruct } );\n\t\tthis.fns = new NodeProxyObject( {\n\t\t\traycastFirstHit: getRaycastFirstHitFn( this ),\n\t\t\tclosestPointToPoint: getClosestPointToPointFn( this ),\n\t\t\tsampleTrianglePoint: null,\n\t\t}, proxyFn );\n\n\t}\n\n\t/**\n\t * Builds a pair of WGSL shapecast functions (BLAS + TLAS traversal) for a custom shape\n\t * type. The returned TLAS function signature is:\n\t * `fn name( shape: ShapeStruct[, result: ptr<function, ResultStruct>] ) -> bool`\n\t *\n\t * @param {Object} options\n\t * @param {string} [options.name] - Function name. Defaults to a random identifier.\n\t * @param {StructTypeNode} options.shapeStruct - TSL struct or definition describing the query shape.\n\t * @param {StructTypeNode|null} [options.resultStruct] - TSL struct for the accumulated result, or null.\n\t * @param {Function|null} [options.boundsOrderFn] - function node controlling left/right child traversal order.\n\t * @param {Function} options.intersectsBoundsFn - function node testing the shape against a BVH node's bounds.\n\t * @param {Function} options.intersectRangeFn - function node testing the shape against a leaf triangle range.\n\t * @param {Function|null} [options.transformShapeFn] - function node that transforms the shape into object local space.\n\t * @param {Function|null} [options.transformResultFn] - function node that transforms a hit result back to world space.\n\t * @param {Function|null} [options.resetShapeFn] - function node called after each BLAS traversal to reset any per-object state set by `transformShapeFn`.\n\t * @returns {Function} TSL function node for the TLAS traversal.\n\t */\n\tgetShapecastFn( options ) {\n\n\t\treturn getShapecastFn( this, options );\n\n\t}\n\n\t/**\n\t * Rebuilds all GPU storage buffers from the current scene state. Must be called at least\n\t * once before using `this.storage` or `this.fns` in a shader, and again whenever the\n\t * scene topology changes (objects added/removed, geometry modified).\n\t */\n\tupdate() {\n\n\t\t// free any buffers from a previous update before swapping in the new ones\n\t\tthis.dispose();\n\n\t\tconst { attributes, structs, bvh } = this;\n\n\t\t// collect the BVHs\n\t\tconst bvhInfo = [];\n\t\tconst transformInfo = [];\n\n\t\t// accumulate the sizes of the bvh nodes buffer, number of objects, and geometry buffers\n\t\tlet bvhNodesBufferLength = getTotalBVHByteLength( bvh );\n\t\tlet indexBufferLength = 0;\n\t\tlet attributesBufferLength = 0;\n\t\tbvh.primitiveBuffer.forEach( compositeId => {\n\n\t\t\tconst object = bvh.getObjectFromId( compositeId );\n\t\t\tconst instanceId = bvh.getInstanceFromId( compositeId );\n\t\t\tconst range = { start: 0, count: 0, vertexStart: 0, vertexCount: 0 };\n\t\t\tconst primBvh = this.getBVH( object, instanceId, range );\n\n\t\t\tif ( ! primBvh ) {\n\n\t\t\t\tthrow new Error( 'BVHComputeData: BVH not found.' );\n\n\t\t\t}\n\n\t\t\t// if we haven't added this bvh, yet\n\t\t\tif ( ! bvhInfo.find( info => info.bvh === primBvh ) ) {\n\n\t\t\t\t// save the geometry info to write later and increment the buffer sizes\n\t\t\t\tconst info = {\n\t\t\t\t\tindex: bvhInfo.length,\n\t\t\t\t\tbvh: primBvh,\n\t\t\t\t\trange: range,\n\n\t\t\t\t\tbvhNodeOffsets: null,\n\t\t\t\t\tindexBufferOffset: null,\n\n\t\t\t\t};\n\n\t\t\t\t// increase the buffer sizes for bvh and geometry\n\t\t\t\tbvhNodesBufferLength += getTotalBVHByteLength( primBvh );\n\t\t\t\tindexBufferLength += info.range.count;\n\t\t\t\tattributesBufferLength += info.range.vertexCount;\n\t\t\t\tbvhInfo.push( info );\n\n\t\t\t}\n\n\t\t\t// save the index of the bvh associated with this transform\n\t\t\tconst data = bvhInfo.find( info => primBvh === info.bvh );\n\t\t\tprimBvh._roots.forEach( ( root, i ) => {\n\n\t\t\t\ttransformInfo.push( {\n\t\t\t\t\tdata,\n\t\t\t\t\troot: i,\n\t\t\t\t\tobject,\n\t\t\t\t\tinstanceId,\n\t\t\t\t\tcompositeId,\n\t\t\t\t} );\n\n\t\t\t} );\n\n\t\t} );\n\n\t\t//\n\n\t\t// @note These buffer lengths are increased to a minimum size of 2 to avoid TSL converting storage buffers\n\t\t// with length 1 being converted to a scalar value.\n\t\t// TODO: remove this when fixed in three\n\t\tconst transformBufferLength = Math.max( transformInfo.length, 2 );\n\t\tindexBufferLength = Math.max( indexBufferLength, 2 );\n\t\tattributesBufferLength = Math.max( attributesBufferLength, 2 );\n\n\t\t// construct the attribute struct\n\t\tconst attributeStruct = new StructTypeNode( attributes, 'bvh_GeometryStruct' );\n\n\t\t// write the geometry buffer attributes & bvh data\n\t\tlet attributesOffset = 0;\n\t\tlet indexOffset = 0;\n\t\tlet nodeWriteOffset = 0;\n\t\tconst indexBuffer = new Uint32Array( indexBufferLength );\n\t\tconst attributesBuffer = new ArrayBuffer( attributesBufferLength * attributeStruct.getLength() * 4 );\n\t\tconst bvhNodesBuffer = new ArrayBuffer( bvhNodesBufferLength );\n\n\t\t// append TLAS data\n\t\tappendBVHData( bvh, 0, transformInfo, 0, bvhNodesBuffer, true );\n\t\tnodeWriteOffset += getTotalBVHByteLength( bvh ) / BYTES_PER_NODE;\n\t\tbvhInfo.forEach( info => {\n\n\t\t\t// append bvh data\n\t\t\tconst bvhNodeOffsets = appendBVHData( info.bvh, indexOffset / 3, transformInfo, nodeWriteOffset, bvhNodesBuffer, false );\n\t\t\tinfo.bvhNodeOffsets = bvhNodeOffsets;\n\n\t\t\t// append geometry data\n\t\t\tappendIndexData( info.bvh, info.range, attributesOffset, indexOffset, indexBuffer );\n\t\t\tappendGeometryData( info.bvh, info.range, attributesOffset, attributesBuffer, attributeStruct, this );\n\t\t\tinfo.indexBufferOffset = indexOffset;\n\n\t\t\t// step the write offsets forward\n\t\t\tindexOffset += info.range.count;\n\t\t\tattributesOffset += info.range.vertexCount;\n\t\t\tnodeWriteOffset += getTotalBVHByteLength( info.bvh ) / BYTES_PER_NODE;\n\n\t\t} );\n\n\t\t//\n\n\t\t// write the transforms\n\t\tconst transformArrayBuffer = new ArrayBuffer( structs.transform.getLength() * transformBufferLength * 4 );\n\t\ttransformInfo.forEach( ( info, i ) => {\n\n\t\t\t_inverseMatrix.copy( bvh.matrixWorld ).invert();\n\t\t\tthis.writeTransformData( info, _inverseMatrix, i, transformArrayBuffer );\n\n\t\t} );\n\n\t\t//\n\n\t\t// set up the storage buffers\n\t\t// if itemSize for StorageBufferAttribute == arraySize,\n\t\t// then buffer is treated not as array of structs, but as a single struct\n\t\t// And that breaks code. For now itemSize = 1 does not seem to break anything\n\t\tconst bvhNodesStorage = storage( new StorageBufferAttribute( new Uint32Array( bvhNodesBuffer ), 1 ), bvhNodeStruct ).toReadOnly().setName( 'bvh_nodes' );\n\t\tconst transformsBuffer = new StorageBufferAttribute( new Uint32Array( transformArrayBuffer ), 1 );\n\t\tconst transformsStorage = storage( transformsBuffer, structs.transform ).toReadOnly().setName( 'bvh_transforms' );\n\t\tconst indexStorage = storage( new StorageBufferAttribute( indexBuffer, 1 ), 'uint' ).toReadOnly().setName( 'bvh_index' );\n\t\tconst attributesStorage = storage( new StorageBufferAttribute( new Uint32Array( attributesBuffer ), attributeStruct.getLength() ), attributeStruct ).toReadOnly().setName( 'bvh_attributes' );\n\n\t\tthis.storage.transforms = transformsStorage;\n\t\tthis.storage.nodes = bvhNodesStorage;\n\t\tthis.storage.index = indexStorage;\n\t\tthis.storage.attributes = attributesStorage;\n\t\tthis.structs.attributes = attributeStruct;\n\n\t\t// depends on the resolved attribute struct, so it must be built here rather than up front\n\t\tthis.fns.sampleTrianglePoint = getSampleTrianglePointFn( this );\n\n\t\tthis._bvhCache.clear();\n\n\t}\n\n\t/**\n\t * Writes the world/inverse-world matrices, node offset, and visibility flag for one\n\t * transform entry into a raw ArrayBuffer. Override this in a subclass to inject\n\t * additional per-object data (e.g. material index).\n\t *\n\t * @private\n\t * @param {Object3D} info - Transform entry from the internal transform info array.\n\t * @param {Matrix4} premultiplyMatrix - Matrix pre-multiplied onto the object's world matrix (usually the inverse TLAS root matrix).\n\t * @param {number} writeOffset - Index of the transform slot to write into.\n\t * @param {ArrayBuffer} targetBuffer - Destination buffer.\n\t */\n\twriteTransformData( info, premultiplyMatrix, writeOffset, targetBuffer ) {\n\n\t\tconst { structs } = this;\n\t\tconst transformBufferF32 = new Float32Array( targetBuffer );\n\t\tconst transformBufferU32 = new Uint32Array( targetBuffer );\n\n\t\tconst { object, instanceId, root, data } = info;\n\t\tconst { bvhNodeOffsets } = data;\n\t\tif ( object.isInstancedMesh || object.isBatchedMesh ) {\n\n\t\t\tobject.getMatrixAt( instanceId, _matrix );\n\t\t\t_matrix.premultiply( object.matrixWorld );\n\n\t\t} else {\n\n\t\t\t_matrix.copy( object.matrixWorld );\n\n\t\t}\n\n\t\t// write transform\n\t\t_matrix.premultiply( premultiplyMatrix );\n\t\t_matrix.toArray( transformBufferF32, writeOffset * structs.transform.getLength() );\n\n\t\t// write inverse transform\n\t\t_matrix.invert();\n\t\t_matrix.toArray( transformBufferF32, writeOffset * structs.transform.getLength() + 16 );\n\n\t\t// write node offset\n\t\ttransformBufferU32[ writeOffset * structs.transform.getLength() + 32 ] = bvhNodeOffsets[ root ];\n\n\t\tlet visible = isObjectVisible( object );\n\t\tif ( object.isBatchedMesh ) {\n\n\t\t\tvisible = visible && object.getVisibleAt( instanceId );\n\n\t\t}\n\n\t\ttransformBufferU32[ writeOffset * structs.transform.getLength() + 33 ] = visible ? 1 : 0;\n\n\t}\n\n\t/**\n\t * Returns the BVH for a given object/instance, populating `rangeTarget` with the\n\t * corresponding index and vertex ranges within the packed geometry buffers. Override\n\t * to support custom BVH types or caching strategies.\n\t *\n\t * @private\n\t * @param {Object3D} object - The object to generate a BVH for.\n\t * @param {number} instanceId - Instance index (relevant for InstancedMesh / BatchedMesh).\n\t * @param {{start:number,count:number,vertexStart:number,vertexCount:number}} rangeTarget - Populated with the object's geometry range.\n\t * @returns {MeshBVH|SkinnedMeshBVH|null}\n\t */\n\tgetBVH( object, instanceId, rangeTarget ) {\n\n\t\tconst { autogenerateBvh, _bvhCache } = this;\n\n\t\tlet bvh = null;\n\t\tif ( object.boundsTree || object.isSkinnedMesh ) {\n\n\t\t\t// this is a case where a mesh has morph targets and skinned meshes\n\t\t\tconst geometry = object.geometry;\n\t\t\trangeTarget.count = geometry.index ? geometry.index.count : geometry.attributes.position.count;\n\t\t\trangeTarget.vertexCount = geometry.attributes.position.count;\n\t\t\tbvh = object.boundsTree || null;\n\n\t\t\tif ( bvh === null && autogenerateBvh ) {\n\n\t\t\t\tconst id = object.uuid;\n\t\t\t\tbvh = _bvhCache.get( id ) || new SkinnedMeshBVH( object );\n\t\t\t\t_bvhCache.set( id, bvh );\n\n\t\t\t}\n\n\t\t} else if ( object.isBatchedMesh ) {\n\n\t\t\tconst geometryId = object.getGeometryIdAt( instanceId );\n\t\t\tconst range = object.getGeometryRangeAt( geometryId );\n\t\t\tObject.assign( rangeTarget, range );\n\t\t\tbvh = object.boundsTrees[ geometryId ] || null;\n\n\t\t\tif ( bvh === null && autogenerateBvh ) {\n\n\t\t\t\tconst id = `batched_${ object.geometry.uuid }_${ range.start }_${ range.count }`;\n\t\t\t\tbvh = _bvhCache.get( id ) || new MeshBVH( object.geometry, { range: { ...rangeTarget } } );\n\t\t\t\t_bvhCache.set( id, bvh );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst geometry = object.geometry;\n\t\t\trangeTarget.count = geometry.index ? geometry.index.count : geometry.attributes.position.count;\n\t\t\trangeTarget.vertexCount = geometry.attributes.position.count;\n\t\t\tbvh = object.geometry.boundsTree || null;\n\n\t\t\tif ( bvh === null && autogenerateBvh ) {\n\n\t\t\t\tconst id = geometry.uuid;\n\t\t\t\tbvh = _bvhCache.get( id ) || new MeshBVH( geometry );\n\t\t\t\t_bvhCache.set( id, bvh );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn bvh;\n\n\t}\n\n\t/**\n\t * Returns the default vec4 value written to the attribute buffer for vertices that lack\n\t * a given attribute. Override to change per-attribute defaults.\n\t *\n\t * @private\n\t * @param {string} key - Attribute name (e.g. `'position'`, `'normal'`).\n\t * @param {Vector4} target - Receives the default value.\n\t * @returns {Vector4}\n\t */\n\tgetDefaultAttributeValue( key, target ) {\n\n\t\tswitch ( key ) {\n\n\t\t\tcase 'position':\n\t\t\tcase 'color':\n\t\t\t\ttarget.set( 1, 1, 1, 1 );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\ttarget.set( 0, 0, 0, 0 );\n\n\t\t}\n\n\t\treturn target;\n\n\t}\n\n\t/**\n\t * Releases GPU resources held by this instance.\n\t */\n\tdispose() {\n\n\t\tconst { storage } = this;\n\t\tfor ( const key in storage ) {\n\n\t\t\tstorage[ key ].value?.dispose();\n\t\t\tdelete storage[ key ];\n\n\t\t}\n\n\t}\n\n}\n\n\n// A container whose string members are returned as stable proxy nodes. Assigning a member stores\n// the underlying node.\n// TODO: we should automatically infer a proxy node vs fn. Perhaps in r185 we won't need the difference?\nclass NodeProxyObject {\n\n\tconstructor( initialization = {}, createProxy = proxy ) {\n\n\t\tconst proxies = {};\n\n\t\t// the raw backing object holds the underlying nodes and is the proxy target. \"createProxy\"\n\t\t// selects the proxy variant - \"proxy\" for plain nodes, \"proxyFn\" for callable function nodes.\n\t\treturn new Proxy( { ...initialization }, {\n\n\t\t\tget( target, property ) {\n\n\t\t\t\tif ( ! proxies[ property ] ) {\n\n\t\t\t\t\tproxies[ property ] = createProxy( property, target );\n\n\t\t\t\t}\n\n\t\t\t\treturn proxies[ property ];\n\n\t\t\t},\n\n\t\t\tset( target, property, value ) {\n\n\t\t\t\ttarget[ property ] = value;\n\t\t\t\treturn true;\n\n\t\t\t},\n\n\t\t} );\n\n\t}\n\n}\n","import { MeshBasicNodeMaterial, NoToneMapping, StorageTexture } from 'three/webgpu';\nimport { uv, varying, texture, vec4, toneMapping, uniform, wgslFn } from 'three/tsl';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\n// TODO: we could fall back to hardware-based filtering if available but it has to be specifically\n// requested and available on the renderer which we don't have access to immediately. It's possible this\n// can be detected during build time via a custom node to adjust the sample approach used?\nconst sampleTexelFn = wgslFn( /* wgsl */`\n\tfn sampleTexel( tex: texture_2d<f32>, coord: vec2f ) -> vec4f {\n\n\t\t// Manual bilinear filtering using textureLoad to support filterable float32 textures\n\t\t// on all devices\n\t\tlet size = vec2f( textureDimensions( tex, 0 ) );\n\t\tlet pxCoord = coord * size - 0.5;\n\t\tlet px = vec2i( floor( pxCoord ) );\n\t\tlet fr = fract( pxCoord );\n\n\t\t// get the four sibling samples\n\t\tlet s00 = textureLoad( tex, clamp( px, vec2i( 0 ), vec2i( size ) - 1 ), 0 );\n\t\tlet s10 = textureLoad( tex, clamp( px + vec2i( 1, 0 ), vec2i( 0 ), vec2i( size ) - 1 ), 0 );\n\t\tlet s01 = textureLoad( tex, clamp( px + vec2i( 0, 1 ), vec2i( 0 ), vec2i( size ) - 1 ), 0 );\n\t\tlet s11 = textureLoad( tex, clamp( px + vec2i( 1, 1 ), vec2i( 0 ), vec2i( size ) - 1 ), 0 );\n\n\t\t// interpolate on the x axis\n\t\tlet y0 = mix( s00, s10, fr.x );\n\t\tlet y1 = mix( s01, s11, fr.x );\n\n\t\t// then y\n\t\treturn mix( y0, y1, fr.y );\n\n\t}\n` );\n\n// Material to apply tone mapping _before_ applying alpha blending\nexport class RenderToScreenNodeMaterial extends MeshBasicNodeMaterial {\n\n\tget texture() {\n\n\t\treturn this._texNode.value;\n\n\t}\n\n\tset texture( v ) {\n\n\t\tthis._texNode.value = v;\n\n\t}\n\n\tget fromTexture() {\n\n\t\treturn this._fromTexNode.value;\n\n\t}\n\n\tset fromTexture( v ) {\n\n\t\tthis._fromTexNode.value = v;\n\n\t}\n\n\tget toneMapping() {\n\n\t\treturn this._toneMapping.toneMapping;\n\n\t}\n\n\tset toneMapping( v ) {\n\n\t\tthis._toneMapping.setToneMapping( v );\n\n\t}\n\n\tget transition() {\n\n\t\treturn this._transitionUniform.value;\n\n\t}\n\n\tset transition( v ) {\n\n\t\tthis._transitionUniform.value = v;\n\n\t}\n\n\tget exposure() {\n\n\t\treturn this._toneMapping.exposureNode.value;\n\n\t}\n\n\tset exposure( v ) {\n\n\t\tthis._toneMapping.exposureNode.value = v;\n\n\t}\n\n\tconstructor( params ) {\n\n\t\tsuper();\n\n\t\tconst texNode = texture( new StorageTexture() );\n\t\tthis._texNode = texNode;\n\n\t\tconst fromTexNode = texture( new StorageTexture() );\n\t\tthis._fromTexNode = fromTexNode;\n\n\t\tconst texUV = varying( uv() );\n\n\t\tconst transitionUniform = uniform( 1.0 );\n\t\tthis._transitionUniform = transitionUniform;\n\n\t\t// NOTE: varyings cannot be referenced directly and must be passed as arguments\n\t\tconst getFadedColorFn = wgslTagFn/* wgsl */`\n\t\t\tfn fade( uv: vec2f ) -> vec4f {\n\n\t\t\t\tif ( ${ transitionUniform } <= 0.0 ) {\n\n\t\t\t\t\treturn ${ sampleTexelFn }( ${ fromTexNode }, uv );\n\n\t\t\t\t} else if ( ${ transitionUniform } >= 1.0 ) {\n\n\t\t\t\t\treturn ${ sampleTexelFn }( ${ texNode }, uv );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet col0 = ${ sampleTexelFn }( ${ fromTexNode }, uv );\n\t\t\t\t\tlet col1 = ${ sampleTexelFn }( ${ texNode }, uv );\n\t\t\t\t\treturn mix( col0, col1, ${ transitionUniform } );\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t`;\n\n\t\tconst toneMappingNode = toneMapping( NoToneMapping, 1.0, getFadedColorFn( texUV ) );\n\t\tthis._toneMapping = toneMappingNode;\n\n\t\t// apply alpha _after_ applying tone mapping\n\t\t// NOTE: alpha is being multiplied twice here to accommodate some odd blending in three.js\n\t\t// See mrdoob/three.js#33104. It's possible this should be removed or rethought once fixed.\n\t\tthis.transparent = true;\n\t\tthis.colorNode = vec4( toneMappingNode.rgb, toneMappingNode.a );\n\n\t\tthis.setValues( params );\n\n\t}\n\n}\n","export class ComputeKernel {\n\n\tget computeNode() {\n\n\t\treturn this.kernel.computeNode;\n\n\t}\n\n\tget workgroupSize() {\n\n\t\treturn this.kernel.workgroupSize;\n\n\t}\n\n\tset needsUpdate( v ) {\n\n\t\t// TODO: hack to force the kernel to rebuild since \"needsUpdate\" is not respected\n\t\tthis.setWorkgroupSize( ...this.workgroupSize );\n\n\t}\n\n\tconstructor( fn, options = {} ) {\n\n\t\tconst {\n\t\t\tworkgroupSize = [ 64 ],\n\t\t} = options;\n\n\t\t// this.workgroupSize = [ ...workgroupSize ];\n\t\tthis._fn = fn;\n\t\tthis.kernel = null;\n\n\t\tthis.setWorkgroupSize( ...workgroupSize );\n\n\t}\n\n\tdefineUniformAccessors( parameters ) {\n\n\t\tfor ( const key in parameters ) {\n\n\t\t\tif ( key in this ) {\n\n\t\t\t\tthrow new Error( `ComputeNode: Uniform name ${ key } is already defined.` );\n\n\t\t\t}\n\n\t\t\tconst node = parameters[ key ];\n\t\t\tif ( 'value' in node ) {\n\n\t\t\t\tObject.defineProperty( this, key, {\n\t\t\t\t\tget() {\n\n\t\t\t\t\t\treturn parameters[ key ].value;\n\n\t\t\t\t\t},\n\t\t\t\t\tset( v ) {\n\n\t\t\t\t\t\tparameters[ key ].value = v;\n\n\t\t\t\t\t},\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tsetWorkgroupSize( x = 64, y = 1, z = 1 ) {\n\n\t\tthis.kernel = this._fn.computeKernel( [ x, y, z ] );\n\t\treturn this;\n\n\t}\n\n\tgetDispatchSize( tx = 1, ty = 1, tz = 1, target = [] ) {\n\n\t\tconst [ wgx, wgy, wgz ] = this.workgroupSize;\n\t\ttarget.length = 3;\n\t\ttarget[ 0 ] = Math.ceil( tx / wgx );\n\t\ttarget[ 1 ] = Math.ceil( ty / wgy );\n\t\ttarget[ 2 ] = Math.ceil( tz / wgz );\n\t\treturn target;\n\n\t}\n\n}\n","import { uint, float, wgsl, wgslFn } from 'three/tsl';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\n// Alpha test should be the last index as it is summed with triangle index\nexport const RNG_INDEX_RAY_JITTER = 0;\nexport const RNG_INDEX_ENVIRONMENT_SAMPLE = 1;\nexport const RNG_INDEX_SCATTER_TYPE = 2;\nexport const RNG_INDEX_SCATTER_DIRECTION = 3;\nexport const RNG_INDEX_ALPHA_TEST = 4;\n\nexport const pcgStateStruct = wgsl( /* wgsl */`\n\n\tstruct PcgState {\n\t\ts0: vec4u,\n\t\ts1: vec4u,\n\t};\n\n\tvar<private> g_state: PcgState;\n` );\n\nexport const pcgInitFunc = wgslFn( /* wgsl */`\n\tfn pcgInitialize( pixelIndex: u32, pathIndex: u32, bounceIndex: u32 ) -> void {\n\t\tlet pixel = vec2( ( pixelIndex >> 16 ) & 0xFF, pixelIndex & 0xFF );\n\n\t\t//white noise seed\n\t\tg_state.s0 = vec4u( pixel | vec2( bounceIndex << 16 ), pathIndex, pixel.x + pixel.y);\n\n\t\t//blue noise seed\n\t\tg_state.s1 = vec4u(pathIndex, pathIndex*15843, pathIndex*31 + 4566, pathIndex*2345 + 58585);\n\n\t}\n`, [ pcgStateStruct ] );\n\nconst pcg4d = wgslFn( /* wgsl */ `\n\tfn pcg4d(v: ptr<private, vec4u>) -> void {\n\t\t*v = *v * 1664525u + 1013904223u;\n\t\t*v = *v + v.yzxy * v.wxyz;\n\t\t*v = *v ^ (*v >> vec4u(16u));\n\t\t*v = *v + v.yzxy * v.wxyz;\n\t}\n` );\n\nexport const pcgRandFunc = wgslFn( /*wgsl*/`\n\tfn pcgRand( _id: u32 ) -> f32 {\n\t\tpcg4d(&g_state.s0);\n\t\treturn abs( f32( g_state.s0.x ) / f32(0xffffffffu) );\n\t}\n`, [ pcg4d, pcgStateStruct ] );\n\nexport const pcgRand2Func = wgslFn( /*wgsl*/`\n\tfn pcgRand2( _id: u32 ) -> vec2f {\n\t\tpcg4d(&g_state.s0);\n\t\treturn abs( vec2f( g_state.s0.xy ) / f32(0xffffffffu) );\n\t}\n`, [ pcg4d, pcgStateStruct ] );\n\nexport const pcgRand3Func = wgslFn( /*wgsl*/`\n\tfn pcgRand3( _id: u32 ) -> vec3f {\n\t\tpcg4d(&g_state.s0);\n\t\treturn abs( vec3f( g_state.s0.xyz ) / f32(0xffffffffu) );\n\t}\n`, [ pcg4d, pcgStateStruct ] );\n\nexport const pcgRand4Func = wgslFn( /*wgsl*/`\n\tfn pcgRand4( _id: u32 ) -> vec4f {\n\t\tpcg4d(&g_state.s0);\n\t\treturn abs( vec4f( g_state.s0 ) / f32(0xffffffffu) );\n\t}\n`, [ pcg4d, pcgStateStruct ] );\n\nexport const pcgNextBounceFunc = wgslFn( /* wgsl */ 'fn noop() -> void {}' );\n\n// References\n// - https://jcgt.org/published/0009/04/01/\n// - Code from https://www.shadertoy.com/view/WtGyDm\n// Ported from WebGL version at sobol.glsl.js\n\nconst SOBOL_MAX_POINTS = uint( 256 * 256 );\nconst SOBOL_FACTOR = float( 1.0 / 16777216.0 );\n\nconst sobolConstants = wgsl( /* wgsl */ `\n\n\tconst SOBOL_DIRECTIONS_1 = array<u32, 32>(\n\t\t0x80000000u, 0xc0000000u, 0xa0000000u, 0xf0000000u,\n\t\t0x88000000u, 0xcc000000u, 0xaa000000u, 0xff000000u,\n\t\t0x80800000u, 0xc0c00000u, 0xa0a00000u, 0xf0f00000u,\n\t\t0x88880000u, 0xcccc0000u, 0xaaaa0000u, 0xffff0000u,\n\t\t0x80008000u, 0xc000c000u, 0xa000a000u, 0xf000f000u,\n\t\t0x88008800u, 0xcc00cc00u, 0xaa00aa00u, 0xff00ff00u,\n\t\t0x80808080u, 0xc0c0c0c0u, 0xa0a0a0a0u, 0xf0f0f0f0u,\n\t\t0x88888888u, 0xccccccccu, 0xaaaaaaaau, 0xffffffffu\n\t);\n\n\tconst SOBOL_DIRECTIONS_2 = array<u32, 32>(\n\t\t0x80000000u, 0xc0000000u, 0x60000000u, 0x90000000u,\n\t\t0xe8000000u, 0x5c000000u, 0x8e000000u, 0xc5000000u,\n\t\t0x68800000u, 0x9cc00000u, 0xee600000u, 0x55900000u,\n\t\t0x80680000u, 0xc09c0000u, 0x60ee0000u, 0x90550000u,\n\t\t0xe8808000u, 0x5cc0c000u, 0x8e606000u, 0xc5909000u,\n\t\t0x6868e800u, 0x9c9c5c00u, 0xeeee8e00u, 0x5555c500u,\n\t\t0x8000e880u, 0xc0005cc0u, 0x60008e60u, 0x9000c590u,\n\t\t0xe8006868u, 0x5c009c9cu, 0x8e00eeeeu, 0xc5005555u\n\t);\n\n\tconst SOBOL_DIRECTIONS_3 = array<u32, 32>(\n\t\t0x80000000u, 0xc0000000u, 0x20000000u, 0x50000000u,\n\t\t0xf8000000u, 0x74000000u, 0xa2000000u, 0x93000000u,\n\t\t0xd8800000u, 0x25400000u, 0x59e00000u, 0xe6d00000u,\n\t\t0x78080000u, 0xb40c0000u, 0x82020000u, 0xc3050000u,\n\t\t0x208f8000u, 0x51474000u, 0xfbea2000u, 0x75d93000u,\n\t\t0xa0858800u, 0x914e5400u, 0xdbe79e00u, 0x25db6d00u,\n\t\t0x58800080u, 0xe54000c0u, 0x79e00020u, 0xb6d00050u,\n\t\t0x800800f8u, 0xc00c0074u, 0x200200a2u, 0x50050093u\n\t);\n\n\tconst SOBOL_DIRECTIONS_4 = array<u32, 32>(\n\t\t0x80000000u, 0x40000000u, 0x20000000u, 0xb0000000u,\n\t\t0xf8000000u, 0xdc000000u, 0x7a000000u, 0x9d000000u,\n\t\t0x5a800000u, 0x2fc00000u, 0xa1600000u, 0xf0b00000u,\n\t\t0xda880000u, 0x6fc40000u, 0x81620000u, 0x40bb0000u,\n\t\t0x22878000u, 0xb3c9c000u, 0xfb65a000u, 0xddb2d000u,\n\t\t0x78022800u, 0x9c0b3c00u, 0x5a0fb600u, 0x2d0ddb00u,\n\t\t0xa2878080u, 0xf3c9c040u, 0xdb65a020u, 0x6db2d0b0u,\n\t\t0x800228f8u, 0x400b3cdcu, 0x200fb67au, 0xb00ddb9du\n\t);\n\n` );\n\nconst sobolPixelIndex = uint( 0 ).toVar( 'sobolPixelIndex' );\nconst sobolPathIndex = uint( 0 ).toVar( 'sobolPathIndex' );\nconst sobolBounceIndex = uint( 0 ).toVar( 'sobolBounceIndex' );\n\nconst getMaskedSobolFunc = wgslFn( /* wgsl */ `\n\n\tfn getMaskedSobol( index: u32, directions: array<u32, 32> ) -> u32 {\n\n\t\tvar X = 0u;\n\t\tfor ( var bit = 0u; bit < 32u; bit ++ ) {\n\n\t\t\tlet mask = ( index >> bit ) & 1u;\n\t\t\tX ^= mask * directions[ bit ];\n\n\t\t}\n\t\treturn X;\n\n\t}\n\n` );\n\n// functions to generate multi-dimensions variables of the same functions\n// to support 1, 2, 3, and 4 dimensional sobol sampling.\nconst sobolScrambleNodesGenerator = ( dim = 1 ) => {\n\n\tif ( dim <= 0 ) {\n\n\t\treturn;\n\n\t}\n\n\tconst type = dim > 1 ? `vec${dim}u` : 'u32';\n\n\tconst sobolReverseBitsFunc = wgslFn( /* wgsl */ `\n\n\t\t\tfn sobolReverseBits_${type}( in: ${type} ) -> ${type} {\n\n\t\t\t\tvar x = in;\n\t\t\t\tx = ( ( ( x & ${type}( 0xaaaaaaaau ) ) >> ${type}( 1 ) ) | ( ( x & ${type}( 0x55555555u ) ) << ${type}( 1 ) ) );\n\t\t\t\tx = ( ( ( x & ${type}( 0xccccccccu ) ) >> ${type}( 2 ) ) | ( ( x & ${type}( 0x33333333u ) ) << ${type}( 2 ) ) );\n\t\t\t\tx = ( ( ( x & ${type}( 0xf0f0f0f0u ) ) >> ${type}( 4 ) ) | ( ( x & ${type}( 0x0f0f0f0fu ) ) << ${type}( 4 ) ) );\n\t\t\t\tx = ( ( ( x & ${type}( 0xff00ff00u ) ) >> ${type}( 8 ) ) | ( ( x & ${type}( 0x00ff00ffu ) ) << ${type}( 8 ) ) );\n\t\t\t\treturn ( ( x >> ${type}( 16 ) ) | ( x << ${type}( 16 ) ) );\n\n\t\t\t}\n\n\t` );\n\n\tconst sobolHashCombineFunc = wgslFn( /* wgsl */ `\n\n\t\tfn sobolHashCombine_${type}( seed: u32, v: ${type} ) -> ${type} {\n\n\t\t\treturn ${type}( seed ) ^ ( v + ${ type }( ( seed << 6 ) + ( seed >> 2 ) ) );\n\n\t\t}\n\n\t` );\n\n\tconst sobolLaineKarrasPermutationFunc = wgslFn( /* wgsl */ `\n\n\t\tfn sobolLaineKarrasPermutation_${type}( in: ${type}, seed: ${type} ) -> ${type} {\n\n\t\t\tvar x = in;\n\t\t\tx += seed;\n\t\t\tx ^= x * 0x6c50b47cu;\n\t\t\tx ^= x * 0xb82f1e52u;\n\t\t\tx ^= x * 0xc7afe638u;\n\t\t\tx ^= x * 0x8d22f6e6u;\n\t\t\treturn x;\n\n\t\t}\n\n\t` );\n\n\tconst nestedUniformScrambleBase2Func = wgslTagFn/* wgsl */ `\n\n\t\tfn nestedUniformScrambleBase2_${type}( x: ${type}, seed: ${type} ) -> ${type} {\n\n\t\t\tvar res = ${ sobolLaineKarrasPermutationFunc }( x, seed );\n\t\t\tres = ${ sobolReverseBitsFunc }( res );\n\t\t\treturn res;\n\n\t\t}\n\n\t`;\n\n\treturn {\n\t\treverseBits: sobolReverseBitsFunc,\n\t\thashCombine: sobolHashCombineFunc,\n\t\tlkPermutation: sobolLaineKarrasPermutationFunc,\n\t\tscramble: nestedUniformScrambleBase2Func,\n\t};\n\n};\n\n// 0th node is intentionally empty to make access pattern more intuitive:\n// sobolNodes[ i ] are nodes that are needed to sample i-dimensional vectors\n// 1-dimensional vector = f32\nconst sobolNodes = Array.from( { length: 5 }, ( _, i ) => sobolScrambleNodesGenerator( i ) );\n\nexport const generateSobolPointFunc = wgslTagFn`\n ${ [ sobolConstants ] }\n\n\tfn generateSobolPoint( id: u32 ) -> vec4f {\n\n\t\tvar index = id;\n\t\tif ( index >= ${ SOBOL_MAX_POINTS } ) {\n\n\t\t\tindex = index % ${ SOBOL_MAX_POINTS };\n\t\t\t// return vec4( 0.0 );\n\n\t\t}\n\n\t\t// NOTE: this sobol \"direction\" is also available but we can't write out 5 components\n\t\t// uint x = index & 0x00ffffffu;\n\t\tlet x = ${ sobolNodes[ 1 ].reverseBits }( ${ getMaskedSobolFunc }( index, SOBOL_DIRECTIONS_1 ) ) & 0x00ffffffu;\n\t\tlet y = ${ sobolNodes[ 1 ].reverseBits }( ${ getMaskedSobolFunc }( index, SOBOL_DIRECTIONS_2 ) ) & 0x00ffffffu;\n\t\tlet z = ${ sobolNodes[ 1 ].reverseBits }( ${ getMaskedSobolFunc }( index, SOBOL_DIRECTIONS_3 ) ) & 0x00ffffffu;\n\t\tlet w = ${ sobolNodes[ 1 ].reverseBits }( ${ getMaskedSobolFunc }( index, SOBOL_DIRECTIONS_4 ) ) & 0x00ffffffu;\n\n\t\treturn vec4( f32( x ), f32( y ), f32( z ), f32( w ) ) * ${ SOBOL_FACTOR };\n\n\t}\n\n`;\n\nconst sobolHashFunc = wgslFn( /* wgsl */ `\n\n\tfn sobolHash( in: u32 ) -> u32 {\n\n\t\tvar x = in;\n\t\t// finalizer from murmurhash3\n\t\tx ^= x >> 16;\n\t\tx *= 0x85ebca6bu;\n\t\tx ^= x >> 13;\n\t\tx *= 0xc2b2ae35u;\n\t\tx ^= x >> 16;\n\t\treturn x;\n\n\t}\n\n` );\n\nconst sobolGetSeedFunc = wgslTagFn`\n\n\tfn sobolGetSeed( effect: u32 ) -> u32 {\n\n\t\treturn ${ sobolHashFunc }(\n\t\t\t${ sobolNodes[ 1 ].hashCombine }(\n\t\t\t\t${ sobolNodes[ 1 ].hashCombine }(\n\t\t\t\t\t${ sobolHashFunc }( ${ sobolBounceIndex } ),\n\t\t\t\t\t${ sobolPixelIndex }\n\t\t\t\t),\n\t\t\t\teffect\n\t\t\t)\n\t\t);\n\n\t}\n\n`;\n\nconst sobolGenerator = ( dim = 1, sobolPointFunc = generateSobolPointFunc ) => {\n\n\tif ( dim <= 0 ) {\n\n\t\treturn;\n\n\t}\n\n\tconst utype = dim > 1 ? `vec${dim}u` : 'u32';\n\tconst ftype = dim > 1 ? `vec${dim}f` : 'f32';\n\n\tlet components = '.r';\n\tlet combineValues = '1u';\n\tif ( dim === 2 ) {\n\n\t\tcomponents = '.rg';\n\t\tcombineValues = 'vec2( 1u, 2u )';\n\n\t} else if ( dim === 3 ) {\n\n\t\tcomponents = '.rgb';\n\t\tcombineValues = 'vec3( 1u, 2u, 3u )';\n\n\t} else if ( dim === 4 ) {\n\n\t\tcomponents = '';\n\t\tcombineValues = 'vec4( 1u, 2u, 3u, 4u )';\n\n\t}\n\n\treturn wgslTagFn`\n\n\t\tfn sobol${dim}( effect: u32 ) -> ${ftype} {\n\n\t\t\tlet seed = ${sobolGetSeedFunc}( effect );\n\t\t\tlet index = ${sobolPathIndex};\n\n\t\t\tlet shuffle_seed = ${ sobolNodes[ 1 ].hashCombine }( seed, 0u );\n\t\t\tlet shuffled_index = ${ sobolNodes[ 1 ].scramble }( ${ sobolNodes[ 1 ].reverseBits }( index ), shuffle_seed );\n\t\t\tlet sobol_pt = ${ sobolPointFunc }( shuffled_index )${ components };\n\t\t\tvar result = ${ utype }( sobol_pt * 16777216.0 );\n\n\t\t\tlet seed2 = ${ sobolNodes[ dim ].hashCombine }( seed, ${ combineValues } );\n\t\t\tresult = ${ sobolNodes[ dim ].scramble }( result, seed2 );\n\n\t\t\treturn ${ SOBOL_FACTOR } * ${ ftype }( result >> ${utype}( 8 ) );\n\n\t\t}\n\n\t`;\n\n};\n\nexport const sobolRand1Func = sobolGenerator( 1 );\nexport const sobolRand2Func = sobolGenerator( 2 );\nexport const sobolRand3Func = sobolGenerator( 3 );\nexport const sobolRand4Func = sobolGenerator( 4 );\n\nexport const sobolInitFunc = wgslTagFn`\n\n\tfn sobolInit( pixelIndex: u32, pathIndex: u32, bounceIndex: u32 ) -> void {\n\n\t\t${ sobolPixelIndex } = pixelIndex;\n\t\t${ sobolPathIndex } = pathIndex;\n\t\t${ sobolBounceIndex } = bounceIndex;\n\n\t}\n\n`;\n\nexport const sobolNextBounceFunc = wgslTagFn`\n\n\tfn sobolNextBounce() -> void {\n\n\t\t${ sobolBounceIndex }++;\n\n\t}\n\n`;\n\n// PCG definitions\n// export {\n// \tpcgInitFunc as rngInit,\n// \tpcgNextBounceFunc as rngNextBounce,\n// \tpcgRandFunc as rand1,\n// \tpcgRand2Func as rand2,\n// \tpcgRand3Func as rand3,\n// \tpcgRand4Func as rand4,\n// };\n\n// Sobol definitions\nexport {\n\tsobolInitFunc as rngInit,\n\tsobolNextBounceFunc as rngNextBounce,\n\tsobolRand1Func as rand1,\n\tsobolRand2Func as rand2,\n\tsobolRand3Func as rand3,\n\tsobolRand4Func as rand4,\n};\n","import { wgsl } from 'three/tsl';\nimport { StructTypeNode } from 'three/webgpu';\n\n// TODO: Move to node-based constants that are embedded with wgslTagFn\nexport const constants = wgsl( /* wgsl */ `\n\n\tconst PI: f32 = 3.141592653589793;\n\tconst EPSILON: f32 = 1e-5;\n\tconst MIN_ROUGHNESS: f32 = 1e-3;\n\n` );\n\nexport const scatterRecordStruct = new StructTypeNode( {\n\tcolor: 'vec3f',\n\tspecularPdf: 'float',\n\tdirection: 'vec3f',\n\tpdf: 'float',\n}, 'ScatterRecord' );\n\n// NOTE: all \"*Map\" fields are bit-packed integers of texture index & settings:\n// bits 0-23: texture index\n// bits 24-25: wrapS setting\n// bits 26-27: wrapT setting\n// bit 28: filter setting\n// bits 29-30: unused\n// bit 31: negative bit used for indicating unused texture\nexport const materialStruct = new StructTypeNode( {\n\t// offset 0\n\tcolor: 'vec3',\n\tmap: 'int',\n\n\t// offset 4 floats\n\tmetalness: 'float',\n\tmetalnessMap: 'int',\n\n\troughness: 'float',\n\troughnessMap: 'int',\n\n\t// offset 8 floats\n\tior: 'float',\n\ttransmission: 'float',\n\ttransmissionMap: 'int',\n\n\temissiveIntensity: 'float',\n\t// offset 12 floats\n\temissive: 'vec3',\n\temissiveMap: 'int',\n\n\t// offset 16 floats\n\tnormalMap: 'int',\n\tnormalScale: 'vec2',\n\n\t// offset 20 floats\n\tclearcoat: 'float',\n\tclearcoatMap: 'int',\n\tclearcoatNormalMap: 'int',\n\t// offset 24 floats\n\tclearcoatNormalScale: 'vec2',\n\tclearcoatRoughness: 'float',\n\tclearcoatRoughnessMap: 'int',\n\n\t// offset 28 floats\n\tiridescenceMap: 'int',\n\tiridescenceThicknessMap: 'int',\n\tiridescence: 'float',\n\tiridescenceIor: 'float',\n\t// offset 32 floats\n\tiridescenceThicknessMinimum: 'float',\n\tiridescenceThicknessMaximum: 'float',\n\n\t// offset 36 floats\n\tspecularColor: 'vec3',\n\tspecularColorMap: 'int',\n\n\t// offset 40 floats\n\tspecularIntensity: 'float',\n\tspecularIntensityMap: 'int',\n\tthinFilm: 'int', // actually a boolean\n\n\t// offset 44 floats\n\tattenuationColor: 'vec3',\n\tattenuationDistance: 'float',\n\n\t// offset 48 floats\n\talphaMap: 'int',\n\n\tcastShadow: 'int', // actually a boolean\n\topacity: 'float',\n\talphaTest: 'float',\n\n\t// offset 52 floats\n\tside: 'float',\n\tmatte: 'int', // actually a boolean\n\n\tsheen: 'float',\n\t// offset 56 floats\n\tsheenColor: 'vec3',\n\tsheenColorMap: 'int',\n\t// offset 60 floats\n\tsheenRoughness: 'float',\n\tsheenRoughnessMap: 'int',\n\n\t// All those are booleans\n\tvertexColors: 'int',\n\tflatShading: 'int',\n\t// offset 64 floats\n\ttransparent: 'int',\n\tfogVolume: 'int',\n\n\t// offset 68 floats\n\tmapTransform: 'mat3',\n\t// offset 80 floats\n\tmetalnessMapTransform: 'mat3',\n\t// offset 92 floats\n\troughnessMapTransform: 'mat3',\n\t// offset 104 floats\n\ttransmissionMapTransform: 'mat3',\n\t// offset 116 floats\n\temissiveMapTransform: 'mat3',\n\t// offset 128 floats\n\tnormalMapTransform: 'mat3',\n\t// offset 140 floats\n\tclearcoatMapTransform: 'mat3',\n\t// offset 152 floats\n\tclearcoatNormalMapTransform: 'mat3',\n\t// offset 164 floats\n\tclearcoatRoughnessMapTransform: 'mat3',\n\t// offset 176 floats\n\tsheenColorMapTransform: 'mat3',\n\t// offset 188 floats\n\tsheenRoughnessMapTransform: 'mat3',\n\t// offset 200 floats\n\tiridescenceMapTransform: 'mat3',\n\t// offset 212 floats\n\tiridescenceThicknessMapTransform: 'mat3',\n\t// offset 224 floats\n\tspecularColorMapTransform: 'mat3',\n\t// offset 236 floats\n\tspecularIntensityMapTransform: 'mat3',\n\t// offset 248 floats\n\talphaMapTransform: 'mat3',\n\t// total size = 260\n}, 'Material' );\n\nexport const surfaceRecordStruct = new StructTypeNode( {\n\t// surface type\n\tvolumeParticle: 'bool',\n\n\t// geometry\n\tfaceNormal: 'vec3f',\n\tfrontFace: 'bool',\n\tnormal: 'vec3f',\n\tnormalBasis: 'mat3x3f',\n\tnormalInvBasis: 'mat3x3f',\n\n\t// cached properties\n\teta: 'f32',\n\tf0: 'f32',\n\n\t// material\n\troughness: 'f32',\n\tmetalness: 'f32',\n\tcolor: 'vec3f',\n\temission: 'vec3f',\n\n\t// transmission\n\tior: 'f32',\n\ttransmission: 'f32',\n\tthinFilm: 'bool',\n\tattenuationColor: 'vec3f',\n\tattenuationDistance: ' f32',\n\n\t// clearcoat\n\tclearcoatNormal: 'vec3f',\n\tclearcoatBasis: 'mat3x3f',\n\tclearcoatInvBasis: 'mat3x3f',\n\tclearcoat: 'f32',\n\tclearcoatRoughness: 'f32',\n\n\t// sheen\n\tsheen: 'f32',\n\tsheenColor: 'vec3f',\n\tsheenRoughness: 'f32',\n\n\t// iridescence\n\tiridescence: 'f32',\n\tiridescenceIor: 'f32',\n\tiridescenceThickness: 'f32',\n\n\t// specular\n\tspecularColor: 'vec3f',\n\tspecularIntensity: 'f32',\n}, 'SurfaceRecord' );\n\nexport const environmentInfoStruct = new StructTypeNode( {\n\trotation: 'mat3x3f',\n\tintensity: 'float',\n\tblur: 'float',\n}, 'EnvironmentInfo' );\n\nexport const lobeWeightsStruct = new StructTypeNode( {\n\tdiffuse: 'float',\n\tspecular: 'float',\n\ttransmission: 'float',\n\tclearcoat: 'float',\n}, 'LobeWeights' );\n\nexport const bxdfContextStruct = new StructTypeNode( {\n\tNdotV: 'float',\n\tNdotL: 'float',\n\tNdotH: 'float',\n\tVdotH: 'float',\n\n\tVdotNc: 'float',\n\tLdotNc: 'float',\n\tHdotNc: 'float',\n\n}, 'BxDFContext' );\n","import { wgslFn } from 'three/tsl';\nimport { scatterRecordStruct } from './structs.wgsl.js';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\nexport const inverseMat3x3Func = wgslFn( /* wgsl */ `\n\n\tfn inverse(m: mat3x3f) -> mat3x3f {\n\t\tvar adj: mat3x3f;\n\t\tadj[0][0] = (m[1][1] * m[2][2] - m[2][1] * m[1][2]);\n\t\tadj[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n\t\tadj[2][0] = (m[1][0] * m[2][1] - m[2][0] * m[1][1]);\n\t\tadj[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n\t\tadj[1][1] = (m[0][0] * m[2][2] - m[2][0] * m[0][2]);\n\t\tadj[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n\t\tadj[0][2] = (m[0][1] * m[1][2] - m[1][1] * m[0][2]);\n\t\tadj[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n\t\tadj[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]);\n\n\t\tlet det = ( m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])\n\t\t\t- m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])\n\t\t\t+ m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]));\n\n\t\treturn adj * ( 1.0 / det );\n\t}\n\n` );\n\nexport const getBasisFromNormalFunc = wgslFn( /* wgsl */ `\n\n\tfn getBasisFromNormal( normal: vec3f ) -> mat3x3f {\n\n\t\tvar other: vec3f;\n\t\tif ( abs( normal.x ) > 0.5 ) {\n\n\t\t\tother = vec3f( 0.0, 1.0, 0.0 );\n\n\t\t} else {\n\n\t\t\tother = vec3f( 1.0, 0.0, 0.0 );\n\n\t\t}\n\n\t\tlet ortho = normalize( cross( normal, other ) );\n\t\tlet ortho2 = normalize( cross( normal, ortho ) );\n\t\treturn mat3x3f( ortho2, ortho, normal );\n\n\t}\n\n` );\n\nexport const iorToF0Func = wgslFn( /* wgsl */ `\n\n\tfn iorToF0( ior: f32 ) -> f32 {\n\t\treturn pow( ( 1 - ior ) / ( 1 + ior ), 2 );\n\t}\n\n` );\n\nexport const iorToF0GeneralFunc = wgslFn( /* wgsl */ `\n\n\tfn iorToF0General( transmittedIor: f32, incidentIor: f32 ) -> f32 {\n\n\t\treturn pow( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ), 2 );\n\n\t}\n\n` );\n\nexport const iorToF0GeneralVecFunc = wgslFn( /* wgsl */ `\n\n\tfn iorToF0GeneralVec( transmittedIor: vec3f, incidentIor: vec3f ) -> vec3f {\n\n\t\tlet v = ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor );\n\t\treturn v * v;\n\n\t}\n\n` );\n\nexport const fresnel0ToIorFunc = wgslFn( /* wgsl */ `\n\n\tfn fresnel0ToIor( f0: vec3f ) -> vec3f {\n\n\t\tlet sqrtF0 = sqrt( f0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\n\t}\n\n` );\n\nexport const schlickFresnelFunc = wgslFn( /* wgsl */ `\n\n\tfn schlickFresnel( cosine: f32, f0: f32 ) -> f32 {\n\n\t\treturn f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n\t}\n\n` );\n\nexport const schlickFresnelVecFunc = wgslFn( /* wgsl */ `\n\n\tfn schlickFresnelVec( cosine: f32, f0: vec3f, f90: vec3f ) -> vec3f {\n\n\t\treturn f0 + ( f90 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n\t}\n\n` );\n\nexport const totalInternalReflectionFunc = wgslFn( /* wgsl */ `\n\n\tfn totalInternalReflection( cosTheta: f32, eta: f32 ) -> bool {\n\n\t\tlet sinTheta = sqrt( 1.0 - cosTheta * cosTheta );\n\t\treturn eta * sinTheta > 1.0;\n\n\t}\n\n` );\n\nexport const evaluateFresnelFunc = wgslFn( /* wgsl */ `\n\n\tfn evaluateFresnel( cosine: f32, eta: f32, f0: vec3f, f90: vec3f ) -> vec3f {\n\n\t\tif ( totalInternalReflection( cosine, eta ) ) {\n\n\t\t\treturn f90;\n\n\t\t}\n\n\t\treturn f0 + ( f90 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\t}\n\n`, [ totalInternalReflectionFunc ] );\n\nexport const isTerminatingScatterFunc = wgslFn( /* wgsl */ `\n\n\tfn isTerminatingScatter( scatterRec: ScatterRecord ) -> bool {\n\t\treturn scatterRec.pdf <= 0;\n\t}\n\n`, [ scatterRecordStruct ] );\n\nexport const applyWrapFunc = wgslFn( /* wgsl */ `\n\n\tfn applyWrap( v: f32, wrapMode: i32 ) -> f32 {\n\n\t\tvar res = v;\n\t\tif ( wrapMode == 1 ) {\n\n\t\t\t// ClampToEdge\n\t\t\tres = clamp( res, 0.0, 1.0 );\n\n\t\t} else if ( wrapMode == 2 ) {\n\n\t\t\t// MirroredRepeat\n\t\t\tres = 1.0 - abs( 2.0 * fract( res * 0.5 ) - 1.0 );\n\n\t\t} else {\n\n\t\t\t// Repeat\n\t\t\tres = fract( res );\n\n\t\t}\n\n\t\treturn res;\n\n\t}\n\n` );\n\n// Factory: builds sampleTexel bound to the given per-instance textureInfo uniform\n// array node ( must be named \"textureInfo\" ). Called once per scene so a single\n// sampleTexel / textureInfo binding is shared by every caller in a pipeline.\nexport const sampleTexelFunc = ( textureInfoUniform, atlas, atlasSampler ) => wgslTagFn/* wgsl */ `\n\n\tfn sampleTexel( uv: vec2f, packed: i32, lod: f32 ) -> vec4f {\n\n\t\tlet wrapS = ( packed >> 24 ) & 0x3;\n\t\tlet wrapT = ( packed >> 26 ) & 0x3;\n\t\tlet nearest = ( packed >> 28 ) & 0x1;\n\t\tlet texIndex = packed & 0xFFFFFF;\n\n\t\t// look up the texture's rect and page within the atlas. three wraps a\n\t\t// uniformArray in a struct ( textureInfoStruct ) with a \"value\" array member.\n\t\tlet info = ${ textureInfoUniform }[ u32( texIndex ) ];\n\t\tlet offset = vec2f( vec2u( info.x & 0xFFFFu, info.x >> 16u ) );\n\t\tlet size = vec2f( vec2u( info.y & 0xFFFFu, info.y >> 16u ) );\n\t\tlet page = i32( info.z & 0xFFFFu );\n\n\t\t// wrap is applied on the logical uv first, then remapped into the tile\n\t\tlet wrappedUv = vec2f(\n\t\t\t${ applyWrapFunc }( uv.x, wrapS ),\n\t\t\t${ applyWrapFunc }( uv.y, wrapT ),\n\t\t);\n\n\t\tlet pageDim = vec2f( textureDimensions( ${ atlas }, 0 ).xy );\n\n\t\tif ( nearest == 1 ) {\n\n\t\t\tlet tileTexel = clamp( vec2i( wrappedUv * size ), vec2i( 0 ), vec2i( size ) - vec2i( 1 ) );\n\t\t\treturn textureLoad( ${ atlas }, vec2i( offset ) + tileTexel, page, 0 );\n\n\t\t} else {\n\n\t\t\tvar atlasUv = ( offset + wrappedUv * size ) / pageDim;\n\n\t\t\t// clamp to half a texel inside the tile so bilinear taps never bleed into\n\t\t\t// neighboring atlas tiles\n\t\t\tlet minUv = ( offset + vec2f( 0.5 ) ) / pageDim;\n\t\t\tlet maxUv = ( offset + size - vec2f( 0.5 ) ) / pageDim;\n\t\t\tatlasUv = clamp( atlasUv, minUv, maxUv );\n\n\t\t\treturn textureSampleLevel( ${ atlas }, ${ atlasSampler }, atlasUv, page, lod );\n\n\t\t}\n\n\t}\n`;\n\n","import { wgslFn } from 'three/tsl';\nimport { environmentInfoStruct, constants, lobeWeightsStruct } from './structs.wgsl.js';\nimport { evaluateFresnelFunc, iorToF0Func, schlickFresnelFunc } from './utils.wgsl.js';\n\n/*\nwi : incident vector or light vector (pointing toward the light)\nwo : outgoing vector or view vector (pointing towards the camera)\nwh : computed half vector from wo and wi\nVectors above are assumed to be in tangent space. i.e. +z is along macronormal of the surface\neta : Greek character used to denote the \"ratio of ior\"\n*/\n\nexport const sampleSphereFunc = wgslFn( /* wgsl */ `\n\n\tfn sampleSphere( uv: vec2f ) -> vec3f {\n\n\t\tlet u = ( uv.x - 0.5 ) * 2.0;\n\t\tlet t = uv.y * PI * 2.0;\n\t\tlet f = sqrt( 1.0 - u * u );\n\n\t\treturn vec3f( f * cos( t ), f * sin( t ), u );\n\n\t}\n\n`, [ constants ] );\n\n// TODO: Investigate sampling directly in tagent space?\n// See 16.6.1 in https://www.realtimerendering.com/raytracinggems/unofficial_RayTracingGems_v1.9.pdf\nexport const diffuseDirectionFunc = wgslFn( /* wgsl */ `\n\n\tfn diffuseDirection( wo: vec3f, uv: vec2f ) -> vec3f {\n\n\t\tvar lightDirection = sampleSphere( uv );\n\t\tlightDirection.z += 1.0;\n\t\tlightDirection = normalize( lightDirection );\n\n\t\treturn lightDirection;\n\n\t}\n\n`, [ sampleSphereFunc ] );\n\nexport const getLobeWeightsFunc = wgslFn( /* wgsl */ `\n\n\tfn getLobeWeights(wo: vec3f, woClearcoat: vec3f, wh: vec3f, clearcoatIor: f32, surf: SurfaceRecord) -> LobeWeights {\n\n\t\t// TODO: experiment with this; I don't see any usage of normal?\n\t\tlet metalness = surf.metalness;\n\t\tlet transmission = surf.transmission;\n\t\tlet HdotL = dot( wh, wo );\n\t\tlet fEstimate = evaluateFresnel( HdotL, surf.eta, vec3f( surf.f0 ), vec3f( 1.0 ) ).x;\n\n\t\tlet transSpecularProb = mix( max( 0.25, fEstimate ), 1.0, metalness );\n\t\tlet diffSpecularProb = 0.5 + 0.5 * metalness;\n\n\t\tvar weights: LobeWeights;\n\t\tweights.diffuse = ( 1.0 - transmission ) * ( 1.0 - diffSpecularProb );\n\t\tweights.specular = transmission * transSpecularProb + ( 1.0 - transmission ) * diffSpecularProb;\n\n\t\tlet clearcoatF0 = iorToF0( clearcoatIor );\n\t\tlet clearcoatFresnel = schlickFresnel( saturate( woClearcoat.z ), clearcoatF0 );\n\t\tweights.clearcoat = surf.clearcoat * clearcoatFresnel;\n\n\t\tweights.transmission = transmission * ( 1.0 - transSpecularProb );\n\n\t\tlet totalWeight = weights.diffuse + weights.specular;\n\t\tif ( totalWeight > 0 ) {\n\t\t\tweights.diffuse = ( weights.diffuse / totalWeight ) * ( 1 - weights.clearcoat );\n\t\t\tweights.specular = ( weights.specular / totalWeight ) * ( 1 - weights.clearcoat );\n\t\t}\n\t\t// weights.transmission /= totalWeight;\n\n\t\treturn weights;\n\n\t}\n\n`, [ schlickFresnelFunc, iorToF0Func, evaluateFresnelFunc, lobeWeightsStruct, constants ] );\n\nconst equirectDirectionToUvFn = wgslFn( /* wgsl */`\n\n\tfn equirectDirectionToUv(direction: vec3f) -> vec2f {\n\n\t\t// from Spherical.setFromCartesianCoords\n\t\tvar uv = vec2f( atan2( direction.z, direction.x ), acos( direction.y ) );\n\t\tuv /= vec2f( 2.0 * PI, PI );\n\n\t\t// apply adjustments to get values in range [0, 1] and y right side up\n\t\tuv.x += 0.5;\n\t\tuv.y = 1.0 - uv.y;\n\t\treturn uv;\n\n\t}\n\n` );\n\nconst sampleEquirectColorFn = wgslFn( /* wgsl */ `\n\n\tfn sampleEquirectColor( envMap: texture_2d<f32>, envMapSampler: sampler, direction: vec3f ) -> vec4f {\n\n\t\treturn textureSampleLevel( envMap, envMapSampler, equirectDirectionToUv( direction ), 0 );\n\n\t}\n\n`, [ equirectDirectionToUvFn ] );\n\nconst sampleHemisphereFn = wgslFn( /* wgsl */ `\n\n\tfn sampleHemisphere( n: vec3f, uv: vec2f ) -> vec3f {\n\n\t\t// https://www.rorydriscoll.com/2009/01/07/better-sampling/\n\t\t// https://graphics.pixar.com/library/OrthonormalB/paper.pdf\n\t\tlet sign = select( sign( n.z ), 1.0, n.z == 0.0 );\n\t\tlet a = - 1.0 / ( sign + n.z );\n\t\tlet b = n.x * n.y * a;\n\t\tlet b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );\n\t\tlet b2 = vec3( b, sign + n.y * n.y * a, - n.y );\n\n\t\tlet r = sqrt( uv.x );\n\t\tlet theta = 2.0 * PI * uv.y;\n\t\tlet x = r * cos( theta );\n\t\tlet y = r * sin( theta );\n\t\treturn x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;\n\n\t}\n\n`, [ constants ] );\n\nexport const sampleEnvironmentFn = wgslFn( /* wgsl */ `\n\n\tfn sampleEnvironment(\n\t\tenvMap: texture_2d<f32>,\n\t\tenvMapSampler: sampler,\n\t\tenv: EnvironmentInfo,\n\t\tdirection: vec3f,\n\t\tuv: vec2f,\n\t) -> vec4f {\n\n\t\tlet offsetDir = sampleHemisphere( direction, uv ) * 0.5 * env.blur;\n\t\tlet sampleDir = normalize( env.rotation * direction + offsetDir );\n\t\tlet col = sampleEquirectColor( envMap, envMapSampler, sampleDir );\n\n\t\treturn vec4f( env.intensity * col.rgb, col.a );\n\n\t}\n\n`, [ sampleEquirectColorFn, sampleHemisphereFn, environmentInfoStruct ] );\n\nexport const weightedAlphaBlendFn = wgslFn( /* wgsl */`\n\n\tfn weightedAlphaBlend( prevColor: vec4f, newColor: vec4f, weight: f32 ) -> vec4f {\n\n\t\tlet invWeight = 1.0 - weight;\n\t\tlet totalAlpha = prevColor.a * invWeight + newColor.a * weight;\n\t\tvar blendedColor = vec4f( 0 );\n\t\tif ( totalAlpha != 0.0 ) {\n\n\t\t\tlet prevContrib = prevColor.rgb * invWeight * prevColor.a / totalAlpha;\n\t\t\tlet resContrib = newColor.rgb * weight * newColor.a / totalAlpha;\n\t\t\tblendedColor = vec4f( prevContrib + resContrib, totalAlpha );\n\n\t\t}\n\n\t\treturn blendedColor;\n\n\t}\n\n` );\n","import { DataTexture, Matrix3, Matrix4, Vector2, StorageTexture } from 'three/webgpu';\nimport { ComputeKernel } from './ComputeKernel.js';\nimport { texture, sampler, uniform, globalId, textureStore } from 'three/tsl';\nimport { rngInit, rngNextBounce, rand2, RNG_INDEX_RAY_JITTER, RNG_INDEX_ENVIRONMENT_SAMPLE } from '../nodes/random.wgsl.js';\nimport { sampleEnvironmentFn, weightedAlphaBlendFn } from '../nodes/sampling.wgsl.js';\nimport { ndcToCameraRay, proxy, proxyFn, wgslTagFn } from '../lib/three-mesh-bvh/index.js';\nimport { isTerminatingScatterFunc } from '../nodes/utils.wgsl.js';\n\nexport class PathTracerMegaKernel extends ComputeKernel {\n\n\tconstructor( ) {\n\n\t\tconst params = {\n\t\t\tbvhData: { value: null },\n\t\t\tmaterial: { value: null },\n\n\t\t\tprevOutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadOnly(),\n\t\t\toutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toWriteOnly(),\n\t\t\tsampleCountTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadWrite(),\n\n\t\t\toffset: uniform( new Vector2() ),\n\t\t\ttileSize: uniform( new Vector2() ),\n\t\t\tseed: uniform( 0 ),\n\t\t\tbounces: uniform( 5 ),\n\n\t\t\t// transforms\n\t\t\tinverseProjectionMatrix: uniform( new Matrix4() ),\n\t\t\tcameraToModelMatrix: uniform( new Matrix4() ),\n\n\t\t\t// environment\n\t\t\tenvMap: texture( new DataTexture() ),\n\t\t\tenvMapSampler: sampler( new DataTexture() ),\n\t\t\tenvMapRotation: uniform( new Matrix3() ),\n\t\t\tenvMapIntensity: uniform( 1 ),\n\n\t\t\tbackground: texture( new DataTexture() ),\n\t\t\tbackgroundSampler: sampler( new DataTexture() ),\n\t\t\tbackgroundRotation: uniform( new Matrix3() ),\n\t\t\tbackgroundIntensity: uniform( 1 ),\n\t\t\tbackgroundBlurriness: uniform( 0 ),\n\n\t\t\ttextures: texture( new DataTexture() ),\n\t\t\ttextureSampler: sampler( new DataTexture() ),\n\n\t\t\t// compute variables\n\t\t\tglobalId: globalId,\n\t\t};\n\n\t\tconst raycastOutput = proxy( 'bvhData.value.fns.raycastFirstHit.outputType', params );\n\t\tconst raycastFirstHitFn = proxyFn( 'bvhData.value.fns.raycastFirstHit', params );\n\t\tconst sampleTrianglePointFn = proxyFn( 'bvhData.value.fns.sampleTrianglePoint', params );\n\t\tconst getSurfaceRecordFn = proxyFn( 'bvhData.value.fns.getSurfaceRecord', params );\n\t\tconst bsdfSampleFn = proxyFn( 'material.value.bsdfSample', params );\n\n\t\tconst shader = wgslTagFn/* wgsl */`\n\n\t\t\tfn compute(\n\n\t\t\t\t// indices and target\n\t\t\t\tglobalId: vec3u,\n\n\t\t\t\t// tiles\n\t\t\t\toffset: vec2u,\n\t\t\t\ttileSize: vec2u,\n\n\t\t\t\t// settings\n\t\t\t\tinverseProjectionMatrix: mat4x4f,\n\t\t\t\tcameraToModelMatrix: mat4x4f,\n\t\t\t\tseed: u32,\n\t\t\t\tbounces: u32,\n\n\t\t\t\t// environment\n\t\t\t\tenvMap: texture_2d<f32>,\n\t\t\t\tenvMapSampler: sampler,\n\t\t\t\tenvMapRotation: mat3x3f,\n\t\t\t\tenvMapIntensity: f32,\n\n\t\t\t\tbackground: texture_2d<f32>,\n\t\t\t\tbackgroundSampler: sampler,\n\t\t\t\tbackgroundRotation: mat3x3f,\n\t\t\t\tbackgroundIntensity: f32,\n\t\t\t\tbackgroundBlurriness: f32,\n\n\t\t\t) -> void {\n\n\t\t\t\tlet transforms = &${ proxy( 'bvhData.value.storage.transforms', params ) };\n\t\t\t\tlet materials = &${ proxy( 'bvhData.value.storage.materials', params ) };\n\n\t\t\t\tlet envInfo = EnvironmentInfo(\n\t\t\t\t\tenvMapRotation,\n\t\t\t\t\tenvMapIntensity,\n\t\t\t\t\t0.0 // blur,\n\t\t\t\t);\n\n\t\t\t\tlet backgroundInfo = EnvironmentInfo(\n\t\t\t\t\tbackgroundRotation,\n\t\t\t\t\tbackgroundIntensity,\n\t\t\t\t\tbackgroundBlurriness,\n\t\t\t\t);\n\n\t\t\t\t// make sure we don't bleed over the edge of our tile\n\t\t\t\tif ( globalId.x >= tileSize.x || globalId.y >= tileSize.y ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// to screen coordinates\n\t\t\t\tlet indexUV = offset + globalId.xy;\n\t\t\t\tlet targetDimensions = textureDimensions( ${ params.outputTarget } );\n\t\t\t\tif ( indexUV.x >= targetDimensions.x || indexUV.y >= targetDimensions.y ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tlet uv = vec2f( indexUV ) / vec2f( targetDimensions );\n\t\t\t\tlet ndc = uv * 2.0 - vec2f( 1.0 );\n\n\t\t\t\tlet pixelIndex = ( indexUV.x << 16 ) | indexUV.y;\n\t\t\t\t${ rngInit }( pixelIndex, seed, 0 );\n\n\t\t\t\t// scene ray\n\t\t\t\tvar jitter = 2.0 * ${ rand2 }( ${ RNG_INDEX_RAY_JITTER } ) / vec2f( targetDimensions.xy );\n\t\t\t\tvar ray = ${ ndcToCameraRay }( ndc + jitter, cameraToModelMatrix * inverseProjectionMatrix );\n\t\t\t\tray.direction = normalize( ray.direction );\n\n\t\t\t\tvar resultColor = vec4f( 0, 0, 0, 1 );\n\t\t\t\tvar throughputColor = vec3f( 1.0 );\n\n\t\t\t\tfor ( var bounce = 0u; bounce < bounces; bounce ++ ) {\n\n\t\t\t\t\tvar hitResult: ${ raycastOutput };\n\t\t\t\t\tif ( ${ raycastFirstHitFn }( ray, &hitResult ) ) {\n\n\t\t\t\t\t\tlet object = transforms[ hitResult.objectIndex ];\n\t\t\t\t\t\tvar material = materials[ object.materialIndex ];\n\n\t\t\t\t\t\t// apply per-object colors\n\t\t\t\t\t\tmaterial.color *= object.color.rgb;\n\t\t\t\t\t\tmaterial.opacity *= object.color.a;\n\n\t\t\t\t\t\tvar vertexData = ${ sampleTrianglePointFn }( hitResult.barycoord, hitResult.indices.xyz );\n\t\t\t\t\t\tvertexData.normal = normalize( transpose( object.inverseMatrixWorld ) * vertexData.normal );\n\t\t\t\t\t\tvertexData.position = object.matrixWorld * vertexData.position;\n\n\t\t\t\t\t\tlet surface = ${ getSurfaceRecordFn }( material, vertexData, hitResult.side, hitResult.normal );\n\n\t\t\t\t\t\tresultColor += vec4f( throughputColor * surface.emission, 0.0 );\n\n\t\t\t\t\t\tlet scatterRec = ${ bsdfSampleFn }( - ray.direction, surface );\n\n\t\t\t\t\t\tif ( ${ isTerminatingScatterFunc }( scatterRec ) ) {\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthroughputColor *= scatterRec.color;\n\t\t\t\t\t\tthroughputColor /= scatterRec.pdf;\n\n\t\t\t\t\t\t// TODO: Investigate offsetting this position to not self-intersect multiple times\n\t\t\t\t\t\t// Adding + scatterRec.direction * 1e-1 seems to fix almost all the fireflies\n\t\t\t\t\t\t// However that seems like a very large distance to offset\n\t\t\t\t\t\tray.origin = vertexData.position.xyz;\n\t\t\t\t\t\tray.direction = scatterRec.direction;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tlet rng = ${ rand2 }( ${ RNG_INDEX_ENVIRONMENT_SAMPLE } );\n\t\t\t\t\t\tif ( bounce > 0u ) {\n\n\t\t\t\t\t\t\tresultColor += ${ sampleEnvironmentFn }( envMap, envMapSampler, envInfo, ray.direction, rng ) * vec4f( throughputColor, 0.0 );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tresultColor = ${ sampleEnvironmentFn }( background, backgroundSampler, backgroundInfo, ray.direction, rng );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t${ rngNextBounce }();\n\n\t\t\t\t}\n\n\t\t\t\tlet sampleCount = textureLoad( ${ params.sampleCountTarget }, indexUV ).r + 1;\n\t\t\t\tlet prevColor = textureLoad( ${ params.prevOutputTarget }, indexUV );\n\t\t\t\tlet blendedColor = ${ weightedAlphaBlendFn }( prevColor, resultColor, 1.0 / f32( sampleCount ) );\n\t\t\t\ttextureStore( ${ params.sampleCountTarget }, indexUV, vec4( sampleCount ) );\n\t\t\t\ttextureStore( ${ params.outputTarget }, indexUV, blendedColor );\n\n\t\t\t}`;\n\n\t\tsuper( shader( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { DataUtils } from 'three';\n\n\nexport function toHalfFloatArray( f32Array ) {\n\n\tconst f16Array = new Uint16Array( f32Array.length );\n\tfor ( let i = 0, n = f32Array.length; i < n; ++ i ) {\n\n\t\tf16Array[ i ] = DataUtils.toHalfFloat( f32Array[ i ] );\n\n\t}\n\n\treturn f16Array;\n\n}\n","import { DataTexture, RedFormat, LinearFilter, DataUtils, HalfFloatType, Source, RepeatWrapping, RGBAFormat, FloatType, ClampToEdgeWrapping } from 'three';\nimport { toHalfFloatArray } from '../utils/TextureUtils.js';\n\nfunction binarySearchFindClosestIndexOf( array, targetValue, offset = 0, count = array.length ) {\n\n\tlet lower = offset;\n\tlet upper = offset + count - 1;\n\n\twhile ( lower < upper ) {\n\n\t\t// calculate the midpoint for this iteration using a bitwise shift right operator to save 1 floating point multiplication\n\t\t// and 1 truncation from the double tilde operator to improve performance\n\t\t// this results in much better performance over using standard \"~ ~ ( (lower + upper) ) / 2\" to calculate the midpoint\n\t\tconst mid = ( lower + upper ) >> 1;\n\n\t\t// check if the middle array value is above or below the target and shift\n\t\t// which half of the array we're looking at\n\t\tif ( array[ mid ] < targetValue ) {\n\n\t\t\tlower = mid + 1;\n\n\t\t} else {\n\n\t\t\tupper = mid;\n\n\t\t}\n\n\t}\n\n\treturn lower - offset;\n\n}\n\nfunction colorToLuminance( r, g, b ) {\n\n\t// https://en.wikipedia.org/wiki/Relative_luminance\n\treturn 0.2126 * r + 0.7152 * g + 0.0722 * b;\n\n}\n\n// ensures the data is all floating point values and flipY is false\nfunction preprocessEnvMap( envMap, targetType = HalfFloatType ) {\n\n\tconst map = envMap.clone();\n\tmap.source = new Source( { ...map.image } );\n\tconst { width, height, data } = map.image;\n\n\t// TODO: is there a simple way to avoid cloning and adjusting the env map data here?\n\t// convert the data from half float uint 16 arrays to float arrays for cdf computation\n\tlet newData = data;\n\tif ( map.type !== targetType ) {\n\n\t\tif ( targetType === HalfFloatType ) {\n\n\t\t\tnewData = new Uint16Array( data.length );\n\n\t\t} else {\n\n\t\t\tnewData = new Float32Array( data.length );\n\n\t\t}\n\n\t\tlet maxIntValue;\n\t\tif ( data instanceof Int8Array || data instanceof Int16Array || data instanceof Int32Array ) {\n\n\t\t\tmaxIntValue = 2 ** ( 8 * data.BYTES_PER_ELEMENT - 1 ) - 1;\n\n\t\t} else {\n\n\t\t\tmaxIntValue = 2 ** ( 8 * data.BYTES_PER_ELEMENT ) - 1;\n\n\t\t}\n\n\t\tfor ( let i = 0, l = data.length; i < l; i ++ ) {\n\n\t\t\tlet v = data[ i ];\n\t\t\tif ( map.type === HalfFloatType ) {\n\n\t\t\t\tv = DataUtils.fromHalfFloat( data[ i ] );\n\n\t\t\t}\n\n\t\t\tif ( map.type !== FloatType && map.type !== HalfFloatType ) {\n\n\t\t\t\tv /= maxIntValue;\n\n\t\t\t}\n\n\t\t\tif ( targetType === HalfFloatType ) {\n\n\t\t\t\tnewData[ i ] = DataUtils.toHalfFloat( v );\n\n\t\t\t}\n\n\t\t}\n\n\t\tmap.image.data = newData;\n\t\tmap.type = targetType;\n\n\t}\n\n\t// remove any y flipping for cdf computation\n\tif ( map.flipY ) {\n\n\t\tconst ogData = newData;\n\t\tnewData = newData.slice();\n\t\tfor ( let y = 0; y < height; y ++ ) {\n\n\t\t\tfor ( let x = 0; x < width; x ++ ) {\n\n\t\t\t\tconst newY = height - y - 1;\n\t\t\t\tconst ogIndex = 4 * ( y * width + x );\n\t\t\t\tconst newIndex = 4 * ( newY * width + x );\n\n\t\t\t\tnewData[ newIndex + 0 ] = ogData[ ogIndex + 0 ];\n\t\t\t\tnewData[ newIndex + 1 ] = ogData[ ogIndex + 1 ];\n\t\t\t\tnewData[ newIndex + 2 ] = ogData[ ogIndex + 2 ];\n\t\t\t\tnewData[ newIndex + 3 ] = ogData[ ogIndex + 3 ];\n\n\t\t\t}\n\n\t\t}\n\n\t\tmap.flipY = false;\n\t\tmap.image.data = newData;\n\n\t}\n\n\treturn map;\n\n}\n\nexport class EquirectHdrInfoUniform {\n\n\tconstructor() {\n\n\t\t// Default to a white texture and associated weights so we don't\n\t\t// just render black initially.\n\t\tconst blackTex = new DataTexture( toHalfFloatArray( new Float32Array( [ 0, 0, 0, 0 ] ) ), 1, 1 );\n\t\tblackTex.type = HalfFloatType;\n\t\tblackTex.format = RGBAFormat;\n\t\tblackTex.minFilter = LinearFilter;\n\t\tblackTex.magFilter = LinearFilter;\n\t\tblackTex.wrapS = RepeatWrapping;\n\t\tblackTex.wrapT = RepeatWrapping;\n\t\tblackTex.generateMipmaps = false;\n\t\tblackTex.needsUpdate = true;\n\n\t\t// Stores a map of [0, 1] value -> cumulative importance row & pdf\n\t\t// used to sampling a random value to a relevant row to sample from\n\t\tconst marginalWeights = new DataTexture( toHalfFloatArray( new Float32Array( [ 0, 1 ] ) ), 1, 2 );\n\t\tmarginalWeights.type = HalfFloatType;\n\t\tmarginalWeights.format = RedFormat;\n\t\tmarginalWeights.minFilter = LinearFilter;\n\t\tmarginalWeights.magFilter = LinearFilter;\n\t\tmarginalWeights.generateMipmaps = false;\n\t\tmarginalWeights.needsUpdate = true;\n\n\t\t// Stores a map of [0, 1] value -> cumulative importance column & pdf\n\t\t// used to sampling a random value to a relevant pixel to sample from\n\t\tconst conditionalWeights = new DataTexture( toHalfFloatArray( new Float32Array( [ 0, 0, 1, 1 ] ) ), 2, 2 );\n\t\tconditionalWeights.type = HalfFloatType;\n\t\tconditionalWeights.format = RedFormat;\n\t\tconditionalWeights.minFilter = LinearFilter;\n\t\tconditionalWeights.magFilter = LinearFilter;\n\t\tconditionalWeights.generateMipmaps = false;\n\t\tconditionalWeights.needsUpdate = true;\n\n\t\tthis.map = blackTex;\n\t\tthis.marginalWeights = marginalWeights;\n\t\tthis.conditionalWeights = conditionalWeights;\n\t\tthis.totalSum = 0;\n\n\t\t// TODO: Add support for float or half float types here. We need to pass this into\n\t\t// the preprocess function and ensure our CDF and MDF textures are appropriately sized\n\t\t// Ideally we wouldn't upscale a bit depth if we didn't need to.\n\t\t// this.type = HalfFloatType;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.marginalWeights.dispose();\n\t\tthis.conditionalWeights.dispose();\n\t\tthis.map.dispose();\n\n\t}\n\n\tupdateFrom( hdr ) {\n\n\t\t// https://github.com/knightcrawler25/GLSL-PathTracer/blob/3c6fd9b6b3da47cd50c527eeb45845eef06c55c3/src/loaders/hdrloader.cpp\n\t\t// https://pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Sampling_Light_Sources#InfiniteAreaLights\n\t\tconst map = preprocessEnvMap( hdr );\n\t\tmap.wrapS = RepeatWrapping;\n\t\tmap.wrapT = ClampToEdgeWrapping;\n\n\t\tconst { width, height, data } = map.image;\n\n\t\t// \"conditional\" = \"pixel relative to row pixels sum\"\n\t\t// \"marginal\" = \"row relative to row sum\"\n\n\t\t// track the importance of any given pixel in the image by tracking its weight relative to other pixels in the image\n\t\tconst pdfConditional = new Float32Array( width * height );\n\t\tconst cdfConditional = new Float32Array( width * height );\n\n\t\tconst pdfMarginal = new Float32Array( height );\n\t\tconst cdfMarginal = new Float32Array( height );\n\n\t\tlet totalSumValue = 0.0;\n\t\tlet cumulativeWeightMarginal = 0.0;\n\t\tfor ( let y = 0; y < height; y ++ ) {\n\n\t\t\tlet cumulativeRowWeight = 0.0;\n\t\t\tfor ( let x = 0; x < width; x ++ ) {\n\n\t\t\t\tconst i = y * width + x;\n\t\t\t\tconst r = DataUtils.fromHalfFloat( data[ 4 * i + 0 ] );\n\t\t\t\tconst g = DataUtils.fromHalfFloat( data[ 4 * i + 1 ] );\n\t\t\t\tconst b = DataUtils.fromHalfFloat( data[ 4 * i + 2 ] );\n\n\t\t\t\t// the probability of the pixel being selected in this row is the\n\t\t\t\t// scale of the luminance relative to the rest of the pixels.\n\t\t\t\t// TODO: this should also account for the solid angle of the pixel when sampling\n\t\t\t\tconst weight = colorToLuminance( r, g, b );\n\t\t\t\tcumulativeRowWeight += weight;\n\t\t\t\ttotalSumValue += weight;\n\n\t\t\t\tpdfConditional[ i ] = weight;\n\t\t\t\tcdfConditional[ i ] = cumulativeRowWeight;\n\n\t\t\t}\n\n\t\t\t// can happen if the row is all black\n\t\t\tif ( cumulativeRowWeight !== 0 ) {\n\n\t\t\t\t// scale the pdf and cdf to [0.0, 1.0]\n\t\t\t\tfor ( let i = y * width, l = y * width + width; i < l; i ++ ) {\n\n\t\t\t\t\tpdfConditional[ i ] /= cumulativeRowWeight;\n\t\t\t\t\tcdfConditional[ i ] /= cumulativeRowWeight;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tcumulativeWeightMarginal += cumulativeRowWeight;\n\n\t\t\t// compute the marginal pdf and cdf along the height of the map.\n\t\t\tpdfMarginal[ y ] = cumulativeRowWeight;\n\t\t\tcdfMarginal[ y ] = cumulativeWeightMarginal;\n\n\t\t}\n\n\t\t// can happen if the texture is all black\n\t\tif ( cumulativeWeightMarginal !== 0 ) {\n\n\t\t\t// scale the marginal pdf and cdf to [0.0, 1.0]\n\t\t\tfor ( let i = 0, l = pdfMarginal.length; i < l; i ++ ) {\n\n\t\t\t\tpdfMarginal[ i ] /= cumulativeWeightMarginal;\n\t\t\t\tcdfMarginal[ i ] /= cumulativeWeightMarginal;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// compute a sorted index of distributions and the probabilities along them for both\n\t\t// the marginal and conditional data. These will be used to sample with a random number\n\t\t// to retrieve a uv value to sample in the environment map.\n\t\t// These values continually increase so it's okay to interpolate between them.\n\t\tconst marginalDataArray = new Uint16Array( height );\n\t\tconst conditionalDataArray = new Uint16Array( width * height );\n\n\t\t// we add a half texel offset so we're sampling the center of the pixel\n\t\tfor ( let i = 0; i < height; i ++ ) {\n\n\t\t\tconst dist = ( i + 1 ) / height;\n\t\t\tconst row = binarySearchFindClosestIndexOf( cdfMarginal, dist );\n\n\t\t\tmarginalDataArray[ i ] = DataUtils.toHalfFloat( ( row + 0.5 ) / height );\n\n\t\t}\n\n\t\tfor ( let y = 0; y < height; y ++ ) {\n\n\t\t\tfor ( let x = 0; x < width; x ++ ) {\n\n\t\t\t\tconst i = y * width + x;\n\t\t\t\tconst dist = ( x + 1 ) / width;\n\t\t\t\tconst col = binarySearchFindClosestIndexOf( cdfConditional, dist, y * width, width );\n\n\t\t\t\tconditionalDataArray[ i ] = DataUtils.toHalfFloat( ( col + 0.5 ) / width );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.dispose();\n\n\t\tconst { marginalWeights, conditionalWeights } = this;\n\t\tmarginalWeights.image = { width: height, height: 1, data: marginalDataArray };\n\t\tmarginalWeights.needsUpdate = true;\n\n\t\tconditionalWeights.image = { width, height, data: conditionalDataArray };\n\t\tconditionalWeights.needsUpdate = true;\n\n\t\tthis.totalSum = totalSumValue;\n\t\tthis.map = map;\n\n\t}\n\n}\n","import { StorageTexture } from 'three/webgpu';\nimport { ComputeKernel } from './ComputeKernel.js';\nimport { textureStore, globalId } from 'three/tsl';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\nexport class ZeroOutKernel extends ComputeKernel {\n\n\tconstructor() {\n\n\t\tconst params = {\n\t\t\tglobalId: globalId,\n\t\t\toutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toWriteOnly(),\n\t\t};\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\t\t\tfn compute( globalId: vec3u ) -> void {\n\n\t\t\t\ttextureStore( ${ params.outputTarget }, globalId.xy, vec4( 0, 0, 0, 1 ) );\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( {\n\t\t\ttarget: params.outputTarget,\n\t\t} );\n\n\t}\n\n}\n","import { ColorManagement, FloatType, RGBAFormat } from 'three';\nimport { RedIntegerFormat, StorageTexture, UnsignedIntType } from 'three/webgpu';\nimport { ZeroOutKernel } from './compute/ZeroOutKernel.js';\n\nexport class PathTracerBackend {\n\n\tconstructor( renderer ) {\n\n\t\tthis.renderer = renderer;\n\t\tthis.camera = null;\n\t\tthis.samples = 0;\n\t\tthis.bounces = 7;\n\t\tthis.lowResMode = false;\n\n\t\tthis._renderTask = null;\n\n\t\tthis.outputTarget = new StorageTexture( 1, 1, );\n\t\tthis.outputTarget.format = RGBAFormat;\n\t\tthis.outputTarget.type = FloatType;\n\t\tthis.outputTarget.colorSpace = ColorManagement.workingColorSpace;\n\t\tthis.outputTarget.name = 'Output #0';\n\t\tthis.outputTarget.generateMipmaps = false;\n\n\t\tthis.prevOutputTarget = new StorageTexture( 1, 1, );\n\t\tthis.prevOutputTarget.format = RGBAFormat;\n\t\tthis.prevOutputTarget.type = FloatType;\n\t\tthis.prevOutputTarget.colorSpace = ColorManagement.workingColorSpace;\n\t\tthis.prevOutputTarget.name = 'Output #1';\n\t\tthis.prevOutputTarget.generateMipmaps = false;\n\n\t\tthis.sampleCountTarget = new StorageTexture( 1, 1, );\n\t\tthis.sampleCountTarget.format = RedIntegerFormat;\n\t\tthis.sampleCountTarget.type = UnsignedIntType;\n\t\tthis.sampleCountTarget.name = 'Sample Count';\n\t\tthis.sampleCountTarget.generateMipmaps = false;\n\n\t\tthis.sampleCountClearKernel = new ZeroOutKernel().setWorkgroupSize( 8, 8, 1 );\n\t\tthis.outputTargetClearKernel = new ZeroOutKernel().setWorkgroupSize( 8, 8, 1 );\n\n\t}\n\n\tsetCamera( camera ) {\n\n\t\tthis.camera = camera;\n\t\tthis.reset();\n\n\t}\n\n\tsetBVHData( data ) {\n\n\t}\n\n\tsetTextures( textures ) {\n\n\t}\n\n\tsetMaterial( material ) {\n\n\t}\n\n\tsetEnvironment(\n\t\tenvMap,\n\t\tenvMapIntensity,\n\t\tenvMapRotation,\n\n\t\tbackground,\n\t\tbackgroundIntensity,\n\t\tbackgroundRotation,\n\t\tbackgroundBlurriness,\n\t) {\n\n\t}\n\n\tsetSize( w, h ) {\n\n\t\tw = Math.ceil( w );\n\t\th = Math.ceil( h );\n\n\t\tconst { width, height } = this.outputTarget;\n\t\tif ( width === w && height === h ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tthis.outputTarget.dispose();\n\t\tthis.prevOutputTarget.dispose();\n\t\tthis.sampleCountTarget.dispose();\n\n\t\tthis.outputTarget = this.outputTarget.clone();\n\t\tthis.prevOutputTarget = this.outputTarget.clone();\n\t\tthis.sampleCountTarget = this.sampleCountTarget.clone();\n\n\t\tthis.outputTarget.setSize( w, h );\n\t\tthis.prevOutputTarget.setSize( w, h );\n\t\tthis.sampleCountTarget.setSize( w, h );\n\n\t\tthis.reset();\n\t\treturn true;\n\n\t}\n\n\tgetSize( target ) {\n\n\t\tconst { width, height } = this.outputTarget;\n\t\ttarget.x = width;\n\t\ttarget.y = height;\n\n\t\treturn target;\n\n\t}\n\n\tupdate() {\n\n\t\tconst { camera, renderer } = this;\n\t\tif ( ! camera || ! renderer.initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( ! this._renderTask ) {\n\n\t\t\tthis._renderTask = this.createRenderTask();\n\n\t\t}\n\n\t\tthis._renderTask.next();\n\n\t}\n\n\t*createRenderTask() {\n\n\t}\n\n\treset() {\n\n\t\tconst {\n\t\t\trenderer,\n\t\t\toutputTargetClearKernel,\n\t\t\tsampleCountClearKernel,\n\n\t\t\toutputTarget,\n\t\t\tprevOutputTarget,\n\t\t\tsampleCountTarget,\n\t\t} = this;\n\n\t\tif ( ! renderer.initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst { width, height } = outputTarget;\n\t\tconst dispatchSize = outputTargetClearKernel.getDispatchSize( width, height );\n\n\t\toutputTargetClearKernel.target = outputTarget;\n\t\trenderer.compute( outputTargetClearKernel.kernel, dispatchSize );\n\n\t\toutputTargetClearKernel.target = prevOutputTarget;\n\t\trenderer.compute( outputTargetClearKernel.kernel, dispatchSize );\n\n\t\tsampleCountClearKernel.target = sampleCountTarget;\n\t\trenderer.compute( sampleCountClearKernel.kernel, dispatchSize );\n\n\t\tthis.samples = 0;\n\t\tthis._renderTask = null;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.outputTarget.dispose();\n\t\tthis.prevOutputTarget.dispose();\n\t\tthis.sampleCountTarget.dispose();\n\n\t\tthis._renderTask = null;\n\n\t}\n\n}\n","import { Matrix4, Vector2 } from 'three/webgpu';\nimport { PathTracerMegaKernel } from './compute/PathTracerMegaKernel.js';\nimport { EquirectHdrInfoUniform } from '../uniforms/EquirectHdrInfoUniform.js';\nimport { PathTracerBackend } from './PathTracerBackend.js';\n\nexport class MegaKernelPathTracer extends PathTracerBackend {\n\n\tconstructor( renderer ) {\n\n\t\tsuper( renderer );\n\n\t\t// options\n\t\tthis.tiles = new Vector2( 2, 2 );\n\t\tthis.envInfo = new EquirectHdrInfoUniform();\n\t\tthis.samples = 0;\n\n\t\t// kernels\n\t\tthis.kernel = new PathTracerMegaKernel( ).setWorkgroupSize( 8, 8, 1 );\n\n\t}\n\n\tsetBVHData( bvhData ) {\n\n\t\tthis.kernel.bvhData = bvhData;\n\t\tthis.kernel.needsUpdate = true;\n\t\tthis.reset();\n\n\t}\n\n\tsetMaterial( material ) {\n\n\t\tthis.kernel.material = material.getData();\n\t\tthis.kernel.needsUpdate = true;\n\t\tthis.reset();\n\n\t}\n\n\tsetEnvironment(\n\t\tenvMap,\n\t\tenvMapIntensity,\n\t\tenvMapRotation,\n\n\t\tbackground,\n\t\tbackgroundIntensity,\n\t\tbackgroundRotation,\n\t\tbackgroundBlurriness,\n\t) {\n\n\t\tconst { kernel } = this;\n\n\t\tif ( kernel.background.isTexture ) {\n\n\t\t\tkernel.background.dispose();\n\n\t\t}\n\n\t\tif ( envMap !== null ) {\n\n\t\t\tthis.envInfo.updateFrom( envMap );\n\t\t\tkernel.envMap = this.envInfo.map;\n\t\t\tkernel.kernel.computeNode.parameters.envMapSampler.node.value = this.envInfo.map;\n\n\t\t}\n\n\t\tconst rotationMatrix = new Matrix4().makeRotationFromEuler( envMapRotation ).invert();\n\t\tkernel.envMapRotation.setFromMatrix4( rotationMatrix );\n\t\tkernel.envMapIntensity = envMapIntensity;\n\n\t\tkernel.background = background;\n\t\tkernel.kernel.computeNode.parameters.backgroundSampler.node.value = background;\n\t\trotationMatrix.makeRotationFromEuler( backgroundRotation ).invert();\n\t\tkernel.backgroundRotation.setFromMatrix4( rotationMatrix );\n\t\tkernel.backgroundIntensity = backgroundIntensity;\n\t\tkernel.backgroundBlurriness = backgroundBlurriness;\n\n\t}\n\n\tsetTiles( tiles ) {\n\n\t\tthis.tiles.copy( tiles );\n\n\t}\n\n\t*createRenderTask() {\n\n\t\tconst {\n\t\t\trenderer,\n\t\t\tcamera,\n\t\t\tkernel,\n\t\t\tbounces,\n\n\t\t\ttiles,\n\t\t\toutputTarget,\n\t\t\tsampleCountTarget,\n\t\t\tlowResMode,\n\t\t} = this;\n\n\t\tcamera.updateMatrixWorld();\n\n\t\t// init parameters\n\t\tkernel.outputTarget = outputTarget;\n\t\tkernel.sampleCountTarget = sampleCountTarget;\n\n\t\tkernel.bounces = bounces;\n\t\tkernel.inverseProjectionMatrix.copy( camera.projectionMatrixInverse );\n\t\tkernel.cameraToModelMatrix.copy( camera.matrixWorld );\n\n\t\twhile ( true ) {\n\n\t\t\tconst tileSize = kernel.tileSize;\n\t\t\tif ( lowResMode ) {\n\n\t\t\t\tthis.getSize( tileSize );\n\n\t\t\t} else {\n\n\t\t\t\tthis.getSize( tileSize ).divide( tiles ).ceil();\n\n\t\t\t}\n\n\t\t\tconst dispatchSize = kernel.getDispatchSize( tileSize.x, tileSize.y );\n\t\t\tkernel.seed += 1;\n\n\t\t\t// Swap targets to support devices without <rgba32float, read_write> textures\n\t\t\t// Copy latest data to a new outputTarget to keep the appearance\n\t\t\trenderer.copyTextureToTexture( this.outputTarget, this.prevOutputTarget );\n\t\t\t[ this.outputTarget, this.prevOutputTarget ] = [ this.prevOutputTarget, this.outputTarget ];\n\t\t\tkernel.prevOutputTarget = this.prevOutputTarget;\n\t\t\tkernel.outputTarget = this.outputTarget;\n\n\t\t\tfor ( let x = 0; x < tiles.x; x ++ ) {\n\n\t\t\t\tfor ( let y = 0; y < tiles.y; y ++ ) {\n\n\t\t\t\t\tkernel.offset.set( x, y ).multiply( tileSize );\n\t\t\t\t\trenderer.compute( kernel.kernel, dispatchSize );\n\t\t\t\t\tyield;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.samples ++;\n\n\t\t}\n\n\t}\n\n\tdispose() {\n\n\t\tsuper.dispose();\n\n\t\t// TODO: dispose of all buffers\n\t\tthis.envInfo.dispose();\n\n\t}\n\n}\n","import { StructTypeNode } from 'three/webgpu';\n\nexport const queuedRayStruct = new StructTypeNode( {\n\n\torigin: 'vec3f',\n\tseed: 'uint',\n\n\tdirection: 'vec3f',\n\t_alignment0: 'uint',\n\n\tthroughputColor: 'vec3f',\n\tcurrentBounce: 'uint',\n\n\tpixel: 'vec2u',\n\n\tresultColor: 'vec4f',\n\n}, 'QueuedRay' );\n\nexport const queuedHitStruct = new StructTypeNode( {\n\n\tindices: 'vec3u',\n\tseed: 'uint',\n\n\tbarycoord: 'vec2f',\n\tpixel_x: 'uint',\n\tpixel_y: 'uint',\n\n\tview: 'vec3f',\n\tcurrentBounce: 'uint',\n\n\tthroughputColor: 'vec3f',\n\tobjectIndex: 'uint',\n\n\tnormal: 'vec3f',\n\tside: 'float',\n\n\tresultColor: 'vec4f',\n\n}, 'QueuedHit' );\n","import { Vector2, Vector3 } from 'three';\nimport { IndirectStorageBufferAttribute } from 'three/webgpu';\nimport { uniform, storage } from 'three/tsl';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { queuedRayStruct } from './structs.js';\nimport { wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\n\nexport class PrimeRayGenerationDispatchKernel extends ComputeKernel {\n\n\tconstructor() {\n\n\t\tconst params = {\n\t\t\trayWorkGroupSize: uniform( new Vector3() ),\n\n\t\t\ttileSize: uniform( new Vector2() ),\n\t\t\ttileCount: uniform( new Vector2() ),\n\t\t\ttileOffset: uniform( 1 ),\n\n\t\t\trayQueue: storage( new IndirectStorageBufferAttribute( 1, queuedRayStruct.getLength() ), queuedRayStruct ).toReadOnly(),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ),\n\n\t\t\toutputTileIndex: storage( new IndirectStorageBufferAttribute( 2, 1 ), 'u32' ).setName( 'outputTileIndex' ),\n\t\t\toutputDispatch: storage( new IndirectStorageBufferAttribute( 3, 1 ), 'u32' ).setName( 'outputDispatch' ),\n\t\t};\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\t\t\tfn compute(\n\t\t\t\trayWorkGroupSize: vec3u,\n\n\t\t\t\ttileSize: vec2u,\n\t\t\t\ttileCount: vec2u,\n\t\t\t\ttileOffset: u32,\n\t\t\t) -> void {\n\n\t\t\t\tlet rayQueue = &${ params.rayQueue };\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\n\t\t\t\tlet outputTileIndex = &${ params.outputTileIndex };\n\t\t\t\tlet outputDispatch = &${ params.outputDispatch };\n\n\t\t\t\t// reset hit queue size from previous iteration\n\t\t\t\tqueueSizes[ 2 ] = 0u;\n\t\t\t\tqueueSizes[ 3 ] = 0u;\n\n\t\t\t\t// keep the queue index small\n\t\t\t let queueCapacity = arrayLength( rayQueue );\n\t\t\t\tif ( queueSizes[ 0 ] >= queueCapacity ) {\n\n\t\t\t\t\t// uint division results in a floored value\n\t\t\t\t\tlet offset = queueSizes[ 0 ] / queueCapacity;\n\t\t\t\t\tqueueSizes[ 0 ] = queueSizes[ 0 ] - queueCapacity * offset;\n\t\t\t\t\tqueueSizes[ 1 ] = queueSizes[ 1 ] - queueCapacity * offset;\n\n\t\t\t\t}\n\n\t\t\t\t// calculate the amount of elements in the queue\n\t\t\t var queueSize = queueSizes[ 1 ] - queueSizes[ 0 ];\n\n\t\t\t\t// calculate the overhead of space in the queue and how much space we need to run a new tile\n\t\t\t\tlet overhead = queueCapacity - queueSize;\n\t\t\t\tlet requiredSpace = tileSize.x * tileSize.y;\n\n\t\t\t\tif ( overhead >= requiredSpace ) {\n\n\t\t\t\t\t// calculate the necessary dispatch size to cover the tile\n\t\t\t\t\toutputDispatch[ 0 ] = u32( ceil( f32( tileSize.x ) / f32( rayWorkGroupSize.x ) ) );\n\t\t\t\t\toutputDispatch[ 1 ] = u32( ceil( f32( tileSize.y ) / f32( rayWorkGroupSize.y ) ) );\n\t\t\t\t\toutputDispatch[ 2 ] = 1;\n\n\t\t\t\t\t// calculate the tile index to generate rays for\n\t\t\t\t\tlet totalTiles = tileCount.x * tileCount.y;\n\t\t\t\t\tlet currentIndex = outputTileIndex[ 1 ] * tileCount.x + outputTileIndex[ 0 ];\n\t\t\t\t\tlet nextIndex = ( currentIndex + tileOffset ) % totalTiles;\n\n\t\t\t\t\toutputTileIndex[ 0 ] = nextIndex % tileCount.x;\n\t\t\t\t\toutputTileIndex[ 1 ] = nextIndex / tileCount.x;\n\n\t\t\t\t} else {\n\n\t\t\t\t\toutputDispatch[ 0 ] = 0;\n\t\t\t\t\toutputDispatch[ 1 ] = 0;\n\t\t\t\t\toutputDispatch[ 2 ] = 0;\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { Vector2, Matrix4 } from 'three';\nimport { IndirectStorageBufferAttribute, StorageTexture } from 'three/webgpu';\nimport { uniform, storage, globalId, textureStore } from 'three/tsl';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { rngInit, rand2, RNG_INDEX_RAY_JITTER } from '../../nodes/random.wgsl.js';\nimport { queuedRayStruct } from './structs.js';\nimport { ndcToCameraRay, wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\n\nexport class RayGenerationKernel extends ComputeKernel {\n\n\tconstructor( ) {\n\n\t\tconst params = {\n\t\t\tcameraToModelMatrix: uniform( new Matrix4() ),\n\t\t\tinverseProjectionMatrix: uniform( new Matrix4() ),\n\n\t\t\tseed: uniform( 0 ),\n\n\t\t\ttileIndexBuffer: storage( new IndirectStorageBufferAttribute( 2, 1 ), 'u32' ),\n\t\t\ttileSize: uniform( new Vector2() ),\n\n\t\t\trayQueue: storage( new IndirectStorageBufferAttribute( 1, queuedRayStruct.getLength() ), queuedRayStruct ),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ).toAtomic(),\n\n\t\t\tsampleCountTarget: textureStore( new StorageTexture() ).toReadWrite(),\n\n\t\t\tglobalId: globalId,\n\t\t};\n\n\t\tconst fn = wgslTagFn /* wgsl */`\n\t\t\tfn compute(\n\t\t\t\tcameraToModelMatrix: mat4x4f,\n\t\t\t\tinverseProjectionMatrix: mat4x4f,\n\n\t\t\t\tseed: u32,\n\t\t\t\ttileSize: vec2u,\n\n\t\t\t\tglobalId: vec3u\n\t\t\t) -> void {\n\n\t\t\t\tlet rayQueue = &${ params.rayQueue };\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\t\t\t\tlet tileIndexBuffer = &${ params.tileIndexBuffer };\n\n\t\t\t\t// don't overstep the edge of the tile\n\t\t\t\tif ( globalId.x >= tileSize.x || globalId.y >= tileSize.y ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// calculate the pixel index and ensure we are not generating rays outside the texture bounds\n\t\t\t\tlet offset = vec2( tileIndexBuffer[ 0 ] * tileSize.x, tileIndexBuffer[ 1 ] * tileSize.y );\n\t\t\t\tlet indexUV = offset + globalId.xy;\n\t\t\t\tlet targetDimensions = textureDimensions( ${ params.sampleCountTarget } );\n\t\t\t\tif ( indexUV.x >= targetDimensions.x || indexUV.y >= targetDimensions.y ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// calculate the screen uv\n\t\t\t\tlet uv = vec2f( indexUV ) / vec2f( targetDimensions );\n\t\t\t\tlet ndc = uv * 2.0 - vec2f( 1.0 );\n\n\t\t\t\t// check whether ray is already active (added on the queue) and skip it if it is\n\t\t\t\tlet ACTIVE_FLAG = 0xF0000000u;\n\t\t\t\tlet combinedField = textureLoad( ${ params.sampleCountTarget }, indexUV ).r;\n\t\t\t\tlet isActive = ( ACTIVE_FLAG & combinedField ) != 0;\n\t\t\t\tlet samples = ( ( ~ ACTIVE_FLAG ) & combinedField );\n\n\t\t\t\tif ( isActive ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// get the ray index\n\t\t\t\tlet queueCapacity = arrayLength( rayQueue );\n\t\t\t\tlet index = atomicAdd( &queueSizes[ 1 ], 1 ) % queueCapacity;\n\n\t\t\t\tlet pixelIndex = ( indexUV.x << 16 ) | indexUV.y;\n\t\t\t\t${ rngInit }( pixelIndex, seed, 0 );\n\n\t\t\t\t// write the ray data\n\t\t\t\tvar jitter = 2.0 * ${ rand2 }( ${ RNG_INDEX_RAY_JITTER } ) / vec2f( targetDimensions.xy );\n\t\t\t\tvar ray = ${ ndcToCameraRay }( ndc + jitter, cameraToModelMatrix * inverseProjectionMatrix );\n\t\t\t\tray.direction = normalize( ray.direction );\n\n\t\t\t\trayQueue[ index ].origin = ray.origin;\n\t\t\t\trayQueue[ index ].direction = ray.direction;\n\t\t\t\trayQueue[ index ].pixel = indexUV;\n\t\t\t\trayQueue[ index ].throughputColor = vec3f( 1.0 );\n\t\t\t\trayQueue[ index ].currentBounce = 0;\n\t\t\t\trayQueue[ index ].resultColor = vec4f( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\trayQueue[ index ].seed = seed;\n\n\t\t\t\t// write the active params\n\t\t\t\ttextureStore( ${ params.sampleCountTarget }, indexUV, vec4( ACTIVE_FLAG | samples ) );\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { DataTexture, Matrix3, IndirectStorageBufferAttribute, StorageTexture } from 'three/webgpu';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { uniform, texture, sampler, storage, textureStore, globalId } from 'three/tsl';\nimport { rngInit, rand2, RNG_INDEX_ENVIRONMENT_SAMPLE } from '../../nodes/random.wgsl.js';\nimport { queuedRayStruct, queuedHitStruct } from './structs.js';\nimport { proxy, wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\nimport { sampleEnvironmentFn, weightedAlphaBlendFn } from '../../nodes/sampling.wgsl.js';\n\nexport class RayIntersectionKernel extends ComputeKernel {\n\n\tconstructor( ) {\n\n\t\tconst params = {\n\t\t\tbvhData: { value: null },\n\n\t\t\tprevOutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadOnly(),\n\t\t\toutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toWriteOnly(),\n\t\t\tsampleCountTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadWrite(),\n\n\t\t\t// rays\n\t\t\trayQueue: storage( new IndirectStorageBufferAttribute( 1, queuedRayStruct.getLength() ), queuedRayStruct ).toReadOnly(),\n\t\t\thitQueue: storage( new IndirectStorageBufferAttribute( 1, queuedHitStruct.getLength() ), queuedHitStruct ),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ).toAtomic(),\n\n\t\t\t// environment\n\t\t\tenvMap: texture( new DataTexture() ),\n\t\t\tenvMapSampler: sampler( new DataTexture() ),\n\t\t\tenvMapRotation: uniform( new Matrix3() ),\n\t\t\tenvMapIntensity: uniform( 1 ),\n\n\t\t\tbackground: texture( new DataTexture() ),\n\t\t\tbackgroundSampler: sampler( new DataTexture() ),\n\t\t\tbackgroundRotation: uniform( new Matrix3() ),\n\t\t\tbackgroundIntensity: uniform( 1 ),\n\t\t\tbackgroundBlurriness: uniform( 0 ),\n\n\t\t\tglobalId: globalId,\n\t\t};\n\n\t\tconst raycastOutput = proxy( 'bvhData.value.fns.raycastFirstHit.outputType', params );\n\t\tconst raycastFirstHitFn = proxy( 'bvhData.value.fns.raycastFirstHit', params );\n\n\t\tconst fn = wgslTagFn /* wgsl */`\n\n\t\t\tfn compute(\n\t\t\t\t// environment\n\t\t\t\tenvMap: texture_2d<f32>,\n\t\t\t\tenvMapSampler: sampler,\n\t\t\t\tenvMapRotation: mat3x3f,\n\t\t\t\tenvMapIntensity: f32,\n\n\t\t\t\tbackground: texture_2d<f32>,\n\t\t\t\tbackgroundSampler: sampler,\n\t\t\t\tbackgroundRotation: mat3x3f,\n\t\t\t\tbackgroundIntensity: f32,\n\t\t\t\tbackgroundBlurriness: f32,\n\n\t\t\t\tglobalId: vec3u\n\t\t\t) -> void {\n\n\t\t\t\tlet rayQueue = &${ params.rayQueue };\n\t\t\t\tlet hitQueue = &${ params.hitQueue };\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\n\t\t\t\tlet envInfo = EnvironmentInfo(\n\t\t\t\t\tenvMapRotation,\n\t\t\t\t\tenvMapIntensity,\n\t\t\t\t\t0.0 // blur,\n\t\t\t\t);\n\n\t\t\t\tlet backgroundInfo = EnvironmentInfo(\n\t\t\t\t\tbackgroundRotation,\n\t\t\t\t\tbackgroundIntensity,\n\t\t\t\t\tbackgroundBlurriness,\n\t\t\t\t);\n\n\t\t\t\t// skip any rays invocations beyond the ray count\n\t\t\t\tlet queueCapacity = arrayLength( rayQueue );\n\t\t\t\tlet rayIndex = ( globalId.x + atomicLoad( &queueSizes[ 0 ] ) );\n\t\t\t\tif ( rayIndex >= atomicLoad( &queueSizes[ 1 ] ) ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// get the ray info\n\t\t\t\tlet ACTIVE_FLAG = 0xF0000000u;\n\t\t\t\tlet input = rayQueue[ rayIndex % queueCapacity ];\n\t\t\t\tlet indexUV = input.pixel;\n\n\t\t\t\tlet pixelIndex = ( indexUV.x << 16 ) | indexUV.y;\n\t\t\t\t${ rngInit }( pixelIndex, input.seed, input.currentBounce );\n\n\t\t\t\t// run intersection\n\t\t\t\tlet ray = Ray( input.origin, input.direction );\n\t\t\t\tvar hitResult: ${ raycastOutput };\n\t\t\t\tif ( ${ raycastFirstHitFn }( ray, &hitResult ) ) {\n\n\t\t\t\t\t// TODO: we process all of these materials immediately to push to the ray queue\n\t\t\t\t\tlet index = atomicAdd( &queueSizes[ 3 ], 1 );\n\t\t\t\t\thitQueue[ index ].view = - input.direction;\n\t\t\t\t\thitQueue[ index ].indices = hitResult.indices.xyz;\n\t\t\t\t\thitQueue[ index ].barycoord = hitResult.barycoord.xy;\n\t\t\t\t\thitQueue[ index ].normal = hitResult.normal.xyz;\n\t\t\t\t\thitQueue[ index ].side = hitResult.side;\n\t\t\t\t\thitQueue[ index ].pixel_x = indexUV.x;\n\t\t\t\t\thitQueue[ index ].pixel_y = indexUV.y;\n\t\t\t\t\thitQueue[ index ].objectIndex = hitResult.objectIndex;\n\t\t\t\t\thitQueue[ index ].throughputColor = input.throughputColor;\n\t\t\t\t\thitQueue[ index ].currentBounce = input.currentBounce;\n\t\t\t\t\thitQueue[ index ].resultColor = input.resultColor;\n\t\t\t\t\thitQueue[ index ].seed = input.seed;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet rng = ${ rand2 }( ${ RNG_INDEX_ENVIRONMENT_SAMPLE } );\n\t\t\t\t\tvar resultColor = input.resultColor;\n\t\t\t\t\tif ( input.currentBounce > 0u ) {\n\n\t\t\t\t\t\tresultColor += ${ sampleEnvironmentFn }( envMap, envMapSampler, envInfo, input.direction, rng ) * vec4f( input.throughputColor, 0.0 );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tresultColor = ${ sampleEnvironmentFn }( background, backgroundSampler, backgroundInfo, input.direction, rng );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet sampleCount = ( textureLoad( ${ params.sampleCountTarget }, indexUV ).r & ( ~ ACTIVE_FLAG ) ) + 1;\n\t\t\t\t\tlet prevColor = textureLoad( ${ params.prevOutputTarget }, indexUV );\n\t\t\t\t\tlet blendedColor = ${ weightedAlphaBlendFn }( prevColor, resultColor, 1.0 / f32( sampleCount ) );\n\t\t\t\t\ttextureStore( ${ params.sampleCountTarget }, indexUV, vec4( sampleCount ) );\n\t\t\t\t\ttextureStore( ${ params.outputTarget }, indexUV, blendedColor );\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { IndirectStorageBufferAttribute } from 'three/webgpu';\nimport { uniform, storage } from 'three/tsl';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\n\nexport class UpdateRayQueueParamsKernel extends ComputeKernel {\n\n\tconstructor() {\n\n\t\tconst params = {\n\t\t\tprocessed: uniform( 0 ),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ),\n\t\t};\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\t\t\tfn compute( processed: u32 ) -> void {\n\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\t\t\t var queueSize = queueSizes[ 1 ] - queueSizes[ 0 ];\n\t\t\t\tif ( processed > queueSize ) {\n\n\t\t\t\t\tqueueSizes[ 0 ] = queueSizes[ 1 ];\n\n\t\t\t\t} else {\n\n\t\t\t\t\tqueueSizes[ 0 ] = queueSizes[ 0 ] + processed;\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { IndirectStorageBufferAttribute } from 'three/webgpu';\nimport { ComputeKernel } from './ComputeKernel.js';\nimport { storage, globalId } from 'three/tsl';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\nexport class ZeroOutBufferKernel extends ComputeKernel {\n\n\tconstructor( options = {} ) {\n\n\t\tconst {\n\t\t\ttype = 'u32',\n\t\t} = options;\n\n\t\tconst params = {\n\t\t\tglobalId: globalId,\n\t\t\toutputTarget: storage( new IndirectStorageBufferAttribute( 1, 1 ), type ),\n\t\t};\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\t\t\tfn compute( globalId: vec3u ) -> void {\n\n\t\t\t\t${ params.outputTarget }[ globalId.x ] = 0;\n\n\t\t\t}\n\t\t`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( {\n\t\t\ttarget: params.outputTarget,\n\t\t} );\n\n\t}\n\n}\n","import { IndirectStorageBufferAttribute, StorageTexture, DataTexture } from 'three/webgpu';\nimport { ComputeKernel } from '../ComputeKernel.js';\nimport { uniform, storage, textureStore, globalId, texture, sampler } from 'three/tsl';\nimport { queuedRayStruct, queuedHitStruct } from './structs.js';\nimport { proxy, proxyFn, wgslTagFn } from '../../lib/three-mesh-bvh/index.js';\nimport { weightedAlphaBlendFn } from '../../nodes/sampling.wgsl.js';\nimport { isTerminatingScatterFunc } from '../../nodes/utils.wgsl.js';\nimport { rngInit } from '../../nodes/random.wgsl.js';\n\nexport class ProcessHitsKernel extends ComputeKernel {\n\n\tconstructor( ) {\n\n\t\tconst params = {\n\t\t\tbvhData: { value: null },\n\t\t\tmaterial: { value: null },\n\n\t\t\tprevOutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadOnly(),\n\t\t\toutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toWriteOnly(),\n\t\t\tsampleCountTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadWrite(),\n\n\t\t\t// settings\n\t\t\tsmoothNormals: uniform( 1 ),\n\t\t\tbounces: uniform( 1 ),\n\n\t\t\t// rays\n\t\t\trayQueue: storage( new IndirectStorageBufferAttribute( 1, queuedRayStruct.getLength() ), queuedRayStruct ),\n\t\t\thitQueue: storage( new IndirectStorageBufferAttribute( 1, queuedHitStruct.getLength() ), queuedHitStruct ),\n\t\t\tqueueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ).toAtomic(),\n\n\t\t\ttextures: texture( new DataTexture() ),\n\t\t\ttextureSampler: sampler( new DataTexture() ),\n\n\t\t\tglobalId: globalId,\n\t\t};\n\n\t\tconst sampleTrianglePointFn = proxyFn( 'bvhData.value.fns.sampleTrianglePoint', params );\n\t\tconst getSurfaceRecordFn = proxyFn( 'bvhData.value.fns.getSurfaceRecord', params );\n\t\tconst bsdfSampleFn = proxyFn( 'material.value.bsdfSample', params );\n\n\t\tconst fn = wgslTagFn/* wgsl */`\n\n\t\t\tfn compute(\n\t\t\t\t// settings\n\t\t\t\tsmoothNormals: u32,\n\t\t\t\tbounces: u32,\n\n\t\t\t\tglobalId: vec3u\n\t\t\t) -> void {\n\n\t\t\t\tlet rayQueue = &${ params.rayQueue };\n\t\t\t\tlet hitQueue = &${ params.hitQueue };\n\t\t\t\tlet queueSizes = &${ params.queueSizes };\n\n\t\t\t\tlet materials = &${ proxy( 'bvhData.value.storage.materials', params ) };\n\t\t\t\tlet transforms = &${ proxy( 'bvhData.value.storage.transforms', params ) };\n\n\t\t\t\t// skip any rays invocations beyond the ray count\n\t\t\t\tlet hitQueueCapacity = arrayLength( hitQueue );\n\t\t\t\tlet hitIndex = ( globalId.x + atomicLoad( &queueSizes[ 2 ] ) );\n\t\t\t\tif ( hitIndex >= atomicLoad( &queueSizes[ 3 ] ) ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// get the ray info\n\t\t\t\tlet ACTIVE_FLAG = 0xF0000000u;\n\t\t\t\tlet input = hitQueue[ hitIndex ];\n\t\t\t\tlet indexUV = vec2u( input.pixel_x, input.pixel_y );\n\n\t\t\t\tlet pixelIndex = ( indexUV.x << 16 ) | indexUV.y;\n\t\t\t\t${ rngInit }( pixelIndex, input.seed, input.currentBounce );\n\n\t\t\t\tlet object = transforms[ input.objectIndex ];\n\t\t\t\tvar material = materials[ object.materialIndex ];\n\n\t\t\t\t// apply per-object colors\n\t\t\t\tmaterial.color *= object.color.rgb;\n\t\t\t\tmaterial.opacity *= object.color.a;\n\n\t\t\t\tlet barycoord = vec3( input.barycoord, 1.0 - input.barycoord.x - input.barycoord.y );\n\t\t\t\tvar vertexData = ${ sampleTrianglePointFn }( barycoord, input.indices.xyz );\n\t\t\t\tvertexData.normal = normalize( transpose( object.inverseMatrixWorld ) * vertexData.normal );\n\t\t\t\tvertexData.position = object.matrixWorld * vertexData.position;\n\n\t\t\t\tlet surface = ${ getSurfaceRecordFn }( material, vertexData, input.side, input.normal );\n\n\t\t\t\tlet scatterRec = ${ bsdfSampleFn }( input.view, surface );\n\n\t\t\t\tlet resultColor = input.resultColor + vec4f( input.throughputColor * surface.emission, 0.0 );\n\n\t\t\t\tlet isTerminated = input.currentBounce >= bounces || ${ isTerminatingScatterFunc }( scatterRec );\n\n\t\t\t\tif ( isTerminated ) {\n\n\t\t\t\t\t// terminate ray, write color\n\t\t\t\t\tlet sampleCount = ( textureLoad( ${ params.sampleCountTarget }, indexUV ).r & ( ~ ACTIVE_FLAG ) ) + 1;\n\t\t\t\t\tlet prevColor = textureLoad( ${ params.prevOutputTarget }, indexUV );\n\t\t\t\t\tlet blendedColor = ${ weightedAlphaBlendFn }( prevColor, resultColor, 1.0 / f32( sampleCount ) );\n\t\t\t\t\ttextureStore( ${ params.sampleCountTarget }, indexUV, vec4( sampleCount ) );\n\t\t\t\t\ttextureStore( ${ params.outputTarget }, indexUV, blendedColor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet rayQueueCapacity = arrayLength( rayQueue );\n\t\t\t\t\tlet index = atomicAdd( &queueSizes[ 1 ], 1 ) % rayQueueCapacity;\n\t\t\t\t\trayQueue[ index ].origin = vertexData.position.xyz;\n\t\t\t\t\trayQueue[ index ].direction = scatterRec.direction;\n\t\t\t\t\trayQueue[ index ].pixel = indexUV;\n\t\t\t\t\trayQueue[ index ].throughputColor = input.throughputColor * scatterRec.color / scatterRec.pdf;\n\t\t\t\t\trayQueue[ index ].currentBounce = input.currentBounce + 1;\n\t\t\t\t\trayQueue[ index ].resultColor = resultColor;\n\t\t\t\t\trayQueue[ index ].seed = input.seed;\n\n\t\t\t\t}\n\n\t\t\t}`;\n\n\t\tsuper( fn( params ) );\n\n\t\tthis.defineUniformAccessors( params );\n\n\t}\n\n}\n","import { Matrix4, IndirectStorageBufferAttribute, Vector2 } from 'three/webgpu';\nimport { PrimeRayGenerationDispatchKernel } from './compute/wavefront/PrimeRayGenerationDispatchKernel.js';\nimport { RayGenerationKernel } from './compute/wavefront/RayGenerationKernel.js';\nimport { RayIntersectionKernel } from './compute/wavefront/RayIntersectionKernel.js';\nimport { UpdateRayQueueParamsKernel } from './compute/wavefront/UpdateRayQueueParamsKernel.js';\nimport { ZeroOutBufferKernel } from './compute/ZeroOutBufferKernel.js';\nimport { ProcessHitsKernel } from './compute/wavefront/ProcessHitsKernel.js';\nimport { EquirectHdrInfoUniform } from '../uniforms/EquirectHdrInfoUniform.js';\nimport { queuedHitStruct, queuedRayStruct } from './compute/wavefront/structs.js';\nimport { PathTracerBackend } from './PathTracerBackend.js';\n\n// set the buffers to the max possible size supported by default (128MB)\n// TODO: this can be increased based on platform.\nconst RAYS_TO_PROCESS = 250000;\nconst MAX_BUFFER_SIZE = 134217728;\nconst MAX_RAY_COUNT = Math.floor( MAX_BUFFER_SIZE / ( queuedRayStruct.getLength() * 4 ) );\nconst MAX_HIT_COUNT = Math.floor( MAX_BUFFER_SIZE / ( queuedHitStruct.getLength() * 4 ) );\n\nexport class WaveFrontPathTracer extends PathTracerBackend {\n\n\tconstructor( renderer ) {\n\n\t\tsuper( renderer );\n\n\t\t// options\n\t\tthis.tiles = new Vector2( 3, 3 );\n\t\tthis.envInfo = new EquirectHdrInfoUniform();\n\n\t\t// queues\n\t\tthis.rayQueue = new IndirectStorageBufferAttribute( MAX_RAY_COUNT, queuedRayStruct.getLength() );\n\t\tthis.rayQueue.name = 'Ray Queue';\n\n\t\tthis.hitQueue = new IndirectStorageBufferAttribute( MAX_HIT_COUNT, queuedHitStruct.getLength() );\n\t\tthis.hitQueue.name = 'Hit Queue';\n\n\t\t// [0] ray head, [1] ray count, [2] hit head, [3] hit count\n\t\tthis.queueSizes = new IndirectStorageBufferAttribute( 4, 1 );\n\t\tthis.queueSizes.name = 'Queue Sizes';\n\n\t\t// dispatches\n\t\tthis.tileIndexBuffer = new IndirectStorageBufferAttribute( 2, 1 );\n\t\tthis.rayGenerationDispatch = new IndirectStorageBufferAttribute( 3, 1 );\n\t\tthis.hitProcessDispatch = new IndirectStorageBufferAttribute( 3, 1 );\n\n\t\t// kernels\n\t\tthis.primeRayGenerationDispatchKernel = new PrimeRayGenerationDispatchKernel().setWorkgroupSize( 1, 1, 1 );\n\t\tthis.enqueueRaysKernel = new RayGenerationKernel( ).setWorkgroupSize( 8, 8, 1 );\n\t\tthis.rayIntersectionKernel = new RayIntersectionKernel( ).setWorkgroupSize( 64, 1, 1 );\n\t\tthis.updateRayQueueParamsKernel = new UpdateRayQueueParamsKernel().setWorkgroupSize( 1, 1, 1 );\n\t\tthis.hitProcessKernel = new ProcessHitsKernel( ).setWorkgroupSize( 64, 1, 1 );\n\n\t\t// clear kernels\n\t\tthis.zeroDispatchKernel = new ZeroOutBufferKernel().setWorkgroupSize( 1, 1, 1 );\n\n\t\t// later\n\t\tthis.volumeKernel = null;\n\t\tthis.lightConnectionKernel = null;\n\n\t}\n\n\tsetBVHData( bvhData ) {\n\n\t\tthis.rayIntersectionKernel.bvhData = bvhData;\n\t\tthis.rayIntersectionKernel.needsUpdate = true;\n\n\t\tthis.hitProcessKernel.bvhData = bvhData;\n\t\tthis.hitProcessKernel.needsUpdate = true;\n\n\t\tthis.reset();\n\n\t}\n\n\tsetMaterial( material ) {\n\n\t\tthis.hitProcessKernel.material = material.getData();\n\t\tthis.hitProcessKernel.needsUpdate = true;\n\t\tthis.reset();\n\n\t}\n\n\tsetEnvironment(\n\t\tenvMap,\n\t\tenvMapIntensity,\n\t\tenvMapRotation,\n\n\t\tbackground,\n\t\tbackgroundIntensity,\n\t\tbackgroundRotation,\n\t\tbackgroundBlurriness,\n\t) {\n\n\t\tconst kernel = this.rayIntersectionKernel;\n\n\t\tif ( kernel.background.isTexture ) {\n\n\t\t\tkernel.background.dispose();\n\n\t\t}\n\n\t\tif ( envMap !== null ) {\n\n\t\t\tthis.envInfo.updateFrom( envMap );\n\t\t\tkernel.envMap = this.envInfo.map;\n\t\t\tkernel.kernel.computeNode.parameters.envMapSampler.node.value = this.envInfo.map;\n\n\t\t}\n\n\t\tconst rotationMatrix = new Matrix4().makeRotationFromEuler( envMapRotation ).invert();\n\t\tkernel.envMapRotation.setFromMatrix4( rotationMatrix );\n\t\tkernel.envMapIntensity = envMapIntensity;\n\n\t\tkernel.background = background;\n\t\tkernel.kernel.computeNode.parameters.backgroundSampler.node.value = background;\n\t\trotationMatrix.makeRotationFromEuler( backgroundRotation ).invert();\n\t\tkernel.backgroundRotation.setFromMatrix4( rotationMatrix );\n\t\tkernel.backgroundIntensity = backgroundIntensity;\n\t\tkernel.backgroundBlurriness = backgroundBlurriness;\n\n\t}\n\n\tsetTiles( tiles ) {\n\n\t\tthis.tiles.copy( tiles );\n\n\t}\n\n\tgetTileSize( target ) {\n\n\t\tthis.getSize( target ).divide( this.tiles ).ceil();\n\n\t\treturn target;\n\n\t}\n\n\tdispose() {\n\n\t\tsuper.dispose();\n\n\t\t// TODO: dispose of all buffers\n\t\tthis.envInfo.dispose();\n\n\t}\n\n\treset() {\n\n\t\tconst {\n\t\t\trenderer,\n\n\t\t\tsampleCountClearKernel,\n\t\t\tzeroDispatchKernel,\n\n\t\t\tsampleCountTarget,\n\n\t\t\thitProcessDispatch,\n\t\t\trayGenerationDispatch,\n\t\t\tqueueSizes,\n\t\t\ttileIndexBuffer,\n\t\t} = this;\n\n\t\tif ( ! renderer.initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tsuper.reset();\n\n\t\tthis.enqueueRaysKernel.seed = 0;\n\n\t\tconst { width, height } = sampleCountTarget;\n\t\tconst dispatchSize = sampleCountClearKernel.getDispatchSize( width, height );\n\n\t\t// clear buffers\n\t\tsampleCountClearKernel.target = sampleCountTarget;\n\t\trenderer.compute( sampleCountClearKernel.kernel, dispatchSize );\n\n\t\t// clear queues\n\t\t// TODO: why do we need to se the work group size here?\n\t\tzeroDispatchKernel.target = queueSizes;\n\t\trenderer.compute( zeroDispatchKernel.kernel, [ queueSizes.count ] );\n\n\t\t// clear dispatch sizes\n\t\tzeroDispatchKernel.target = hitProcessDispatch;\n\t\trenderer.compute( zeroDispatchKernel.kernel, [ hitProcessDispatch.count ] );\n\n\t\tzeroDispatchKernel.target = rayGenerationDispatch;\n\t\trenderer.compute( zeroDispatchKernel.kernel, [ rayGenerationDispatch.count ] );\n\n\t\tzeroDispatchKernel.target = tileIndexBuffer;\n\t\trenderer.compute( zeroDispatchKernel.kernel, [ tileIndexBuffer.count ] );\n\n\t}\n\n\t*createRenderTask() {\n\n\t\tconst {\n\t\t\trenderer,\n\t\t\tcamera,\n\t\t\tbounces,\n\n\t\t\ttiles,\n\t\t\tsampleCountTarget,\n\n\t\t\trayQueue,\n\t\t\thitQueue,\n\t\t\tqueueSizes,\n\t\t\trayGenerationDispatch,\n\t\t\t// hitProcessDispatch,\n\t\t\ttileIndexBuffer,\n\n\t\t\tprimeRayGenerationDispatchKernel,\n\t\t\tenqueueRaysKernel,\n\t\t\trayIntersectionKernel,\n\t\t\tupdateRayQueueParamsKernel,\n\t\t\thitProcessKernel,\n\n\t\t\tlowResMode\n\t\t} = this;\n\n\t\tcamera.updateMatrixWorld();\n\n\t\tprimeRayGenerationDispatchKernel.tileOffset = 0;\n\n\t\tconst tileSize = new Vector2();\n\t\tconst samplesPerIteration = RAYS_TO_PROCESS / ( sampleCountTarget.width * sampleCountTarget.height * bounces );\n\t\tconst iter = lowResMode ? 5 : 1;\n\t\tlet samples = 0;\n\n\t\twhile ( true ) {\n\n\t\t\tfor ( let i = 0; i < iter; i ++ ) {\n\n\t\t\t\tthis.getTileSize( tileSize );\n\n\t\t\t\t// Swap targets to support devices without <rgba32float, read_write> textures\n\t\t\t\t// Copy latest data to a new outputTarget to keep the appearance\n\t\t\t\trenderer.copyTextureToTexture( this.outputTarget, this.prevOutputTarget );\n\t\t\t\t[ this.outputTarget, this.prevOutputTarget ] = [ this.prevOutputTarget, this.outputTarget ];\n\t\t\t\trayIntersectionKernel.prevOutputTarget = this.prevOutputTarget;\n\t\t\t\trayIntersectionKernel.outputTarget = this.outputTarget;\n\t\t\t\thitProcessKernel.prevOutputTarget = this.prevOutputTarget;\n\t\t\t\thitProcessKernel.outputTarget = this.outputTarget;\n\n\t\t\t\t// Step 1: Top up the ray queue\n\t\t\t\t// set up the ray prime kernel\n\t\t\t\tprimeRayGenerationDispatchKernel.rayWorkGroupSize.set( 8, 8, 1 );\n\t\t\t\tprimeRayGenerationDispatchKernel.tileCount.copy( tiles );\n\t\t\t\tprimeRayGenerationDispatchKernel.tileSize.copy( tileSize );\n\t\t\t\tprimeRayGenerationDispatchKernel.rayQueue = rayQueue;\n\t\t\t\tprimeRayGenerationDispatchKernel.queueSizes = queueSizes;\n\t\t\t\tprimeRayGenerationDispatchKernel.outputTileIndex = tileIndexBuffer;\n\t\t\t\tprimeRayGenerationDispatchKernel.outputDispatch = rayGenerationDispatch;\n\n\t\t\t\t// set up the ray generation kernel\n\t\t\t\tenqueueRaysKernel.seed ++;\n\t\t\t\tenqueueRaysKernel.cameraToModelMatrix.copy( camera.matrixWorld );\n\t\t\t\tenqueueRaysKernel.inverseProjectionMatrix.copy( camera.projectionMatrixInverse );\n\t\t\t\tenqueueRaysKernel.tileIndexBuffer = tileIndexBuffer;\n\t\t\t\tenqueueRaysKernel.tileSize.copy( tileSize );\n\t\t\t\tenqueueRaysKernel.rayQueue = rayQueue;\n\t\t\t\tenqueueRaysKernel.queueSizes = queueSizes;\n\t\t\t\tenqueueRaysKernel.sampleCountTarget = sampleCountTarget;\n\n\t\t\t\tfor ( let i = 0; i < tiles.x * tiles.y; i ++ ) {\n\n\t\t\t\t\t// TODO: skip rays that have converged, have reach max samples\n\t\t\t\t\trenderer.compute( primeRayGenerationDispatchKernel.kernel, [ 1, 1, 1 ] );\n\t\t\t\t\trenderer.compute( enqueueRaysKernel.kernel, rayGenerationDispatch );\n\t\t\t\t\tprimeRayGenerationDispatchKernel.tileOffset = 1;\n\n\t\t\t\t}\n\n\t\t\t\t// Step 2: run intersections, add color for terminated rays, add material handling to a dedicated queue\n\t\t\t\t// TODO: setting dispatch size to 10000 is causing failures / missed rays\n\t\t\t\tconst intersectDispatch = rayIntersectionKernel.getDispatchSize( RAYS_TO_PROCESS, 1, 1 );\n\t\t\t\trayIntersectionKernel.sampleCountTarget = sampleCountTarget;\n\t\t\t\trayIntersectionKernel.rayQueue = rayQueue;\n\t\t\t\trayIntersectionKernel.queueSizes = queueSizes;\n\t\t\t\trayIntersectionKernel.hitQueue = hitQueue;\n\t\t\t\trenderer.compute( rayIntersectionKernel.kernel, intersectDispatch );\n\n\t\t\t\t// mark the rays as consumed\n\t\t\t\tconst processed = intersectDispatch[ 0 ] * rayIntersectionKernel.workgroupSize[ 0 ];\n\t\t\t\tupdateRayQueueParamsKernel.processed = processed;\n\t\t\t\tupdateRayQueueParamsKernel.queueSizes = queueSizes;\n\t\t\t\trenderer.compute( updateRayQueueParamsKernel.kernel, [ 1, 1, 1 ] );\n\n\t\t\t\t// TODO: we should use an indirect dispatch here to only kick off the number of threads\n\t\t\t\t// as needed to iterate over all the fields\n\t\t\t\t// Step 3: attenuate ray color, scatter, run russian roulette\n\t\t\t\thitProcessKernel.sampleCountTarget = sampleCountTarget;\n\t\t\t\thitProcessKernel.bounces = bounces;\n\t\t\t\thitProcessKernel.rayQueue = rayQueue;\n\t\t\t\thitProcessKernel.queueSizes = queueSizes;\n\t\t\t\thitProcessKernel.hitQueue = hitQueue;\n\t\t\t\trenderer.compute( hitProcessKernel.kernel, hitProcessKernel.getDispatchSize( processed, 1, 1 ) );\n\t\t\t\t// Note: hit queue size ([2] and [3]) is reset at the top of the next iteration by PrimeRayGenerationDispatchKernel\n\n\t\t\t\t// Step 4: connect to lights\n\t\t\t\t// TODO\n\n\t\t\t\t// Future\n\t\t\t\t// - track variance to skip rays\n\t\t\t\t// - switch to rays pushing themselves onto the queue when terminating to avoid tiles once enough pixels have completed\n\t\t\t\t// - separate \"volume\" step?\n\t\t\t\t// - allow for simultaneous writes by queue pixel writes, sorting, and blending them in a single thread\n\n\t\t\t\tsamples += samplesPerIteration;\n\t\t\t\tthis.samples = Math.floor( samples );\n\n\t\t\t}\n\n\t\t\tyield;\n\n\t\t}\n\n\t}\n\n}\n","export const util_functions = /* glsl */`\n\n\t// TODO: possibly this should be renamed something related to material or path tracing logic\n\n\t#ifndef RAY_OFFSET\n\t#define RAY_OFFSET 1e-4\n\t#endif\n\n\t// adjust the hit point by the surface normal by a factor of some offset and the\n\t// maximum component-wise value of the current point to accommodate floating point\n\t// error as values increase.\n\tvec3 stepRayOrigin( vec3 rayOrigin, vec3 rayDirection, vec3 offset, float dist ) {\n\n\t\tvec3 point = rayOrigin + rayDirection * dist;\n\t\tvec3 absPoint = abs( point );\n\t\tfloat maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );\n\t\treturn point + offset * ( maxPoint + 1.0 ) * RAY_OFFSET;\n\n\t}\n\n\t// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation\n\tvec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {\n\n\t\tvec3 ot = - log( attColor ) / attDist;\n\t\treturn exp( - ot * dist );\n\n\t}\n\n\tvec3 getHalfVector( vec3 wi, vec3 wo, float eta ) {\n\n\t\t// get the half vector - assuming if the light incident vector is on the other side\n\t\t// of the that it's transmissive.\n\t\tvec3 h;\n\t\tif ( wi.z > 0.0 ) {\n\n\t\t\th = normalize( wi + wo );\n\n\t\t} else {\n\n\t\t\t// Scale by the ior ratio to retrieve the appropriate half vector\n\t\t\t// From Section 2.2 on computing the transmission half vector:\n\t\t\t// https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf\n\t\t\th = normalize( wi + wo * eta );\n\n\t\t}\n\n\t\th *= sign( h.z );\n\t\treturn h;\n\n\t}\n\n\tvec3 getHalfVector( vec3 a, vec3 b ) {\n\n\t\treturn normalize( a + b );\n\n\t}\n\n\t// The discrepancy between interpolated surface normal and geometry normal can cause issues when a ray\n\t// is cast that is on the top side of the geometry normal plane but below the surface normal plane. If\n\t// we find a ray like that we ignore it to avoid artifacts.\n\t// This function returns if the direction is on the same side of both planes.\n\tbool isDirectionValid( vec3 direction, vec3 surfaceNormal, vec3 geometryNormal ) {\n\n\t\tbool aboveSurfaceNormal = dot( direction, surfaceNormal ) > 0.0;\n\t\tbool aboveGeometryNormal = dot( direction, geometryNormal ) > 0.0;\n\t\treturn aboveSurfaceNormal == aboveGeometryNormal;\n\n\t}\n\n\t// ray sampling x and z are swapped to align with expected background view\n\tvec2 equirectDirectionToUv( vec3 direction ) {\n\n\t\t// from Spherical.setFromCartesianCoords\n\t\tvec2 uv = vec2( atan( direction.z, direction.x ), acos( direction.y ) );\n\t\tuv /= vec2( 2.0 * PI, PI );\n\n\t\t// apply adjustments to get values in range [0, 1] and y right side up\n\t\tuv.x += 0.5;\n\t\tuv.y = 1.0 - uv.y;\n\t\treturn uv;\n\n\t}\n\n\tvec3 equirectUvToDirection( vec2 uv ) {\n\n\t\t// undo above adjustments\n\t\tuv.x -= 0.5;\n\t\tuv.y = 1.0 - uv.y;\n\n\t\t// from Vector3.setFromSphericalCoords\n\t\tfloat theta = uv.x * 2.0 * PI;\n\t\tfloat phi = uv.y * PI;\n\n\t\tfloat sinPhi = sin( phi );\n\n\t\treturn vec3( sinPhi * cos( theta ), cos( phi ), sinPhi * sin( theta ) );\n\n\t}\n\n\t// power heuristic for multiple importance sampling\n\tfloat misHeuristic( float a, float b ) {\n\n\t\tfloat aa = a * a;\n\t\tfloat bb = b * b;\n\t\treturn aa / ( aa + bb );\n\n\t}\n\n\t// tentFilter from Peter Shirley's 'Realistic Ray Tracing (2nd Edition)' book, pg. 60\n\t// erichlof/THREE.js-PathTracing-Renderer/\n\tfloat tentFilter( float x ) {\n\n\t\treturn x < 0.5 ? sqrt( 2.0 * x ) - 1.0 : 1.0 - sqrt( 2.0 - ( 2.0 * x ) );\n\n\t}\n`;\n","import {\n\tDataTexture,\n\tDataUtils,\n\tEquirectangularReflectionMapping,\n\tFloatType,\n\tHalfFloatType,\n\tLinearFilter,\n\tLinearMipMapLinearFilter,\n\tRGBAFormat,\n\tRepeatWrapping,\n\tShaderMaterial,\n\tWebGLRenderTarget,\n} from 'three';\nimport { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';\nimport * as CommonGLSL from '../shader/common/index.js';\n\nclass CubeToEquirectMaterial extends ShaderMaterial {\n\n\tconstructor() {\n\n\t\tsuper( {\n\n\t\t\tuniforms: {\n\n\t\t\t\tenvMap: { value: null },\n\t\t\t\tflipEnvMap: { value: - 1 },\n\n\t\t\t},\n\n\t\t\tvertexShader: /* glsl */`\n\t\t\t\tvarying vec2 vUv;\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvUv = uv;\n\t\t\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t\t\t}`,\n\n\t\t\tfragmentShader: /* glsl */`\n\t\t\t\t#define ENVMAP_TYPE_CUBE_UV\n\n\t\t\t\tuniform samplerCube envMap;\n\t\t\t\tuniform float flipEnvMap;\n\t\t\t\tvarying vec2 vUv;\n\n\t\t\t\t#include <common>\n\t\t\t\t#include <cube_uv_reflection_fragment>\n\n\t\t\t\t${ CommonGLSL.util_functions }\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 rayDirection = equirectUvToDirection( vUv );\n\t\t\t\t\trayDirection.x *= flipEnvMap;\n\t\t\t\t\tgl_FragColor = textureCube( envMap, rayDirection );\n\n\t\t\t\t}`\n\t\t} );\n\n\t\tthis.depthWrite = false;\n\t\tthis.depthTest = false;\n\n\t}\n\n}\n\nexport class CubeToEquirectGenerator {\n\n\tconstructor( renderer ) {\n\n\t\tthis._renderer = renderer;\n\t\tthis._quad = new FullScreenQuad( new CubeToEquirectMaterial() );\n\n\t}\n\n\tgenerate( source, width = null, height = null ) {\n\n\t\tif ( ! source.isCubeTexture ) {\n\n\t\t\tthrow new Error( 'CubeToEquirectMaterial: Source can only be cube textures.' );\n\n\t\t}\n\n\t\tconst image = source.images[ 0 ];\n\t\tconst renderer = this._renderer;\n\t\tconst quad = this._quad;\n\n\t\t// determine the dimensions if not provided\n\t\tif ( width === null ) {\n\n\t\t\twidth = 4 * image.height;\n\n\t\t}\n\n\t\tif ( height === null ) {\n\n\t\t\theight = 2 * image.height;\n\n\t\t}\n\n\t\tconst target = new WebGLRenderTarget( width, height, {\n\t\t\ttype: FloatType,\n\t\t\tcolorSpace: image.colorSpace,\n\t\t} );\n\n\t\t// prep the cube map data\n\t\tconst imageHeight = image.height;\n\t\tconst maxMip = Math.log2( imageHeight ) - 2;\n\t\tconst texelHeight = 1.0 / imageHeight;\n\t\tconst texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );\n\n\t\tquad.material.defines.CUBEUV_MAX_MIP = `${ maxMip }.0`;\n\t\tquad.material.defines.CUBEUV_TEXEL_WIDTH = texelWidth;\n\t\tquad.material.defines.CUBEUV_TEXEL_HEIGHT = texelHeight;\n\t\tquad.material.uniforms.envMap.value = source;\n\t\tquad.material.uniforms.flipEnvMap.value = source.isRenderTargetTexture ? 1 : - 1;\n\t\tquad.material.needsUpdate = true;\n\n\t\t// save state and render the contents\n\t\tconst currentTarget = renderer.getRenderTarget();\n\t\tconst currentAutoClear = renderer.autoClear;\n\t\trenderer.autoClear = true;\n\t\trenderer.setRenderTarget( target );\n\t\tquad.render( renderer );\n\t\trenderer.setRenderTarget( currentTarget );\n\t\trenderer.autoClear = currentAutoClear;\n\n\t\t// read the data back\n\t\tconst buffer = new Uint16Array( width * height * 4 );\n\t\tconst readBuffer = new Float32Array( width * height * 4 );\n\t\trenderer.readRenderTargetPixels( target, 0, 0, width, height, readBuffer );\n\t\ttarget.dispose();\n\n\t\tfor ( let i = 0, l = readBuffer.length; i < l; i ++ ) {\n\n\t\t\tbuffer[ i ] = DataUtils.toHalfFloat( readBuffer[ i ] );\n\n\t\t}\n\n\t\t// produce the data texture\n\t\tconst result = new DataTexture( buffer, width, height, RGBAFormat, HalfFloatType );\n\t\tresult.minFilter = LinearMipMapLinearFilter;\n\t\tresult.magFilter = LinearFilter;\n\t\tresult.wrapS = RepeatWrapping;\n\t\tresult.wrapT = RepeatWrapping;\n\t\tresult.mapping = EquirectangularReflectionMapping;\n\t\tresult.needsUpdate = true;\n\n\t\treturn result;\n\n\t}\n\n\tdispose() {\n\n\t\tthis._quad.dispose();\n\n\t}\n\n}\n","function uuidSort( a, b ) {\n\n\tif ( a.uuid < b.uuid ) return 1;\n\tif ( a.uuid > b.uuid ) return - 1;\n\treturn 0;\n\n}\n\n// we must hash the texture to determine uniqueness using the encoding, as well, because the\n// when rendering each texture to the texture array they must have a consistent color space.\nexport function getTextureHash( t ) {\n\n\treturn `${ t.source.uuid }:${ t.colorSpace }`;\n\n}\n\n// reduce the set of textures to just those with a unique source while retaining\n// the order of the textures.\nfunction reduceTexturesToUniqueSources( textures ) {\n\n\tconst sourceSet = new Set();\n\tconst result = [];\n\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\tconst tex = textures[ i ];\n\t\tconst hash = getTextureHash( tex );\n\t\tif ( ! sourceSet.has( hash ) ) {\n\n\t\t\tsourceSet.add( hash );\n\t\t\tresult.push( tex );\n\n\t\t}\n\n\t}\n\n\treturn result;\n\n}\n\nexport function getIesTextures( lights ) {\n\n\tconst textures = lights.map( l => l.iesMap || null ).filter( t => t );\n\tconst textureSet = new Set( textures );\n\treturn Array.from( textureSet ).sort( uuidSort );\n\n}\n\nexport function getTextures( materials ) {\n\n\tconst textureSet = new Set();\n\tfor ( let i = 0, l = materials.length; i < l; i ++ ) {\n\n\t\tconst material = materials[ i ];\n\t\tfor ( const key in material ) {\n\n\t\t\tconst value = material[ key ];\n\t\t\tif ( value && value.isTexture ) {\n\n\t\t\t\ttextureSet.add( value );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tconst textureArray = Array.from( textureSet );\n\treturn reduceTexturesToUniqueSources( textureArray ).sort( uuidSort );\n\n}\n\nexport function getLights( scene ) {\n\n\tconst lights = [];\n\tscene.traverse( c => {\n\n\t\tif ( c.visible ) {\n\n\t\t\tif (\n\t\t\t\tc.isRectAreaLight ||\n\t\t\t\tc.isSpotLight ||\n\t\t\t\tc.isPointLight ||\n\t\t\t\tc.isDirectionalLight\n\t\t\t) {\n\n\t\t\t\tlights.push( c );\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\treturn lights.sort( uuidSort );\n\n}\n","import { wgslFn } from 'three/tsl';\nimport { constants } from './structs.wgsl.js';\n\n// See sampling.wgsl for vector shorthand explanations\n// The GGX functions provide sampling and distribution information for normals as output so\n// in order to get probability of scatter direction the half vector must be computed and provided.\n// [0] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf\n// [1] https://hal.archives-ouvertes.fr/hal-01509746/document\n// [2] http://jcgt.org/published/0007/04/01/\n// [4] http://jcgt.org/published/0003/02/03/\n// [5] https://seblagarde.wordpress.com/wp-content/uploads/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf\n// trowbridge-reitz === GGX === GTR\nexport const ggxDirectionFunc = wgslFn( /* wgsl */ `\n\n\tfn ggxDirection( incidentDir: vec3f, alpha: vec2f, uv: vec2f ) -> vec3f {\n\n\t\t// Implementation from reference [1]\n\t\t// stretch view\n\t\tlet V = normalize( vec3f( alpha * incidentDir.xy, incidentDir.z ) );\n\n\t\t// orthonormal basis\n\t\tvar T1: vec3f;\n\t\tif ( V.z < 0.9999 ) {\n\t\t\tT1 = normalize( cross( V, vec3( 0.0, 0.0, 1.0 ) ) );\n\t\t} else {\n\t\t\tT1 = vec3( 1.0, 0.0, 0.0 );\n\t\t}\n\n\t\tlet T2 = cross( T1, V );\n\n\t\t// sample point with polar coordinates (r, phi)\n\t\tlet a = 1.0 / ( 1.0 + V.z );\n\t\tlet r = sqrt( uv.x );\n\t\tvar phi: f32;\n\t\tif ( uv.y < a ) {\n\t\t\tphi = uv.y / a * PI;\n\t\t} else {\n\t\t\tphi = PI + ( uv.y - a ) / ( 1.0 - a ) * PI;\n\t\t}\n\t\tlet P1 = r * cos( phi );\n\t\tvar P2 = r * sin( phi );\n\t\tif ( uv.y >= a ) {\n\t\t\tP2 *= V.z;\n\t\t}\n\n\t\t// compute normal\n\t\tvar N = P1 * T1 + P2 * T2 + V * sqrt( max( 0.0, 1.0 - P1 * P1 - P2 * P2 ) );\n\n\t\t// unstretch\n\t\tN = normalize( vec3( alpha * N.xy, max( 0.0, N.z ) ) );\n\n\t\treturn N;\n\n\t}\n\n`, [ constants ] );\n\n// Below are PDF and related functions for use in a Monte Carlo path tracer\n// as specified in Appendix B of the following paper\n// See equation (34) from reference [0]\nexport const ggxLamdaFunc = wgslFn( /* wgsl */ `\n\n\tfn ggxLamda( theta: f32, alpha: f32 ) -> f32 {\n\n\t\tlet tanTheta = tan( theta );\n\t\tlet tanTheta2 = tanTheta * tanTheta;\n\t\tlet alpha2 = alpha * alpha;\n\n\t\tlet numerator = - 1.0 + sqrt( 1.0 + alpha2 * tanTheta2 );\n\t\treturn numerator / 2.0;\n\n\t}\n\n` );\n\n// Based on equation (34) from reference [0]\nexport const ggxShadowMaskG1Func = wgslFn( /* wgsl */ `\n\n\tfn ggxShadowMaskG1( cosTheta: f32, alpha: f32 ) -> f32 {\n\n\t\tlet a2 = alpha * alpha;\n\t\tlet cosTheta2 = cosTheta * cosTheta;\n\t\tlet denom = cosTheta + sqrt( cosTheta2 * ( 1 - a2 ) + a2 );\n\t\treturn 2.0 * cosTheta / denom;\n\n\t}\n\n`, [ ggxLamdaFunc ] );\n\n// See listing 2 from reference [5]\nexport const ggxSmithVisibilityFunc = wgslFn( /* wgsl */ `\n\n\tfn ggxSmithVisibility( NdotV: f32, NdotL: f32, alpha: f32 ) -> f32 {\n\n\t\t// Original formulation of G_SmithGGX Correlated\n\t\t// lambda_v = ( -1 + sqrt ( alphaG2 * (1 - NdotL2 ) / NdotL2 + 1)) * 0.5 f;\n\t\t// lambda_l = ( -1 + sqrt ( alphaG2 * (1 - NdotV2 ) / NdotV2 + 1)) * 0.5 f;\n\t\t// G_SmithGGXCorrelated = 1 / (1 + lambda_v + lambda_l );\n\t\t// V_SmithGGXCorrelated = G_SmithGGXCorrelated / (4.0 f * NdotL * NdotV );\n\n\t\t// This is an optimized version\n\t\tlet alpha2 = alpha * alpha;\n\t\t// Caution: the \"NdotL *\" and \"NdotV *\" are explicitely inversed , this is not a mistake.\n\t\tlet Lambda_GGXV = NdotL * sqrt (( - NdotV * alpha2 + NdotV ) * NdotV + alpha2 );\n\t\tlet Lambda_GGXL = NdotV * sqrt (( - NdotL * alpha2 + NdotL ) * NdotL + alpha2 );\n\n\t\treturn 0.5 / ( Lambda_GGXV + Lambda_GGXL );\n\n\t}\n\n`, [ ggxLamdaFunc ] );\n\n\n// See listing 2 from reference [5]\nexport const ggxDistributionFunc = wgslFn( /* wgsl */ `\n\tfn ggxDistribution( NdotH: f32, alpha: f32 ) -> f32 {\n\n\t\tlet a2 = max( alpha * alpha, EPSILON );\n\t\tlet denom = NdotH * NdotH * ( a2 - 1 ) + 1;\n\n\t\treturn ( a2 / ( PI * denom * denom ) );\n\n\t}\n`, );\n\n// ggxPDF, divided by the Jacobian of reflection operation\n// See equation (17) from [2]\n// Note: HdotV cancel out bc its guaranteed to be > 0\nexport const ggxReflectionAdjustedPDFFunc = wgslFn( /* wgsl */ `\n\tfn ggxReflectionAdjustedPDF( NdotV: f32, NdotH: f32, alpha: f32 ) -> f32 {\n\n\t\tlet D = ggxDistribution( NdotH, alpha );\n\t\tlet G1 = ggxShadowMaskG1( NdotV, alpha );\n\n\t\treturn D * G1 / ( 4 * NdotV );\n\n\t}\n`, [ ggxDistributionFunc, ggxShadowMaskG1Func ] );\n","import { wgslFn, mat3 } from 'three/tsl';\nimport {\n\tinverseMat3x3Func,\n\tgetBasisFromNormalFunc,\n\tiorToF0Func,\n\tschlickFresnelFunc,\n\tschlickFresnelVecFunc,\n\tiorToF0GeneralFunc,\n\tfresnel0ToIorFunc,\n\tiorToF0GeneralVecFunc,\n} from './utils.wgsl.js';\nimport {\n\tggxSmithVisibilityFunc,\n\tggxDistributionFunc,\n\tggxDirectionFunc,\n\tggxReflectionAdjustedPDFFunc,\n} from './ggx.wgsl.js';\nimport { constants, surfaceRecordStruct } from './structs.wgsl.js';\nimport { rngInit, rand2, RNG_INDEX_SCATTER_DIRECTION } from './random.wgsl.js';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\n\n// Builds getSurfaceRecord using the given per-instance sampleTexel\nexport const getSurfaceRecordFunc = sampleTexel => wgslFn( /* wgsl */ `\n\n\tfn getSurfaceRecord(\n\t\tmaterial: Material,\n\t\tvertexData: bvh_GeometryStruct,\n\t\tside: f32,\n\t\tfaceNormal: vec3f,\n\t) -> SurfaceRecord {\n\t\tlet uv = vertexData.uv.xy;\n\n\t\tvar normal = faceNormal * side;\n\t\tif ( material.flatShading == 0 ) {\n\n\t\t\tnormal = vertexData.normal.xyz;\n\n\t\t}\n\t\tnormal = normalize( normal );\n\t\tlet baseNormal = normal;\n\n\t\tif ( material.normalMap != -1 ) {\n\n\t\t\t// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate\n\t\t\t// resulting in NaNs and slow path tracing.\n\t\t\tif ( length( vertexData.tangent.xyz ) > 0.0 && vertexData.tangent.w != 0.0 ) {\n\n\t\t\t\tlet tangent = normalize( vertexData.tangent.xyz );\n\t\t\t\tlet bitangent = normalize( cross( baseNormal, tangent ) * vertexData.tangent.w );\n\t\t\t\tlet vTBN = mat3x3f( tangent, bitangent, baseNormal );\n\n\t\t\t\tlet uvPrime = material.normalMapTransform * vec3( uv, 1.0 );\n\t\t\t\tvar texNormal = sampleTexel( uvPrime.xy, material.normalMap, 0 ).xyz;\n\t\t\t\ttexNormal = texNormal * 2.0 - 1.0;\n\t\t\t\ttexNormal = texNormal * vec3f( material.normalScale, 1.0 );\n\t\t\t\tnormal = normalize( vTBN * texNormal );\n\n\t\t\t}\n\n\t\t}\n\n\t\tnormal *= side;\n\n\t\tvar albedo = vec4( material.color, material.opacity );\n\n\t\tif ( material.vertexColors == 1 ) {\n\n\t\t\tlet vertexColor = vertexData.color.xyz;\n\t\t\talbedo *= vec4f( vertexColor, 1.0 );\n\n\t\t}\n\n\t\tif ( material.map != -1 ) {\n\n\t\t\tlet uvPrime = material.mapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.map, 0 );\n\t\t\talbedo *= vec4f( texColor.rgb, 1.0 );\n\n\t\t}\n\n\t\tvar roughness = material.roughness;\n\t\tif ( material.roughnessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.roughnessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.roughnessMap, 0 );\n\t\t\troughness *= texColor.g;\n\n\t\t}\n\n\t\tvar metalness = material.metalness;\n\t\tif ( material.metalnessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.metalnessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.metalnessMap, 0 );\n\t\t\tmetalness *= texColor.b;\n\n\t\t}\n\n\t\tvar emission = material.emissiveIntensity * material.emissive;\n\t\tif ( material.emissiveMap != -1 ) {\n\n\t\t\tlet uvPrime = material.emissiveMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.emissiveMap, 0 );\n\t\t\temission *= texColor.rgb;\n\n\t\t}\n\n\t\tvar transmission = material.transmission;\n\t\tif ( material.transmissionMap != -1 ) {\n\n\t\t\tlet uvPrime = material.transmissionMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.transmissionMap, 0 );\n\t\t\ttransmission *= texColor.r;\n\n\t\t}\n\n\t\tvar clearcoat = material.clearcoat;\n\t\tif ( material.clearcoatMap != -1 ) {\n\n\t\t\tlet uvPrime = material.clearcoatMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.clearcoatMap, 0 );\n\t\t\tclearcoat *= texColor.r;\n\n\t\t}\n\n\t\tvar clearcoatRoughness = material.clearcoatRoughness;\n\t\tif ( material.clearcoatRoughnessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.clearcoatRoughnessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.clearcoatRoughnessMap, 0 );\n\t\t\tclearcoatRoughness *= texColor.g;\n\n\t\t}\n\n\t\tvar clearcoatNormal = baseNormal;\n\t\tif ( material.clearcoatNormalMap != -1 ) {\n\n\t\t\t// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate\n\t\t\t// resulting in NaNs and slow path tracing.\n\t\t\tif ( length( vertexData.tangent.xyz ) > 0.0 && vertexData.tangent.w != 0.0 ) {\n\n\t\t\t\tlet tangent = normalize( vertexData.tangent.xyz );\n\t\t\t\tlet bitangent = normalize( cross( baseNormal, tangent ) * vertexData.tangent.w );\n\t\t\t\tlet vTBN = mat3x3f( tangent, bitangent, baseNormal );\n\n\t\t\t\tlet uvPrime = material.clearcoatNormalMapTransform * vec3( uv, 1.0 );\n\t\t\t\tvar texNormal = sampleTexel( uvPrime.xy, material.clearcoatNormalMap, 0 ).xyz;\n\t\t\t\ttexNormal = texNormal * 2.0 - 1.0;\n\t\t\t\ttexNormal = texNormal * vec3f( material.clearcoatNormalScale, 1.0 );\n\t\t\t\tclearcoatNormal = normalize( vTBN * texNormal );\n\n\t\t\t}\n\n\t\t}\n\t\tclearcoatNormal *= side;\n\n\t\tvar sheenColor = material.sheenColor;\n\t\tif ( material.sheenColorMap != -1 ) {\n\n\t\t\tlet uvPrime = material.sheenColorMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.sheenColorMap, 0 );\n\t\t\tsheenColor *= texColor.rgb;\n\n\t\t}\n\n\t\tvar sheenRoughness = material.sheenRoughness;\n\t\tif ( material.sheenRoughnessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.sheenRoughnessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.sheenRoughnessMap, 0 );\n\t\t\tsheenRoughness *= texColor.r;\n\n\t\t}\n\n\t\tvar iridescence = material.iridescence;\n\t\tif ( material.iridescenceMap != -1 ) {\n\n\t\t\tlet uvPrime = material.iridescenceMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.iridescenceMap, 0 );\n\t\t\tiridescence *= texColor.r;\n\n\t\t}\n\n\t\tvar iridescenceThickness = material.iridescenceThicknessMaximum;\n\t\tif ( material.iridescenceThicknessMap != -1 ) {\n\n\t\t\tlet uvPrime = material.iridescenceThicknessMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.iridescenceThicknessMap, 0 );\n\n\t\t\tiridescenceThickness = mix(\n\t\t\t\tmaterial.iridescenceThicknessMinimum,\n\t\t\t\tmaterial.iridescenceThicknessMaximum,\n\t\t\t\ttexColor.g,\n\t\t\t);\n\n\t\t}\n\n\t\tvar specularColor = material.specularColor;\n\t\tif ( material.specularColorMap != -1 ) {\n\n\t\t\tlet uvPrime = material.specularColorMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.specularColorMap, 0 );\n\t\t\tspecularColor *= texColor.rgb;\n\n\t\t}\n\n\t\tvar specularIntensity = material.specularIntensity;\n\t\tif ( material.specularIntensityMap != -1 ) {\n\n\t\t\tlet uvPrime = material.specularIntensityMapTransform * vec3f( uv, 1 );\n\t\t\tlet texColor = sampleTexel( uvPrime.xy, material.specularIntensityMap, 0 );\n\t\t\tspecularIntensity *= texColor.r;\n\n\t\t}\n\n\t\tvar surf: SurfaceRecord;\n\n\t\tsurf.volumeParticle = false;\n\t\tsurf.faceNormal = faceNormal;\n\t\tsurf.normal = normal;\n\n\t\tsurf.metalness = metalness;\n\t\tsurf.color = albedo.rgb;\n\t\tsurf.emission = emission;\n\n\t\tsurf.ior = material.ior;\n\t\tsurf.transmission = transmission;\n\t\tsurf.thinFilm = material.thinFilm == 1;\n\t\tsurf.attenuationColor = material.attenuationColor;\n\t\tsurf.attenuationDistance = material.attenuationDistance;\n\n\t\tsurf.clearcoatNormal = clearcoatNormal;\n\t\tsurf.clearcoat = clearcoat;\n\n\t\tsurf.iridescence = iridescence;\n\t\tsurf.iridescenceIor = material.iridescenceIor;\n\t\tsurf.iridescenceThickness = iridescenceThickness;\n\n\t\tsurf.specularColor = specularColor;\n\t\tsurf.specularIntensity = specularIntensity;\n\n\t\tsurf.roughness = clamp( roughness, MIN_ROUGHNESS, 1.0 );\n\t\tsurf.clearcoatRoughness = clamp( clearcoatRoughness, MIN_ROUGHNESS, 1.0 );\n\t\tsurf.sheenRoughness = clamp( sheenRoughness, MIN_ROUGHNESS, 1.0 );\n\n\t\t// frontFace is used to determine transmissive properties and PDF. If no transmission is used\n\t\t// then we can just always assume this is a front face.\n\t\tsurf.frontFace = side == 1.0 || transmission == 0.0;\n\t\tif ( material.thinFilm == 1 || surf.frontFace ) {\n\t\t\tsurf.eta = 1.0 / material.ior;\n\t\t} else {\n\t\t\tsurf.eta = material.ior;\n\t\t}\n\t\tsurf.f0 = iorToF0( surf.eta );\n\n\t\t// get the normal frames\n\t\tsurf.normalBasis = getBasisFromNormal( surf.normal );\n\t\tsurf.normalInvBasis = inverse( surf.normalBasis );\n\n\t\tsurf.clearcoatBasis = getBasisFromNormal( surf.clearcoatNormal );\n\t\tsurf.clearcoatInvBasis = inverse( surf.clearcoatBasis );\n\n\t\treturn surf;\n\t}\n\n`, [\n\tinverseMat3x3Func,\n\tiorToF0Func,\n\tgetBasisFromNormalFunc,\n\tsampleTexel,\n\tsurfaceRecordStruct,\n\tconstants,\n] );\n\n/*\n *\n * N \t\t\t : Macronormal of the surface\n * V ( wo ) : View direction\n * L ( wi ) : Light direction\n * H ( wh ) : Halfvector between V and L, micronormal of the surface in ggx\n * f0 : Amount of light reflected when looking at a surface head on - \"fresnel 0\"\n * f90 : Amount of light reflected at grazing angles\n *\n */\n\n// Disney Diffuse BRDF without subsurface approximation\nexport const diffuseBrdfFunc = wgslFn( /* wgsl */ `\n\n\tfn diffuseBrdf( NdotV: f32, NdotL: f32, VdotH: f32, surf: SurfaceRecord ) -> vec3f {\n\n\t\t// https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf\n\t\t// See equation (4)\n\n\t\tlet fl = schlickFresnel( NdotL, 0.0 );\n\t\tlet fv = schlickFresnel( NdotV, 0.0 );\n\n\t\tlet alpha = surf.roughness * surf.roughness;\n\t\tlet bias = mix( 0.0, 0.5, alpha ) - 1;\n\t\tlet energyFactor = mix( 1.0, 1.0 / 1.51, alpha );\n\n\t\tlet rr = 2.0 * alpha * VdotH * VdotH;\n\t\tlet retro = rr * ( fl + fv + fl * fv * ( rr + 2.0 * bias ) );\n\t\tlet fresnel = ( 1.0 + bias * fl ) * ( 1.0f + bias * fv );\n\n\t\t// TODO: subsurface approx?\n\n\t\treturn energyFactor * ( surf.color / PI ) * ( retro + fresnel );\n\n\t}\n\n`, [ constants, schlickFresnelFunc, surfaceRecordStruct ] );\n\nexport const specularBrdfFunc = wgslFn( /* wgsl */ `\n\n\tfn specularBrdf( NdotL: f32, NdotV: f32, NdotH: f32, alpha: f32 ) -> vec3f {\n\n\t\tlet Vis = ggxSmithVisibility( NdotV, NdotL, alpha );\n\t\tlet D = ggxDistribution( NdotH, alpha );\n\n\t\treturn vec3f( D * Vis );\n\n\t}\n\n`, [ ggxSmithVisibilityFunc, ggxDistributionFunc ] );\n\nexport const fresnelMixFunc = wgslFn( /* wgsl */ `\n\n\tfn fresnelMix( VdotH: f32, ior: f32, base: vec3f, layer: vec3f ) -> vec3f {\n\n\t\tlet f0 = iorToF0( ior );\n \tlet F = schlickFresnel( abs( VdotH ), f0 );\n\n \treturn base + F * layer;\n\n\t}\n\n`, [ schlickFresnelFunc, iorToF0Func ] );\n\nconst XYZ_TO_REC709 = mat3(\n\t3.2404542, - 0.9692660, 0.0556434,\n\t- 1.5371385, 1.8760108, - 0.2040259,\n\t- 0.4985314, 0.0415560, 1.0572252,\n);\n\nconst evalSensitivityFunc = wgslTagFn/* wgsl */`\n\n\tfn evalSensitivity( OPD: f32, shift: vec3f ) -> vec3f {\n\n\t\tlet phase = 2.0 * ${ Math.PI } * OPD * 1.0e-9;\n\t\tconst val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13);\n\t\tconst pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06);\n\t\tconst _var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09);\n\n\t\tvar xyz = val * sqrt(2.0 * ${ Math.PI } * _var) * cos(pos * phase + shift) * exp(-phase * phase * _var);\n\t\txyz.x += 9.7470e-14 * sqrt(2.0 * ${ Math.PI } * 4.5282e+09) * cos(2.2399e+06 * phase + shift.x) * exp(-4.5282e+09 * phase * phase);\n\t\txyz /= 1.0685e-7;\n\n\t\tlet rgb = ${ XYZ_TO_REC709 } * xyz;\n\t\treturn rgb;\n\n\t}\n\n`;\n\n// Reference: Belcour/Barla, 2017\n// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html\n// This is a simplified model that ignores light polarization and uses fresnel approximation\nexport const iridescentFresnelFunc = wgslFn( /* wgsl */ `\n\n\tfn iridescentFresnel(\n\t\tcosTheta1: f32, baseF0: vec3f, iridescenceIor: f32,\n\t\toutsideIor: f32, iridescenceThickness: f32,\n\t) -> vec3f {\n\n\t\tlet sinTheta2Sq = pow( outsideIor / iridescenceIor, 2.0 ) * ( 1.0 - pow( cosTheta1, 2.0 ) );\n\t\tlet cosTheta2Sq = 1.0 - sinTheta2Sq;\n\n\t\t// Handle total internal reflection\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\n\t\t\treturn vec3( 1.0 );\n\n\t\t}\n\n\t\tlet cosTheta2 = sqrt( cosTheta2Sq );\n\n\t\t// First interface: air -> iridescent thin film\n\t\tlet R0 = iorToF0General( iridescenceIor, outsideIor );\n\t\tlet R12 = schlickFresnel( cosTheta1, R0 );\n\t\tlet R21 = R12;\n\t\tlet T121 = 1.0 - R12;\n\t\tlet phi12 = select( 0.0, PI, iridescenceIor < outsideIor );\n\t\tlet phi21 = PI - phi12;\n\n\t\t// Second interface: iridescent thin film -> base material\n\t\tlet baseIor = fresnel0ToIor( baseF0 + 0.0001 ); // guard against 1.0\n\t\tlet R1 = iorToF0GeneralVec( baseIor, vec3( iridescenceIor ) );\n\t\tlet R23 = schlickFresnelVec( cosTheta2, R1, vec3( 1.0 ) );\n\t\tlet phi23 = select( vec3( 0.0 ), vec3( PI ), baseIor < vec3( iridescenceIor ) );\n\n\t\t// Phase shift\n\t\tlet OPD = 2.0 * iridescenceIor * iridescenceThickness * cosTheta2;\n\t\tlet phi = vec3( phi21 ) + phi23;\n\n\t\t// Analytical integration\n\t\t// Compound terms\n\t\tlet R123 = clamp( R12 * R23, vec3( 1e-5 ), vec3( 0.9999 ) );\n\t\tlet r123 = sqrt( R123 );\n\t\tlet Rs = T121 * T121 * R23 / ( vec3( 1.0 ) - R123 );\n\n\t\t// Reflectance term for m = 0 (DC term amplitude)\n\t\tlet C0 = R12 + Rs;\n\t\tvar I = C0;\n\n\t\t// Reflectance term for m > 0 (pairs of diracs)\n\t\tvar Cm = Rs - T121;\n\t\tfor (var m = 1; m <= 2; m += 1) {\n\n\t\t\tCm *= r123;\n\t\t\tlet Sm = 2.0 * evalSensitivity( f32( m ) * OPD, f32( m ) * phi );\n\t\t\tI += Cm * Sm;\n\n\t\t}\n\n\t\treturn max( I, vec3(0.0) );\n\n\t}\n\n`, [ iorToF0GeneralFunc, iorToF0GeneralVecFunc, schlickFresnelFunc, fresnel0ToIorFunc, evalSensitivityFunc ] );\n\nconst rgbMixFunc = wgslFn( /* wgsl */ `\n\n\tfn rgbMix( base: vec3f, specular: vec3f, rgbAlpha: vec3f ) -> vec3f {\n\n\t\tlet alphaMax = max( max( rgbAlpha.x, rgbAlpha.y ), rgbAlpha.z );\n\t\treturn ( 1 - alphaMax ) * base + rgbAlpha * specular;\n\n\t}\n\n` );\n\nexport const iridescentDielectricLayerFunc = wgslFn( /* wgsl */ `\n\n\tfn iridescentDielectricLayer(\n\t\tdielectricBase: vec3f, base: vec3f, specular: vec3f, HdotL: f32,\n\t\toutsideIor: f32, baseIor: f32, iridescenceIor: f32, thickness: f32, strength: f32,\n\t) -> vec3f {\n\n\t\tlet baseF0 = vec3( iorToF0( baseIor ) );\n\n\t\tlet iridescentF = iridescentFresnel( HdotL, baseF0, iridescenceIor, outsideIor, thickness );\n\n\t\treturn mix( dielectricBase, rgbMix( base, specular, iridescentF ), strength );\n\n\t}\n\n`, [ iorToF0Func, iridescentFresnelFunc, rgbMixFunc ] );\n\nexport const iridescentConductorLayerFunc = wgslFn( /* wgsl */ `\n\n\tfn iridescentConductorLayer(\n\t\tmetalBase: vec3f, specular: vec3f, baseF0: vec3f, HdotL: f32,\n\t\toutsideIor: f32, iridescenceIor: f32, thickness: f32, strength: f32,\n\t) -> vec3f {\n\n\t\tlet iridescenceF = iridescentFresnel( HdotL, baseF0, iridescenceIor, outsideIor, thickness );\n\n\t\treturn mix( metalBase, specular * iridescenceF, strength );\n\n\t}\n\n`, [ iridescentFresnelFunc ] );\n\nexport const conductorFresnelFunc = ( turquinTexture ) => wgslFn( /* wgsl */ `\n\n\tfn conductorFresnel( NdotV: f32, VdotH: f32, f0: vec3f, bsdf: vec3f, alpha: f32 ) -> vec3f {\n\n\t let ss = bsdf * schlickFresnelVec( abs( VdotH ), f0, vec3f( 1 ) );\n\n\t\tlet uv = vec2( NdotV, sqrt( alpha ) );\n\t\tlet energySs = max( textureSampleLevel( turquinTexture, turquinTexture_sampler, uv, 0 ).r, 1e-5 );\n\n\t\treturn ss * ( 1.0 + f0 * ( 1.0 - energySs ) / energySs );\n\n\t}\n\n`, [ schlickFresnelVecFunc, turquinTexture ] );\n\nexport const fresnelCoatFunc = wgslFn( /* wgsl */ `\n\n\tfn fresnelCoat( VdotNc: f32, ior: f32, base: vec3f, layer: vec3f, weight: f32 ) -> vec3f {\n\n\t\tlet f0 = iorToF0( ior );\n\t\tlet F = schlickFresnel( abs( VdotNc ), f0 );\n\n\t\treturn mix( base, layer, weight * F );\n\n\t}\n\n`, [ iorToF0Func, schlickFresnelFunc ] );\n\n// GGX Multibounce compensation using Turquin's method\n\nexport const albedoIntegralMetallic = wgslTagFn/* wgsl */ `\n\n\tfn albedo(\n\t\ttexture: texture_storage_2d<r16float, write>,\n\n\t\tglobalId: vec3u,\n\t) -> void {\n\n\t\tconst INTEGRATION_SAMPLES = ( 1 << 20 );\n\t\tlet pixelIndex = ( globalId.x << 16 ) | globalId.y;\n\t\t${ rngInit }( pixelIndex, 0, 0 );\n\n\t\tlet dimensions = textureDimensions( texture ).xy;\n\t\tlet uv = ( vec2f( globalId.xy ) + vec2f( 0.5 ) ) / vec2f( dimensions );\n\n\t\tlet cosThetaO = uv.x;\n\t\tlet roughness = uv.y;\n\n\t\tlet alpha = roughness * roughness;\n\n\t\tlet wo = vec3( sqrt( 1 - cosThetaO * cosThetaO ), 0 , cosThetaO );\n\n\t\tvar result = 0.0;\n\t\tfor ( var i = 0; i < INTEGRATION_SAMPLES; i++ ) {\n\n\t\t\tlet wh = ${ ggxDirectionFunc }( wo, vec2( alpha ), ${ rand2 }(${ RNG_INDEX_SCATTER_DIRECTION }) );\n\t\t\tvar wi = - reflect( wo, wh );\n\n\t\t\tlet NdotV = max( wo.z, EPSILON );\n\t\t\tlet NdotL = saturate( wi.z );\n\t\t\tlet NdotH = saturate( wh.z );\n\n\t\t\tlet specular = ${ specularBrdfFunc }( NdotL, NdotV, NdotH, alpha );\n\t\t\tlet pdf = ${ ggxReflectionAdjustedPDFFunc }( NdotV, NdotH, alpha );\n\n\t\t\tvar weight = 0.0;\n\t\t\tif ( pdf != 0.0 ) {\n\t\t\t\tweight = 1 / pdf;\n\t\t\t}\n\n\t\t\tresult += specular.x * NdotL * weight;\n\n\t\t}\n\n\t\tresult /= f32( INTEGRATION_SAMPLES );\n\n\t\ttextureStore( texture, globalId.xy, vec4( result ) );\n\n\t}\n\n`;\n","import {\n\tMeshBasicMaterial,\n\tRenderTarget,\n\tNoToneMapping,\n\tQuadMesh,\n\tNoBlending,\n\tColor,\n\tVector4,\n} from 'three/webgpu';\n\nconst MAX_TEXTURE_SIZE = 4096;\nconst _prevClearColor = new Color();\n\nfunction getTextureHash( texture ) {\n\n\treturn `${ texture.source.uuid }:${ texture.source.version }`;\n\n}\n\n// TODO: consider adding a \"waste map\"\n// TODO: consider using \"best fit\"\n\n// Skyline rectangle packing (bottom-left, no waste map).\n// A \"skyline\" is an array of contiguous segments { x, y, width } that always\n// spans [ 0, pageWidth ] and describes the upper contour of placed rectangles.\n// Each rect is placed where its top edge is lowest ( leftmost on ties ).\n//\n// Reference: Jukka Jylänki, \"A Thousand Ways to Pack the Bin - A Practical\n// Approach to Two-Dimensional Rectangle Bin Packing\" (2010), the Skyline\n// Bottom-Left (SkylineBL) heuristic. See also Sean Barrett's stb_rect_pack.h:\n// https://github.com/nothings/stb/blob/master/stb_rect_pack.h\n\n// Resting y for a w-wide rect whose left edge sits at nodes[ i ].x. The rect\n// bridges every segment it spans and rests on the tallest of them. Returns -1\n// if it would run off the right edge.\nfunction skylineFit( nodes, i, w, pageWidth ) {\n\n\tconst x = nodes[ i ].x;\n\tif ( x + w > pageWidth ) {\n\n\t\treturn - 1;\n\n\t}\n\n\tlet widthLeft = w;\n\tlet y = 0;\n\tlet j = i;\n\twhile ( widthLeft > 0 ) {\n\n\t\t// defensive: the skyline should always cover the full page width\n\t\tif ( j >= nodes.length ) {\n\n\t\t\treturn - 1;\n\n\t\t}\n\n\t\ty = Math.max( y, nodes[ j ].y );\n\t\twidthLeft -= nodes[ j ].width;\n\t\tj ++;\n\n\t}\n\n\treturn y;\n\n}\n\n// Patch the skyline after placing a rect spanning [ x, x + w ] with top edge y.\n// The left edge x always aligns to an existing segment boundary, so only the\n// right edge can split a segment. Mutates nodes in place.\nfunction addSkylineNode( nodes, x, y, w ) {\n\n\tconst right = x + w;\n\tconst result = [];\n\tlet inserted = false;\n\n\tfor ( let i = 0; i < nodes.length; i ++ ) {\n\n\t\tconst node = nodes[ i ];\n\t\tconst nodeRight = node.x + node.width;\n\n\t\tif ( nodeRight <= x ) {\n\n\t\t\t// entirely left of the new node\n\t\t\tresult.push( node );\n\n\t\t} else if ( node.x >= right ) {\n\n\t\t\t// entirely right of the new node\n\t\t\tif ( ! inserted ) {\n\n\t\t\t\tresult.push( { x, y, width: w } );\n\t\t\t\tinserted = true;\n\n\t\t\t}\n\n\t\t\tresult.push( node );\n\n\t\t} else {\n\n\t\t\t// overlapped by the new node\n\t\t\tif ( ! inserted ) {\n\n\t\t\t\tresult.push( { x, y, width: w } );\n\t\t\t\tinserted = true;\n\n\t\t\t}\n\n\t\t\t// keep any right-side remainder at its original height\n\t\t\tif ( nodeRight > right ) {\n\n\t\t\t\tresult.push( { x: right, y: node.y, width: nodeRight - right } );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tif ( ! inserted ) {\n\n\t\tresult.push( { x, y, width: w } );\n\n\t}\n\n\t// merge adjacent segments of equal height and write back into nodes\n\tnodes.length = 0;\n\tfor ( let i = 0; i < result.length; i ++ ) {\n\n\t\tconst node = result[ i ];\n\t\tconst last = nodes[ nodes.length - 1 ];\n\t\tif ( last && last.y === node.y && last.x + last.width === node.x ) {\n\n\t\t\tlast.width += node.width;\n\n\t\t} else {\n\n\t\t\tnodes.push( node );\n\n\t\t}\n\n\t}\n\n}\n\n// Try to place a w x h rect into a single page's skyline. Returns the chosen\n// { x, y } or null if it does not fit.\nfunction skylineInsert( nodes, w, h, pageWidth, pageHeight ) {\n\n\tlet bestY = Infinity;\n\tlet bestX = 0;\n\tlet bestIndex = - 1;\n\n\tfor ( let i = 0; i < nodes.length; i ++ ) {\n\n\t\tconst y = skylineFit( nodes, i, w, pageWidth );\n\t\tif ( y >= 0 && y + h <= pageHeight && y < bestY ) {\n\n\t\t\tbestY = y;\n\t\t\tbestX = nodes[ i ].x;\n\t\t\tbestIndex = i;\n\n\t\t}\n\n\t}\n\n\tif ( bestIndex === - 1 ) {\n\n\t\treturn null;\n\n\t}\n\n\taddSkylineNode( nodes, bestX, bestY + h, w );\n\treturn { x: bestX, y: bestY };\n\n}\n\n// Packs a set of textures into one or more atlas pages and exposes both the\n// packed texture and a Uint32Array of per-texture info ( atlas bounds + page )\n// suitable for upload as a uniform array.\nexport class AtlasTexture {\n\n\tget width() {\n\n\t\treturn this.renderTarget.width;\n\n\t}\n\n\tget height() {\n\n\t\treturn this.renderTarget.height;\n\n\t}\n\n\tget pageCount() {\n\n\t\treturn this.renderTarget.depth;\n\n\t}\n\n\tget texture() {\n\n\t\treturn this.renderTarget.texture;\n\n\t}\n\n\tconstructor( options = {} ) {\n\n\t\t// RenderTarget already defaults to RGBA8, linear filtering, clamp wrapping\n\t\t// and no mipmaps, so we only specify the array-target-specific options here.\n\t\tthis.renderTarget = new RenderTarget( 1, 1, {\n\t\t\tdepthBuffer: false,\n\t\t\tdepth: 1,\n\t\t\t...options,\n\t\t} );\n\t\tthis.texture.isArrayTexture = true;\n\n\t\t// per-texture packed info ( one Vector4 each ): see _buildTextureInfo\n\t\tthis.textureInfo = [ new Vector4() ];\n\n\t\tthis.hashes = [];\n\t\tthis.quadMesh = new QuadMesh( new MeshBasicMaterial() );\n\t\tthis.quadMesh.material.blending = NoBlending;\n\n\t}\n\n\tsetTextures( renderer, textures ) {\n\n\t\t// nothing to do if the set of textures is unchanged\n\t\tif ( this._hashesMatch( textures ) ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// calculate the maximum dimension of the atlas\n\t\tlet maxDim = textures.reduce( ( v, t ) => Math.max( v, t.width, t.height ), 1 );\n\t\tmaxDim = Math.min( MAX_TEXTURE_SIZE, maxDim );\n\n\t\tconst width = maxDim;\n\t\tconst height = maxDim;\n\n\t\t// full repack of every texture\n\t\tconst { renderTarget } = this;\n\t\tconst { placements, pageCount } = this._packTextures( textures, width, height );\n\n\t\t// RenderTarget.setSize resets isArrayTexture to \"image.depth > 1\" so\n\t\t// we reset it here.\n\t\trenderTarget.setSize( width, height, pageCount );\n\t\tthis.texture.isArrayTexture = true;\n\n\t\tthis._buildTextureInfo( placements );\n\t\tthis._renderTextures( renderer, textures, placements );\n\n\t\t// rebuild hashes and the texture -> index lookup\n\t\tconst hashes = new Array( textures.length );\n\t\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\t\tconst hash = getTextureHash( textures[ i ] );\n\t\t\thashes[ i ] = hash;\n\n\t\t}\n\n\t\tthis.hashes = hashes;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.renderTarget.dispose();\n\t\tthis.quadMesh.material.dispose();\n\n\t}\n\n\t_hashesMatch( textures ) {\n\n\t\tconst hashes = this.hashes;\n\t\tif ( hashes.length !== textures.length ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\t\tif ( hashes[ i ] !== getTextureHash( textures[ i ] ) ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\t_packTextures( textures, width, height ) {\n\n\t\t// use each texture's native size, clamped so it can physically fit a page\n\t\t// ( anything larger is downsampled into its rect during the blit )\n\t\tconst items = [];\n\t\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\t\tconst texture = textures[ i ];\n\t\t\titems.push( {\n\t\t\t\tindex: i,\n\t\t\t\tw: Math.min( texture.width, width ),\n\t\t\t\th: Math.min( texture.height, height ),\n\t\t\t} );\n\n\t\t}\n\n\t\t// place taller rects first for tighter skyline occupancy\n\t\tconst order = items.sort( ( a, b ) => b.h - a.h );\n\n\t\tconst placements = new Array( textures.length );\n\t\tconst pages = [];\n\n\t\tfor ( let k = 0, l = order.length; k < l; k ++ ) {\n\n\t\t\tconst item = order[ k ];\n\t\t\tlet placed = null;\n\t\t\tlet page = - 1;\n\n\t\t\t// try to fit into an existing page\n\t\t\tfor ( let p = 0; p < pages.length; p ++ ) {\n\n\t\t\t\tplaced = skylineInsert( pages[ p ], item.w, item.h, width, height );\n\t\t\t\tif ( placed ) {\n\n\t\t\t\t\tpage = p;\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// otherwise open a new page\n\t\t\tif ( ! placed ) {\n\n\t\t\t\tconst skyline = [ { x: 0, y: 0, width: width } ];\n\t\t\t\tplaced = skylineInsert( skyline, item.w, item.h, width, height );\n\t\t\t\tpages.push( skyline );\n\t\t\t\tpage = pages.length - 1;\n\n\t\t\t}\n\n\t\t\tplacements[ item.index ] = { x: placed.x, y: placed.y, w: item.w, h: item.h, page };\n\n\t\t}\n\n\t\treturn { placements, pageCount: Math.max( pages.length, 1 ) };\n\n\t}\n\n\t_buildTextureInfo( placements ) {\n\n\t\tconst info = this.textureInfo;\n\t\tinfo.length = 0;\n\t\tfor ( let i = 0, l = placements.length; i < l; i ++ ) {\n\n\t\t\t// offsetX and Y in pixels (16 bits + 16 bits)\n\t\t\t// width and height in pixels (16 bit + 16 bits)\n\t\t\t// page + reserved (16 bits)\n\t\t\t// reserved\n\t\t\tconst { x, y, w, h, page } = placements[ i ];\n\t\t\tconst v = new Vector4();\n\t\t\tv.x = ( x & 0xFFFF ) | ( ( y & 0xFFFF ) << 16 );\n\t\t\tv.y = ( w & 0xFFFF ) | ( ( h & 0xFFFF ) << 16 );\n\t\t\tv.z = page & 0xFFFF;\n\t\t\tv.w = 0;\n\t\t\tinfo.push( v );\n\n\t\t}\n\n\t\tif ( info.length === 0 ) {\n\n\t\t\tinfo.push( new Vector4( 0, 0, 0, 0 ) );\n\n\t\t}\n\n\t}\n\n\t_renderTextures( renderer, textures, placements ) {\n\n\t\tconst { quadMesh, renderTarget, width, height } = this;\n\n\t\t// Save previous renderer state\n\t\tconst prevRenderTarget = renderer.getRenderTarget();\n\t\tconst prevToneMapping = renderer.toneMapping;\n\t\tconst prevAutoClear = renderer.autoClear;\n\t\tconst prevScissorTest = renderer.getScissorTest();\n\t\tconst prevClearAlpha = renderer.getClearAlpha();\n\t\trenderer.getClearColor( _prevClearColor );\n\n\t\t// blit each tile into its sub-rect without clearing the rest of the page\n\t\trenderer.toneMapping = NoToneMapping;\n\t\trenderer.autoClear = false;\n\t\trenderer.setScissorTest( true );\n\t\trenderer.setClearColor( 0, 0 );\n\n\t\t// clear the pages\n\t\tfor ( let i = 0, l = renderTarget.depth; i < l; i ++ ) {\n\n\t\t\trenderTarget.viewport.set( 0, 0, width, height );\n\t\t\trenderTarget.scissor.set( 0, 0, width, height );\n\t\t\trenderer.setRenderTarget( renderTarget, i );\n\t\t\trenderer.clear();\n\n\t\t}\n\n\t\tfor ( let i = 0, l = textures.length; i < l; i ++ ) {\n\n\t\t\tconst { x, y, w, h, page } = placements[ i ];\n\n\t\t\t// Clone the source so we get an independent texture handle\n\t\t\tconst texture = textures[ i ].clone();\n\t\t\ttexture.matrixAutoUpdate = false;\n\t\t\ttexture.matrix.identity();\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\tquadMesh.material.map = texture;\n\n\t\t\t// three.js uses the render target viewport / scissor\n\t\t\trenderTarget.viewport.set( x, y, w, h );\n\t\t\trenderTarget.scissor.set( x, y, w, h );\n\t\t\trenderer.setRenderTarget( renderTarget, page );\n\t\t\tquadMesh.render( renderer );\n\n\t\t\ttexture.dispose();\n\n\t\t}\n\n\t\t// restore the render target's full-size viewport/scissor and the renderer\n\t\trenderTarget.viewport.set( 0, 0, width, height );\n\t\trenderTarget.scissor.set( 0, 0, width, height );\n\t\tquadMesh.material.map = null;\n\t\trenderer.setClearColor( _prevClearColor, prevClearAlpha );\n\t\trenderer.setScissorTest( prevScissorTest );\n\t\trenderer.autoClear = prevAutoClear;\n\t\trenderer.setRenderTarget( prevRenderTarget );\n\t\trenderer.toneMapping = prevToneMapping;\n\n\t}\n\n}\n","import { BackSide, FrontSide, DoubleSide, BufferAttribute, BufferGeometry, StorageBufferAttribute, StructTypeNode, Vector4, SkinnedMesh, StructNode, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, NearestFilter } from 'three/webgpu';\nimport { BVHComputeData, intersectRayTriangle, bvhNodeBoundsStruct, bvhNodeStruct, rayStruct, rayIntersectionResultStruct as intersectionResultStruct, wgslTagFn } from '../lib/three-mesh-bvh/index.js';\nimport { storage, float, sampler, texture, uniformArray } from 'three/tsl';\nimport { SkinnedMeshBVH, MeshBVH, SAH } from 'three-mesh-bvh';\nimport { materialStruct } from './structs.wgsl.js';\nimport { getTextureHash } from '../../core/utils/sceneUpdateUtils.js';\nimport { rand1, RNG_INDEX_ALPHA_TEST } from './random.wgsl.js';\nimport { sampleTexelFunc } from './utils.wgsl.js';\nimport { getSurfaceRecordFunc } from './material.wgsl.js';\nimport { AtlasTexture } from '../AtlasTexture.js';\n\nconst _colorVec = new Vector4();\nconst transformStruct = new StructTypeNode( {\n\tmatrixWorld: 'mat4x4f',\n\tinverseMatrixWorld: 'mat4x4f',\n\tnodeOffset: 'uint',\n\tvisible: 'uint',\n\tmaterialIndex: 'uint',\n\t_alignment0: 'uint',\n\tcolor: 'vec4f',\n}, 'TransformStruct' );\n\n// Pathtracer-specific version of the BVHComputeData tht includes material mapping, property structs\nexport class PathtracerBVHComputeData extends BVHComputeData {\n\n\tconstructor( bvh, options = {} ) {\n\n\t\t// TODO: once supported we should use the appropriately-sized member sizes\n\t\tsuper( bvh, {\n\t\t\tattributes: {\n\t\t\t\tposition: 'vec4f',\n\t\t\t\tnormal: 'vec4f',\n\t\t\t\ttangent: 'vec4f',\n\t\t\t\tcolor: 'vec4f',\n\t\t\t\tuv: 'vec4f',\n\t\t\t},\n\t\t\t...options,\n\t\t} );\n\n\t\tthis.structs.transform = transformStruct;\n\t\tthis.structs.material = materialStruct;\n\t\tthis.storage.materials = null;\n\t\tthis.materials = [];\n\t\tthis.bvhMap = new Map();\n\t\tthis.textureAtlas = new AtlasTexture();\n\n\t}\n\n\tuseTransparencyRaycastFn() {\n\n\t\tconst { textureAtlas, storage, structs, fns } = this;\n\t\tconst textures = textureAtlas.texture;\n\t\tconst textureInfo = uniformArray( textureAtlas.textureInfo, 'uvec4' );\n\n\t\t// build the single sampleTexel bound to this instance's textureInfo node\n\t\tconst sampleTexel = sampleTexelFunc( textureInfo, texture( textures ), sampler( textures ) );\n\n\t\t// getSurfaceRecord shares the same sampleTexel, so the surface shading and\n\t\t// the transparency raycast resolve to one textureInfo binding per pipeline\n\t\tfns.getSurfaceRecord = getSurfaceRecordFunc( sampleTexel );\n\n\t\t// raycast first hit\n\t\tconst currentMaterial = new StructNode( structs.material ).toVar( 'bvh_material' );\n\t\tconst scratchRayScalar = float( 1.0 ).toVar( 'bvh_rayScalar' );\n\t\tconst baseOpacityScalar = float( 1.0 ).toVar( 'bvh_baseOpacity' );\n\n\t\tfns.raycastFirstHit = this.getShapecastFn( {\n\t\t\tname: 'raycastFirstHit',\n\t\t\tshapeStruct: rayStruct,\n\t\t\tresultStruct: intersectionResultStruct,\n\n\t\t\tboundsOrderFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn getBoundsOrder( ray: ${ rayStruct }, splitAxis: u32, node: ${ bvhNodeStruct } ) -> bool {\n\n\t\t\t\t\treturn ray.direction[ splitAxis ] >= 0.0;\n\n\t\t\t\t}\n\t\t\t`,\n\t\t\tintersectsBoundsFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn rayIntersectsBounds( ray: ${ rayStruct }, bounds: ${ bvhNodeBoundsStruct }, result: ptr<function, ${ intersectionResultStruct }> ) -> u32 {\n\n\t\t\t\t\t// early-out if our object is completely transparent\n\t\t\t\t\tif ( ${ baseOpacityScalar } == 0.0 ) {\n\n\t\t\t\t\t\treturn 0u;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet boundsMin = vec3( bounds.min[0], bounds.min[1], bounds.min[2] );\n\t\t\t\t\tlet boundsMax = vec3( bounds.max[0], bounds.max[1], bounds.max[2] );\n\n\t\t\t\t\tlet invDir = 1.0 / ray.direction;\n\t\t\t\t\tlet tMinPlane = ( boundsMin - ray.origin ) * invDir;\n\t\t\t\t\tlet tMaxPlane = ( boundsMax - ray.origin ) * invDir;\n\n\t\t\t\t\tlet tMinHit = min( tMinPlane, tMaxPlane );\n\t\t\t\t\tlet tMaxHit = max( tMinPlane, tMaxPlane );\n\n\t\t\t\t\tlet t0 = max( max( tMinHit.x, tMinHit.y ), tMinHit.z );\n\t\t\t\t\tlet t1 = min( min( tMaxHit.x, tMaxHit.y ), tMaxHit.z );\n\n\t\t\t\t\tlet dist = max( t0, 0.0 );\n\t\t\t\t\tif ( t1 < dist ) {\n\n\t\t\t\t\t\treturn 0u;\n\n\t\t\t\t\t} else if ( result.didHit && dist * ${ scratchRayScalar } >= result.dist ) {\n\n\t\t\t\t\t\treturn 0u;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\treturn 1u;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t`,\n\t\t\tintersectRangeFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn intersectRange( ray: ${ rayStruct }, offset: u32, count: u32, result: ptr<function, ${ intersectionResultStruct }> ) -> bool {\n\n\t\t\t\t\tvar didHit = false;\n\t\t\t\t\tfor ( var ti = offset; ti < offset + count; ti = ti + 1u ) {\n\n\t\t\t\t\t\tlet i0 = ${ storage.index }[ ti * 3u ];\n\t\t\t\t\t\tlet i1 = ${ storage.index }[ ti * 3u + 1u ];\n\t\t\t\t\t\tlet i2 = ${ storage.index }[ ti * 3u + 2u ];\n\n\t\t\t\t\t\tlet a = ${ storage.attributes }[ i0 ].position.xyz;\n\t\t\t\t\t\tlet b = ${ storage.attributes }[ i1 ].position.xyz;\n\t\t\t\t\t\tlet c = ${ storage.attributes }[ i2 ].position.xyz;\n\n\t\t\t\t\t\tvar triResult = ${ intersectRayTriangle }( ray, a, b, c, 1e-5 );\n\t\t\t\t\t\ttriResult.dist *= ${ scratchRayScalar };\n\t\t\t\t\t\tif ( triResult.didHit && ( ! result.didHit || triResult.dist < result.dist ) ) {\n\n\t\t\t\t\t\t\tlet material = ${ currentMaterial };\n\n\t\t\t\t\t\t\t// TODO: if material is a transmissive volume we may need to assume double-sidedness\n\t\t\t\t\t\t\tif ( material.side != 0 && triResult.side != material.side ) {\n\n\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( material.transparent != 0 || material.alphaTest > 0.0 ) {\n\n\t\t\t\t\t\t\t\tvar opacity = ${ baseOpacityScalar };\n\n\t\t\t\t\t\t\t\t// account for alpha component of albedo map\n\t\t\t\t\t\t\t\tif ( material.map != - 1 ) {\n\n\t\t\t\t\t\t\t\t\tlet barycoord = triResult.barycoord;\n\t\t\t\t\t\t\t\t\tlet a = ${ storage.attributes }[ i0 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet b = ${ storage.attributes }[ i1 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet c = ${ storage.attributes }[ i2 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet uv = barycoord.x * a + barycoord.y * b + barycoord.z * c;\n\t\t\t\t\t\t\t\t\tlet uvPrime = material.mapTransform * vec3f( uv, 1 );\n\n\t\t\t\t\t\t\t\t\topacity *= ${ sampleTexel }( uvPrime.xy, material.map, 0 ).a;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// account for green component of alpha map\n\t\t\t\t\t\t\t\tif ( material.alphaMap != - 1 ) {\n\n\t\t\t\t\t\t\t\t\tlet barycoord = triResult.barycoord;\n\t\t\t\t\t\t\t\t\tlet a = ${ storage.attributes }[ i0 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet b = ${ storage.attributes }[ i1 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet c = ${ storage.attributes }[ i2 ].uv.xy;\n\t\t\t\t\t\t\t\t\tlet uv = barycoord.x * a + barycoord.y * b + barycoord.z * c;\n\t\t\t\t\t\t\t\t\tlet uvPrime = material.alphaMapTransform * vec3f( uv, 1 );\n\n\t\t\t\t\t\t\t\t\topacity *= ${ sampleTexel }( uvPrime.xy, material.alphaMap, 0 ).g;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif ( material.transparent != 0 && opacity < ${ rand1 }( ${ RNG_INDEX_ALPHA_TEST } + ti ) ) {\n\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif ( opacity < material.alphaTest ) {\n\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tresult.didHit = true;\n\t\t\t\t\t\t\tresult.dist = triResult.dist;\n\t\t\t\t\t\t\tresult.normal = triResult.normal;\n\t\t\t\t\t\t\tresult.side = triResult.side;\n\t\t\t\t\t\t\tresult.barycoord = triResult.barycoord;\n\t\t\t\t\t\t\tresult.indices = vec4u( i0, i1, i2, ti );\n\n\t\t\t\t\t\t\tdidHit = true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn didHit;\n\n\t\t\t\t}\n\t\t\t`,\n\t\t\ttransformShapeFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn transformRay( ray: ptr<function, ${ rayStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\t\tlet toLocal = ${ storage.transforms }[ objectIndex ].inverseMatrixWorld;\n\t\t\t\t\tray.origin = ( toLocal * vec4f( ray.origin, 1.0 ) ).xyz;\n\t\t\t\t\tray.direction = ( toLocal * vec4f( ray.direction, 0.0 ) ).xyz;\n\n\t\t\t\t\tlet len = length( ray.direction );\n\t\t\t\t\tray.direction /= len;\n\t\t\t\t\t${ scratchRayScalar } = 1.0 / len;\n\n\t\t\t\t\tlet object = ${ storage.transforms }[ objectIndex ];\n\t\t\t\t\t${ currentMaterial } = ${ storage.materials }[ object.materialIndex ];\n\t\t\t\t\tif ( ${ currentMaterial }.transparent == 1 ) {\n\n\t\t\t\t\t\t${ baseOpacityScalar } = ${ currentMaterial }.opacity * object.color.a;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t${ baseOpacityScalar } = 1.0;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t`,\n\t\t\ttransformResultFn: wgslTagFn/* wgsl */`\n\t\t\t\tfn transformResult( hit: ptr<function, ${ intersectionResultStruct }>, objectIndex: u32 ) -> void {\n\n\t\t\t\t\tlet toLocal = ${ storage.transforms }[ objectIndex ].inverseMatrixWorld;\n\t\t\t\t\thit.normal = normalize( ( transpose( toLocal ) * vec4f( hit.normal, 0.0 ) ).xyz );\n\t\t\t\t\thit.objectIndex = objectIndex;\n\n\t\t\t\t}\n\t\t\t`,\n\t\t} );\n\n\t}\n\n\tupdate() {\n\n\t\tsuper.update();\n\n\t\t// build material storage\n\t\tconst { materials, structs } = this;\n\n\t\tconst { materialData, textures } = this.writeMaterialsBuffer( materials );\n\n\t\tthis.textures = textures;\n\n\t\tconst materialAttribute = new StorageBufferAttribute( materialData, structs.material.getLength() );\n\t\tconst materialStorage = storage( materialAttribute, structs.material ).toReadOnly().setName( 'bvh_materials' );\n\t\tthis.storage.materials = materialStorage;\n\n\t\tthis.bvhMap.clear();\n\t\tthis.materials.length = 0;\n\t\tthis.useTransparencyRaycastFn();\n\n\t}\n\n\twriteMaterialsBuffer( materials ) {\n\n\t\tfunction encodeTextureWrap( wrap ) {\n\n\t\t\tswitch ( wrap ) {\n\n\t\t\t\tcase RepeatWrapping:\n\t\t\t\t\treturn 0;\n\t\t\t\tcase ClampToEdgeWrapping:\n\t\t\t\t\treturn 1;\n\t\t\t\tcase MirroredRepeatWrapping:\n\t\t\t\t\treturn 2;\n\t\t\t\tdefault:\n\t\t\t\t\treturn 0;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getTexture( material, key ) {\n\n\t\t\tif ( key in material && material[ key ] ) {\n\n\t\t\t\tconst texture = material[ key ];\n\t\t\t\tconst hash = getTextureHash( texture );\n\n\t\t\t\tif ( ! textureLookUp.has( hash ) ) {\n\n\t\t\t\t\ttextureLookUp.set( hash, textureLookUp.size );\n\t\t\t\t\ttextures.push( texture );\n\n\t\t\t\t}\n\n\t\t\t\tconst idx = textureLookUp.get( hash );\n\t\t\t\tconst wrapS = encodeTextureWrap( texture.wrapS );\n\t\t\t\tconst wrapT = encodeTextureWrap( texture.wrapT );\n\t\t\t\tconst nearest = texture.magFilter === NearestFilter ? 1 : 0;\n\t\t\t\treturn ( nearest << 28 ) | ( wrapT << 26 ) | ( wrapS << 24 ) | idx;\n\n\t\t\t} else {\n\n\t\t\t\treturn - 1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getField( material, key, def ) {\n\n\t\t\treturn key in material ? material[ key ] : def;\n\n\t\t}\n\n\t\tfunction writeTextureMatrixToArray( material, textureKey, array, offset ) {\n\n\t\t\tconst texture = material[ textureKey ] && material[ textureKey ].isTexture ? material[ textureKey ] : null;\n\n\t\t\t// check if texture exists\n\t\t\tif ( texture ) {\n\n\t\t\t\tif ( texture.matrixAutoUpdate ) {\n\n\t\t\t\t\ttexture.updateMatrix();\n\n\t\t\t\t}\n\n\t\t\t\tconst elements = texture.matrix.elements;\n\n\t\t\t\t// Both wgsl struct and elements should be in column-major format\n\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\tarray[ offset + 4 * i + 0 ] = elements[ 3 * i + 0 ];\n\t\t\t\t\tarray[ offset + 4 * i + 1 ] = elements[ 3 * i + 1 ];\n\t\t\t\t\tarray[ offset + 4 * i + 2 ] = elements[ 3 * i + 2 ];\n\t\t\t\t\tarray[ offset + 4 * i + 3 ] = 0; // padding float\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn 12;\n\n\t\t}\n\n\t\tlet index = 0;\n\n\t\t// Collect and index the list of textures based on shareable source\n\t\tconst textureLookUp = new Map();\n\t\tconst textures = [];\n\n\t\t// NOTE: make the minimum material buffer length 2 in order to avoid TSL converting it to a scalar\n\t\t// TODO: remove this when fixed in three\n\t\tconst materialBufferLength = Math.max( materials.length, 2 );\n\t\tconst floatArray = new Float32Array( materialBufferLength * this.structs.material.getLength() );\n\t\tconst intArray = new Int32Array( floatArray.buffer );\n\n\t\t// TODO: make features work\n\t\t// features.reset();\n\t\tfor ( let i = 0, l = materials.length; i < l; i ++ ) {\n\n\t\t\tconst m = materials[ i ];\n\n\t\t\t// if ( m.isFogVolumeMaterial ) {\n\t\t\t//\n\t\t\t// \t// features.setUsed( 'FOG' );\n\t\t\t//\n\t\t\t// \tfor ( let j = 0; j < MATERIAL_STRIDE; j ++ ) {\n\t\t\t//\n\t\t\t// \t\tfloatArray[ index + j ] = 0;\n\t\t\t//\n\t\t\t// \t}\n\t\t\t//\n\t\t\t// \t// sample 0 .rgb\n\t\t\t// \tfloatArray[ index + 0 * 4 + 0 ] = m.color.r;\n\t\t\t// \tfloatArray[ index + 0 * 4 + 1 ] = m.color.g;\n\t\t\t// \tfloatArray[ index + 0 * 4 + 2 ] = m.color.b;\n\t\t\t//\n\t\t\t// \t// sample 2 .a\n\t\t\t// \tfloatArray[ index + 2 * 4 + 3 ] = getField( m, 'emissiveIntensity', 0.0 );\n\t\t\t//\n\t\t\t// \t// sample 3 .rgb\n\t\t\t// \tfloatArray[ index + 3 * 4 + 0 ] = m.emissive.r;\n\t\t\t// \tfloatArray[ index + 3 * 4 + 1 ] = m.emissive.g;\n\t\t\t// \tfloatArray[ index + 3 * 4 + 2 ] = m.emissive.b;\n\t\t\t//\n\t\t\t// \t// sample 13 .g\n\t\t\t// \t// reusing opacity field\n\t\t\t// \tfloatArray[ index + 13 * 4 + 1 ] = m.density;\n\t\t\t//\n\t\t\t// \t// side\n\t\t\t// \tfloatArray[ index + 13 * 4 + 3 ] = 0.0;\n\t\t\t//\n\t\t\t// \t// sample 14 .b\n\t\t\t// \tfloatArray[ index + 14 * 4 + 2 ] = 1 << 2;\n\t\t\t//\n\t\t\t// \tindex += MATERIAL_STRIDE;\n\t\t\t// \tcontinue;\n\t\t\t//\n\t\t\t// }\n\n\t\t\t// color - offset 0\n\t\t\tfloatArray[ index ++ ] = m.color.r;\n\t\t\tfloatArray[ index ++ ] = m.color.g;\n\t\t\tfloatArray[ index ++ ] = m.color.b;\n\t\t\tintArray[ index ++ ] = getTexture( m, 'map' );\n\n\t\t\t// metalness & roughness - offset 4\n\t\t\tfloatArray[ index ++ ] = getField( m, 'metalness', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'metalnessMap' );\n\t\t\tfloatArray[ index ++ ] = getField( m, 'roughness', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'roughnessMap' );\n\n\t\t\t// transmission & emissiveIntensity - offset 8\n\t\t\t// three.js assumes a default f0 of 0.04 if no ior is provided which equates to an ior of 1.5\n\t\t\tfloatArray[ index ++ ] = getField( m, 'ior', 1.5 );\n\t\t\tfloatArray[ index ++ ] = getField( m, 'transmission', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'transmissionMap' );\n\t\t\tfloatArray[ index ++ ] = getField( m, 'emissiveIntensity', 0.0 );\n\n\t\t\t// emission - offset 12\n\t\t\tif ( 'emissive' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.emissive.r;\n\t\t\t\tfloatArray[ index ++ ] = m.emissive.g;\n\t\t\t\tfloatArray[ index ++ ] = m.emissive.b;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\n\t\t\t}\n\n\t\t\tintArray[ index ++ ] = getTexture( m, 'emissiveMap' );\n\n\t\t\t// normals - offset 16\n\t\t\tintArray[ index ++ ] = getTexture( m, 'normalMap' );\n\t\t\tindex ++; // because of vec2 alignment\n\t\t\tif ( 'normalScale' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.normalScale.x;\n\t\t\t\tfloatArray[ index ++ ] = m.normalScale.y;\n\n \t\t\t} else {\n\n \t\t\t\tfloatArray[ index ++ ] = 1;\n \t\t\t\tfloatArray[ index ++ ] = 1;\n\n \t\t\t}\n\n\t\t\t// clearcoat - offset 20\n\t\t\tfloatArray[ index ++ ] = getField( m, 'clearcoat', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'clearcoatMap' );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'clearcoatNormalMap' );\n\t\t\tindex ++; // because of vec2 alignment\n\n\t\t\t// offset 24\n\t\t\tif ( 'clearcoatNormalScale' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.clearcoatNormalScale.x;\n\t\t\t\tfloatArray[ index ++ ] = m.clearcoatNormalScale.y;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 1;\n\t\t\t\tfloatArray[ index ++ ] = 1;\n\n\t\t\t}\n\n\t\t\tfloatArray[ index ++ ] = getField( m, 'clearcoatRoughness', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'clearcoatRoughnessMap' );\n\n\t\t\t// iridescence - offset 28\n\t\t\tintArray[ index ++ ] = getTexture( m, 'iridescenceMap' );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'iridescenceThicknessMap' );\n\n\t\t\tfloatArray[ index ++ ] = getField( m, 'iridescence', 0.0 );\n\t\t\tfloatArray[ index ++ ] = getField( m, 'iridescenceIOR', 1.3 );\n\n\t\t\t// offset 32\n\t\t\tconst iridescenceThicknessRange = getField( m, 'iridescenceThicknessRange', [ 100, 400 ] );\n\t\t\tfloatArray[ index ++ ] = iridescenceThicknessRange[ 0 ];\n\t\t\tfloatArray[ index ++ ] = iridescenceThicknessRange[ 1 ];\n\t\t\t// vec3f alignment requirements\n\t\t\tindex ++;\n\t\t\tindex ++;\n\n\t\t\t// specular color - offset 36\n\t\t\tif ( 'specularColor' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.specularColor.r;\n\t\t\t\tfloatArray[ index ++ ] = m.specularColor.g;\n\t\t\t\tfloatArray[ index ++ ] = m.specularColor.b;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\n\t\t\t}\n\n\t\t\tintArray[ index ++ ] = getTexture( m, 'specularColorMap' );\n\n\t\t\t// specular intensity - offset 40\n\t\t\tfloatArray[ index ++ ] = getField( m, 'specularIntensity', 1.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'specularIntensityMap' );\n\n\t\t\t// isThinFilm\n\t\t\tconst isThinFilm = getField( m, 'thickness', 0.0 ) === 0.0 && getField( m, 'attenuationDistance', Infinity ) === Infinity;\n\t\t\tintArray[ index ++ ] = Number( isThinFilm );\n\t\t\tindex ++;\n\n\t\t\t// attenuation - offset 44\n\t\t\tif ( 'attenuationColor' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.attenuationColor.r;\n\t\t\t\tfloatArray[ index ++ ] = m.attenuationColor.g;\n\t\t\t\tfloatArray[ index ++ ] = m.attenuationColor.b;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\t\t\t\tfloatArray[ index ++ ] = 1.0;\n\n\t\t\t}\n\n\t\t\tfloatArray[ index ++ ] = getField( m, 'attenuationDistance', Infinity );\n\n\t\t\t// alphaMap - offset 48\n\t\t\tintArray[ index ++ ] = getTexture( m, 'alphaMap' );\n\t\t\tintArray[ index ++ ] = Number( getField( m, 'castShadow', true ) ); // shadow\n\t\t\tfloatArray[ index ++ ] = m.opacity;\n\t\t\tfloatArray[ index ++ ] = m.alphaTest;\n\n\t\t\t// side & matte - offset 52\n\t\t\tif ( ! isThinFilm && m.transmission > 0.0 ) {\n\n\t\t\t\tfloatArray[ index ++ ] = 0;\n\n\t\t\t} else {\n\n\t\t\t\tswitch ( m.side ) {\n\n\t\t\t\t\tcase FrontSide:\n\t\t\t\t\t\tfloatArray[ index ++ ] = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BackSide:\n\t\t\t\t\t\tfloatArray[ index ++ ] = - 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DoubleSide:\n\t\t\t\t\t\tfloatArray[ index ++ ] = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tintArray[ index ++ ] = Number( getField( m, 'matte', false ) ); // matte\n\t\t\tfloatArray[ index ++ ] = getField( m, 'sheen', 0.0 );\n\t\t\tindex ++; // vec3 alignment requirements\n\n\t\t\t// sheenColor - offset 56\n\t\t\tif ( 'sheenColor' in m ) {\n\n\t\t\t\tfloatArray[ index ++ ] = m.sheenColor.r;\n\t\t\t\tfloatArray[ index ++ ] = m.sheenColor.g;\n\t\t\t\tfloatArray[ index ++ ] = m.sheenColor.b;\n\n\t\t\t} else {\n\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\t\t\t\tfloatArray[ index ++ ] = 0.0;\n\n\t\t\t}\n\n\t\t\tintArray[ index ++ ] = getTexture( m, 'sheenColorMap' );\n\n\t\t\t// sheenRoughness, flags - offset 60\n\t\t\tfloatArray[ index ++ ] = getField( m, 'sheenRoughness', 0.0 );\n\t\t\tintArray[ index ++ ] = getTexture( m, 'sheenRoughnessMap' );\n\n\t\t\tintArray[ index ++ ] = Number( m.vertexColors );\n\t\t\tintArray[ index ++ ] = Number( m.flatShading );\n\n\t\t\t// transparent, fogVolume - offset 64\n\t\t\tintArray[ index ++ ] = Number( m.transparent );\n\t\t\tintArray[ index ++ ] = 0;\n\t\t\tindex ++;\n\t\t\tindex ++;\n\n\t\t\t// map transform - offset 68\n\t\t\tindex += writeTextureMatrixToArray( m, 'map', floatArray, index );\n\n\t\t\t// metalnessMap transform - offset 80\n\t\t\tindex += writeTextureMatrixToArray( m, 'metalnessMap', floatArray, index );\n\n\t\t\t// roughnessMap transform - offset 92\n\t\t\tindex += writeTextureMatrixToArray( m, 'roughnessMap', floatArray, index );\n\n\t\t\t// transmissionMap transform - offset 104\n\t\t\tindex += writeTextureMatrixToArray( m, 'transmissionMap', floatArray, index );\n\n\t\t\t// emissiveMap transform - offset 116\n\t\t\tindex += writeTextureMatrixToArray( m, 'emissiveMap', floatArray, index );\n\n\t\t\t// normalMap transform - offset 128\n\t\t\tindex += writeTextureMatrixToArray( m, 'normalMap', floatArray, index );\n\n\t\t\t// clearcoatMap transform - offset 140\n\t\t\tindex += writeTextureMatrixToArray( m, 'clearcoatMap', floatArray, index );\n\n\t\t\t// clearcoatNormalMap transform - offset 152\n\t\t\tindex += writeTextureMatrixToArray( m, 'clearcoatNormalMap', floatArray, index );\n\n\t\t\t// clearcoatRoughnessMap transform - offset 164\n\t\t\tindex += writeTextureMatrixToArray( m, 'clearcoatRoughnessMap', floatArray, index );\n\n\t\t\t// sheenColorMap transform - offset 176\n\t\t\tindex += writeTextureMatrixToArray( m, 'sheenColorMap', floatArray, index );\n\n\t\t\t// sheenRoughnessMap transform - offset 188\n\t\t\tindex += writeTextureMatrixToArray( m, 'sheenRoughnessMap', floatArray, index );\n\n\t\t\t// iridescenceMap transform - offset 200\n\t\t\tindex += writeTextureMatrixToArray( m, 'iridescenceMap', floatArray, index );\n\n\t\t\t// iridescenceThicknessMap transform - offset 212\n\t\t\tindex += writeTextureMatrixToArray( m, 'iridescenceThicknessMap', floatArray, index );\n\n\t\t\t// specularColorMap transform - offset 224\n\t\t\tindex += writeTextureMatrixToArray( m, 'specularColorMap', floatArray, index );\n\n\t\t\t// specularIntensityMap transform - offset 236\n\t\t\tindex += writeTextureMatrixToArray( m, 'specularIntensityMap', floatArray, index );\n\n\t\t\t// alphaMap transform - offset 248\n\t\t\tindex += writeTextureMatrixToArray( m, 'alphaMap', floatArray, index );\n\n\t\t}\n\n\t\treturn { materialData: floatArray, textures };\n\n\t}\n\n\twriteTransformData( info, premultiplyMatrix, writeOffset, targetBuffer ) {\n\n\t\tsuper.writeTransformData( info, premultiplyMatrix, writeOffset, targetBuffer );\n\n\t\t// write material data to the transforms\n\t\tconst { materials } = this;\n\t\tconst { object, instanceId, root } = info;\n\n\t\t// get the material associated with the bvh group\n\t\tlet material = object.material;\n\t\tif ( Array.isArray( material ) ) {\n\n\t\t\tconst { materialIndex } = object.geometry.groups[ root ];\n\t\t\tmaterial = material[ materialIndex ];\n\n\t\t}\n\n\t\t// save the index\n\t\tlet index = materials.indexOf( material );\n\t\tif ( index === - 1 ) {\n\n\t\t\tindex = materials.length;\n\t\t\tmaterials.push( material );\n\n\t\t}\n\n\t\tconst transformBufferU32 = new Uint32Array( targetBuffer );\n\t\ttransformBufferU32[ writeOffset * transformStruct.getLength() + 34 ] = index;\n\n\t\t// write color\n\t\t// TODO: note that both BatchedMesh and InstancedMesh \"getColorAt\" functions throw\n\t\t// if colors have not been defined.\n\t\tif ( object.isInstancedMesh && object.instanceColor ) {\n\n\t\t\tobject.getColorAt( instanceId, _colorVec );\n\t\t\t_colorVec.w = 1.0;\n\n\t\t} else if ( object.isBatchedMesh && object._colorsTexture ) {\n\n\t\t\tobject.getColorAt( instanceId, _colorVec );\n\n\t\t} else {\n\n\t\t\t_colorVec.setScalar( 1 );\n\n\t\t}\n\n\t\tconst transformBufferF32 = new Float32Array( targetBuffer );\n\t\t_colorVec.toArray( transformBufferF32, writeOffset * transformStruct.getLength() + 36 );\n\n\t}\n\n\tgetBVH( object, instanceId, rangeTarget ) {\n\n\t\tconst { bvhMap } = this;\n\t\tconst bvh = super.getBVH( object, instanceId, rangeTarget );\n\t\tif ( bvhMap.has( bvh ) ) {\n\n\t\t\tconst data = bvhMap.get( bvh );\n\t\t\tObject.assign( rangeTarget, data.range );\n\n\t\t\t// make sure the mesh and bvh are updated if it's being reused across updates\n\t\t\tif ( bvh !== data.bvh && bvh instanceof SkinnedMeshBVH ) {\n\n\t\t\t\tconst sourceMesh = bvh.mesh;\n\t\t\t\tconst clonedMesh = data.bvh.mesh;\n\t\t\t\tclonedMesh.matrixWorld\n\t\t\t\t\t.copy( sourceMesh.matrixWorld )\n\t\t\t\t\t.decompose( clonedMesh.position, clonedMesh.quaternion, clonedMesh.scale );\n\n\t\t\t\tbvh.refit();\n\n\t\t\t}\n\n\t\t\treturn data.bvh;\n\n\t\t} else if ( bvh.indirect ) {\n\n\t\t\t// \"indirect\" bvhs are not supported since they cannot be unpacked in a way tht will allow for coherent material indices\n\t\t\tconst proxyGeometry = new BufferGeometry();\n\t\t\tproxyGeometry.attributes = bvh.geometry.attributes;\n\n\t\t\tlet array;\n\t\t\tif ( bvh.geometry.index ) {\n\n\t\t\t\tarray = bvh.geometry.index.array.slice( rangeTarget.start, rangeTarget.count + rangeTarget.start );\n\n\t\t\t} else {\n\n\t\t\t\tconst { start, count } = rangeTarget;\n\t\t\t\tarray = new Uint32Array( count );\n\t\t\t\tfor ( let i = 0, l = rangeTarget.count; i < l; i ++ ) {\n\n\t\t\t\t\tarray[ i ] = start + i;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tproxyGeometry.index = new BufferAttribute( array, 1 );\n\t\t\trangeTarget.start = 0;\n\n\t\t\tlet newBVH;\n\t\t\tif ( bvh instanceof SkinnedMeshBVH ) {\n\n\t\t\t\tconst sourceMesh = bvh.mesh;\n\t\t\t\tconst clonedMesh = new SkinnedMesh( proxyGeometry );\n\t\t\t\tclonedMesh.copy( sourceMesh );\n\t\t\t\tclonedMesh.matrixWorld\n\t\t\t\t\t.copy( sourceMesh.matrixWorld )\n\t\t\t\t\t.decompose( clonedMesh.position, clonedMesh.quaternion, clonedMesh.scale );\n\n\t\t\t\tnewBVH = new SkinnedMeshBVH( clonedMesh, { strategy: SAH, maxLeafSize: 5 } );\n\n\t\t\t} else {\n\n\t\t\t\tnewBVH = new MeshBVH( proxyGeometry, { strategy: SAH, maxLeafSize: 5 } );\n\n\t\t\t}\n\n\t\t\tbvhMap.set( bvh, { bvh: newBVH, range: { ...rangeTarget } } );\n\t\t\treturn newBVH;\n\n\t\t} else {\n\n\t\t\treturn bvh;\n\n\t\t}\n\n\t}\n\n}\n","import { MeshBasicNodeMaterial, DataTexture, NoBlending } from 'three/webgpu';\nimport { uv, varying, texture, uniform, wgslFn } from 'three/tsl';\n\nexport class AtlasDebugMaterial extends MeshBasicNodeMaterial {\n\n\tset texture( v ) {\n\n\t\tthis._texNode.value = v;\n\n\t}\n\n\tset layer( v ) {\n\n\t\tthis._layerUniform.value = v;\n\n\t}\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.blending = NoBlending;\n\n\t\tthis._texNode = texture( new DataTexture() );\n\t\tthis._layerUniform = uniform( 0 );\n\n\t\t// Shows one layer of the atlas array texture.\n\t\tthis.colorNode = wgslFn( /* wgsl */ `\n\t\t\tfn atlasDebug( tex: texture_2d_array<f32>, coord: vec2f, layer: f32 ) -> vec4f {\n\n\t\t\t\t// flip y so texel origin shows at the top-left\n\t\t\t\tlet dims = vec2f( textureDimensions( tex, 0 ).xy );\n\t\t\t\tlet texel = vec2i( vec2f( coord.x, 1.0 - coord.y ) * dims );\n\t\t\t\treturn textureLoad( tex, texel, i32( layer ), 0 );\n\n\t\t\t}\n\t\t` )( this._texNode, varying( uv() ), this._layerUniform );\n\n\t}\n\n}\n","import { BufferAttribute } from 'three';\n\nexport function updateMaterialIndexAttribute( geometry, materials, allMaterials ) {\n\n\tconst indexAttr = geometry.index;\n\tconst posAttr = geometry.attributes.position;\n\tconst vertCount = posAttr.count;\n\tconst totalCount = indexAttr ? indexAttr.count : vertCount;\n\tlet groups = geometry.groups;\n\tif ( groups.length === 0 ) {\n\n\t\tgroups = [ { count: totalCount, start: 0, materialIndex: 0 } ];\n\n\t}\n\n\tlet materialIndexAttribute = geometry.getAttribute( 'materialIndex' );\n\tif ( ! materialIndexAttribute || materialIndexAttribute.count !== vertCount ) {\n\n\t\t// use an array with the minimum precision required to store all material id references.\n\t\tlet array;\n\t\tif ( allMaterials.length <= 255 ) {\n\n\t\t\tarray = new Uint8Array( vertCount );\n\n\t\t} else {\n\n\t\t\tarray = new Uint16Array( vertCount );\n\n\t\t}\n\n\t\tmaterialIndexAttribute = new BufferAttribute( array, 1, false );\n\t\tgeometry.deleteAttribute( 'materialIndex' );\n\t\tgeometry.setAttribute( 'materialIndex', materialIndexAttribute );\n\n\t}\n\n\tconst materialArray = materialIndexAttribute.array;\n\tfor ( let i = 0; i < groups.length; i ++ ) {\n\n\t\tconst group = groups[ i ];\n\t\tconst start = group.start;\n\t\tconst count = group.count;\n\t\tconst endCount = Math.min( count, totalCount - start );\n\n\t\tconst mat = Array.isArray( materials ) ? materials[ group.materialIndex ] : materials;\n\t\tconst materialIndex = allMaterials.indexOf( mat );\n\n\t\tfor ( let j = 0; j < endCount; j ++ ) {\n\n\t\t\tlet index = start + j;\n\t\t\tif ( indexAttr ) {\n\n\t\t\t\tindex = indexAttr.getX( index );\n\n\t\t\t}\n\n\t\t\tmaterialArray[ index ] = materialIndex;\n\n\t\t}\n\n\t}\n\n}\n\nexport function setCommonAttributes( geometry, attributes ) {\n\n\tif ( ! geometry.index ) {\n\n\t\t// TODO: compute a typed array\n\t\tconst indexCount = geometry.attributes.position.count;\n\t\tconst array = new Array( indexCount );\n\t\tfor ( let i = 0; i < indexCount; i ++ ) {\n\n\t\t\tarray[ i ] = i;\n\n\t\t}\n\n\t\tgeometry.setIndex( array );\n\n\t}\n\n\tif ( ! geometry.attributes.normal && ( attributes && attributes.includes( 'normal' ) ) ) {\n\n\t\tgeometry.computeVertexNormals();\n\n\t}\n\n\tif ( ! geometry.attributes.uv && ( attributes && attributes.includes( 'uv' ) ) ) {\n\n\t\tconst vertCount = geometry.attributes.position.count;\n\t\tgeometry.setAttribute( 'uv', new BufferAttribute( new Float32Array( vertCount * 2 ), 2, false ) );\n\n\t}\n\n\tif ( ! geometry.attributes.uv2 && ( attributes && attributes.includes( 'uv2' ) ) ) {\n\n\t\tconst vertCount = geometry.attributes.position.count;\n\t\tgeometry.setAttribute( 'uv2', new BufferAttribute( new Float32Array( vertCount * 2 ), 2, false ) );\n\n\t}\n\n\tif ( ! geometry.attributes.tangent && ( attributes && attributes.includes( 'tangent' ) ) ) {\n\n\t\t// compute tangents requires a uv and normal buffer\n\t\tif ( geometry.attributes.uv && geometry.attributes.normal ) {\n\n\t\t\tgeometry.computeTangents();\n\n\t\t} else {\n\n\t\t\tconst vertCount = geometry.attributes.position.count;\n\t\t\tgeometry.setAttribute( 'tangent', new BufferAttribute( new Float32Array( vertCount * 4 ), 4, false ) );\n\n\t\t}\n\n\t}\n\n\tif ( ! geometry.attributes.color && ( attributes && attributes.includes( 'color' ) ) ) {\n\n\t\tconst vertCount = geometry.attributes.position.count;\n\t\tconst array = new Float32Array( vertCount * 4 );\n\t\tarray.fill( 1.0 );\n\t\tgeometry.setAttribute( 'color', new BufferAttribute( array, 4 ) );\n\n\t}\n\n}\n","import { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\nimport { rand2, RNG_INDEX_SCATTER_DIRECTION } from '../nodes/random.wgsl.js';\nimport { diffuseDirectionFunc } from '../nodes/sampling.wgsl.js';\n\n/**\n * Defines a material sampled by the pathtracer\n */\nexport class PathtracingMaterial {\n\n\t/**\n\t *\n\t * Called once per material\n\t * Adds ability to initialize state\n\t *\n\t */\n\tinit( /* renderer */ ) {\n\n\t}\n\n\t/**\n\t *\n\t * Must return a bsdf sampling function node with signature\n\t * ( worldView: vec3f, surface: Surface ) -> ScatterRecord\n\t *\n\t */\n\tgetBsdfNode() {\n\n\t\treturn wgslTagFn`\n\n\t\t\tfn bsdfSample( worldWo: vec3f, surf: SurfaceRecord ) -> ScatterRecord {\n\n\t\t\t\tvar record: ScatterRecord;\n\n\t\t\t\tlet wo = normalize( surf.normalInvBasis * worldWo );\n\t\t\t\tlet wi = ${ diffuseDirectionFunc }( wo, ${ rand2 }( ${ RNG_INDEX_SCATTER_DIRECTION } ) );\n\t\t\t\trecord.color = surf.color * max( wi.z, 0.0 );\n\t\t\t\trecord.pdf = max( wi.z, 0.0 ) / PI;\n\t\t\t\trecord.direction = normalize( surf.normalBasis * wi );\n\n\t\t\t\treturn record;\n\n\t\t\t}\n\n\t\t`;\n\n\t}\n\n\tgetData() {\n\n\t\treturn {\n\n\t\t\tbsdfSample: this.getBsdfNode(),\n\n\t\t};\n\n\t}\n\n}\n","import { texture, textureStore, globalId, float } from 'three/tsl';\nimport { StorageTexture, RedFormat, LinearFilter, TextureLoader, HalfFloatType } from 'three/webgpu';\nimport { wgslTagFn } from '../lib/three-mesh-bvh/index.js';\nimport { PathtracingMaterial } from './PathtracingMaterial';\nimport { specularBrdfFunc, diffuseBrdfFunc, fresnelMixFunc, conductorFresnelFunc, albedoIntegralMetallic, fresnelCoatFunc, iridescentDielectricLayerFunc, iridescentConductorLayerFunc } from '../nodes/material.wgsl.js';\nimport { diffuseDirectionFunc, getLobeWeightsFunc } from '../nodes/sampling.wgsl.js';\nimport { ggxDirectionFunc, ggxReflectionAdjustedPDFFunc } from '../nodes/ggx.wgsl.js';\nimport { bxdfContextStruct, scatterRecordStruct, surfaceRecordStruct } from '../nodes/structs.wgsl.js';\nimport { rand1, rand2, RNG_INDEX_SCATTER_DIRECTION, RNG_INDEX_SCATTER_TYPE } from '../nodes/random.wgsl.js';\nimport { ComputeKernel } from '../compute/ComputeKernel';\n\nconst TURQUIN_METAL_URL = new URL( '../../textures/turquinMetal.png', import.meta.url ).toString();\nconst TURQUIN_METAL_TEXTURE = await new TextureLoader().loadAsync( TURQUIN_METAL_URL );\n\nconst CLEARCOAT_IOR = float( 1.5 );\nconst MIN_INCIDENT_COS = float( 1e-3 );\n\nexport class GltfCompliantMaterial extends PathtracingMaterial {\n\n\tconstructor( options = {} ) {\n\n\t\tsuper();\n\n\t\tconst {\n\t\t\tspecularBrdf = specularBrdfFunc,\n\t\t\tdiffuseBrdf = diffuseBrdfFunc,\n\t\t\tfresnelMix = fresnelMixFunc,\n\t\t\tconductorFresnel = conductorFresnelFunc,\n\t\t\tfresnelCoat = fresnelCoatFunc,\n\t\t\tiridescentDielectricLayer = iridescentDielectricLayerFunc,\n\t\t\tiridescentConductorLayer = iridescentConductorLayerFunc,\n\t\t\tcalculateTurquinTexture = false,\n\t\t} = options;\n\n\t\tif ( calculateTurquinTexture ) {\n\n\t\t\tthis.turquinTexture = new StorageTexture( 32, 32 );\n\t\t\tthis.turquinTexture.type = HalfFloatType;\n\n\t\t} else {\n\n\t\t\tthis.turquinTexture = TURQUIN_METAL_TEXTURE;\n\t\t\tthis.turquinTexture.flipY = false;\n\n\t\t}\n\n\t\tthis.turquinTexture.format = RedFormat;\n\t\tthis.turquinTexture.minFilter = LinearFilter;\n\t\tthis.turquinTexture.magFilter = LinearFilter;\n\n\t\tconst turquinNode = texture( this.turquinTexture ).setName( 'turquinTexture' );\n\n\t\tthis.specularBrdf = specularBrdf;\n\t\tthis.diffuseBrdf = diffuseBrdf;\n\t\tthis.fresnelMix = fresnelMix;\n\t\tthis.conductorFresnel = conductorFresnel( turquinNode );\n\t\tthis.fresnelCoat = fresnelCoat;\n\t\tthis.iridescentDielectricLayer = iridescentDielectricLayer;\n\t\tthis.iridescentConductorLayer = iridescentConductorLayer;\n\t\tthis.calculateTurquinTexture = calculateTurquinTexture;\n\n\t}\n\n\tinit( renderer ) {\n\n\t\tif ( ! this.calculateTurquinTexture ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst turquinParams = {\n\t\t\ttexture: textureStore( this.turquinTexture ).toWriteOnly(),\n\t\t\tglobalId,\n\t\t};\n\t\tconst turquinKernel = new ComputeKernel( albedoIntegralMetallic( turquinParams ), { workgroupSize: [ 16, 16, 1 ] } );\n\n\t\trenderer.compute( turquinKernel.kernel, [ 2, 2, 1 ] );\n\n\t}\n\n\tgetBsdfNode() {\n\n\t\tconst bsdfEvalFunc = wgslTagFn/* wgsl */`\n\n\t\t\tfn bsdfEval( ctx: ${ bxdfContextStruct }, surf: ${ surfaceRecordStruct } ) -> vec3f {\n\n\t\t\t\tlet alpha = surf.roughness * surf.roughness;\n\n\t\t\t\tlet specular = ${ this.specularBrdf }( ctx.NdotL, ctx.NdotV, ctx.NdotH, alpha );\n\t\t\t\tlet diffuse = ${ this.diffuseBrdf }( ctx.NdotV, ctx.NdotL, ctx.VdotH, surf );\n\t\t\t\tlet dielectricBase = ${ this.fresnelMix }( ctx.VdotH, surf.ior, diffuse, specular );\n\n\t\t\t\tlet dielectric = ${ this.iridescentDielectricLayer }(\n\t\t\t\t\tdielectricBase, diffuse, specular, ctx.VdotH, /* outsideIor */ 1.0,\n\t\t\t\t\tsurf.ior, surf.iridescenceIor, surf.iridescenceThickness, surf.iridescence\n\t\t\t\t);\n\n\t\t\t\tlet metallicBase = ${ this.conductorFresnel }( ctx.NdotV, ctx.VdotH, surf.color, specular, alpha );\n\n\t\t\t\tlet metallic = ${ this.iridescentConductorLayer }(\n\t\t\t\t\tmetallicBase, specular, surf.color, ctx.VdotH, /* outsideIor */ 1.0,\n\t\t\t\t\tsurf.iridescenceIor, surf.iridescenceThickness, surf.iridescence\n\t\t\t\t);\n\n\t\t\t\tlet material = mix( dielectric, metallic, surf.metalness );\n\n\t\t\t\tlet clearcoatAlpha = surf.clearcoatRoughness * surf.clearcoatRoughness;\n\t\t\t\tlet clearcoat = ${ this.specularBrdf }( ctx.LdotNc, ctx.VdotNc, ctx.HdotNc, clearcoatAlpha );\n\n\t\t\t\tlet coatedMaterial = ${ this.fresnelCoat }( ctx.VdotNc, ${ CLEARCOAT_IOR }, material, clearcoat, surf.clearcoat );\n\n\t\t\t\treturn coatedMaterial;\n\n\t\t\t}\n\n\t\t`;\n\n\t\treturn wgslTagFn/* wgsl */`\n\n\t\t\tfn bsdfSample( worldWo: vec3f, surf: ${ surfaceRecordStruct } ) -> ${ scatterRecordStruct } {\n\n\t\t\t\tvar result: ${ scatterRecordStruct };\n\t\t\t\tresult.pdf = 0.0;\n\n\t\t\t\tlet alpha = surf.roughness * surf.roughness;\n\t\t\t\tlet clearcoatAlpha = surf.clearcoatRoughness * surf.clearcoatRoughness;\n\n\t\t\t\tlet normalBasis = surf.normalBasis;\n\t\t\t\tlet invBasis = surf.normalInvBasis;\n\t\t\t\tlet clearcoatBasis = surf.clearcoatBasis;\n\t\t\t\tlet invClearcoatBasis = surf.clearcoatInvBasis;\n\n\t\t\t\tlet wo = normalize( invBasis * worldWo );\n\t\t\t\tlet woClearcoat = normalize( invClearcoatBasis * worldWo );\n\n\t\t\t\t// TODO: handle such intersections better;\n\t\t\t\t// Sometimes .z < 0.0 on a pretty round surface e.g. sphere\n\t\t\t\t// Disabling this condition leads to more fireflies on ClearCoatCarPaint example\n\t\t\t\t// This could also be fixed by offsetting rays by 1e-1\n\t\t\t\t// Also, this will be an invalid condition when transmission is implemented\n\t\t\t\tif ( wo.z < 0.0 || woClearcoat.z < 0.0 ) {\n\n\t\t\t\t\treturn result;\n\n\t\t\t\t}\n\n\t\t\t\tlet weights = ${ getLobeWeightsFunc }( wo, woClearcoat, vec3( 0, 0, 1 ), ${ CLEARCOAT_IOR }, surf );\n\n\t\t\t\tvar cdf: vec4f;\n\t\t\t\tcdf.x = weights.diffuse;\n\t\t\t\tcdf.y = weights.specular + cdf.x;\n\t\t\t\tcdf.z = weights.clearcoat + cdf.y;\n\t\t\t\tcdf.w = 0; // weights.transmission + cdf.z;\n\n\t\t\t\tlet r = ${ rand1 }( ${ RNG_INDEX_SCATTER_TYPE } ) * cdf.z;\n\n\t\t\t\tlet directionUV = ${ rand2 }( ${ RNG_INDEX_SCATTER_DIRECTION } );\n\t\t\t\tvar wi: vec3f;\n\t\t\t\tvar wiClearcoat: vec3f;\n\t\t\t\tvar wh: vec3f;\n\t\t\t\tvar whClearcoat: vec3f;\n\n\t\t\t\tif ( r <= cdf.x ) { // diffuse\n\n\t\t\t\t\twi = ${ diffuseDirectionFunc }( wo, directionUV );\n\t\t\t\t\twh = normalize( wi + wo );\n\n\t\t\t\t\twiClearcoat = normalize( invClearcoatBasis * normalBasis * wi );\n\t\t\t\t\twhClearcoat = normalize( invClearcoatBasis * normalBasis * wh );\n\n\t\t\t\t} else if ( r <= cdf.y ) { // specular\n\n\t\t\t\t\twh = ${ ggxDirectionFunc }( wo, vec2( alpha ), directionUV );\n\t\t\t\t\twi = - normalize( reflect( wo, wh ) );\n\n\t\t\t\t\twiClearcoat = normalize( invClearcoatBasis * normalBasis * wi );\n\t\t\t\t\twhClearcoat = normalize( invClearcoatBasis * normalBasis * wh );\n\n\t\t\t\t} else if ( r <= cdf.z ) { // clearcoat\n\n\t\t\t\t\twhClearcoat = ${ ggxDirectionFunc }( woClearcoat, vec2( clearcoatAlpha ), directionUV );\n\t\t\t\t\twiClearcoat = - normalize( reflect( woClearcoat, whClearcoat ) );\n\n\t\t\t\t\twi = normalize( invBasis * clearcoatBasis * wiClearcoat );\n\t\t\t\t\twh = normalize( invBasis * clearcoatBasis * whClearcoat );\n\n\t\t\t\t} else if ( r <= cdf.w ) { // transmission / refraction\n\n\t\t\t\t\t// NOT IMPLEMENTED\n\n\t\t\t\t}\n\n\t\t\t\tvar ctx: ${ bxdfContextStruct };\n\t\t\t\tctx.NdotV = max( wo.z, ${ MIN_INCIDENT_COS } );\n\t\t\t\tctx.NdotL = max( wi.z, ${ MIN_INCIDENT_COS } );\n\t\t\t\tctx.NdotH = saturate( wh.z );\n\t\t\t\tctx.VdotH = saturate( dot( wo, wh ) );\n\n\t\t\t\tctx.VdotNc = max( woClearcoat.z, ${ MIN_INCIDENT_COS } );\n\t\t\t\tctx.LdotNc = max( wiClearcoat.z, ${ MIN_INCIDENT_COS } );\n\t\t\t\tctx.HdotNc = saturate( whClearcoat.z );\n\n\t\t\t\tif ( weights.diffuse > 0.0 ) {\n\n\t\t\t\t\tresult.pdf += weights.diffuse * max( wi.z, 0.0 ) / PI;\n\n\t\t\t\t}\n\n\t\t\t\tif ( weights.specular > 0.0 && wi.z > 0.0 ) {\n\n\t\t\t\t\tresult.pdf += weights.specular * ${ ggxReflectionAdjustedPDFFunc }( ctx.NdotV, ctx.NdotH, alpha );\n\n\t\t\t\t}\n\n\t\t\t\tif ( weights.clearcoat > 0.0 && wiClearcoat.z > 0.0 ) {\n\n\t\t\t\t\tresult.pdf += weights.clearcoat * ${ ggxReflectionAdjustedPDFFunc }( ctx.VdotNc, ctx.HdotNc, clearcoatAlpha );\n\n\t\t\t\t}\n\n\t\t\t\tresult.color = ${ bsdfEvalFunc }( ctx, surf );\n\t\t\t\tresult.color *= max( 0.0, wi.z );\n\t\t\t\tresult.direction = normalize( normalBasis * wi );\n\n\t\t\t\treturn result;\n\n\t\t\t}\n\n\t\t`;\n\n\t}\n\n}\n","import { DataTexture, LinearFilter, Vector2, Scene, PerspectiveCamera, Color, NoToneMapping, FloatType, Timer, StorageTexture } from 'three/webgpu';\nimport { SkinnedMeshBVH, MeshBVH, SAH } from 'three-mesh-bvh';\nimport { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';\nimport { RenderToScreenNodeMaterial } from './materials/RenderToScreenMaterial.js';\nimport { MegaKernelPathTracer } from './MegaKernelPathTracer.js';\nimport { WaveFrontPathTracer } from './WaveFrontPathTracer.js';\nimport { CubeToEquirectGenerator } from '../utils/CubeToEquirectGenerator.js';\nimport { PathtracerBVHComputeData } from './nodes/PathtracerBVHComputeData.js';\nimport { AtlasDebugMaterial } from './materials/debug/AtlasDebugMaterial.js';\nimport { setCommonAttributes } from '../core/utils/GeometryPreparationUtils.js';\nimport { GltfCompliantMaterial } from './materials/GltfCompliantMaterial.js';\n\nconst _resolution = new Vector2();\nconst _color = new Color();\n\nexport class WebGPUPathTracer {\n\n\tget bounces() {\n\n\t\treturn this._pathTracer.bounces;\n\n\t}\n\n\tset bounces( v ) {\n\n\t\tthis._pathTracer.bounces = v;\n\t\tthis._pathTracer.reset();\n\n\t}\n\n\tget samples() {\n\n\t\treturn this._pathTracer.samples;\n\n\t}\n\n\tget fadeState() {\n\n\t\treturn this._fadeState;\n\n\t}\n\n\tget textureAtlas() {\n\n\t\treturn this._bvhData.textureAtlas;\n\n\t}\n\n\tuseMegakernel( value ) {\n\n\t\tthis._pathTracer.dispose();\n\t\tthis._pathTracer = value ? new MegaKernelPathTracer( this._renderer ) : new WaveFrontPathTracer( this._renderer );\n\t\tthis._pathTracer.setBVHData( this._bvhData );\n\t\tthis._pathTracer.setMaterial( this.material );\n\t\tthis.setCamera( this.camera );\n\t\tthis.updateEnvironment();\n\n\t}\n\n\tconstructor( renderer ) {\n\n\t\t// members\n\t\tthis._renderer = renderer;\n\t\tthis._timer = new Timer();\n\n\t\tthis._envColorTexture = new DataTexture( );\n\t\tthis._envColorTexture.image.data = new Uint8Array( [ 255, 255, 255, 255 ] );\n\t\tthis._envColorTexture.needsUpdate = true;\n\t\tthis._envColorTexture.minFilter = LinearFilter;\n\t\tthis._envColorTexture.magFilter = LinearFilter;\n\n\t\tthis._backgroundColorTexture = new DataTexture( );\n\t\tthis._backgroundColorTexture.image.data = new Uint8Array( [ 255, 255, 255, 255 ] );\n\t\tthis._backgroundColorTexture.needsUpdate = true;\n\t\tthis._backgroundColorTexture.minFilter = LinearFilter;\n\t\tthis._backgroundColorTexture.magFilter = LinearFilter;\n\n\t\tthis._resetTime = - 1;\n\t\tthis._fadeState = 0;\n\t\tthis._size = new Vector2();\n\t\tthis._blitQuad = new FullScreenQuad( new RenderToScreenNodeMaterial() );\n\n\t\t// avoid mipmap gen on copy, not always supported with float type\n\t\tthis._lowResTarget = new StorageTexture( 1, 1 );\n\t\tthis._lowResTarget.type = FloatType;\n\t\tthis._lowResTarget.generateMipmaps = false;\n\n\t\t// options\n\t\tthis.minSamples = 1;\n\t\tthis.renderDelay = 500;\n\t\tthis.fadeDuration = 500;\n\t\tthis.dynamicLowRes = true;\n\t\tthis.lowResScale = 0.2;\n\t\tthis.renderScale = 1;\n\t\tthis.synchronizeRenderSize = true;\n\t\tthis.generateMissingAttributes = true;\n\t\tthis.commonAttributes = [ 'normal', 'uv', 'tangent', 'color' ];\n\n\t\tthis.material = new GltfCompliantMaterial();\n\t\tthis._pathTracer = new MegaKernelPathTracer( renderer );\n\n\t\t// initialize the scene so it doesn't fail\n\t\tthis.setScene( new Scene(), new PerspectiveCamera() );\n\n\t}\n\n\tsetScene( scene, camera ) {\n\n\t\tscene.updateMatrixWorld( true );\n\t\tcamera.updateMatrixWorld();\n\n\t\t// Build BVH for each mesh geometry\n\t\tscene.traverse( child => {\n\n\t\t\tif ( this.generateMissingAttributes && child.geometry?.isBufferGeometry ) {\n\n\t\t\t\tsetCommonAttributes( child.geometry, this.commonAttributes );\n\n\t\t\t}\n\n\t\t\tif ( child.isSkinnedMesh ) {\n\n\t\t\t\tif ( ! child.boundsTree ) {\n\n\t\t\t\t\tchild.boundsTree = new SkinnedMeshBVH( child, { strategy: SAH, maxLeafSize: 5, indirect: true } );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tchild.boundsTree.refit();\n\n\t\t\t\t}\n\n\t\t\t} else if ( child.isMesh ) {\n\n\t\t\t\tif ( ! child.geometry.boundsTree ) {\n\n\t\t\t\t\tchild.geometry.boundsTree = new MeshBVH( child.geometry, { strategy: SAH, maxLeafSize: 5 } );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} );\n\n\t\t// Build TLAS and compute functions\n\t\tconst bvhData = new PathtracerBVHComputeData( scene );\n\t\tbvhData.update();\n\t\tbvhData.textureAtlas.setTextures( this._renderer, bvhData.textures );\n\n\t\tthis.scene = scene;\n\t\tthis._bvhData = bvhData;\n\t\tthis._pathTracer.setBVHData( bvhData );\n\t\tthis.setCamera( camera );\n\t\tthis.updateEnvironment();\n\n\t}\n\n\tgetMaterial() {\n\n\t\treturn this.material;\n\n\t}\n\n\tsetMaterial( material ) {\n\n\t\tthis.material = material;\n\t\tthis._pathTracer.setMaterial( material );\n\n\t}\n\n\t// TODO: support async generation of ObjectBVH\n\tsetSceneAsync( ...args ) {\n\n\t\tthis.setScene( ...args );\n\n\t}\n\n\tsetCamera( camera ) {\n\n\t\tthis.camera = camera;\n\t\tthis.updateCamera();\n\n\t}\n\n\tupdateCamera() {\n\n\t\tconst camera = this.camera;\n\t\tcamera.updateMatrixWorld();\n\n\t\tthis._pathTracer.setCamera( camera );\n\t\tthis.reset();\n\n\t}\n\n\tupdateEnvironment() {\n\n\t\tconst {\n\t\t\t_renderer,\n\t\t\t_pathTracer,\n\t\t\tscene,\n\t\t\t_envColorTexture,\n\t\t\t_backgroundColorTexture,\n\t\t} = this;\n\n\t\tconst environment = convertToTexture( _renderer, scene.environment || _color.set( 0 ), _envColorTexture );\n\t\tconst background = convertToTexture( _renderer, scene.background, _backgroundColorTexture );\n\n\t\t_pathTracer.setEnvironment(\n\t\t\tenvironment,\n\t\t\tscene.environmentIntensity,\n\t\t\tscene.environmentRotation,\n\n\t\t\tbackground,\n\t\t\tscene.backgroundIntensity,\n\t\t\tscene.backgroundRotation,\n\t\t\tscene.backgroundBlurriness,\n\t\t);\n\n\t}\n\n\tsetSize( x, y ) {\n\n\t\tif ( this._size.x !== x || this._size.y !== y ) {\n\n\t\t\tthis._size.set( x, y );\n\t\t\tthis.reset();\n\n\t\t}\n\n\t}\n\n\treset() {\n\n\t\tthis._pathTracer.reset();\n\t\tthis._resetTime = 0;\n\t\tthis._fadeState = 0;\n\n\t}\n\n\trenderSample() {\n\n\t\tconst renderer = this._renderer;\n\t\tconst size = this._size;\n\t\tconst blitQuad = this._blitQuad;\n\t\tconst pathTracer = this._pathTracer;\n\t\tconst lowResTarget = this._lowResTarget;\n\t\tconst timer = this._timer;\n\t\tconst {\n\t\t\trenderDelay,\n\t\t\tdynamicLowRes,\n\t\t\tsynchronizeRenderSize,\n\t\t\trenderScale,\n\t\t\tlowResScale,\n\t\t\tminSamples,\n\t\t} = this;\n\n\t\ttimer.update();\n\n\t\tif ( ! this._renderer._initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( ! this.material.initialized ) {\n\n\t\t\tthis.material.init( renderer );\n\t\t\tthis.material.initialized = true;\n\n\t\t}\n\n\t\tconst delta = 1000 * timer.getDelta();\n\t\tthis._resetTime += delta;\n\n\t\tconst originalToneMapping = renderer.toneMapping;\n\t\tconst originalExposure = renderer.toneMappingExposure;\n\t\tconst originalTarget = renderer.getRenderTarget();\n\t\tconst originalAutoClear = renderer.autoClear;\n\t\trenderer.toneMapping = NoToneMapping;\n\t\trenderer.toneMappingExposure = 1.0;\n\n\t\t// handle canvas-size auto synchronization\n\t\tif ( synchronizeRenderSize ) {\n\n\t\t\trenderer.getDrawingBufferSize( _resolution );\n\t\t\tconst w = Math.floor( renderScale * _resolution.x );\n\t\t\tconst h = Math.floor( renderScale * _resolution.y );\n\t\t\tthis.setSize( w, h );\n\n\t\t}\n\n\t\t// check if we should be in low res mode and calculate the target size\n\t\tlet { width, height } = size;\n\t\tconst lowResMode = this._resetTime < renderDelay;\n\t\tif ( lowResMode ) {\n\n\t\t\twidth = Math.ceil( lowResScale * width );\n\t\t\theight = Math.ceil( lowResScale * height );\n\n\t\t}\n\n\t\t// set the size if necessary\n\t\tpathTracer.getSize( _resolution );\n\n\t\tconst resized = _resolution.x !== width || _resolution.y !== height;\n\t\tif ( resized ) {\n\n\t\t\tif ( ! lowResMode && dynamicLowRes ) {\n\n\t\t\t\t// copy the low reset content if we're transitioning to the full\n\t\t\t\t// resolution view so we can fade to it\n\t\t\t\tlowResTarget.setSize( Math.ceil( lowResScale * width ), Math.ceil( lowResScale * height ) );\n\t\t\t\trenderer.copyTextureToTexture( pathTracer.outputTarget, lowResTarget );\n\n\t\t\t}\n\n\t\t\tpathTracer.setSize( width, height );\n\n\t\t}\n\n\t\tif ( ! lowResMode && pathTracer.samples >= minSamples ) {\n\n\t\t\tthis._fadeState += delta / this.fadeDuration;\n\t\t\tthis._fadeState = Math.min( 1.0, this._fadeState );\n\n\t\t}\n\n\n\t\t// update the samples\n\t\tif ( ! lowResMode || ( lowResMode && dynamicLowRes ) ) {\n\n\t\t\tpathTracer.lowResMode = lowResMode;\n\t\t\tpathTracer.update();\n\n\t\t}\n\n\n\t\t// render the content to the canvas\n\t\tconst opacity = ( lowResMode && dynamicLowRes ? 1.0 : this._fadeState );\n\n\t\trenderer.autoClear = dynamicLowRes ? true : opacity === 1.0;\n\t\tblitQuad.material.transition = dynamicLowRes ? opacity : 1.0;\n\t\tblitQuad.material.opacity = dynamicLowRes ? 1.0 : opacity;\n\t\tblitQuad.material.fromTexture = lowResTarget;\n\t\tblitQuad.material.texture = pathTracer.outputTarget;\n\t\tblitQuad.material.toneMapping = originalToneMapping;\n\t\tblitQuad.material.toneMappingExposure = originalExposure;\n\t\tblitQuad.render( renderer );\n\n\t\t// reset the renderer\n\t\trenderer.autoClear = originalAutoClear;\n\t\trenderer.toneMapping = originalToneMapping;\n\t\trenderer.toneMappingExposure = originalExposure;\n\t\trenderer.setRenderTarget( originalTarget );\n\n\t}\n\n\trenderTextureAtlas( layer = 0 ) {\n\n\t\tconst renderer = this._renderer;\n\t\tif ( ! renderer._initialized ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( ! this._atlasDebugQuad ) {\n\n\t\t\tthis._atlasDebugQuad = new FullScreenQuad( new AtlasDebugMaterial() );\n\n\t\t}\n\n\t\tconst quad = this._atlasDebugQuad;\n\t\tquad.material.texture = this.textureAtlas.texture;\n\t\tquad.material.layer = layer;\n\t\trenderer.setRenderTarget( null );\n\t\tquad.render( renderer );\n\n\t}\n\n\tdispose() {\n\n\t\tthis._pathTracer.dispose();\n\t\tthis._blitQuad.dispose();\n\t\tthis._lowResTarget.dispose();\n\t\tthis._envColorTexture.dispose();\n\t\tthis._backgroundColorTexture.dispose();\n\t\tthis._atlasDebugQuad?.dispose();\n\n\t}\n\n\tasync getDetailedSampleCount() {\n\n\t\tconst sampleCountTarget = this._pathTracer.sampleCountTarget;\n\t\tconst { width, height } = sampleCountTarget;\n\t\tconst renderer = this._renderer;\n\n\t\t// Create a stub \"render target\" with just textures field to read from the storage texture\n\t\tconst targetStub = { textures: [ sampleCountTarget ] };\n\n\t\tconst buffer = await renderer.readRenderTargetPixelsAsync( targetStub, 0, 0, width, height );\n\t\tconst uintBuffer = new Uint32Array( buffer.buffer );\n\n\t\t// copyTexture requires a multiple of 256 bytes for texelsPerRow\n\t\t// Hence a multiple of 64 u32 per row\n\t\tconst texelsPerRow = Math.ceil( width / 64 ) * 64;\n\n\t\t// Sum up all sample counts and divide by pixel count to get average samples per pixel\n\t\tlet totalSamples = 0;\n\t\tlet minSamples = Number.MAX_VALUE;\n\t\tlet maxSamples = - Number.MAX_VALUE;\n\t\tfor ( let i = 0, l = uintBuffer.length; i < l; i ++ ) {\n\n\t\t\t// Skip padding\n\t\t\tif ( i % texelsPerRow >= width ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\t// Each entry contains sample count in lower bits and active flag in high bit\n\t\t\t// Mask out the active flag (0xF0000000) to get just the sample count\n\t\t\tconst samples = uintBuffer[ i ] & 0x0FFFFFFF;\n\n\t\t\ttotalSamples += samples;\n\t\t\tminSamples = Math.min( minSamples, samples );\n\t\t\tmaxSamples = Math.max( maxSamples, samples );\n\n\t\t}\n\n\t\treturn {\n\t\t\tmin: minSamples,\n\t\t\tmax: maxSamples,\n\t\t\tavg: Math.floor( totalSamples / ( width * height ) ),\n\t\t};\n\n\n\t}\n\n\t// Returns time since last reset in ms\n\tgetRenderTime() {\n\n\t\treturn this._resetTime;\n\n\t}\n\n}\n\nfunction convertToTexture( renderer, value, colorTexture ) {\n\n\tif ( ! value ) {\n\n\t\tconst clearAlpha = renderer.getClearAlpha();\n\t\trenderer.getClearColor( _color );\n\n\t\tcolorTexture.image.data[ 0 ] = _color.r * 255;\n\t\tcolorTexture.image.data[ 1 ] = _color.g * 255;\n\t\tcolorTexture.image.data[ 2 ] = _color.b * 255;\n\t\tcolorTexture.image.data[ 3 ] = clearAlpha * 255;\n\n\t\tcolorTexture.needsUpdate = true;\n\t\tvalue = colorTexture;\n\n\t} else if ( value.isColor ) {\n\n\t\tcolorTexture.image.data[ 0 ] = value.r * 255;\n\t\tcolorTexture.image.data[ 1 ] = value.g * 255;\n\t\tcolorTexture.image.data[ 2 ] = value.b * 255;\n\t\tcolorTexture.image.data[ 3 ] = 255;\n\t\tcolorTexture.needsUpdate = true;\n\t\tvalue = colorTexture;\n\n\t} else if ( value?.isCubeTexture ) {\n\n\t\tvalue = new CubeToEquirectGenerator( renderer ).generate( value );\n\n\t}\n\n\treturn value;\n\n}\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"mappings":"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"}