@driftengine/core 4.10.0 → 4.11.0

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 (140) hide show
  1. package/CHANGELOG.json +71 -0
  2. package/README.md +1 -1
  3. package/dist/index.d.ts +4 -3
  4. package/dist/index.js +1 -1
  5. package/dist/render/backend/webgl2/renderer.d.ts +99 -2
  6. package/dist/render/backend/webgl2/renderer.js +361 -42
  7. package/dist/render/backend/webgpu/buffers.d.ts +5 -0
  8. package/dist/render/backend/webgpu/buffers.js +98 -48
  9. package/dist/render/backend/webgpu/clothKernels.d.ts +8 -0
  10. package/dist/render/backend/webgpu/clothKernels.js +76 -0
  11. package/dist/render/backend/webgpu/clothOps.d.ts +39 -0
  12. package/dist/render/backend/webgpu/clothOps.js +78 -0
  13. package/dist/render/backend/webgpu/clothSetLayout.d.ts +25 -0
  14. package/dist/render/backend/webgpu/clothSetLayout.js +84 -0
  15. package/dist/render/backend/webgpu/clothSetPack.d.ts +33 -0
  16. package/dist/render/backend/webgpu/clothSetPack.js +144 -0
  17. package/dist/render/backend/webgpu/drawCommand.d.ts +2 -0
  18. package/dist/render/backend/webgpu/drawCommand.js +1 -0
  19. package/dist/render/backend/webgpu/flatPass.d.ts +1 -1
  20. package/dist/render/backend/webgpu/flatPass.js +2 -1
  21. package/dist/render/backend/webgpu/gpuClothSet.d.ts +80 -0
  22. package/dist/render/backend/webgpu/gpuClothSet.js +462 -0
  23. package/dist/render/backend/webgpu/latePass.js +1 -0
  24. package/dist/render/backend/webgpu/motionPass.js +15 -6
  25. package/dist/render/backend/webgpu/pipelineCache.d.ts +22 -1
  26. package/dist/render/backend/webgpu/pipelineCache.js +39 -1
  27. package/dist/render/backend/webgpu/postPass.d.ts +1 -1
  28. package/dist/render/backend/webgpu/renderer.d.ts +48 -0
  29. package/dist/render/backend/webgpu/renderer.js +207 -27
  30. package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.d.ts +9 -2
  31. package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.js +121 -47
  32. package/dist/render/backend/webgpu/staticBundles.js +2 -1
  33. package/dist/render/backend/webgpu/vertexFormats.d.ts +22 -0
  34. package/dist/render/backend/webgpu/vertexFormats.js +97 -0
  35. package/dist/render/globalMediumPass.d.ts +2 -0
  36. package/dist/render/globalMediumPass.js +1 -0
  37. package/dist/render/indexWidth.d.ts +17 -0
  38. package/dist/render/indexWidth.js +23 -0
  39. package/dist/render/lightMatrix.d.ts +11 -0
  40. package/dist/render/lightMatrix.js +14 -0
  41. package/dist/render/mesh.d.ts +9 -0
  42. package/dist/render/mesh.js +38 -14
  43. package/dist/render/renderQuality.d.ts +30 -0
  44. package/dist/render/renderQuality.js +5 -0
  45. package/dist/render/rendererHarness.d.ts +7 -0
  46. package/dist/render/rendererHarness.js +12 -0
  47. package/dist/render/shader.d.ts +15 -0
  48. package/dist/render/shader.js +41 -0
  49. package/dist/render/shaders/flat/directionalShadow.js +84 -10
  50. package/dist/render/shaders/flat/glassTint.d.ts +1 -1
  51. package/dist/render/shaders/flat/glassTint.js +3 -0
  52. package/dist/render/shaders/flat/index.d.ts +15 -0
  53. package/dist/render/shaders/flat/index.js +15 -2
  54. package/dist/render/shaders/flat/layered.d.ts +19 -0
  55. package/dist/render/shaders/flat/layered.js +115 -0
  56. package/dist/render/shaders/flat/main.d.ts +1 -1
  57. package/dist/render/shaders/flat/main.js +43 -16
  58. package/dist/render/shaders/flat/mapReads.d.ts +10 -0
  59. package/dist/render/shaders/flat/mapReads.js +38 -0
  60. package/dist/render/shaders/flat/movingSun.d.ts +21 -0
  61. package/dist/render/shaders/flat/movingSun.js +46 -0
  62. package/dist/render/shaders/flat/normalMap.d.ts +6 -2
  63. package/dist/render/shaders/flat/normalMap.js +14 -3
  64. package/dist/render/shaders/flat/overlay.d.ts +3 -2
  65. package/dist/render/shaders/flat/overlay.js +41 -19
  66. package/dist/render/shaders/flat/preamble.js +23 -5
  67. package/dist/render/shaders/flat/worldUv.d.ts +22 -0
  68. package/dist/render/shaders/flat/worldUv.js +113 -0
  69. package/dist/render/shaders/generated/flat.wgsl.d.ts +768 -368
  70. package/dist/render/shaders/generated/flat.wgsl.js +791 -391
  71. package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +8 -3
  72. package/dist/render/shaders/generated/globalMedium.wgsl.js +8 -3
  73. package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +15 -10
  74. package/dist/render/shaders/generated/lightVolume.wgsl.js +16 -11
  75. package/dist/render/shaders/globalMedium.js +9 -1
  76. package/dist/render/shaders/lightVolume.js +9 -1
  77. package/dist/render/shaders/tangentFrame.d.ts +1 -1
  78. package/dist/render/shaders/tangentFrame.js +16 -3
  79. package/dist/render/skinnedClothRun.d.ts +28 -0
  80. package/dist/render/skinnedClothRun.js +103 -35
  81. package/dist/render/surfaceLayers.d.ts +39 -0
  82. package/dist/render/surfaceLayers.js +26 -0
  83. package/dist/render/surfaceOverlay.d.ts +16 -3
  84. package/dist/render/surfaceOverlay.js +11 -6
  85. package/dist/render/surfaceProjection.d.ts +34 -0
  86. package/dist/render/surfaceProjection.js +30 -0
  87. package/dist/render/surfaceTexture.d.ts +30 -0
  88. package/dist/render/vertexPacking.d.ts +48 -0
  89. package/dist/render/vertexPacking.js +68 -0
  90. package/package.json +6 -6
  91. package/src/index.ts +4 -2
  92. package/src/render/backend/webgl2/renderer.ts +408 -55
  93. package/src/render/backend/webgpu/buffers.ts +153 -54
  94. package/src/render/backend/webgpu/clothKernels.ts +86 -0
  95. package/src/render/backend/webgpu/clothOps.ts +86 -0
  96. package/src/render/backend/webgpu/clothSetLayout.ts +102 -0
  97. package/src/render/backend/webgpu/clothSetPack.ts +197 -0
  98. package/src/render/backend/webgpu/drawCommand.ts +3 -0
  99. package/src/render/backend/webgpu/flatPass.ts +26 -28
  100. package/src/render/backend/webgpu/gpuClothSet.ts +564 -0
  101. package/src/render/backend/webgpu/latePass.ts +1 -0
  102. package/src/render/backend/webgpu/motionPass.ts +18 -7
  103. package/src/render/backend/webgpu/pipelineCache.ts +46 -7
  104. package/src/render/backend/webgpu/renderer.ts +274 -48
  105. package/src/render/backend/webgpu/shaders/clothSolve.wgsl.ts +121 -47
  106. package/src/render/backend/webgpu/staticBundles.ts +2 -1
  107. package/src/render/backend/webgpu/vertexFormats.ts +113 -0
  108. package/src/render/globalMediumPass.ts +7 -0
  109. package/src/render/indexWidth.ts +27 -0
  110. package/src/render/lightMatrix.ts +15 -0
  111. package/src/render/mesh.ts +66 -14
  112. package/src/render/renderQuality.ts +38 -0
  113. package/src/render/rendererHarness.ts +15 -0
  114. package/src/render/shader.ts +59 -0
  115. package/src/render/shaders/flat/directionalShadow.ts +84 -10
  116. package/src/render/shaders/flat/glassTint.ts +7 -1
  117. package/src/render/shaders/flat/index.ts +30 -2
  118. package/src/render/shaders/flat/layered.ts +115 -0
  119. package/src/render/shaders/flat/main.ts +43 -16
  120. package/src/render/shaders/flat/mapReads.ts +38 -0
  121. package/src/render/shaders/flat/movingSun.ts +46 -0
  122. package/src/render/shaders/flat/normalMap.ts +14 -3
  123. package/src/render/shaders/flat/overlay.ts +41 -19
  124. package/src/render/shaders/flat/preamble.ts +23 -5
  125. package/src/render/shaders/flat/worldUv.ts +113 -0
  126. package/src/render/shaders/generated/flat.wgsl.ts +791 -391
  127. package/src/render/shaders/generated/globalMedium.wgsl.ts +8 -3
  128. package/src/render/shaders/generated/lightVolume.wgsl.ts +16 -11
  129. package/src/render/shaders/globalMedium.ts +9 -1
  130. package/src/render/shaders/lightVolume.ts +9 -1
  131. package/src/render/shaders/tangentFrame.ts +16 -3
  132. package/src/render/skinnedClothRun.ts +138 -38
  133. package/src/render/surfaceLayers.ts +57 -0
  134. package/src/render/surfaceOverlay.ts +24 -7
  135. package/src/render/surfaceProjection.ts +57 -0
  136. package/src/render/surfaceTexture.ts +30 -0
  137. package/src/render/vertexPacking.ts +109 -0
  138. package/dist/render/backend/webgpu/gpuSkinnedCloth.d.ts +0 -74
  139. package/dist/render/backend/webgpu/gpuSkinnedCloth.js +0 -452
  140. package/src/render/backend/webgpu/gpuSkinnedCloth.ts +0 -502
@@ -5,7 +5,7 @@
5
5
  * the next generation, and `npm run wgsl:check` fails the build when this is stale.
6
6
  */
7
7
 
8
- export const MEDIUM_FRAG_WGSL = "struct Uniforms {\n uDepthToWorld: mat4x4<f32>,\n uCameraPos: vec3<f32>,\n uSunDir: vec3<f32>,\n uSunColor: vec3<f32>,\n uAmbient: vec3<f32>,\n uDensity: f32,\n uAlbedo: f32,\n uAnisotropy: f32,\n uMaxDistance: f32,\n uSteps: i32,\n uSunShadow: f32,\n uLightViewProj: mat4x4<f32>,\n uPeeledShadowEnabled: i32,\n}\n\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(34) \nvar uSunShadows_t: texture_2d_array<f32>;\n@group(0) @binding(35) \nvar uSunShadows_s: sampler;\nvar<private> vUv_1: vec2<f32>;\n@group(0) @binding(32) \nvar uDepth_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uDepth_s: sampler;\nvar<private> fragColor: vec4<f32>;\nvar<private> gl_FragCoord_1: vec4<f32>;\n\nfn occlusion_u0028_f1_u003b_f1_u003b(stored: ptr<function, f32>, compare: ptr<function, f32>) -> f32 {\n let _e48 = (*compare);\n let _e49 = (*stored);\n return smoothstep(-0.0025f, 0.0025f, (_e48 - _e49));\n}\n\nfn sunReach_u0028_vf3_u003b(worldPos: ptr<function, vec3<f32>>) -> f32 {\n var lightPos: vec4<f32>;\n var p: vec3<f32>;\n var fromCentre: vec2<f32>;\n var edgeFade: f32;\n var compare_1: f32;\n var blocked: f32;\n var param: f32;\n var param_1: f32;\n var param_2: f32;\n var param_3: f32;\n var param_4: f32;\n var param_5: f32;\n var phi_99_: bool;\n var phi_106_: bool;\n var phi_114_: bool;\n var phi_121_: bool;\n\n let _e60 = unnamed.uLightViewProj;\n let _e61 = (*worldPos);\n lightPos = (_e60 * vec4<f32>(_e61.x, _e61.y, _e61.z, 1f));\n let _e68 = lightPos[3u];\n if (_e68 <= 0f) {\n return 1f;\n }\n let _e70 = lightPos;\n let _e73 = lightPos[3u];\n p = (((_e70.xyz / vec3(_e73)) * 0.5f) + vec3(0.5f));\n let _e80 = p[2u];\n let _e81 = (_e80 > 1f);\n phi_99_ = _e81;\n if !(_e81) {\n let _e84 = p[0u];\n phi_99_ = (_e84 < 0f);\n }\n let _e87 = phi_99_;\n phi_106_ = _e87;\n if !(_e87) {\n let _e90 = p[0u];\n phi_106_ = (_e90 > 1f);\n }\n let _e93 = phi_106_;\n phi_114_ = _e93;\n if !(_e93) {\n let _e96 = p[1u];\n phi_114_ = (_e96 < 0f);\n }\n let _e99 = phi_114_;\n phi_121_ = _e99;\n if !(_e99) {\n let _e102 = p[1u];\n phi_121_ = (_e102 > 1f);\n }\n let _e105 = phi_121_;\n if _e105 {\n return 1f;\n }\n let _e106 = p;\n fromCentre = (abs((_e106.xy - vec2(0.5f))) * 2f);\n let _e113 = fromCentre[0u];\n let _e115 = fromCentre[1u];\n edgeFade = (1f - smoothstep(0.72f, 0.98f, max(_e113, _e115)));\n let _e120 = p[2u];\n let _e123 = edgeFade;\n edgeFade = (_e123 * (1f - smoothstep(0.9f, 1f, _e120)));\n let _e125 = edgeFade;\n if (_e125 <= 0f) {\n return 1f;\n }\n let _e128 = p[2u];\n compare_1 = (_e128 - 0.0015f);\n let _e130 = p;\n let _e131 = _e130.xy;\n let _e134 = vec3<f32>(_e131.x, _e131.y, 0f);\n let _e140 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e134.x, _e134.y), i32(_e134.z), 0f);\n param = _e140.x;\n let _e142 = compare_1;\n param_1 = _e142;\n let _e143 = occlusion_u0028_f1_u003b_f1_u003b((&param), (&param_1));\n blocked = _e143;\n let _e145 = unnamed.uPeeledShadowEnabled;\n if (_e145 != 0i) {\n let _e147 = blocked;\n let _e148 = p;\n let _e149 = _e148.xy;\n let _e152 = vec3<f32>(_e149.x, _e149.y, 2f);\n let _e158 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e152.x, _e152.y), i32(_e152.z), 0f);\n param_2 = _e158.x;\n let _e160 = compare_1;\n param_3 = _e160;\n let _e161 = occlusion_u0028_f1_u003b_f1_u003b((&param_2), (&param_3));\n blocked = max(_e147, _e161);\n }\n let _e163 = blocked;\n let _e164 = p;\n let _e165 = _e164.xy;\n let _e168 = vec3<f32>(_e165.x, _e165.y, 1f);\n let _e174 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e168.x, _e168.y), i32(_e168.z), 0f);\n param_4 = _e174.x;\n let _e176 = compare_1;\n param_5 = _e176;\n let _e177 = occlusion_u0028_f1_u003b_f1_u003b((&param_4), (&param_5));\n blocked = max(_e163, _e177);\n let _e179 = blocked;\n let _e182 = unnamed.uSunShadow;\n let _e183 = edgeFade;\n return mix(1f, (1f - _e179), (_e182 * _e183));\n}\n\nfn phase_u0028_f1_u003b_f1_u003b(cosTheta: ptr<function, f32>, g: ptr<function, f32>) -> f32 {\n var g2_: f32;\n var d: f32;\n\n let _e50 = (*g);\n let _e51 = (*g);\n g2_ = (_e50 * _e51);\n let _e53 = g2_;\n let _e55 = (*g);\n let _e57 = (*cosTheta);\n d = max(((1f + _e53) - ((2f * _e55) * _e57)), 0.0001f);\n let _e61 = g2_;\n let _e63 = d;\n let _e65 = d;\n return ((1f - _e61) / ((12.566371f * _e63) * sqrt(_e65)));\n}\n\nfn hash21_u0028_vf2_u003b(p_1: ptr<function, vec2<f32>>) -> f32 {\n let _e47 = (*p_1);\n return fract((sin(dot(_e47, vec2<f32>(127.1f, 311.7f))) * 43758.547f));\n}\n\nfn main_1() {\n var ndc: vec2<f32>;\n var probe: vec4<f32>;\n var dir: vec3<f32>;\n var stored_1: f32;\n var far: f32;\n var hit: vec4<f32>;\n var steps: i32;\n var dither: f32;\n var param_6: vec2<f32>;\n var scatter: f32;\n var param_7: f32;\n var param_8: f32;\n var sunLit: vec3<f32>;\n var skyLit: vec3<f32>;\n var inscatter: vec3<f32>;\n var transmittance: f32;\n var previous: f32;\n var i: i32;\n var u: f32;\n var next: f32;\n var segment: f32;\n var travelled: f32;\n var segmentTransmittance: f32;\n var scattered: f32;\n var lit: f32;\n var param_9: vec3<f32>;\n\n let _e72 = vUv_1;\n ndc = ((_e72 * 2f) - vec2(1f));\n let _e77 = unnamed.uDepthToWorld;\n let _e78 = ndc;\n probe = (_e77 * vec4<f32>(_e78.x, _e78.y, 0.5f, 1f));\n let _e83 = probe;\n let _e86 = probe[3u];\n let _e90 = unnamed.uCameraPos;\n dir = normalize(((_e83.xyz / vec3(_e86)) - _e90));\n let _e93 = vUv_1;\n let _e94 = textureSampleLevel(uDepth_t, uDepth_s, _e93, 0f);\n stored_1 = _e94.x;\n let _e97 = unnamed.uMaxDistance;\n far = _e97;\n let _e98 = stored_1;\n if !((_e98 <= 0f)) {\n let _e102 = unnamed.uDepthToWorld;\n let _e103 = ndc;\n let _e104 = stored_1;\n hit = (_e102 * vec4<f32>(_e103.x, _e103.y, _e104, 1f));\n let _e110 = hit[3u];\n if (_e110 > 0.000001f) {\n let _e112 = far;\n let _e113 = hit;\n let _e116 = hit[3u];\n let _e120 = unnamed.uCameraPos;\n let _e122 = dir;\n far = min(_e112, dot(((_e113.xyz / vec3(_e116)) - _e120), _e122));\n }\n }\n let _e125 = far;\n if (_e125 <= 0f) {\n fragColor = vec4<f32>(0f, 0f, 0f, 1f);\n return;\n }\n let _e128 = unnamed.uSteps;\n steps = clamp(_e128, 1i, 64i);\n let _e130 = gl_FragCoord_1;\n param_6 = _e130.xy;\n let _e132 = hash21_u0028_vf2_u003b((&param_6));\n dither = (_e132 - 0.5f);\n let _e135 = unnamed.uAlbedo;\n let _e136 = dir;\n let _e138 = unnamed.uSunDir;\n param_7 = dot(_e136, _e138);\n let _e141 = unnamed.uAnisotropy;\n param_8 = _e141;\n let _e142 = phase_u0028_f1_u003b_f1_u003b((&param_7), (&param_8));\n scatter = (_e135 * _e142);\n let _e145 = unnamed.uSunColor;\n let _e146 = scatter;\n sunLit = (_e145 * _e146);\n let _e149 = unnamed.uAmbient;\n let _e151 = unnamed.uAlbedo;\n skyLit = ((_e149 * _e151) * 0.07957747f);\n inscatter = vec3<f32>(0f, 0f, 0f);\n transmittance = 1f;\n previous = 0f;\n i = 0i;\n loop {\n let _e154 = i;\n if (_e154 < 64i) {\n let _e156 = i;\n let _e157 = steps;\n if (_e156 >= _e157) {\n break;\n }\n let _e159 = i;\n let _e162 = steps;\n u = (f32((_e159 + 1i)) / f32(_e162));\n let _e165 = far;\n let _e166 = u;\n next = (_e165 * pow(_e166, 2f));\n let _e169 = next;\n let _e170 = previous;\n segment = (_e169 - _e170);\n let _e172 = previous;\n let _e173 = next;\n travelled = (0.5f * (_e172 + _e173));\n let _e176 = next;\n previous = _e176;\n let _e178 = unnamed.uDensity;\n let _e180 = segment;\n segmentTransmittance = exp((-(_e178) * _e180));\n let _e183 = segmentTransmittance;\n scattered = (1f - _e183);\n lit = 1f;\n let _e186 = unnamed.uSunShadow;\n if (_e186 > 0f) {\n let _e189 = unnamed.uCameraPos;\n let _e190 = dir;\n let _e191 = travelled;\n let _e192 = dither;\n let _e193 = segment;\n param_9 = (_e189 + (_e190 * (_e191 + (_e192 * _e193))));\n let _e198 = sunReach_u0028_vf3_u003b((&param_9));\n lit = _e198;\n }\n let _e199 = transmittance;\n let _e200 = scattered;\n let _e202 = sunLit;\n let _e203 = lit;\n let _e205 = skyLit;\n let _e208 = inscatter;\n inscatter = (_e208 + (((_e202 * _e203) + _e205) * (_e199 * _e200)));\n let _e210 = segmentTransmittance;\n let _e211 = transmittance;\n transmittance = (_e211 * _e210);\n continue;\n } else {\n break;\n }\n continuing {\n let _e213 = i;\n i = (_e213 + 1i);\n }\n }\n let _e215 = inscatter;\n let _e216 = (_e215 * 12.566371f);\n let _e217 = transmittance;\n fragColor = vec4<f32>(_e216.x, _e216.y, _e216.z, _e217);\n return;\n}\n\n@fragment \nfn main(@location(0) vUv: vec2<f32>, @builtin(position) gl_FragCoord: vec4<f32>) -> @location(0) vec4<f32> {\n vUv_1 = vUv;\n gl_FragCoord_1 = gl_FragCoord;\n main_1();\n let _e5 = fragColor;\n return _e5;\n}\n";
8
+ export const MEDIUM_FRAG_WGSL = "struct Uniforms {\n uDepthToWorld: mat4x4<f32>,\n uCameraPos: vec3<f32>,\n uSunDir: vec3<f32>,\n uSunColor: vec3<f32>,\n uAmbient: vec3<f32>,\n uDensity: f32,\n uAlbedo: f32,\n uAnisotropy: f32,\n uMaxDistance: f32,\n uSteps: i32,\n uSunShadow: f32,\n uLightViewProj: mat4x4<f32>,\n uMovingLightViewProj: mat4x4<f32>,\n uPeeledShadowEnabled: i32,\n}\n\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(34) \nvar uSunShadows_t: texture_2d_array<f32>;\n@group(0) @binding(35) \nvar uSunShadows_s: sampler;\nvar<private> vUv_1: vec2<f32>;\n@group(0) @binding(32) \nvar uDepth_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uDepth_s: sampler;\nvar<private> fragColor: vec4<f32>;\nvar<private> gl_FragCoord_1: vec4<f32>;\n\nfn occlusion_u0028_f1_u003b_f1_u003b(stored: ptr<function, f32>, compare: ptr<function, f32>) -> f32 {\n let _e49 = (*compare);\n let _e50 = (*stored);\n return smoothstep(-0.0025f, 0.0025f, (_e49 - _e50));\n}\n\nfn sunReach_u0028_vf3_u003b(worldPos: ptr<function, vec3<f32>>) -> f32 {\n var lightPos: vec4<f32>;\n var p: vec3<f32>;\n var fromCentre: vec2<f32>;\n var edgeFade: f32;\n var compare_1: f32;\n var blocked: f32;\n var param: f32;\n var param_1: f32;\n var param_2: f32;\n var param_3: f32;\n var movingPos: vec4<f32>;\n var pm: vec3<f32>;\n var param_4: f32;\n var param_5: f32;\n var phi_99_: bool;\n var phi_106_: bool;\n var phi_114_: bool;\n var phi_121_: bool;\n var phi_234_: bool;\n var phi_240_: bool;\n var phi_246_: bool;\n var phi_252_: bool;\n var phi_258_: bool;\n\n let _e63 = unnamed.uLightViewProj;\n let _e64 = (*worldPos);\n lightPos = (_e63 * vec4<f32>(_e64.x, _e64.y, _e64.z, 1f));\n let _e71 = lightPos[3u];\n if (_e71 <= 0f) {\n return 1f;\n }\n let _e73 = lightPos;\n let _e76 = lightPos[3u];\n p = (((_e73.xyz / vec3(_e76)) * 0.5f) + vec3(0.5f));\n let _e83 = p[2u];\n let _e84 = (_e83 > 1f);\n phi_99_ = _e84;\n if !(_e84) {\n let _e87 = p[0u];\n phi_99_ = (_e87 < 0f);\n }\n let _e90 = phi_99_;\n phi_106_ = _e90;\n if !(_e90) {\n let _e93 = p[0u];\n phi_106_ = (_e93 > 1f);\n }\n let _e96 = phi_106_;\n phi_114_ = _e96;\n if !(_e96) {\n let _e99 = p[1u];\n phi_114_ = (_e99 < 0f);\n }\n let _e102 = phi_114_;\n phi_121_ = _e102;\n if !(_e102) {\n let _e105 = p[1u];\n phi_121_ = (_e105 > 1f);\n }\n let _e108 = phi_121_;\n if _e108 {\n return 1f;\n }\n let _e109 = p;\n fromCentre = (abs((_e109.xy - vec2(0.5f))) * 2f);\n let _e116 = fromCentre[0u];\n let _e118 = fromCentre[1u];\n edgeFade = (1f - smoothstep(0.72f, 0.98f, max(_e116, _e118)));\n let _e123 = p[2u];\n let _e126 = edgeFade;\n edgeFade = (_e126 * (1f - smoothstep(0.9f, 1f, _e123)));\n let _e128 = edgeFade;\n if (_e128 <= 0f) {\n return 1f;\n }\n let _e131 = p[2u];\n compare_1 = (_e131 - 0.0015f);\n let _e133 = p;\n let _e134 = _e133.xy;\n let _e137 = vec3<f32>(_e134.x, _e134.y, 0f);\n let _e143 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e137.x, _e137.y), i32(_e137.z), 0f);\n param = _e143.x;\n let _e145 = compare_1;\n param_1 = _e145;\n let _e146 = occlusion_u0028_f1_u003b_f1_u003b((&param), (&param_1));\n blocked = _e146;\n let _e148 = unnamed.uPeeledShadowEnabled;\n if (_e148 != 0i) {\n let _e150 = blocked;\n let _e151 = p;\n let _e152 = _e151.xy;\n let _e155 = vec3<f32>(_e152.x, _e152.y, 2f);\n let _e161 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e155.x, _e155.y), i32(_e155.z), 0f);\n param_2 = _e161.x;\n let _e163 = compare_1;\n param_3 = _e163;\n let _e164 = occlusion_u0028_f1_u003b_f1_u003b((&param_2), (&param_3));\n blocked = max(_e150, _e164);\n }\n let _e167 = unnamed.uMovingLightViewProj;\n let _e168 = (*worldPos);\n movingPos = (_e167 * vec4<f32>(_e168.x, _e168.y, _e168.z, 1f));\n let _e174 = movingPos;\n let _e177 = movingPos[3u];\n pm = (((_e174.xyz / vec3(_e177)) * 0.5f) + vec3(0.5f));\n let _e184 = movingPos[3u];\n let _e185 = (_e184 > 0f);\n phi_234_ = _e185;\n if _e185 {\n let _e187 = pm[2u];\n phi_234_ = (_e187 <= 1f);\n }\n let _e190 = phi_234_;\n phi_240_ = _e190;\n if _e190 {\n let _e192 = pm[0u];\n phi_240_ = (_e192 >= 0f);\n }\n let _e195 = phi_240_;\n phi_246_ = _e195;\n if _e195 {\n let _e197 = pm[0u];\n phi_246_ = (_e197 <= 1f);\n }\n let _e200 = phi_246_;\n phi_252_ = _e200;\n if _e200 {\n let _e202 = pm[1u];\n phi_252_ = (_e202 >= 0f);\n }\n let _e205 = phi_252_;\n phi_258_ = _e205;\n if _e205 {\n let _e207 = pm[1u];\n phi_258_ = (_e207 <= 1f);\n }\n let _e210 = phi_258_;\n if _e210 {\n let _e211 = blocked;\n let _e212 = pm;\n let _e213 = _e212.xy;\n let _e216 = vec3<f32>(_e213.x, _e213.y, 1f);\n let _e222 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e216.x, _e216.y), i32(_e216.z), 0f);\n let _e224 = pm[2u];\n param_4 = _e222.x;\n param_5 = (_e224 - 0.0015f);\n let _e227 = occlusion_u0028_f1_u003b_f1_u003b((&param_4), (&param_5));\n blocked = max(_e211, _e227);\n }\n let _e229 = blocked;\n let _e232 = unnamed.uSunShadow;\n let _e233 = edgeFade;\n return mix(1f, (1f - _e229), (_e232 * _e233));\n}\n\nfn phase_u0028_f1_u003b_f1_u003b(cosTheta: ptr<function, f32>, g: ptr<function, f32>) -> f32 {\n var g2_: f32;\n var d: f32;\n\n let _e51 = (*g);\n let _e52 = (*g);\n g2_ = (_e51 * _e52);\n let _e54 = g2_;\n let _e56 = (*g);\n let _e58 = (*cosTheta);\n d = max(((1f + _e54) - ((2f * _e56) * _e58)), 0.0001f);\n let _e62 = g2_;\n let _e64 = d;\n let _e66 = d;\n return ((1f - _e62) / ((12.566371f * _e64) * sqrt(_e66)));\n}\n\nfn hash21_u0028_vf2_u003b(p_1: ptr<function, vec2<f32>>) -> f32 {\n let _e48 = (*p_1);\n return fract((sin(dot(_e48, vec2<f32>(127.1f, 311.7f))) * 43758.547f));\n}\n\nfn main_1() {\n var ndc: vec2<f32>;\n var probe: vec4<f32>;\n var dir: vec3<f32>;\n var stored_1: f32;\n var far: f32;\n var hit: vec4<f32>;\n var steps: i32;\n var dither: f32;\n var param_6: vec2<f32>;\n var scatter: f32;\n var param_7: f32;\n var param_8: f32;\n var sunLit: vec3<f32>;\n var skyLit: vec3<f32>;\n var inscatter: vec3<f32>;\n var transmittance: f32;\n var previous: f32;\n var i: i32;\n var u: f32;\n var next: f32;\n var segment: f32;\n var travelled: f32;\n var segmentTransmittance: f32;\n var scattered: f32;\n var lit: f32;\n var param_9: vec3<f32>;\n\n let _e73 = vUv_1;\n ndc = ((_e73 * 2f) - vec2(1f));\n let _e78 = unnamed.uDepthToWorld;\n let _e79 = ndc;\n probe = (_e78 * vec4<f32>(_e79.x, _e79.y, 0.5f, 1f));\n let _e84 = probe;\n let _e87 = probe[3u];\n let _e91 = unnamed.uCameraPos;\n dir = normalize(((_e84.xyz / vec3(_e87)) - _e91));\n let _e94 = vUv_1;\n let _e95 = textureSampleLevel(uDepth_t, uDepth_s, _e94, 0f);\n stored_1 = _e95.x;\n let _e98 = unnamed.uMaxDistance;\n far = _e98;\n let _e99 = stored_1;\n if !((_e99 <= 0f)) {\n let _e103 = unnamed.uDepthToWorld;\n let _e104 = ndc;\n let _e105 = stored_1;\n hit = (_e103 * vec4<f32>(_e104.x, _e104.y, _e105, 1f));\n let _e111 = hit[3u];\n if (_e111 > 0.000001f) {\n let _e113 = far;\n let _e114 = hit;\n let _e117 = hit[3u];\n let _e121 = unnamed.uCameraPos;\n let _e123 = dir;\n far = min(_e113, dot(((_e114.xyz / vec3(_e117)) - _e121), _e123));\n }\n }\n let _e126 = far;\n if (_e126 <= 0f) {\n fragColor = vec4<f32>(0f, 0f, 0f, 1f);\n return;\n }\n let _e129 = unnamed.uSteps;\n steps = clamp(_e129, 1i, 64i);\n let _e131 = gl_FragCoord_1;\n param_6 = _e131.xy;\n let _e133 = hash21_u0028_vf2_u003b((&param_6));\n dither = (_e133 - 0.5f);\n let _e136 = unnamed.uAlbedo;\n let _e137 = dir;\n let _e139 = unnamed.uSunDir;\n param_7 = dot(_e137, _e139);\n let _e142 = unnamed.uAnisotropy;\n param_8 = _e142;\n let _e143 = phase_u0028_f1_u003b_f1_u003b((&param_7), (&param_8));\n scatter = (_e136 * _e143);\n let _e146 = unnamed.uSunColor;\n let _e147 = scatter;\n sunLit = (_e146 * _e147);\n let _e150 = unnamed.uAmbient;\n let _e152 = unnamed.uAlbedo;\n skyLit = ((_e150 * _e152) * 0.07957747f);\n inscatter = vec3<f32>(0f, 0f, 0f);\n transmittance = 1f;\n previous = 0f;\n i = 0i;\n loop {\n let _e155 = i;\n if (_e155 < 64i) {\n let _e157 = i;\n let _e158 = steps;\n if (_e157 >= _e158) {\n break;\n }\n let _e160 = i;\n let _e163 = steps;\n u = (f32((_e160 + 1i)) / f32(_e163));\n let _e166 = far;\n let _e167 = u;\n next = (_e166 * pow(_e167, 2f));\n let _e170 = next;\n let _e171 = previous;\n segment = (_e170 - _e171);\n let _e173 = previous;\n let _e174 = next;\n travelled = (0.5f * (_e173 + _e174));\n let _e177 = next;\n previous = _e177;\n let _e179 = unnamed.uDensity;\n let _e181 = segment;\n segmentTransmittance = exp((-(_e179) * _e181));\n let _e184 = segmentTransmittance;\n scattered = (1f - _e184);\n lit = 1f;\n let _e187 = unnamed.uSunShadow;\n if (_e187 > 0f) {\n let _e190 = unnamed.uCameraPos;\n let _e191 = dir;\n let _e192 = travelled;\n let _e193 = dither;\n let _e194 = segment;\n param_9 = (_e190 + (_e191 * (_e192 + (_e193 * _e194))));\n let _e199 = sunReach_u0028_vf3_u003b((&param_9));\n lit = _e199;\n }\n let _e200 = transmittance;\n let _e201 = scattered;\n let _e203 = sunLit;\n let _e204 = lit;\n let _e206 = skyLit;\n let _e209 = inscatter;\n inscatter = (_e209 + (((_e203 * _e204) + _e206) * (_e200 * _e201)));\n let _e211 = segmentTransmittance;\n let _e212 = transmittance;\n transmittance = (_e212 * _e211);\n continue;\n } else {\n break;\n }\n continuing {\n let _e214 = i;\n i = (_e214 + 1i);\n }\n }\n let _e216 = inscatter;\n let _e217 = (_e216 * 12.566371f);\n let _e218 = transmittance;\n fragColor = vec4<f32>(_e217.x, _e217.y, _e217.z, _e218);\n return;\n}\n\n@fragment \nfn main(@location(0) vUv: vec2<f32>, @builtin(position) gl_FragCoord: vec4<f32>) -> @location(0) vec4<f32> {\n vUv_1 = vUv;\n gl_FragCoord_1 = gl_FragCoord;\n main_1();\n let _e5 = fragColor;\n return _e5;\n}\n";
9
9
 
10
10
  export const MEDIUM_UPSAMPLE_FRAG_WGSL = "struct Uniforms {\n uMediumTexel: vec2<f32>,\n uDepthToViewZ: vec4<f32>,\n}\n\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(34) \nvar uDepth_t: texture_2d<f32>;\n@group(0) @binding(35) \nvar uDepth_s: sampler;\nvar<private> vUv_1: vec2<f32>;\n@group(0) @binding(32) \nvar uMedium_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uMedium_s: sampler;\nvar<private> fragColor: vec4<f32>;\n\nfn viewDistance_u0028_f1_u003b(stored: ptr<function, f32>) -> f32 {\n var ndc: f32;\n\n let _e27 = (*stored);\n ndc = (1f - (_e27 * 2f));\n let _e32 = unnamed.uDepthToViewZ[0u];\n let _e33 = ndc;\n let _e37 = unnamed.uDepthToViewZ[1u];\n let _e41 = unnamed.uDepthToViewZ[2u];\n let _e42 = ndc;\n let _e46 = unnamed.uDepthToViewZ[3u];\n return abs((((_e32 * _e33) + _e37) / ((_e41 * _e42) + _e46)));\n}\n\nfn main_1() {\n var here: f32;\n var param: f32;\n var coord: vec2<f32>;\n var base: vec2<f32>;\n var f: vec2<f32>;\n var total: vec4<f32>;\n var weight: f32;\n var nearest: vec4<f32>;\n var nearestGap: f32;\n var i: i32;\n var offset: vec2<f32>;\n var uv: vec2<f32>;\n var bilinear: f32;\n var there: f32;\n var param_1: f32;\n var gap: f32;\n var sampled: vec4<f32>;\n var depthWeight: f32;\n var local: vec4<f32>;\n\n let _e44 = vUv_1;\n let _e45 = textureSampleLevel(uDepth_t, uDepth_s, _e44, 0f);\n param = _e45.x;\n let _e47 = viewDistance_u0028_f1_u003b((&param));\n here = _e47;\n let _e48 = vUv_1;\n let _e50 = unnamed.uMediumTexel;\n coord = ((_e48 / _e50) - vec2(0.5f));\n let _e54 = coord;\n base = floor(_e54);\n let _e56 = coord;\n let _e57 = base;\n f = (_e56 - _e57);\n total = vec4<f32>(0f, 0f, 0f, 0f);\n weight = 0f;\n nearest = vec4<f32>(0f, 0f, 0f, 1f);\n nearestGap = 1000000000000000000000000000000f;\n i = 0i;\n loop {\n let _e59 = i;\n if (_e59 < 4i) {\n let _e61 = i;\n let _e64 = i;\n offset = vec2<f32>(f32((_e61 & 1i)), f32(((_e64 >> bitcast<u32>(1i)) & 1i)));\n let _e70 = base;\n let _e71 = offset;\n let _e76 = unnamed.uMediumTexel;\n uv = (((_e70 + _e71) + vec2(0.5f)) * _e76);\n let _e79 = f[0u];\n let _e82 = f[0u];\n let _e84 = offset[0u];\n let _e87 = f[1u];\n let _e90 = f[1u];\n let _e92 = offset[1u];\n bilinear = (mix((1f - _e79), _e82, _e84) * mix((1f - _e87), _e90, _e92));\n let _e95 = uv;\n let _e96 = textureSampleLevel(uDepth_t, uDepth_s, _e95, 0f);\n param_1 = _e96.x;\n let _e98 = viewDistance_u0028_f1_u003b((&param_1));\n there = _e98;\n let _e99 = there;\n let _e100 = here;\n let _e103 = there;\n let _e104 = here;\n gap = (abs((_e99 - _e100)) / max(min(_e103, _e104), 0.001f));\n let _e108 = uv;\n let _e109 = textureSampleLevel(uMedium_t, uMedium_s, _e108, 0f);\n sampled = _e109;\n let _e110 = gap;\n let _e111 = nearestGap;\n if (_e110 < _e111) {\n let _e113 = gap;\n nearestGap = _e113;\n let _e114 = sampled;\n nearest = _e114;\n }\n let _e115 = gap;\n depthWeight = (1f - smoothstep(0.04f, 0.05f, _e115));\n let _e118 = sampled;\n let _e119 = bilinear;\n let _e121 = depthWeight;\n let _e123 = total;\n total = (_e123 + ((_e118 * _e119) * _e121));\n let _e125 = bilinear;\n let _e126 = depthWeight;\n let _e128 = weight;\n weight = (_e128 + (_e125 * _e126));\n continue;\n } else {\n break;\n }\n continuing {\n let _e130 = i;\n i = (_e130 + 1i);\n }\n }\n let _e132 = weight;\n if (_e132 > 0.0001f) {\n let _e134 = total;\n let _e135 = weight;\n local = (_e134 / vec4(_e135));\n } else {\n let _e138 = nearest;\n local = _e138;\n }\n let _e139 = local;\n fragColor = _e139;\n return;\n}\n\n@fragment \nfn main(@location(0) vUv: vec2<f32>) -> @location(0) vec4<f32> {\n vUv_1 = vUv;\n main_1();\n let _e3 = fragColor;\n return _e3;\n}\n";
11
11
 
@@ -17,7 +17,7 @@ export const MEDIUM_UPSAMPLE_FRAG_WGSL = "struct Uniforms {\n uMediumTexel: v
17
17
  export const GLOBALMEDIUM_BINDINGS = {
18
18
  "MEDIUM_FRAG": {
19
19
  "uniforms": 1,
20
- "uniformSize": 240,
20
+ "uniformSize": 304,
21
21
  "fields": {
22
22
  "uDepthToWorld": {
23
23
  "offset": 0,
@@ -79,8 +79,13 @@ export const GLOBALMEDIUM_BINDINGS = {
79
79
  "size": 64,
80
80
  "type": "mat4"
81
81
  },
82
- "uPeeledShadowEnabled": {
82
+ "uMovingLightViewProj": {
83
83
  "offset": 224,
84
+ "size": 64,
85
+ "type": "mat4"
86
+ },
87
+ "uPeeledShadowEnabled": {
88
+ "offset": 288,
84
89
  "size": 4,
85
90
  "type": "int"
86
91
  }
@@ -8,7 +8,7 @@
8
8
  export const LIGHT_VOLUME_VERT_WGSL = "struct Uniforms {\n uViewProj: mat4x4<f32>,\n uModel: mat4x4<f32>,\n}\n\nstruct gl_PerVertex {\n @builtin(position) gl_Position: vec4<f32>,\n gl_PointSize: f32,\n}\n\nstruct VertexOutput {\n @location(3) member: vec3<f32>,\n @location(4) member_1: vec3<f32>,\n @location(2) member_2: vec3<f32>,\n @location(0) member_3: vec3<f32>,\n @location(1) member_4: f32,\n @builtin(position) gl_Position: vec4<f32>,\n}\n\n@group(0) @binding(0) \nvar<uniform> unnamed: Uniforms;\nvar<private> aPosition_1: vec3<f32>;\nvar<private> vWorldPos: vec3<f32>;\nvar<private> vLocal: vec3<f32>;\nvar<private> vNormal: vec3<f32>;\nvar<private> aNormal_1: vec3<f32>;\nvar<private> vColor: vec3<f32>;\nvar<private> aColor_1: vec3<f32>;\nvar<private> vEnergy: f32;\nvar<private> aEmissive_1: f32;\nvar<private> unnamed_1: gl_PerVertex = gl_PerVertex(vec4<f32>(0f, 0f, 0f, 1f), 1f);\n\nfn main_1() {\n var world: vec4<f32>;\n\n let _e16 = unnamed.uModel;\n let _e17 = aPosition_1;\n world = (_e16 * vec4<f32>(_e17.x, _e17.y, _e17.z, 1f));\n let _e23 = world;\n vWorldPos = _e23.xyz;\n let _e25 = aPosition_1;\n vLocal = _e25;\n let _e27 = unnamed.uModel;\n let _e35 = aNormal_1;\n vNormal = (mat3x3<f32>(_e27[0].xyz, _e27[1].xyz, _e27[2].xyz) * _e35);\n let _e37 = aColor_1;\n vColor = _e37;\n let _e38 = aEmissive_1;\n vEnergy = _e38;\n let _e40 = unnamed.uViewProj;\n let _e41 = world;\n unnamed_1.gl_Position = (_e40 * _e41);\n return;\n}\n\n@vertex \nfn main(@location(0) aPosition: vec3<f32>, @location(1) aNormal: vec3<f32>, @location(2) aColor: vec3<f32>, @location(3) aEmissive: f32) -> VertexOutput {\n aPosition_1 = aPosition;\n aNormal_1 = aNormal;\n aColor_1 = aColor;\n aEmissive_1 = aEmissive;\n main_1();\n let _e16 = unnamed_1.gl_Position.y;\n unnamed_1.gl_Position.y = -(_e16);\n let _e18 = vWorldPos;\n let _e19 = vLocal;\n let _e20 = vNormal;\n let _e21 = vColor;\n let _e22 = vEnergy;\n let _e23 = unnamed_1.gl_Position;\n return VertexOutput(_e18, _e19, _e20, _e21, _e22, _e23);\n}\n";
9
9
 
10
10
  /** Every distinct top-level item of the permutations below, once. See `wgsl/share.mjs`. */
11
- const PARTS: readonly string[] = ["struct Uniforms {\n uCameraPos: vec3<f32>,\n uStrength: f32,\n uLength: f32,\n uSpread: f32,\n uDust: f32,\n uDustScale: f32,\n uDustOffset: vec3<f32>,\n uNear: f32,\n uCameraLocal: vec3<f32>,\n uModelWorld: mat4x4<f32>,\n uSamples: i32,\n uSceneDepthEnabled: i32,\n uInvViewport: vec2<f32>,\n uDepthToLocal: mat4x4<f32>,\n}","@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\nvar<private> vLocal_1: vec3<f32>;\nvar<private> gl_FragCoord_1: vec4<f32>;\n@group(0) @binding(32) \nvar uSceneDepth_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uSceneDepth_s: sampler;\nvar<private> fragColor: vec4<f32>;\nvar<private> vColor_1: vec3<f32>;\nvar<private> vEnergy_1: f32;\nvar<private> vNormal_1: vec3<f32>;\nvar<private> vWorldPos_1: vec3<f32>;","fn hash31_u0028_vf3_u003b(_l0: ptr<function, vec3<f32>>) -> f32 {\n let _e0 = (*_l0);\n return fract((sin(dot(_e0, vec3<f32>(127.1f, 311.7f, 74.7f))) * 43758.547f));\n}","fn volumeNoise_u0028_vf3_u003b(_l0: ptr<function, vec3<f32>>) -> f32 {\n var _l1: vec3<f32>;\n var _l2: vec3<f32>;\n var _l3: vec3<f32>;\n var _l4: f32;\n var _l5: vec3<f32>;\n var _l6: vec3<f32>;\n var _l7: f32;\n var _l8: vec3<f32>;\n var _l9: vec3<f32>;\n var _l10: f32;\n var _l11: vec3<f32>;\n var _l12: vec3<f32>;\n var _l13: f32;\n var _l14: vec3<f32>;\n var _l15: vec3<f32>;\n\n let _e0 = (*_l0);\n _l1 = floor(_e0);\n let _e1 = (*_l0);\n _l2 = fract(_e1);\n let _e2 = _l2;\n let _e3 = _l2;\n let _e4 = _l2;\n _l3 = ((_e2 * _e3) * (vec3(3f) - (_e4 * 2f)));\n let _e5 = _l1;\n _l5 = (_e5 + vec3<f32>(0f, 0f, 0f));\n let _e6 = hash31_u0028_vf3_u003b((&_l5));\n let _e7 = _l1;\n _l6 = (_e7 + vec3<f32>(1f, 0f, 0f));\n let _e8 = hash31_u0028_vf3_u003b((&_l6));\n let _e9 = _l3[0u];\n _l4 = mix(_e6, _e8, _e9);\n let _e10 = _l1;\n _l8 = (_e10 + vec3<f32>(0f, 1f, 0f));\n let _e11 = hash31_u0028_vf3_u003b((&_l8));\n let _e12 = _l1;\n _l9 = (_e12 + vec3<f32>(1f, 1f, 0f));\n let _e13 = hash31_u0028_vf3_u003b((&_l9));\n let _e14 = _l3[0u];\n _l7 = mix(_e11, _e13, _e14);\n let _e15 = _l1;\n _l11 = (_e15 + vec3<f32>(0f, 0f, 1f));\n let _e16 = hash31_u0028_vf3_u003b((&_l11));\n let _e17 = _l1;\n _l12 = (_e17 + vec3<f32>(1f, 0f, 1f));\n let _e18 = hash31_u0028_vf3_u003b((&_l12));\n let _e19 = _l3[0u];\n _l10 = mix(_e16, _e18, _e19);\n let _e20 = _l1;\n _l14 = (_e20 + vec3<f32>(0f, 1f, 1f));\n let _e21 = hash31_u0028_vf3_u003b((&_l14));\n let _e22 = _l1;\n _l15 = (_e22 + vec3<f32>(1f, 1f, 1f));\n let _e23 = hash31_u0028_vf3_u003b((&_l15));\n let _e24 = _l3[0u];\n _l13 = mix(_e21, _e23, _e24);\n let _e25 = _l4;\n let _e26 = _l7;\n let _e27 = _l3[1u];\n let _e28 = _l10;\n let _e29 = _l13;\n let _e30 = _l3[1u];\n let _e31 = _l3[2u];\n return mix(mix(_e25, _e26, _e27), mix(_e28, _e29, _e30), _e31);\n}","fn dustField_u0028_vf3_u003b(_l0: ptr<function, vec3<f32>>) -> f32 {\n var _l1: vec3<f32>;\n var _l2: vec3<f32>;\n\n let _e0 = (*_l0);\n _l1 = _e0;\n let _e1 = volumeNoise_u0028_vf3_u003b((&_l1));\n let _e2 = (*_l0);\n _l2 = ((_e2 * 2.17f) + vec3(19.3f));\n let _e3 = volumeNoise_u0028_vf3_u003b((&_l2));\n return ((_e1 * 0.65f) + (_e3 * 0.35f));\n}","fn densityAt_u0028_vf3_u003b_f1_u003b(_l0: ptr<function, vec3<f32>>, _l1: ptr<function, f32>) -> f32 {\n var _l2: f32;\n var _l3: f32;\n var _l4: f32;\n var _l5: f32;\n\n let _e0 = unnamed.uLength;\n let _e1 = (*_l1);\n _l2 = max((_e0 - _e1), 0.0001f);\n let _e2 = (*_l0)[2u];\n let _e3 = (*_l1);\n let _e4 = _l2;\n _l3 = clamp(((_e2 - _e3) / _e4), 0f, 1f);\n let _e5 = (*_l0);\n let _e6 = (*_l0)[2u];\n _l4 = (length(_e5.xy) / max(_e6, 0.001f));\n let _e7 = _l4;\n let _e8 = unnamed.uSpread;\n _l5 = clamp((_e7 / max(_e8, 0.0001f)), 0f, 1f);\n let _e9 = _l3;\n let _e10 = _l5;\n return (pow((1f - _e9), 1.3f) * pow((1f - _e10), 2f));\n}","fn main_1() {\n var _l0: vec3<f32>;\n var _l1: vec3<f32>;\n var _l2: f32;\n var _l3: vec3<f32>;\n var _l4: vec3<f32>;\n var _l5: f32;\n var _l6: f32;\n var _l7: f32;\n var _l8: f32;\n var _l9: f32;\n var _l10: f32;\n var _l11: f32;\n var _l12: f32;\n var _l13: f32;\n var _l14: f32;\n var _l15: f32;\n var _l16: vec2<f32>;\n var _l17: f32;\n var _l18: vec4<f32>;\n var _l19: i32;\n var _l20: f32;\n var _l21: i32;\n var _l22: f32;\n var _l23: array<f32, 16>;\n var _l24: vec3<f32>;\n var _l25: f32;\n var _l26: i32;\n var _l27: f32;\n var _l28: vec3<f32>;\n var _l29: f32;\n var _l30: vec3<f32>;\n var _l31: f32;\n var _l32: vec3<f32>;\n var _l33: vec3<f32>;\n var _l34: f32;\n var _l35: f32;\n var _l36: bool;\n\n let _e0 = unnamed.uCameraLocal;\n _l0 = _e0;\n let _e1 = vLocal_1;\n let _e2 = _l0;\n _l1 = (_e1 - _e2);\n let _e3 = _l1;\n _l2 = length(_e3);\n let _e4 = _l2;\n if (_e4 > 0.00001f) {\n let _e5 = _l1;\n let _e6 = _l2;\n _l4 = (_e5 / vec3(_e6));\n } else {\n _l4 = vec3<f32>(0f, 0f, 1f);\n }\n let _e7 = _l4;\n _l3 = _e7;\n let _e8 = unnamed.uNear;\n let _e9 = unnamed.uLength;\n _l5 = min(_e8, _e9);\n _l6 = 0f;\n let _e10 = unnamed.uLength;\n _l7 = (_e10 * 2f);\n let _e11 = _l3[2u];\n if (abs(_e11) > 0.00001f) {\n let _e12 = _l5;\n let _e13 = _l0[2u];\n let _e14 = _l3[2u];\n _l8 = ((_e12 - _e13) / _e14);\n let _e15 = unnamed.uLength;\n let _e16 = _l0[2u];\n let _e17 = _l3[2u];\n _l9 = ((_e15 - _e16) / _e17);\n let _e18 = _l8;\n let _e19 = _l9;\n _l6 = min(_e18, _e19);\n let _e20 = _l8;\n let _e21 = _l9;\n _l7 = max(_e20, _e21);\n } else {\n let _e22 = _l0[2u];\n let _e23 = _l5;\n let _e24 = (_e22 < _e23);\n _l36 = _e24;\n if !(_e24) {\n let _e25 = _l0[2u];\n let _e26 = unnamed.uLength;\n _l36 = (_e25 > _e26);\n }\n let _e27 = _l36;\n if _e27 {\n discard;\n }\n }\n let _e28 = unnamed.uSpread;\n let _e29 = unnamed.uLength;\n _l10 = ((_e28 * _e29) * 1.05f);\n let _e30 = _l3;\n let _e31 = _l3;\n _l11 = dot(_e30.xy, _e31.xy);\n let _e32 = _l0;\n let _e33 = _l3;\n _l12 = (2f * dot(_e32.xy, _e33.xy));\n let _e34 = _l0;\n let _e35 = _l0;\n let _e36 = _l10;\n let _e37 = _l10;\n _l13 = (dot(_e34.xy, _e35.xy) - (_e36 * _e37));\n let _e38 = _l11;\n if (_e38 > 0.00000001f) {\n let _e39 = _l12;\n let _e40 = _l12;\n let _e41 = _l11;\n let _e42 = _l13;\n _l14 = ((_e39 * _e40) - ((4f * _e41) * _e42));\n let _e43 = _l14;\n if (_e43 <= 0f) {\n discard;\n }\n let _e44 = _l14;\n _l15 = sqrt(_e44);\n let _e45 = _l6;\n let _e46 = _l12;\n let _e47 = _l15;\n let _e48 = _l11;\n _l6 = max(_e45, ((-(_e46) - _e47) / (2f * _e48)));\n let _e49 = _l7;\n let _e50 = _l12;\n let _e51 = _l15;\n let _e52 = _l11;\n _l7 = min(_e49, ((-(_e50) + _e51) / (2f * _e52)));\n } else {\n let _e53 = _l13;\n if (_e53 > 0f) {\n discard;\n }\n }\n let _e54 = _l6;\n _l6 = max(_e54, 0f);\n let _e55 = _l7;\n let _e56 = _l6;\n let _e57 = unnamed.uLength;\n _l7 = min(_e55, (_e56 + (_e57 * 2f)));\n let _e58 = unnamed.uSceneDepthEnabled;\n if (_e58 != 0i) {\n let _e59 = gl_FragCoord_1;\n let _e60 = unnamed.uInvViewport;\n _l16 = (_e59.xy * _e60);\n let _e61 = _l16;\n let _e62 = textureSampleLevel(uSceneDepth_t, uSceneDepth_s, _e61, 0f);\n _l17 = _e62.x;\n let _e63 = unnamed.uDepthToLocal;\n let _e64 = _l16;\n let _e65 = ((_e64 * 2f) - vec2(1f));\n let _e66 = _l17;\n _l18 = (_e63 * vec4<f32>(_e65.x, _e65.y, _e66, 1f));\n let _e67 = _l18[3u];\n if (_e67 > 0.000001f) {\n let _e68 = _l7;\n let _e69 = _l18;\n let _e70 = _l18[3u];\n let _e71 = _l0;\n let _e72 = _l3;\n _l7 = min(_e68, dot(((_e69.xyz / vec3(_e70)) - _e71), _e72));\n }\n }\n let _e73 = _l7;\n let _e74 = _l6;\n if (_e73 <= _e74) {\n discard;\n }\n let _e75 = unnamed.uSamples;\n _l19 = clamp(_e75, 2i, 64i);\n let _e76 = _l7;\n let _e77 = _l6;\n let _e78 = _l19;\n _l20 = ((_e76 - _e77) / f32(_e78));\n let _e79 = gl_FragCoord_1[1u];\n let _e80 = gl_FragCoord_1[0u];\n _l21 = ((i32((_e79 - (floor((_e79 / 4f)) * 4f))) * 4i) + i32((_e80 - (floor((_e80 / 4f)) * 4f))));\n let _e81 = _l21;\n _l23 = array<f32, 16>(0f, 8f, 2f, 10f, 12f, 4f, 14f, 6f, 3f, 11f, 1f, 9f, 15f, 7f, 13f, 5f);\n let _e82 = _l23[_e81];\n let _e83 = gl_FragCoord_1;\n let _e84 = _e83.xy;\n _l24 = vec3<f32>(_e84.x, _e84.y, 3.7f);\n let _e85 = hash31_u0028_vf3_u003b((&_l24));\n let _e86 = _l20;\n _l22 = ((((_e82 + _e85) / 16f) - 0.5f) * _e86);\n _l25 = 0f;\n _l26 = 0i;\n loop {\n let _e87 = _l26;\n if (_e87 < 64i) {\n let _e88 = _l26;\n let _e89 = _l19;\n if (_e88 >= _e89) {\n break;\n }\n let _e90 = _l6;\n let _e91 = _l26;\n let _e92 = _l20;\n _l27 = (_e90 + ((f32(_e91) + 0.5f) * _e92));\n let _e93 = _l0;\n let _e94 = _l3;\n let _e95 = _l27;\n _l28 = (_e93 + (_e94 * _e95));\n let _e96 = _l28;\n _l30 = _e96;\n let _e97 = _l5;\n _l31 = _e97;\n let _e98 = densityAt_u0028_vf3_u003b_f1_u003b((&_l30), (&_l31));\n _l29 = _e98;\n let _e99 = _l29;\n if (_e99 <= 0f) {\n continue;\n }\n let _e100 = unnamed.uModelWorld;\n let _e101 = _l28;\n _l32 = (_e100 * vec4<f32>(_e101.x, _e101.y, _e101.z, 1f)).xyz;\n let _e102 = unnamed.uDust;\n if (_e102 > 0f) {\n let _e103 = _l32;\n let _e104 = unnamed.uDustOffset;\n let _e105 = unnamed.uDustScale;\n _l33 = ((_e103 + _e104) / vec3(max(_e105, 0.001f)));\n let _e106 = dustField_u0028_vf3_u003b((&_l33));\n let _e107 = unnamed.uDust;\n let _e108 = _l29;\n _l29 = (_e108 * mix(1f, _e106, _e107));\n }\n let _e109 = _l29;\n let _e110 = _l25;\n _l25 = (_e110 + _e109);\n continue;\n } else {\n break;\n }\n continuing {\n let _e111 = _l26;\n _l26 = (_e111 + 1i);\n }\n }\n let _e112 = unnamed.uSpread;\n let _e113 = unnamed.uLength;\n _l34 = max((_e112 * _e113), 0.0001f);\n let _e114 = _l25;\n let _e115 = _l20;\n let _e116 = _l34;\n _l35 = (1f - exp((((-(_e114) * _e115) / _e116) * 3f)));\n let _e117 = vColor_1;\n let _e118 = vEnergy_1;\n let _e119 = _l35;\n let _e120 = unnamed.uStrength;\n let _e121 = (_e117 * ((_e118 * _e119) * _e120));\n fragColor = vec4<f32>(_e121.x, _e121.y, _e121.z, 1f);\n return;\n}","@fragment \nfn main(@location(4) vLocal: vec3<f32>, @builtin(position) gl_FragCoord: vec4<f32>, @location(0) vColor: vec3<f32>, @location(1) vEnergy: f32, @location(2) vNormal: vec3<f32>, @location(3) vWorldPos: vec3<f32>) -> @location(0) vec4<f32> {\n vLocal_1 = vLocal;\n gl_FragCoord_1 = gl_FragCoord;\n vColor_1 = vColor;\n vEnergy_1 = vEnergy;\n vNormal_1 = vNormal;\n vWorldPos_1 = vWorldPos;\n main_1();\n let _e0 = fragColor;\n return _e0;\n}\n","struct Uniforms {\n uCameraPos: vec3<f32>,\n uStrength: f32,\n uLength: f32,\n uSpread: f32,\n uDust: f32,\n uDustScale: f32,\n uDustOffset: vec3<f32>,\n uSunShadow: f32,\n uLightViewProj: mat4x4<f32>,\n uShadowMapSize: f32,\n uPeeledShadowEnabled: i32,\n uNear: f32,\n uCameraLocal: vec3<f32>,\n uModelWorld: mat4x4<f32>,\n uSamples: i32,\n uSceneDepthEnabled: i32,\n uInvViewport: vec2<f32>,\n uDepthToLocal: mat4x4<f32>,\n}","@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(32) \nvar uSunShadows_t: texture_2d_array<f32>;\n@group(0) @binding(33) \nvar uSunShadows_s: sampler;\nvar<private> vLocal_1: vec3<f32>;\nvar<private> gl_FragCoord_1: vec4<f32>;\n@group(0) @binding(34) \nvar uSceneDepth_t: texture_2d<f32>;\n@group(0) @binding(35) \nvar uSceneDepth_s: sampler;\nvar<private> fragColor: vec4<f32>;\nvar<private> vColor_1: vec3<f32>;\nvar<private> vEnergy_1: f32;\nvar<private> vNormal_1: vec3<f32>;\nvar<private> vWorldPos_1: vec3<f32>;","fn occlusion_u0028_f1_u003b_f1_u003b(_l0: ptr<function, f32>, _l1: ptr<function, f32>) -> f32 {\n let _e0 = (*_l1);\n let _e1 = (*_l0);\n return smoothstep(-0.0025f, 0.0025f, (_e0 - _e1));\n}","fn sunReach_u0028_vf3_u003b(_l0: ptr<function, vec3<f32>>) -> f32 {\n var _l1: vec4<f32>;\n var _l2: vec3<f32>;\n var _l3: vec2<f32>;\n var _l4: f32;\n var _l5: f32;\n var _l6: f32;\n var _l7: f32;\n var _l8: f32;\n var _l9: f32;\n var _l10: f32;\n var _l11: f32;\n var _l12: f32;\n var _l13: bool;\n var _l14: bool;\n var _l15: bool;\n var _l16: bool;\n\n let _e0 = unnamed.uLightViewProj;\n let _e1 = (*_l0);\n _l1 = (_e0 * vec4<f32>(_e1.x, _e1.y, _e1.z, 1f));\n let _e2 = _l1[3u];\n if (_e2 <= 0f) {\n return 1f;\n }\n let _e3 = _l1;\n let _e4 = _l1[3u];\n _l2 = (((_e3.xyz / vec3(_e4)) * 0.5f) + vec3(0.5f));\n let _e5 = _l2[2u];\n let _e6 = (_e5 > 1f);\n _l13 = _e6;\n if !(_e6) {\n let _e7 = _l2[0u];\n _l13 = (_e7 < 0f);\n }\n let _e8 = _l13;\n _l14 = _e8;\n if !(_e8) {\n let _e9 = _l2[0u];\n _l14 = (_e9 > 1f);\n }\n let _e10 = _l14;\n _l15 = _e10;\n if !(_e10) {\n let _e11 = _l2[1u];\n _l15 = (_e11 < 0f);\n }\n let _e12 = _l15;\n _l16 = _e12;\n if !(_e12) {\n let _e13 = _l2[1u];\n _l16 = (_e13 > 1f);\n }\n let _e14 = _l16;\n if _e14 {\n return 1f;\n }\n let _e15 = _l2;\n _l3 = (abs((_e15.xy - vec2(0.5f))) * 2f);\n let _e16 = _l3[0u];\n let _e17 = _l3[1u];\n _l4 = (1f - smoothstep(0.72f, 0.98f, max(_e16, _e17)));\n let _e18 = _l2[2u];\n let _e19 = _l4;\n _l4 = (_e19 * (1f - smoothstep(0.9f, 1f, _e18)));\n let _e20 = _l4;\n if (_e20 <= 0f) {\n return 1f;\n }\n let _e21 = _l2[2u];\n _l5 = (_e21 - 0.0015f);\n let _e22 = _l2;\n let _e23 = _e22.xy;\n let _e24 = vec3<f32>(_e23.x, _e23.y, 0f);\n let _e25 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e24.x, _e24.y), i32(_e24.z), 0f);\n _l7 = _e25.x;\n let _e26 = _l5;\n _l8 = _e26;\n let _e27 = occlusion_u0028_f1_u003b_f1_u003b((&_l7), (&_l8));\n _l6 = _e27;\n let _e28 = unnamed.uPeeledShadowEnabled;\n if (_e28 != 0i) {\n let _e29 = _l6;\n let _e30 = _l2;\n let _e31 = _e30.xy;\n let _e32 = vec3<f32>(_e31.x, _e31.y, 2f);\n let _e33 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e32.x, _e32.y), i32(_e32.z), 0f);\n _l9 = _e33.x;\n let _e34 = _l5;\n _l10 = _e34;\n let _e35 = occlusion_u0028_f1_u003b_f1_u003b((&_l9), (&_l10));\n _l6 = max(_e29, _e35);\n }\n let _e36 = _l6;\n let _e37 = _l2;\n let _e38 = _e37.xy;\n let _e39 = vec3<f32>(_e38.x, _e38.y, 1f);\n let _e40 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e39.x, _e39.y), i32(_e39.z), 0f);\n _l11 = _e40.x;\n let _e41 = _l5;\n _l12 = _e41;\n let _e42 = occlusion_u0028_f1_u003b_f1_u003b((&_l11), (&_l12));\n _l6 = max(_e36, _e42);\n let _e43 = _l6;\n let _e44 = unnamed.uSunShadow;\n let _e45 = _l4;\n return mix(1f, (1f - _e43), (_e44 * _e45));\n}","fn main_1() {\n var _l0: vec3<f32>;\n var _l1: vec3<f32>;\n var _l2: f32;\n var _l3: vec3<f32>;\n var _l4: vec3<f32>;\n var _l5: f32;\n var _l6: f32;\n var _l7: f32;\n var _l8: f32;\n var _l9: f32;\n var _l10: f32;\n var _l11: f32;\n var _l12: f32;\n var _l13: f32;\n var _l14: f32;\n var _l15: f32;\n var _l16: vec2<f32>;\n var _l17: f32;\n var _l18: vec4<f32>;\n var _l19: i32;\n var _l20: f32;\n var _l21: i32;\n var _l22: f32;\n var _l23: array<f32, 16>;\n var _l24: vec3<f32>;\n var _l25: f32;\n var _l26: i32;\n var _l27: f32;\n var _l28: vec3<f32>;\n var _l29: f32;\n var _l30: vec3<f32>;\n var _l31: f32;\n var _l32: vec3<f32>;\n var _l33: vec3<f32>;\n var _l34: vec3<f32>;\n var _l35: vec3<f32>;\n var _l36: f32;\n var _l37: f32;\n var _l38: bool;\n\n let _e0 = unnamed.uCameraLocal;\n _l0 = _e0;\n let _e1 = vLocal_1;\n let _e2 = _l0;\n _l1 = (_e1 - _e2);\n let _e3 = _l1;\n _l2 = length(_e3);\n let _e4 = _l2;\n if (_e4 > 0.00001f) {\n let _e5 = _l1;\n let _e6 = _l2;\n _l4 = (_e5 / vec3(_e6));\n } else {\n _l4 = vec3<f32>(0f, 0f, 1f);\n }\n let _e7 = _l4;\n _l3 = _e7;\n let _e8 = unnamed.uNear;\n let _e9 = unnamed.uLength;\n _l5 = min(_e8, _e9);\n _l6 = 0f;\n let _e10 = unnamed.uLength;\n _l7 = (_e10 * 2f);\n let _e11 = _l3[2u];\n if (abs(_e11) > 0.00001f) {\n let _e12 = _l5;\n let _e13 = _l0[2u];\n let _e14 = _l3[2u];\n _l8 = ((_e12 - _e13) / _e14);\n let _e15 = unnamed.uLength;\n let _e16 = _l0[2u];\n let _e17 = _l3[2u];\n _l9 = ((_e15 - _e16) / _e17);\n let _e18 = _l8;\n let _e19 = _l9;\n _l6 = min(_e18, _e19);\n let _e20 = _l8;\n let _e21 = _l9;\n _l7 = max(_e20, _e21);\n } else {\n let _e22 = _l0[2u];\n let _e23 = _l5;\n let _e24 = (_e22 < _e23);\n _l38 = _e24;\n if !(_e24) {\n let _e25 = _l0[2u];\n let _e26 = unnamed.uLength;\n _l38 = (_e25 > _e26);\n }\n let _e27 = _l38;\n if _e27 {\n discard;\n }\n }\n let _e28 = unnamed.uSpread;\n let _e29 = unnamed.uLength;\n _l10 = ((_e28 * _e29) * 1.05f);\n let _e30 = _l3;\n let _e31 = _l3;\n _l11 = dot(_e30.xy, _e31.xy);\n let _e32 = _l0;\n let _e33 = _l3;\n _l12 = (2f * dot(_e32.xy, _e33.xy));\n let _e34 = _l0;\n let _e35 = _l0;\n let _e36 = _l10;\n let _e37 = _l10;\n _l13 = (dot(_e34.xy, _e35.xy) - (_e36 * _e37));\n let _e38 = _l11;\n if (_e38 > 0.00000001f) {\n let _e39 = _l12;\n let _e40 = _l12;\n let _e41 = _l11;\n let _e42 = _l13;\n _l14 = ((_e39 * _e40) - ((4f * _e41) * _e42));\n let _e43 = _l14;\n if (_e43 <= 0f) {\n discard;\n }\n let _e44 = _l14;\n _l15 = sqrt(_e44);\n let _e45 = _l6;\n let _e46 = _l12;\n let _e47 = _l15;\n let _e48 = _l11;\n _l6 = max(_e45, ((-(_e46) - _e47) / (2f * _e48)));\n let _e49 = _l7;\n let _e50 = _l12;\n let _e51 = _l15;\n let _e52 = _l11;\n _l7 = min(_e49, ((-(_e50) + _e51) / (2f * _e52)));\n } else {\n let _e53 = _l13;\n if (_e53 > 0f) {\n discard;\n }\n }\n let _e54 = _l6;\n _l6 = max(_e54, 0f);\n let _e55 = _l7;\n let _e56 = _l6;\n let _e57 = unnamed.uLength;\n _l7 = min(_e55, (_e56 + (_e57 * 2f)));\n let _e58 = unnamed.uSceneDepthEnabled;\n if (_e58 != 0i) {\n let _e59 = gl_FragCoord_1;\n let _e60 = unnamed.uInvViewport;\n _l16 = (_e59.xy * _e60);\n let _e61 = _l16;\n let _e62 = textureSampleLevel(uSceneDepth_t, uSceneDepth_s, _e61, 0f);\n _l17 = _e62.x;\n let _e63 = unnamed.uDepthToLocal;\n let _e64 = _l16;\n let _e65 = ((_e64 * 2f) - vec2(1f));\n let _e66 = _l17;\n _l18 = (_e63 * vec4<f32>(_e65.x, _e65.y, _e66, 1f));\n let _e67 = _l18[3u];\n if (_e67 > 0.000001f) {\n let _e68 = _l7;\n let _e69 = _l18;\n let _e70 = _l18[3u];\n let _e71 = _l0;\n let _e72 = _l3;\n _l7 = min(_e68, dot(((_e69.xyz / vec3(_e70)) - _e71), _e72));\n }\n }\n let _e73 = _l7;\n let _e74 = _l6;\n if (_e73 <= _e74) {\n discard;\n }\n let _e75 = unnamed.uSamples;\n _l19 = clamp(_e75, 2i, 64i);\n let _e76 = _l7;\n let _e77 = _l6;\n let _e78 = _l19;\n _l20 = ((_e76 - _e77) / f32(_e78));\n let _e79 = gl_FragCoord_1[1u];\n let _e80 = gl_FragCoord_1[0u];\n _l21 = ((i32((_e79 - (floor((_e79 / 4f)) * 4f))) * 4i) + i32((_e80 - (floor((_e80 / 4f)) * 4f))));\n let _e81 = _l21;\n _l23 = array<f32, 16>(0f, 8f, 2f, 10f, 12f, 4f, 14f, 6f, 3f, 11f, 1f, 9f, 15f, 7f, 13f, 5f);\n let _e82 = _l23[_e81];\n let _e83 = gl_FragCoord_1;\n let _e84 = _e83.xy;\n _l24 = vec3<f32>(_e84.x, _e84.y, 3.7f);\n let _e85 = hash31_u0028_vf3_u003b((&_l24));\n let _e86 = _l20;\n _l22 = ((((_e82 + _e85) / 16f) - 0.5f) * _e86);\n _l25 = 0f;\n _l26 = 0i;\n loop {\n let _e87 = _l26;\n if (_e87 < 64i) {\n let _e88 = _l26;\n let _e89 = _l19;\n if (_e88 >= _e89) {\n break;\n }\n let _e90 = _l6;\n let _e91 = _l26;\n let _e92 = _l20;\n _l27 = (_e90 + ((f32(_e91) + 0.5f) * _e92));\n let _e93 = _l0;\n let _e94 = _l3;\n let _e95 = _l27;\n _l28 = (_e93 + (_e94 * _e95));\n let _e96 = _l28;\n _l30 = _e96;\n let _e97 = _l5;\n _l31 = _e97;\n let _e98 = densityAt_u0028_vf3_u003b_f1_u003b((&_l30), (&_l31));\n _l29 = _e98;\n let _e99 = _l29;\n if (_e99 <= 0f) {\n continue;\n }\n let _e100 = unnamed.uModelWorld;\n let _e101 = _l28;\n _l32 = (_e100 * vec4<f32>(_e101.x, _e101.y, _e101.z, 1f)).xyz;\n let _e102 = unnamed.uDust;\n if (_e102 > 0f) {\n let _e103 = _l32;\n let _e104 = unnamed.uDustOffset;\n let _e105 = unnamed.uDustScale;\n _l33 = ((_e103 + _e104) / vec3(max(_e105, 0.001f)));\n let _e106 = dustField_u0028_vf3_u003b((&_l33));\n let _e107 = unnamed.uDust;\n let _e108 = _l29;\n _l29 = (_e108 * mix(1f, _e106, _e107));\n }\n let _e109 = unnamed.uSunShadow;\n if (_e109 > 0f) {\n let _e110 = unnamed.uModelWorld;\n let _e111 = _l0;\n let _e112 = _l3;\n let _e113 = _l27;\n let _e114 = _l22;\n let _e115 = (_e111 + (_e112 * (_e113 + _e114)));\n _l34 = (_e110 * vec4<f32>(_e115.x, _e115.y, _e115.z, 1f)).xyz;\n let _e116 = _l34;\n _l35 = _e116;\n let _e117 = sunReach_u0028_vf3_u003b((&_l35));\n let _e118 = _l29;\n _l29 = (_e118 * _e117);\n }\n let _e119 = _l29;\n let _e120 = _l25;\n _l25 = (_e120 + _e119);\n continue;\n } else {\n break;\n }\n continuing {\n let _e121 = _l26;\n _l26 = (_e121 + 1i);\n }\n }\n let _e122 = unnamed.uSpread;\n let _e123 = unnamed.uLength;\n _l36 = max((_e122 * _e123), 0.0001f);\n let _e124 = _l25;\n let _e125 = _l20;\n let _e126 = _l36;\n _l37 = (1f - exp((((-(_e124) * _e125) / _e126) * 3f)));\n let _e127 = vColor_1;\n let _e128 = vEnergy_1;\n let _e129 = _l37;\n let _e130 = unnamed.uStrength;\n let _e131 = (_e127 * ((_e128 * _e129) * _e130));\n fragColor = vec4<f32>(_e131.x, _e131.y, _e131.z, 1f);\n return;\n}"];
11
+ const PARTS: readonly string[] = ["struct Uniforms {\n uCameraPos: vec3<f32>,\n uStrength: f32,\n uLength: f32,\n uSpread: f32,\n uDust: f32,\n uDustScale: f32,\n uDustOffset: vec3<f32>,\n uNear: f32,\n uCameraLocal: vec3<f32>,\n uModelWorld: mat4x4<f32>,\n uSamples: i32,\n uSceneDepthEnabled: i32,\n uInvViewport: vec2<f32>,\n uDepthToLocal: mat4x4<f32>,\n}","@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\nvar<private> vLocal_1: vec3<f32>;\nvar<private> gl_FragCoord_1: vec4<f32>;\n@group(0) @binding(32) \nvar uSceneDepth_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uSceneDepth_s: sampler;\nvar<private> fragColor: vec4<f32>;\nvar<private> vColor_1: vec3<f32>;\nvar<private> vEnergy_1: f32;\nvar<private> vNormal_1: vec3<f32>;\nvar<private> vWorldPos_1: vec3<f32>;","fn hash31_u0028_vf3_u003b(_l0: ptr<function, vec3<f32>>) -> f32 {\n let _e0 = (*_l0);\n return fract((sin(dot(_e0, vec3<f32>(127.1f, 311.7f, 74.7f))) * 43758.547f));\n}","fn volumeNoise_u0028_vf3_u003b(_l0: ptr<function, vec3<f32>>) -> f32 {\n var _l1: vec3<f32>;\n var _l2: vec3<f32>;\n var _l3: vec3<f32>;\n var _l4: f32;\n var _l5: vec3<f32>;\n var _l6: vec3<f32>;\n var _l7: f32;\n var _l8: vec3<f32>;\n var _l9: vec3<f32>;\n var _l10: f32;\n var _l11: vec3<f32>;\n var _l12: vec3<f32>;\n var _l13: f32;\n var _l14: vec3<f32>;\n var _l15: vec3<f32>;\n\n let _e0 = (*_l0);\n _l1 = floor(_e0);\n let _e1 = (*_l0);\n _l2 = fract(_e1);\n let _e2 = _l2;\n let _e3 = _l2;\n let _e4 = _l2;\n _l3 = ((_e2 * _e3) * (vec3(3f) - (_e4 * 2f)));\n let _e5 = _l1;\n _l5 = (_e5 + vec3<f32>(0f, 0f, 0f));\n let _e6 = hash31_u0028_vf3_u003b((&_l5));\n let _e7 = _l1;\n _l6 = (_e7 + vec3<f32>(1f, 0f, 0f));\n let _e8 = hash31_u0028_vf3_u003b((&_l6));\n let _e9 = _l3[0u];\n _l4 = mix(_e6, _e8, _e9);\n let _e10 = _l1;\n _l8 = (_e10 + vec3<f32>(0f, 1f, 0f));\n let _e11 = hash31_u0028_vf3_u003b((&_l8));\n let _e12 = _l1;\n _l9 = (_e12 + vec3<f32>(1f, 1f, 0f));\n let _e13 = hash31_u0028_vf3_u003b((&_l9));\n let _e14 = _l3[0u];\n _l7 = mix(_e11, _e13, _e14);\n let _e15 = _l1;\n _l11 = (_e15 + vec3<f32>(0f, 0f, 1f));\n let _e16 = hash31_u0028_vf3_u003b((&_l11));\n let _e17 = _l1;\n _l12 = (_e17 + vec3<f32>(1f, 0f, 1f));\n let _e18 = hash31_u0028_vf3_u003b((&_l12));\n let _e19 = _l3[0u];\n _l10 = mix(_e16, _e18, _e19);\n let _e20 = _l1;\n _l14 = (_e20 + vec3<f32>(0f, 1f, 1f));\n let _e21 = hash31_u0028_vf3_u003b((&_l14));\n let _e22 = _l1;\n _l15 = (_e22 + vec3<f32>(1f, 1f, 1f));\n let _e23 = hash31_u0028_vf3_u003b((&_l15));\n let _e24 = _l3[0u];\n _l13 = mix(_e21, _e23, _e24);\n let _e25 = _l4;\n let _e26 = _l7;\n let _e27 = _l3[1u];\n let _e28 = _l10;\n let _e29 = _l13;\n let _e30 = _l3[1u];\n let _e31 = _l3[2u];\n return mix(mix(_e25, _e26, _e27), mix(_e28, _e29, _e30), _e31);\n}","fn dustField_u0028_vf3_u003b(_l0: ptr<function, vec3<f32>>) -> f32 {\n var _l1: vec3<f32>;\n var _l2: vec3<f32>;\n\n let _e0 = (*_l0);\n _l1 = _e0;\n let _e1 = volumeNoise_u0028_vf3_u003b((&_l1));\n let _e2 = (*_l0);\n _l2 = ((_e2 * 2.17f) + vec3(19.3f));\n let _e3 = volumeNoise_u0028_vf3_u003b((&_l2));\n return ((_e1 * 0.65f) + (_e3 * 0.35f));\n}","fn densityAt_u0028_vf3_u003b_f1_u003b(_l0: ptr<function, vec3<f32>>, _l1: ptr<function, f32>) -> f32 {\n var _l2: f32;\n var _l3: f32;\n var _l4: f32;\n var _l5: f32;\n\n let _e0 = unnamed.uLength;\n let _e1 = (*_l1);\n _l2 = max((_e0 - _e1), 0.0001f);\n let _e2 = (*_l0)[2u];\n let _e3 = (*_l1);\n let _e4 = _l2;\n _l3 = clamp(((_e2 - _e3) / _e4), 0f, 1f);\n let _e5 = (*_l0);\n let _e6 = (*_l0)[2u];\n _l4 = (length(_e5.xy) / max(_e6, 0.001f));\n let _e7 = _l4;\n let _e8 = unnamed.uSpread;\n _l5 = clamp((_e7 / max(_e8, 0.0001f)), 0f, 1f);\n let _e9 = _l3;\n let _e10 = _l5;\n return (pow((1f - _e9), 1.3f) * pow((1f - _e10), 2f));\n}","fn main_1() {\n var _l0: vec3<f32>;\n var _l1: vec3<f32>;\n var _l2: f32;\n var _l3: vec3<f32>;\n var _l4: vec3<f32>;\n var _l5: f32;\n var _l6: f32;\n var _l7: f32;\n var _l8: f32;\n var _l9: f32;\n var _l10: f32;\n var _l11: f32;\n var _l12: f32;\n var _l13: f32;\n var _l14: f32;\n var _l15: f32;\n var _l16: vec2<f32>;\n var _l17: f32;\n var _l18: vec4<f32>;\n var _l19: i32;\n var _l20: f32;\n var _l21: i32;\n var _l22: f32;\n var _l23: array<f32, 16>;\n var _l24: vec3<f32>;\n var _l25: f32;\n var _l26: i32;\n var _l27: f32;\n var _l28: vec3<f32>;\n var _l29: f32;\n var _l30: vec3<f32>;\n var _l31: f32;\n var _l32: vec3<f32>;\n var _l33: vec3<f32>;\n var _l34: f32;\n var _l35: f32;\n var _l36: bool;\n\n let _e0 = unnamed.uCameraLocal;\n _l0 = _e0;\n let _e1 = vLocal_1;\n let _e2 = _l0;\n _l1 = (_e1 - _e2);\n let _e3 = _l1;\n _l2 = length(_e3);\n let _e4 = _l2;\n if (_e4 > 0.00001f) {\n let _e5 = _l1;\n let _e6 = _l2;\n _l4 = (_e5 / vec3(_e6));\n } else {\n _l4 = vec3<f32>(0f, 0f, 1f);\n }\n let _e7 = _l4;\n _l3 = _e7;\n let _e8 = unnamed.uNear;\n let _e9 = unnamed.uLength;\n _l5 = min(_e8, _e9);\n _l6 = 0f;\n let _e10 = unnamed.uLength;\n _l7 = (_e10 * 2f);\n let _e11 = _l3[2u];\n if (abs(_e11) > 0.00001f) {\n let _e12 = _l5;\n let _e13 = _l0[2u];\n let _e14 = _l3[2u];\n _l8 = ((_e12 - _e13) / _e14);\n let _e15 = unnamed.uLength;\n let _e16 = _l0[2u];\n let _e17 = _l3[2u];\n _l9 = ((_e15 - _e16) / _e17);\n let _e18 = _l8;\n let _e19 = _l9;\n _l6 = min(_e18, _e19);\n let _e20 = _l8;\n let _e21 = _l9;\n _l7 = max(_e20, _e21);\n } else {\n let _e22 = _l0[2u];\n let _e23 = _l5;\n let _e24 = (_e22 < _e23);\n _l36 = _e24;\n if !(_e24) {\n let _e25 = _l0[2u];\n let _e26 = unnamed.uLength;\n _l36 = (_e25 > _e26);\n }\n let _e27 = _l36;\n if _e27 {\n discard;\n }\n }\n let _e28 = unnamed.uSpread;\n let _e29 = unnamed.uLength;\n _l10 = ((_e28 * _e29) * 1.05f);\n let _e30 = _l3;\n let _e31 = _l3;\n _l11 = dot(_e30.xy, _e31.xy);\n let _e32 = _l0;\n let _e33 = _l3;\n _l12 = (2f * dot(_e32.xy, _e33.xy));\n let _e34 = _l0;\n let _e35 = _l0;\n let _e36 = _l10;\n let _e37 = _l10;\n _l13 = (dot(_e34.xy, _e35.xy) - (_e36 * _e37));\n let _e38 = _l11;\n if (_e38 > 0.00000001f) {\n let _e39 = _l12;\n let _e40 = _l12;\n let _e41 = _l11;\n let _e42 = _l13;\n _l14 = ((_e39 * _e40) - ((4f * _e41) * _e42));\n let _e43 = _l14;\n if (_e43 <= 0f) {\n discard;\n }\n let _e44 = _l14;\n _l15 = sqrt(_e44);\n let _e45 = _l6;\n let _e46 = _l12;\n let _e47 = _l15;\n let _e48 = _l11;\n _l6 = max(_e45, ((-(_e46) - _e47) / (2f * _e48)));\n let _e49 = _l7;\n let _e50 = _l12;\n let _e51 = _l15;\n let _e52 = _l11;\n _l7 = min(_e49, ((-(_e50) + _e51) / (2f * _e52)));\n } else {\n let _e53 = _l13;\n if (_e53 > 0f) {\n discard;\n }\n }\n let _e54 = _l6;\n _l6 = max(_e54, 0f);\n let _e55 = _l7;\n let _e56 = _l6;\n let _e57 = unnamed.uLength;\n _l7 = min(_e55, (_e56 + (_e57 * 2f)));\n let _e58 = unnamed.uSceneDepthEnabled;\n if (_e58 != 0i) {\n let _e59 = gl_FragCoord_1;\n let _e60 = unnamed.uInvViewport;\n _l16 = (_e59.xy * _e60);\n let _e61 = _l16;\n let _e62 = textureSampleLevel(uSceneDepth_t, uSceneDepth_s, _e61, 0f);\n _l17 = _e62.x;\n let _e63 = unnamed.uDepthToLocal;\n let _e64 = _l16;\n let _e65 = ((_e64 * 2f) - vec2(1f));\n let _e66 = _l17;\n _l18 = (_e63 * vec4<f32>(_e65.x, _e65.y, _e66, 1f));\n let _e67 = _l18[3u];\n if (_e67 > 0.000001f) {\n let _e68 = _l7;\n let _e69 = _l18;\n let _e70 = _l18[3u];\n let _e71 = _l0;\n let _e72 = _l3;\n _l7 = min(_e68, dot(((_e69.xyz / vec3(_e70)) - _e71), _e72));\n }\n }\n let _e73 = _l7;\n let _e74 = _l6;\n if (_e73 <= _e74) {\n discard;\n }\n let _e75 = unnamed.uSamples;\n _l19 = clamp(_e75, 2i, 64i);\n let _e76 = _l7;\n let _e77 = _l6;\n let _e78 = _l19;\n _l20 = ((_e76 - _e77) / f32(_e78));\n let _e79 = gl_FragCoord_1[1u];\n let _e80 = gl_FragCoord_1[0u];\n _l21 = ((i32((_e79 - (floor((_e79 / 4f)) * 4f))) * 4i) + i32((_e80 - (floor((_e80 / 4f)) * 4f))));\n let _e81 = _l21;\n _l23 = array<f32, 16>(0f, 8f, 2f, 10f, 12f, 4f, 14f, 6f, 3f, 11f, 1f, 9f, 15f, 7f, 13f, 5f);\n let _e82 = _l23[_e81];\n let _e83 = gl_FragCoord_1;\n let _e84 = _e83.xy;\n _l24 = vec3<f32>(_e84.x, _e84.y, 3.7f);\n let _e85 = hash31_u0028_vf3_u003b((&_l24));\n let _e86 = _l20;\n _l22 = ((((_e82 + _e85) / 16f) - 0.5f) * _e86);\n _l25 = 0f;\n _l26 = 0i;\n loop {\n let _e87 = _l26;\n if (_e87 < 64i) {\n let _e88 = _l26;\n let _e89 = _l19;\n if (_e88 >= _e89) {\n break;\n }\n let _e90 = _l6;\n let _e91 = _l26;\n let _e92 = _l20;\n _l27 = (_e90 + ((f32(_e91) + 0.5f) * _e92));\n let _e93 = _l0;\n let _e94 = _l3;\n let _e95 = _l27;\n _l28 = (_e93 + (_e94 * _e95));\n let _e96 = _l28;\n _l30 = _e96;\n let _e97 = _l5;\n _l31 = _e97;\n let _e98 = densityAt_u0028_vf3_u003b_f1_u003b((&_l30), (&_l31));\n _l29 = _e98;\n let _e99 = _l29;\n if (_e99 <= 0f) {\n continue;\n }\n let _e100 = unnamed.uModelWorld;\n let _e101 = _l28;\n _l32 = (_e100 * vec4<f32>(_e101.x, _e101.y, _e101.z, 1f)).xyz;\n let _e102 = unnamed.uDust;\n if (_e102 > 0f) {\n let _e103 = _l32;\n let _e104 = unnamed.uDustOffset;\n let _e105 = unnamed.uDustScale;\n _l33 = ((_e103 + _e104) / vec3(max(_e105, 0.001f)));\n let _e106 = dustField_u0028_vf3_u003b((&_l33));\n let _e107 = unnamed.uDust;\n let _e108 = _l29;\n _l29 = (_e108 * mix(1f, _e106, _e107));\n }\n let _e109 = _l29;\n let _e110 = _l25;\n _l25 = (_e110 + _e109);\n continue;\n } else {\n break;\n }\n continuing {\n let _e111 = _l26;\n _l26 = (_e111 + 1i);\n }\n }\n let _e112 = unnamed.uSpread;\n let _e113 = unnamed.uLength;\n _l34 = max((_e112 * _e113), 0.0001f);\n let _e114 = _l25;\n let _e115 = _l20;\n let _e116 = _l34;\n _l35 = (1f - exp((((-(_e114) * _e115) / _e116) * 3f)));\n let _e117 = vColor_1;\n let _e118 = vEnergy_1;\n let _e119 = _l35;\n let _e120 = unnamed.uStrength;\n let _e121 = (_e117 * ((_e118 * _e119) * _e120));\n fragColor = vec4<f32>(_e121.x, _e121.y, _e121.z, 1f);\n return;\n}","@fragment \nfn main(@location(4) vLocal: vec3<f32>, @builtin(position) gl_FragCoord: vec4<f32>, @location(0) vColor: vec3<f32>, @location(1) vEnergy: f32, @location(2) vNormal: vec3<f32>, @location(3) vWorldPos: vec3<f32>) -> @location(0) vec4<f32> {\n vLocal_1 = vLocal;\n gl_FragCoord_1 = gl_FragCoord;\n vColor_1 = vColor;\n vEnergy_1 = vEnergy;\n vNormal_1 = vNormal;\n vWorldPos_1 = vWorldPos;\n main_1();\n let _e0 = fragColor;\n return _e0;\n}\n","struct Uniforms {\n uCameraPos: vec3<f32>,\n uStrength: f32,\n uLength: f32,\n uSpread: f32,\n uDust: f32,\n uDustScale: f32,\n uDustOffset: vec3<f32>,\n uSunShadow: f32,\n uLightViewProj: mat4x4<f32>,\n uMovingLightViewProj: mat4x4<f32>,\n uShadowMapSize: f32,\n uPeeledShadowEnabled: i32,\n uNear: f32,\n uCameraLocal: vec3<f32>,\n uModelWorld: mat4x4<f32>,\n uSamples: i32,\n uSceneDepthEnabled: i32,\n uInvViewport: vec2<f32>,\n uDepthToLocal: mat4x4<f32>,\n}","@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(32) \nvar uSunShadows_t: texture_2d_array<f32>;\n@group(0) @binding(33) \nvar uSunShadows_s: sampler;\nvar<private> vLocal_1: vec3<f32>;\nvar<private> gl_FragCoord_1: vec4<f32>;\n@group(0) @binding(34) \nvar uSceneDepth_t: texture_2d<f32>;\n@group(0) @binding(35) \nvar uSceneDepth_s: sampler;\nvar<private> fragColor: vec4<f32>;\nvar<private> vColor_1: vec3<f32>;\nvar<private> vEnergy_1: f32;\nvar<private> vNormal_1: vec3<f32>;\nvar<private> vWorldPos_1: vec3<f32>;","fn occlusion_u0028_f1_u003b_f1_u003b(_l0: ptr<function, f32>, _l1: ptr<function, f32>) -> f32 {\n let _e0 = (*_l1);\n let _e1 = (*_l0);\n return smoothstep(-0.0025f, 0.0025f, (_e0 - _e1));\n}","fn sunReach_u0028_vf3_u003b(_l0: ptr<function, vec3<f32>>) -> f32 {\n var _l1: vec4<f32>;\n var _l2: vec3<f32>;\n var _l3: vec2<f32>;\n var _l4: f32;\n var _l5: f32;\n var _l6: f32;\n var _l7: f32;\n var _l8: f32;\n var _l9: f32;\n var _l10: f32;\n var _l11: vec4<f32>;\n var _l12: vec3<f32>;\n var _l13: f32;\n var _l14: f32;\n var _l15: bool;\n var _l16: bool;\n var _l17: bool;\n var _l18: bool;\n var _l19: bool;\n var _l20: bool;\n var _l21: bool;\n var _l22: bool;\n var _l23: bool;\n\n let _e0 = unnamed.uLightViewProj;\n let _e1 = (*_l0);\n _l1 = (_e0 * vec4<f32>(_e1.x, _e1.y, _e1.z, 1f));\n let _e2 = _l1[3u];\n if (_e2 <= 0f) {\n return 1f;\n }\n let _e3 = _l1;\n let _e4 = _l1[3u];\n _l2 = (((_e3.xyz / vec3(_e4)) * 0.5f) + vec3(0.5f));\n let _e5 = _l2[2u];\n let _e6 = (_e5 > 1f);\n _l15 = _e6;\n if !(_e6) {\n let _e7 = _l2[0u];\n _l15 = (_e7 < 0f);\n }\n let _e8 = _l15;\n _l16 = _e8;\n if !(_e8) {\n let _e9 = _l2[0u];\n _l16 = (_e9 > 1f);\n }\n let _e10 = _l16;\n _l17 = _e10;\n if !(_e10) {\n let _e11 = _l2[1u];\n _l17 = (_e11 < 0f);\n }\n let _e12 = _l17;\n _l18 = _e12;\n if !(_e12) {\n let _e13 = _l2[1u];\n _l18 = (_e13 > 1f);\n }\n let _e14 = _l18;\n if _e14 {\n return 1f;\n }\n let _e15 = _l2;\n _l3 = (abs((_e15.xy - vec2(0.5f))) * 2f);\n let _e16 = _l3[0u];\n let _e17 = _l3[1u];\n _l4 = (1f - smoothstep(0.72f, 0.98f, max(_e16, _e17)));\n let _e18 = _l2[2u];\n let _e19 = _l4;\n _l4 = (_e19 * (1f - smoothstep(0.9f, 1f, _e18)));\n let _e20 = _l4;\n if (_e20 <= 0f) {\n return 1f;\n }\n let _e21 = _l2[2u];\n _l5 = (_e21 - 0.0015f);\n let _e22 = _l2;\n let _e23 = _e22.xy;\n let _e24 = vec3<f32>(_e23.x, _e23.y, 0f);\n let _e25 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e24.x, _e24.y), i32(_e24.z), 0f);\n _l7 = _e25.x;\n let _e26 = _l5;\n _l8 = _e26;\n let _e27 = occlusion_u0028_f1_u003b_f1_u003b((&_l7), (&_l8));\n _l6 = _e27;\n let _e28 = unnamed.uPeeledShadowEnabled;\n if (_e28 != 0i) {\n let _e29 = _l6;\n let _e30 = _l2;\n let _e31 = _e30.xy;\n let _e32 = vec3<f32>(_e31.x, _e31.y, 2f);\n let _e33 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e32.x, _e32.y), i32(_e32.z), 0f);\n _l9 = _e33.x;\n let _e34 = _l5;\n _l10 = _e34;\n let _e35 = occlusion_u0028_f1_u003b_f1_u003b((&_l9), (&_l10));\n _l6 = max(_e29, _e35);\n }\n let _e36 = unnamed.uMovingLightViewProj;\n let _e37 = (*_l0);\n _l11 = (_e36 * vec4<f32>(_e37.x, _e37.y, _e37.z, 1f));\n let _e38 = _l11;\n let _e39 = _l11[3u];\n _l12 = (((_e38.xyz / vec3(_e39)) * 0.5f) + vec3(0.5f));\n let _e40 = _l11[3u];\n let _e41 = (_e40 > 0f);\n _l19 = _e41;\n if _e41 {\n let _e42 = _l12[2u];\n _l19 = (_e42 <= 1f);\n }\n let _e43 = _l19;\n _l20 = _e43;\n if _e43 {\n let _e44 = _l12[0u];\n _l20 = (_e44 >= 0f);\n }\n let _e45 = _l20;\n _l21 = _e45;\n if _e45 {\n let _e46 = _l12[0u];\n _l21 = (_e46 <= 1f);\n }\n let _e47 = _l21;\n _l22 = _e47;\n if _e47 {\n let _e48 = _l12[1u];\n _l22 = (_e48 >= 0f);\n }\n let _e49 = _l22;\n _l23 = _e49;\n if _e49 {\n let _e50 = _l12[1u];\n _l23 = (_e50 <= 1f);\n }\n let _e51 = _l23;\n if _e51 {\n let _e52 = _l6;\n let _e53 = _l12;\n let _e54 = _e53.xy;\n let _e55 = vec3<f32>(_e54.x, _e54.y, 1f);\n let _e56 = textureSampleLevel(uSunShadows_t, uSunShadows_s, vec2<f32>(_e55.x, _e55.y), i32(_e55.z), 0f);\n let _e57 = _l12[2u];\n _l13 = _e56.x;\n _l14 = (_e57 - 0.0015f);\n let _e58 = occlusion_u0028_f1_u003b_f1_u003b((&_l13), (&_l14));\n _l6 = max(_e52, _e58);\n }\n let _e59 = _l6;\n let _e60 = unnamed.uSunShadow;\n let _e61 = _l4;\n return mix(1f, (1f - _e59), (_e60 * _e61));\n}","fn main_1() {\n var _l0: vec3<f32>;\n var _l1: vec3<f32>;\n var _l2: f32;\n var _l3: vec3<f32>;\n var _l4: vec3<f32>;\n var _l5: f32;\n var _l6: f32;\n var _l7: f32;\n var _l8: f32;\n var _l9: f32;\n var _l10: f32;\n var _l11: f32;\n var _l12: f32;\n var _l13: f32;\n var _l14: f32;\n var _l15: f32;\n var _l16: vec2<f32>;\n var _l17: f32;\n var _l18: vec4<f32>;\n var _l19: i32;\n var _l20: f32;\n var _l21: i32;\n var _l22: f32;\n var _l23: array<f32, 16>;\n var _l24: vec3<f32>;\n var _l25: f32;\n var _l26: i32;\n var _l27: f32;\n var _l28: vec3<f32>;\n var _l29: f32;\n var _l30: vec3<f32>;\n var _l31: f32;\n var _l32: vec3<f32>;\n var _l33: vec3<f32>;\n var _l34: vec3<f32>;\n var _l35: vec3<f32>;\n var _l36: f32;\n var _l37: f32;\n var _l38: bool;\n\n let _e0 = unnamed.uCameraLocal;\n _l0 = _e0;\n let _e1 = vLocal_1;\n let _e2 = _l0;\n _l1 = (_e1 - _e2);\n let _e3 = _l1;\n _l2 = length(_e3);\n let _e4 = _l2;\n if (_e4 > 0.00001f) {\n let _e5 = _l1;\n let _e6 = _l2;\n _l4 = (_e5 / vec3(_e6));\n } else {\n _l4 = vec3<f32>(0f, 0f, 1f);\n }\n let _e7 = _l4;\n _l3 = _e7;\n let _e8 = unnamed.uNear;\n let _e9 = unnamed.uLength;\n _l5 = min(_e8, _e9);\n _l6 = 0f;\n let _e10 = unnamed.uLength;\n _l7 = (_e10 * 2f);\n let _e11 = _l3[2u];\n if (abs(_e11) > 0.00001f) {\n let _e12 = _l5;\n let _e13 = _l0[2u];\n let _e14 = _l3[2u];\n _l8 = ((_e12 - _e13) / _e14);\n let _e15 = unnamed.uLength;\n let _e16 = _l0[2u];\n let _e17 = _l3[2u];\n _l9 = ((_e15 - _e16) / _e17);\n let _e18 = _l8;\n let _e19 = _l9;\n _l6 = min(_e18, _e19);\n let _e20 = _l8;\n let _e21 = _l9;\n _l7 = max(_e20, _e21);\n } else {\n let _e22 = _l0[2u];\n let _e23 = _l5;\n let _e24 = (_e22 < _e23);\n _l38 = _e24;\n if !(_e24) {\n let _e25 = _l0[2u];\n let _e26 = unnamed.uLength;\n _l38 = (_e25 > _e26);\n }\n let _e27 = _l38;\n if _e27 {\n discard;\n }\n }\n let _e28 = unnamed.uSpread;\n let _e29 = unnamed.uLength;\n _l10 = ((_e28 * _e29) * 1.05f);\n let _e30 = _l3;\n let _e31 = _l3;\n _l11 = dot(_e30.xy, _e31.xy);\n let _e32 = _l0;\n let _e33 = _l3;\n _l12 = (2f * dot(_e32.xy, _e33.xy));\n let _e34 = _l0;\n let _e35 = _l0;\n let _e36 = _l10;\n let _e37 = _l10;\n _l13 = (dot(_e34.xy, _e35.xy) - (_e36 * _e37));\n let _e38 = _l11;\n if (_e38 > 0.00000001f) {\n let _e39 = _l12;\n let _e40 = _l12;\n let _e41 = _l11;\n let _e42 = _l13;\n _l14 = ((_e39 * _e40) - ((4f * _e41) * _e42));\n let _e43 = _l14;\n if (_e43 <= 0f) {\n discard;\n }\n let _e44 = _l14;\n _l15 = sqrt(_e44);\n let _e45 = _l6;\n let _e46 = _l12;\n let _e47 = _l15;\n let _e48 = _l11;\n _l6 = max(_e45, ((-(_e46) - _e47) / (2f * _e48)));\n let _e49 = _l7;\n let _e50 = _l12;\n let _e51 = _l15;\n let _e52 = _l11;\n _l7 = min(_e49, ((-(_e50) + _e51) / (2f * _e52)));\n } else {\n let _e53 = _l13;\n if (_e53 > 0f) {\n discard;\n }\n }\n let _e54 = _l6;\n _l6 = max(_e54, 0f);\n let _e55 = _l7;\n let _e56 = _l6;\n let _e57 = unnamed.uLength;\n _l7 = min(_e55, (_e56 + (_e57 * 2f)));\n let _e58 = unnamed.uSceneDepthEnabled;\n if (_e58 != 0i) {\n let _e59 = gl_FragCoord_1;\n let _e60 = unnamed.uInvViewport;\n _l16 = (_e59.xy * _e60);\n let _e61 = _l16;\n let _e62 = textureSampleLevel(uSceneDepth_t, uSceneDepth_s, _e61, 0f);\n _l17 = _e62.x;\n let _e63 = unnamed.uDepthToLocal;\n let _e64 = _l16;\n let _e65 = ((_e64 * 2f) - vec2(1f));\n let _e66 = _l17;\n _l18 = (_e63 * vec4<f32>(_e65.x, _e65.y, _e66, 1f));\n let _e67 = _l18[3u];\n if (_e67 > 0.000001f) {\n let _e68 = _l7;\n let _e69 = _l18;\n let _e70 = _l18[3u];\n let _e71 = _l0;\n let _e72 = _l3;\n _l7 = min(_e68, dot(((_e69.xyz / vec3(_e70)) - _e71), _e72));\n }\n }\n let _e73 = _l7;\n let _e74 = _l6;\n if (_e73 <= _e74) {\n discard;\n }\n let _e75 = unnamed.uSamples;\n _l19 = clamp(_e75, 2i, 64i);\n let _e76 = _l7;\n let _e77 = _l6;\n let _e78 = _l19;\n _l20 = ((_e76 - _e77) / f32(_e78));\n let _e79 = gl_FragCoord_1[1u];\n let _e80 = gl_FragCoord_1[0u];\n _l21 = ((i32((_e79 - (floor((_e79 / 4f)) * 4f))) * 4i) + i32((_e80 - (floor((_e80 / 4f)) * 4f))));\n let _e81 = _l21;\n _l23 = array<f32, 16>(0f, 8f, 2f, 10f, 12f, 4f, 14f, 6f, 3f, 11f, 1f, 9f, 15f, 7f, 13f, 5f);\n let _e82 = _l23[_e81];\n let _e83 = gl_FragCoord_1;\n let _e84 = _e83.xy;\n _l24 = vec3<f32>(_e84.x, _e84.y, 3.7f);\n let _e85 = hash31_u0028_vf3_u003b((&_l24));\n let _e86 = _l20;\n _l22 = ((((_e82 + _e85) / 16f) - 0.5f) * _e86);\n _l25 = 0f;\n _l26 = 0i;\n loop {\n let _e87 = _l26;\n if (_e87 < 64i) {\n let _e88 = _l26;\n let _e89 = _l19;\n if (_e88 >= _e89) {\n break;\n }\n let _e90 = _l6;\n let _e91 = _l26;\n let _e92 = _l20;\n _l27 = (_e90 + ((f32(_e91) + 0.5f) * _e92));\n let _e93 = _l0;\n let _e94 = _l3;\n let _e95 = _l27;\n _l28 = (_e93 + (_e94 * _e95));\n let _e96 = _l28;\n _l30 = _e96;\n let _e97 = _l5;\n _l31 = _e97;\n let _e98 = densityAt_u0028_vf3_u003b_f1_u003b((&_l30), (&_l31));\n _l29 = _e98;\n let _e99 = _l29;\n if (_e99 <= 0f) {\n continue;\n }\n let _e100 = unnamed.uModelWorld;\n let _e101 = _l28;\n _l32 = (_e100 * vec4<f32>(_e101.x, _e101.y, _e101.z, 1f)).xyz;\n let _e102 = unnamed.uDust;\n if (_e102 > 0f) {\n let _e103 = _l32;\n let _e104 = unnamed.uDustOffset;\n let _e105 = unnamed.uDustScale;\n _l33 = ((_e103 + _e104) / vec3(max(_e105, 0.001f)));\n let _e106 = dustField_u0028_vf3_u003b((&_l33));\n let _e107 = unnamed.uDust;\n let _e108 = _l29;\n _l29 = (_e108 * mix(1f, _e106, _e107));\n }\n let _e109 = unnamed.uSunShadow;\n if (_e109 > 0f) {\n let _e110 = unnamed.uModelWorld;\n let _e111 = _l0;\n let _e112 = _l3;\n let _e113 = _l27;\n let _e114 = _l22;\n let _e115 = (_e111 + (_e112 * (_e113 + _e114)));\n _l34 = (_e110 * vec4<f32>(_e115.x, _e115.y, _e115.z, 1f)).xyz;\n let _e116 = _l34;\n _l35 = _e116;\n let _e117 = sunReach_u0028_vf3_u003b((&_l35));\n let _e118 = _l29;\n _l29 = (_e118 * _e117);\n }\n let _e119 = _l29;\n let _e120 = _l25;\n _l25 = (_e120 + _e119);\n continue;\n } else {\n break;\n }\n continuing {\n let _e121 = _l26;\n _l26 = (_e121 + 1i);\n }\n }\n let _e122 = unnamed.uSpread;\n let _e123 = unnamed.uLength;\n _l36 = max((_e122 * _e123), 0.0001f);\n let _e124 = _l25;\n let _e125 = _l20;\n let _e126 = _l36;\n _l37 = (1f - exp((((-(_e124) * _e125) / _e126) * 3f)));\n let _e127 = vColor_1;\n let _e128 = vEnergy_1;\n let _e129 = _l37;\n let _e130 = unnamed.uStrength;\n let _e131 = (_e127 * ((_e128 * _e129) * _e130));\n fragColor = vec4<f32>(_e131.x, _e131.y, _e131.z, 1f);\n return;\n}"];
12
12
 
13
13
  /** A permutation from its items, joined the first time it is asked for and kept. */
14
14
  function permutations(table: Readonly<Record<string, readonly number[]>>): Readonly<Record<string, string>> {
@@ -138,7 +138,7 @@ export const LIGHTVOLUME_BINDINGS = {
138
138
  },
139
139
  "directionalShadows": {
140
140
  "uniforms": 1,
141
- "uniformSize": 288,
141
+ "uniformSize": 352,
142
142
  "fields": {
143
143
  "uCameraPos": {
144
144
  "offset": 0,
@@ -185,48 +185,53 @@ export const LIGHTVOLUME_BINDINGS = {
185
185
  "size": 64,
186
186
  "type": "mat4"
187
187
  },
188
- "uShadowMapSize": {
188
+ "uMovingLightViewProj": {
189
189
  "offset": 112,
190
+ "size": 64,
191
+ "type": "mat4"
192
+ },
193
+ "uShadowMapSize": {
194
+ "offset": 176,
190
195
  "size": 4,
191
196
  "type": "float"
192
197
  },
193
198
  "uPeeledShadowEnabled": {
194
- "offset": 116,
199
+ "offset": 180,
195
200
  "size": 4,
196
201
  "type": "int"
197
202
  },
198
203
  "uNear": {
199
- "offset": 120,
204
+ "offset": 184,
200
205
  "size": 4,
201
206
  "type": "float"
202
207
  },
203
208
  "uCameraLocal": {
204
- "offset": 128,
209
+ "offset": 192,
205
210
  "size": 12,
206
211
  "type": "vec3"
207
212
  },
208
213
  "uModelWorld": {
209
- "offset": 144,
214
+ "offset": 208,
210
215
  "size": 64,
211
216
  "type": "mat4"
212
217
  },
213
218
  "uSamples": {
214
- "offset": 208,
219
+ "offset": 272,
215
220
  "size": 4,
216
221
  "type": "int"
217
222
  },
218
223
  "uSceneDepthEnabled": {
219
- "offset": 212,
224
+ "offset": 276,
220
225
  "size": 4,
221
226
  "type": "int"
222
227
  },
223
228
  "uInvViewport": {
224
- "offset": 216,
229
+ "offset": 280,
225
230
  "size": 8,
226
231
  "type": "vec2"
227
232
  },
228
233
  "uDepthToLocal": {
229
- "offset": 224,
234
+ "offset": 288,
230
235
  "size": 64,
231
236
  "type": "mat4"
232
237
  }
@@ -80,6 +80,9 @@ uniform int uSteps;
80
80
  /** How much of the medium the sun's own shadow map removes, 0 to 1. At 0 nothing is sampled. */
81
81
  uniform float uSunShadow;
82
82
  uniform mat4 uLightViewProj;
83
+ /* The sun's moving layer's own matrix: the static one's unless a caller fitted it apart. See
84
+ flat/movingSun.ts. */
85
+ uniform mat4 uMovingLightViewProj;
83
86
  /* The sun's static, moving and peeled maps, as layers of one array: see shadowMap.ts. */
84
87
  uniform highp sampler2DArray uSunShadows;
85
88
  uniform int uPeeledShadowEnabled;
@@ -154,7 +157,12 @@ float sunReach(vec3 worldPos) {
154
157
  if (uPeeledShadowEnabled != 0) {
155
158
  blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_PEELED_LAYER}.0), 0.0).r, compare));
156
159
  }
157
- blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r, compare));
160
+ /* The moving layer at its own place, which is this one's where the two share a matrix. */
161
+ vec4 movingPos = uMovingLightViewProj * vec4(worldPos, 1.0);
162
+ vec3 pm = movingPos.xyz / movingPos.w * 0.5 + 0.5;
163
+ if (movingPos.w > 0.0 && pm.z <= 1.0 && pm.x >= 0.0 && pm.x <= 1.0 && pm.y >= 0.0 && pm.y <= 1.0) {
164
+ blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(pm.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r, pm.z - SHADOW_BIAS));
165
+ }
158
166
  return mix(1.0, 1.0 - blocked, uSunShadow * edgeFade);
159
167
  }
160
168
 
@@ -159,6 +159,9 @@ uniform vec3 uDustOffset;
159
159
  /** How much of the volume the sun's own shadow map removes, 0 to 1. At 0 nothing is sampled. */
160
160
  uniform float uSunShadow;
161
161
  uniform mat4 uLightViewProj;
162
+ /* The sun's moving layer's own matrix: the static one's unless a caller fitted it apart. See
163
+ flat/movingSun.ts. */
164
+ uniform mat4 uMovingLightViewProj;
162
165
  uniform float uShadowMapSize;
163
166
  /* The sun's static, moving and peeled maps, as layers of one array: see shadowMap.ts. */
164
167
  uniform highp sampler2DArray uSunShadows;
@@ -328,7 +331,12 @@ float sunReach(vec3 worldPos) {
328
331
  if (uPeeledShadowEnabled != 0) {
329
332
  blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_PEELED_LAYER}.0), 0.0).r, compare));
330
333
  }
331
- blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r, compare));
334
+ /* The moving layer at its own place, which is this one's where the two share a matrix. */
335
+ vec4 movingPos = uMovingLightViewProj * vec4(worldPos, 1.0);
336
+ vec3 pm = movingPos.xyz / movingPos.w * 0.5 + 0.5;
337
+ if (movingPos.w > 0.0 && pm.z <= 1.0 && pm.x >= 0.0 && pm.x <= 1.0 && pm.y >= 0.0 && pm.y <= 1.0) {
338
+ blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(pm.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r, pm.z - BIAS));
339
+ }
332
340
  return mix(1.0, 1.0 - blocked, uSunShadow * edgeFade);
333
341
  }
334
342
  #endif
@@ -40,11 +40,24 @@ export const TANGENT_FRAME_GLSL = `mat3 tangentFrame(vec3 n, vec3 worldPos, vec2
40
40
  * side and nothing else.
41
41
  *
42
42
  * The UV determinant flips with them, so folding its sign back in restores the invariance the
43
- * solve always had. Measured before and after on demo/dev/normal.html: the derived panel stood
43
+ * solve always had — through the orientation below, which flips with them too. Measured before and after on demo/dev/normal.html: the derived panel stood
44
44
  * 86 of 255 rms from the attribute panel on WebGPU and 8.8 on WebGL2; with this they agree.
45
45
  */
46
- float det = duv1.x * duv2.y - duv2.x * duv1.y;
47
- float handed = det < 0.0 ? -1.0 : 1.0;
46
+ /*
47
+ * **And the mapping's own handedness, which the determinant alone does not carry.** The closed
48
+ * form is the determinant times \`Pv × n\` and \`−Pu × n\`, which are \`Pu\` and \`Pv\` where the
49
+ * coordinates are right-handed about the normal and their negations where they are mirrored: a
50
+ * mirrored mapping came out turned half a circle, its normal map lit from the far side. The sign
51
+ * that puts both back is the determinant's times the mapping's handedness, and that product is
52
+ * the surface's orientation on screen, \`dp1 × dp2 = det · (Pu × Pv)\`, against the normal. It
53
+ * flips with \`dFdy\` as the determinant does, so the two backends stay agreed, and it equals the
54
+ * determinant's sign wherever a mapping is not mirrored. Found by a projection laying \`u\` along
55
+ * x and \`v\` along z on ground facing up, which is mirrored: on demo/dev/worldUv.html a normal
56
+ * map leaning along +u read 74.8 derived against 110.8 from the tangent attribute, the light
57
+ * from the side it leans toward, and 110.8 both after. Every published scene and the four panels
58
+ * of demo/dev/normal.html, none of them mirrored and derived, are unchanged to the pixel.
59
+ */
60
+ float handed = dot(cross(dp1, dp2), n) < 0.0 ? -1.0 : 1.0;
48
61
  /* One scale for both axes, so a stretched UV layout does not shear the frame it produces. */
49
62
  float invmax = inversesqrt(max(max(dot(dt, dt), dot(db, db)), 1e-12)) * handed;
50
63
  vec3 derivedT = dt * invmax;
@@ -11,6 +11,10 @@
11
11
  * millisecond a frame on the main thread, and 4,500 are twenty — a garment that size wants the
12
12
  * device. The device solver ran 4,500 particles in 0.65 ms a frame, most of it the dispatches
13
13
  * rather than the particles (`demo/dev/skinnedCloth.html?bench=1`).
14
+ *
15
+ * **Several garments step as one with `createSkinnedClothSet`**: one pass, one submit and one
16
+ * garment's dispatches a step for all of them, where a garment each was a pass, a submit and its
17
+ * own dispatches each. They must share a step, substeps, iterations and most steps a frame.
14
18
  */
15
19
  import { SkinnedCloth } from '@driftengine/physics';
16
20
  import type { SkinnedClothSetup } from '@driftengine/physics';
@@ -18,7 +22,7 @@ import type { SkinnedClothSetup } from '@driftengine/physics';
18
22
  import type { ClothParticlesHandle, RendererApi } from './backend/api.ts';
19
23
  import { computeHostOf } from './backend/webgpu/computeHost.ts';
20
24
  import type { ComputeHost } from './backend/webgpu/computeHost.ts';
21
- import { GpuSkinnedCloth } from './backend/webgpu/gpuSkinnedCloth.ts';
25
+ import { GpuClothSet } from './backend/webgpu/gpuClothSet.ts';
22
26
 
23
27
  /** A garment a renderer solves, from `createSkinnedCloth`. */
24
28
  export interface SkinnedClothSolver {
@@ -43,86 +47,182 @@ export interface SkinnedClothSolver {
43
47
  dispose(): void;
44
48
  }
45
49
 
50
+ /** Garments a renderer solves together, from `createSkinnedClothSet`, each named by its index. */
51
+ export interface SkinnedClothSet {
52
+ /** Each garment's particles, in the order its set-up was given: what `setCloth` draws it by. */
53
+ readonly particles: readonly ClothParticlesHandle[];
54
+ /** Where the set runs: on the device, or on the CPU beneath a backend without compute. */
55
+ readonly runsOn: 'device' | 'cpu';
56
+ /**
57
+ * Garment `g`'s rig for the next `step`: each joint's global matrix, model space, sixteen floats a
58
+ * joint, and the model matrix. A garment not posed in a frame steps toward its last pose.
59
+ */
60
+ setPose(g: number, globals: Float32Array, model: Float32Array): void;
61
+ /** The air garment `g` drags toward from its next step: the frame's sample of the one wind. */
62
+ setWind(g: number, x: number, y: number, z: number): void;
63
+ /** Garment `g` back to its skinned pose, settled, as a teleport resets it. */
64
+ reset(g: number): void;
65
+ /**
66
+ * `dt` seconds for every garment, run as whole fixed steps; each garment's particles at its
67
+ * `alpha` are then what the frame draws. **Once a frame, before the draws**, as a solver's `step`.
68
+ */
69
+ step(dt: number): void;
70
+ dispose(): void;
71
+ }
72
+
46
73
  /** A garment for `renderer`, from a set-up checked by name. */
47
74
  export function createSkinnedCloth(
48
75
  renderer: RendererApi,
49
76
  setup: SkinnedClothSetup,
50
77
  ): SkinnedClothSolver {
51
78
  const host = computeHostOf(renderer);
52
- return host === null ? new CpuCloth(renderer, setup) : new DeviceCloth(host, setup);
79
+ const set =
80
+ host === null ? new CpuClothSet(renderer, [setup]) : new DeviceClothSet(host, [setup]);
81
+ return new OneGarment(set);
53
82
  }
54
83
 
55
- class DeviceCloth implements SkinnedClothSolver {
56
- readonly runsOn = 'device';
84
+ /** A set of one, as a solver: what `createSkinnedCloth` hands back. */
85
+ class OneGarment implements SkinnedClothSolver {
57
86
  readonly particles: ClothParticlesHandle;
58
- private readonly cloth: GpuSkinnedCloth;
87
+ readonly runsOn: 'device' | 'cpu';
88
+
89
+ constructor(private readonly set: DeviceClothSet | CpuClothSet) {
90
+ this.particles = set.particles[0] as ClothParticlesHandle;
91
+ this.runsOn = set.runsOn;
92
+ }
93
+
94
+ step(globals: Float32Array, model: Float32Array, dt: number): void {
95
+ this.set.setPose(0, globals, model);
96
+ this.set.step(dt);
97
+ }
98
+
99
+ setWind(x: number, y: number, z: number): void {
100
+ this.set.setWind(0, x, y, z);
101
+ }
102
+
103
+ reset(): void {
104
+ this.set.reset(0);
105
+ }
106
+
107
+ dispose(): void {
108
+ this.set.dispose();
109
+ }
110
+
111
+ /** The particles where the last step left them: the parity check's door. */
112
+ read(): Promise<Float32Array> {
113
+ return this.set.read(0);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Garments for `renderer` stepped together, from set-ups checked by name: one pass, one submit and
119
+ * one garment's dispatches a step on the device, whatever the count. They must agree on `step`,
120
+ * `substeps`, `iterations` and `maxSteps`, and are refused by the first they disagree on.
121
+ */
122
+ export function createSkinnedClothSet(
123
+ renderer: RendererApi,
124
+ setups: readonly SkinnedClothSetup[],
125
+ ): SkinnedClothSet {
126
+ const host = computeHostOf(renderer);
127
+ return host === null ? new CpuClothSet(renderer, setups) : new DeviceClothSet(host, setups);
128
+ }
129
+
130
+ class DeviceClothSet implements SkinnedClothSet {
131
+ readonly runsOn = 'device';
132
+ readonly particles: readonly ClothParticlesHandle[];
133
+ private readonly set: GpuClothSet;
59
134
 
60
135
  constructor(
61
136
  private readonly host: ComputeHost,
62
- setup: SkinnedClothSetup,
137
+ setups: readonly SkinnedClothSetup[],
63
138
  ) {
64
- this.cloth = new GpuSkinnedCloth(host.device(), setup);
65
- this.particles = this.cloth.particles;
139
+ this.set = new GpuClothSet(host.device(), setups);
140
+ const particles: ClothParticlesHandle[] = [];
141
+ for (let g = 0; g < this.set.size; g++) particles.push(this.set.particles(g));
142
+ this.particles = particles;
66
143
  }
67
144
 
68
- step(globals: Float32Array, model: Float32Array, dt: number): void {
145
+ setPose(g: number, globals: Float32Array, model: Float32Array): void {
69
146
  if (this.host.lost()) return;
70
- this.cloth.advance(globals, model, dt, this.host.changeFrame());
147
+ this.set.setPose(g, globals, model);
71
148
  }
72
149
 
73
- setWind(x: number, y: number, z: number): void {
74
- this.cloth.setWind(x, y, z);
150
+ setWind(g: number, x: number, y: number, z: number): void {
151
+ this.set.setWind(g, x, y, z);
75
152
  }
76
153
 
77
- reset(): void {
154
+ reset(g: number): void {
78
155
  if (this.host.lost()) return;
79
- this.cloth.reset();
156
+ this.set.reset(g);
157
+ }
158
+
159
+ step(dt: number): void {
160
+ if (this.host.lost()) return;
161
+ this.set.step(dt, this.host.changeFrame());
80
162
  }
81
163
 
82
164
  /** Its buffers at once — its work is submitted — and its textures with the frame's. */
83
165
  dispose(): void {
84
- this.cloth.dispose();
85
- this.host.retire(this.cloth.particles.textures);
166
+ this.set.dispose();
167
+ for (let g = 0; g < this.set.size; g++) this.host.retire(this.set.particles(g).textures);
86
168
  }
87
169
 
88
- /** The particles where the last step left them: the parity check's door, waits on the device. */
89
- read(): Promise<Float32Array> {
90
- return this.cloth.read();
170
+ /** Garment `g`'s particles where its last step left them: the parity check's, waits on the device. */
171
+ read(g: number): Promise<Float32Array> {
172
+ return this.set.read(g);
91
173
  }
92
174
  }
93
175
 
94
- class CpuCloth implements SkinnedClothSolver {
176
+ class CpuClothSet implements SkinnedClothSet {
95
177
  readonly runsOn = 'cpu';
96
- readonly particles: ClothParticlesHandle;
97
- private readonly cloth: SkinnedCloth;
98
- /** The frame's particles at `alpha`, before they go up. */
99
- private readonly staging: Float32Array;
178
+ readonly particles: readonly ClothParticlesHandle[];
179
+ private readonly cloths: readonly SkinnedCloth[];
180
+ /** Each garment's particles at `alpha`, before they go up. */
181
+ private readonly staging: readonly Float32Array[];
100
182
 
101
183
  constructor(
102
184
  private readonly renderer: RendererApi,
103
- setup: SkinnedClothSetup,
185
+ setups: readonly SkinnedClothSetup[],
104
186
  ) {
105
- this.cloth = new SkinnedCloth(setup);
106
- this.particles = renderer.createClothParticles(this.cloth.count);
107
- this.staging = new Float32Array(this.cloth.count * 3);
187
+ this.cloths = setups.map((setup) => new SkinnedCloth(setup));
188
+ this.particles = this.cloths.map((cloth) => renderer.createClothParticles(cloth.count));
189
+ this.staging = this.cloths.map((cloth) => new Float32Array(cloth.count * 3));
108
190
  }
109
191
 
110
- step(globals: Float32Array, model: Float32Array, dt: number): void {
111
- this.cloth.setPose(globals, model);
112
- this.cloth.advance(dt);
113
- this.cloth.interpolate(this.cloth.alpha, this.staging);
114
- this.renderer.updateClothParticles(this.particles, this.staging);
192
+ setPose(g: number, globals: Float32Array, model: Float32Array): void {
193
+ this.at(g).setPose(globals, model);
115
194
  }
116
195
 
117
- setWind(x: number, y: number, z: number): void {
118
- this.cloth.setWind(x, y, z);
196
+ setWind(g: number, x: number, y: number, z: number): void {
197
+ this.at(g).setWind(x, y, z);
119
198
  }
120
199
 
121
- reset(): void {
122
- this.cloth.reset();
200
+ reset(g: number): void {
201
+ this.at(g).reset();
202
+ }
203
+
204
+ step(dt: number): void {
205
+ for (let g = 0; g < this.cloths.length; g++) {
206
+ const cloth = this.cloths[g] as SkinnedCloth;
207
+ const staging = this.staging[g] as Float32Array;
208
+ cloth.advance(dt);
209
+ cloth.interpolate(cloth.alpha, staging);
210
+ this.renderer.updateClothParticles(this.particles[g] as ClothParticlesHandle, staging);
211
+ }
123
212
  }
124
213
 
125
214
  dispose(): void {
126
- this.renderer.disposeClothParticles(this.particles);
215
+ for (const particles of this.particles) this.renderer.disposeClothParticles(particles);
216
+ }
217
+
218
+ /** Garment `g`'s particles where its last step left them, as the device set reads its own. */
219
+ read(g: number): Promise<Float32Array> {
220
+ return Promise.resolve(new Float32Array(this.at(g).positions));
221
+ }
222
+
223
+ private at(g: number): SkinnedCloth {
224
+ const cloth = this.cloths[g];
225
+ if (cloth === undefined) throw new Error(`skinned cloth set: no garment ${g}`);
226
+ return cloth;
127
227
  }
128
228
  }