@meimu/mutracer 0.2.0 → 0.3.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 (211) hide show
  1. package/README.md +3 -0
  2. package/dist/assets/bvh.worker.js +1 -1
  3. package/dist/mutracer.umd.js +8949 -7915
  4. package/docs/api.md +42 -21
  5. package/docs/caustics.md +80 -0
  6. package/docs/materials.md +5 -4
  7. package/docs/progressive-rendering.md +50 -9
  8. package/docs/technical/continuous-spectrum.md +93 -0
  9. package/docs/updates.md +3 -1
  10. package/docs/viewer-checklist.md +65 -0
  11. package/docs/viewer.md +7 -5
  12. package/lib/Display.js +1 -1
  13. package/lib/Display.js.map +1 -1
  14. package/lib/Engine.d.ts +2 -0
  15. package/lib/Engine.js +47 -12
  16. package/lib/Engine.js.map +1 -1
  17. package/lib/Render.d.ts +61 -13
  18. package/lib/Render.js +169 -19
  19. package/lib/Render.js.map +1 -1
  20. package/lib/RenderLoop.d.ts +7 -3
  21. package/lib/RenderLoop.js +68 -44
  22. package/lib/RenderLoop.js.map +1 -1
  23. package/lib/main.d.ts +1 -1
  24. package/lib/main.js.map +1 -1
  25. package/lib/oidn.d.ts +1 -1
  26. package/lib/oidnBundledWeights.cdn.d.ts +2 -2
  27. package/lib/renderer/GPUTraceQueue.d.ts +2 -1
  28. package/lib/renderer/GPUTraceQueue.js +3 -1
  29. package/lib/renderer/GPUTraceQueue.js.map +1 -1
  30. package/lib/renderer/RenderingPipeline.d.ts +4 -0
  31. package/lib/renderer/RenderingPipeline.js.map +1 -1
  32. package/lib/renderer/WGPUCausticLightPass.d.ts +48 -0
  33. package/lib/renderer/WGPUCausticLightPass.js +217 -0
  34. package/lib/renderer/WGPUCausticLightPass.js.map +1 -0
  35. package/lib/renderer/WGPUEnvMapDistribution.js +18 -18
  36. package/lib/renderer/WGPUFullQuadPass.js +3 -3
  37. package/lib/renderer/WGPUPhotonMap.d.ts +37 -0
  38. package/lib/renderer/WGPUPhotonMap.js +191 -0
  39. package/lib/renderer/WGPUPhotonMap.js.map +1 -0
  40. package/lib/renderer/WGPURayTraceOutput.d.ts +13 -1
  41. package/lib/renderer/WGPURayTraceOutput.js +122 -28
  42. package/lib/renderer/WGPURayTraceOutput.js.map +1 -1
  43. package/lib/renderer/WGPURayTracePass.d.ts +48 -17
  44. package/lib/renderer/WGPURayTracePass.js +538 -340
  45. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  46. package/lib/renderer/WGPURenderingPipeline.js +83 -47
  47. package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
  48. package/lib/renderer/WebGLFullQuadPass.d.ts +2 -1
  49. package/lib/renderer/WebGLFullQuadPass.js +4 -0
  50. package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
  51. package/lib/renderer/WebGLJNLMDenoiser.js +66 -66
  52. package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
  53. package/lib/renderer/WebGLRayTracePass.d.ts +6 -1
  54. package/lib/renderer/WebGLRayTracePass.js +43 -6
  55. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  56. package/lib/renderer/WebGLRenderingPipeline.js +10 -14
  57. package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
  58. package/lib/renderer/WebGLSkyBaker.js +60 -60
  59. package/lib/renderer/accumulationTarget.d.ts +2 -1
  60. package/lib/renderer/accumulationTarget.js.map +1 -1
  61. package/lib/renderer/causticDiagnostics.d.ts +31 -0
  62. package/lib/renderer/causticDiagnostics.js +5 -0
  63. package/lib/renderer/causticDiagnostics.js.map +1 -0
  64. package/lib/renderer/causticEmission.d.ts +10 -0
  65. package/lib/renderer/causticEmission.js +40 -0
  66. package/lib/renderer/causticEmission.js.map +1 -0
  67. package/lib/renderer/causticUniform.d.ts +12 -0
  68. package/lib/renderer/causticUniform.js +22 -0
  69. package/lib/renderer/causticUniform.js.map +1 -0
  70. package/lib/renderer/caustics.d.ts +16 -0
  71. package/lib/renderer/caustics.js +93 -0
  72. package/lib/renderer/caustics.js.map +1 -0
  73. package/lib/renderer/glsl/aovDisplay.frag.js +5 -5
  74. package/lib/renderer/glsl/aovReflectance.glsl.js +53 -53
  75. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +1 -1
  76. package/lib/renderer/glsl/aovTrace.frag.js +33 -33
  77. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +9 -9
  78. package/lib/renderer/glsl/chunks/emissiveLight.glsl.d.ts +2 -0
  79. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +35 -0
  80. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js.map +1 -0
  81. package/lib/renderer/glsl/chunks/envMap.glsl.js +73 -73
  82. package/lib/renderer/glsl/chunks/intersect.glsl.js +426 -428
  83. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
  84. package/lib/renderer/glsl/chunks/materialBuffer.glsl.d.ts +1 -0
  85. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +156 -153
  86. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
  87. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +771 -771
  88. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  89. package/lib/renderer/glsl/chunks/random.glsl.js +6 -6
  90. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.d.ts +1 -0
  91. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +68 -63
  92. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  93. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +94 -76
  94. package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
  95. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -0
  96. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +140 -117
  97. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
  98. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +14 -14
  99. package/lib/renderer/glsl/chunks/sampling.glsl.js +89 -92
  100. package/lib/renderer/glsl/chunks/sampling.glsl.js.map +1 -1
  101. package/lib/renderer/glsl/chunks/sobol.glsl.js +79 -79
  102. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  103. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
  104. package/lib/renderer/glsl/depthQuery.frag.js +2 -2
  105. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +10 -10
  106. package/lib/renderer/glsl/rayTrace.frag.d.ts +1 -1
  107. package/lib/renderer/glsl/rayTrace.frag.js +260 -237
  108. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
  109. package/lib/renderer/glsl/shadowCatcher.frag.js +26 -26
  110. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  111. package/lib/renderer/glsl/webglPipeline.frag.js +59 -59
  112. package/lib/renderer/lightSampling.d.ts +3 -2
  113. package/lib/renderer/lightSampling.js +14 -8
  114. package/lib/renderer/lightSampling.js.map +1 -1
  115. package/lib/renderer/progressiveScheduler.js +4 -3
  116. package/lib/renderer/progressiveScheduler.js.map +1 -1
  117. package/lib/renderer/renderPipeline.d.ts +1 -0
  118. package/lib/renderer/renderPipeline.js.map +1 -1
  119. package/lib/renderer/researchTransport.d.ts +31 -0
  120. package/lib/renderer/researchTransport.js +5 -0
  121. package/lib/renderer/researchTransport.js.map +1 -0
  122. package/lib/renderer/sceneLayoutSchema.d.ts +1 -0
  123. package/lib/renderer/sceneLayoutSchema.js +2 -2
  124. package/lib/renderer/sceneLayoutSchema.js.map +1 -1
  125. package/lib/renderer/scratchSampling.js +6 -6
  126. package/lib/renderer/spectrum.d.ts +21 -0
  127. package/lib/renderer/spectrum.js +154 -0
  128. package/lib/renderer/spectrum.js.map +1 -0
  129. package/lib/renderer/webglLightSampling.d.ts +39 -0
  130. package/lib/renderer/webglLightSampling.js +15 -0
  131. package/lib/renderer/webglLightSampling.js.map +1 -0
  132. package/lib/renderer/wgpuBindlessSource.js +3 -3
  133. package/lib/renderer/wgpuShaderSource.d.ts +7 -0
  134. package/lib/renderer/wgpuShaderSource.js +2 -0
  135. package/lib/renderer/wgpuShaderSource.js.map +1 -1
  136. package/lib/renderer/wgsl/aovDisplay.wgsl.js +9 -9
  137. package/lib/renderer/wgsl/aovReflectance.wgsl.js +55 -55
  138. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +1 -1
  139. package/lib/renderer/wgsl/aovResolve.wgsl.js +2 -2
  140. package/lib/renderer/wgsl/aovSnapshot.wgsl.js +1 -1
  141. package/lib/renderer/wgsl/aovTrace.wgsl.js +33 -33
  142. package/lib/renderer/wgsl/bloom.wgsl.js +18 -18
  143. package/lib/renderer/wgsl/causticLight.compute.d.ts +6 -0
  144. package/lib/renderer/wgsl/causticLight.compute.js +537 -0
  145. package/lib/renderer/wgsl/causticLight.compute.js.map +1 -0
  146. package/lib/renderer/wgsl/chunks/background.wgsl.d.ts +2 -0
  147. package/lib/renderer/wgsl/chunks/background.wgsl.js +102 -0
  148. package/lib/renderer/wgsl/chunks/background.wgsl.js.map +1 -0
  149. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.d.ts +2 -0
  150. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +12 -0
  151. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js.map +1 -0
  152. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.d.ts +2 -0
  153. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +16 -0
  154. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js.map +1 -0
  155. package/lib/renderer/wgsl/chunks/caustics.wgsl.d.ts +1 -0
  156. package/lib/renderer/wgsl/chunks/caustics.wgsl.js +62 -0
  157. package/lib/renderer/wgsl/chunks/caustics.wgsl.js.map +1 -0
  158. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  159. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +37 -37
  160. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +598 -592
  161. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  162. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +14 -14
  163. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +2 -1
  164. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +75 -73
  165. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  166. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +794 -794
  167. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +139 -139
  168. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  169. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +2 -1
  170. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +35 -25
  171. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  172. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +1 -1
  173. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +142 -138
  174. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -1
  175. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
  176. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +204 -187
  177. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
  178. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +1 -1
  179. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +11 -11
  180. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -1
  181. package/lib/renderer/wgsl/chunks/sampling.wgsl.d.ts +1 -1
  182. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +89 -93
  183. package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -1
  184. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +83 -83
  185. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
  186. package/lib/renderer/wgsl/compose.frag.wgsl.js +98 -98
  187. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  188. package/lib/renderer/wgsl/depthQuery.wgsl.js +2 -2
  189. package/lib/renderer/wgsl/jnlm.compute.js +74 -74
  190. package/lib/renderer/wgsl/offlineAdaptive.compute.js +25 -25
  191. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +3 -3
  192. package/lib/renderer/wgsl/photonMap.compute.d.ts +29 -0
  193. package/lib/renderer/wgsl/photonMap.compute.js +352 -0
  194. package/lib/renderer/wgsl/photonMap.compute.js.map +1 -0
  195. package/lib/renderer/wgsl/proceduralSky.compute.js +64 -64
  196. package/lib/renderer/wgsl/rayTrace.compute.d.ts +9 -1
  197. package/lib/renderer/wgsl/rayTrace.compute.js +448 -522
  198. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  199. package/lib/scene/MaterialState.d.ts +2 -2
  200. package/lib/scene/MaterialState.js +2 -2
  201. package/lib/scene/MaterialState.js.map +1 -1
  202. package/lib/settings/render.d.ts +11 -0
  203. package/lib/settings/render.js +1 -0
  204. package/lib/settings/render.js.map +1 -1
  205. package/lib/util/fromTHREE.js +2 -2
  206. package/lib/util/fromTHREE.js.map +1 -1
  207. package/lib/version.d.ts +1 -1
  208. package/lib/version.js +1 -1
  209. package/lib/version.js.map +1 -1
  210. package/llms.txt +2 -1
  211. package/package.json +3 -3
@@ -5,7 +5,7 @@ import { mapAlphaUsageConstants } from '../../materialConstants.js';
5
5
  // (https://github.com/hoverinc/ray-tracing-renderer).
6
6
  // Copyright (c) 2019 HOVER, MIT license; see LICENSES/RayTracingRenderer-MIT.txt.
7
7
  import { materialAlphaModeConstants } from '../../materialConstants.js';
8
- export function createMaterialBufferWgsl({ hasAnisotropyDirections = true, hasCoatNormals = false, hasSceneAlpha = true, hasTransmission = true, hasMetalness = true } = {}) {
8
+ export function createMaterialBufferWgsl({ hasAnisotropyDirections = true, hasCoatNormals = false, hasSceneAlpha = true, hasTransmission = true, caustics = false, hasMetalness = true } = {}) {
9
9
  const alphaModeAssignment = hasSceneAlpha
10
10
  ? '(*ma).alphaMode = i32(matData.alphaMode);'
11
11
  : '';
@@ -20,7 +20,7 @@ else if ((*ma).alphaMode == ${materialAlphaModeConstants.mask}) {
20
20
  : '(*ma).alpha = 1.0;';
21
21
  return /* wgsl */ `
22
22
 
23
- ${hasAnisotropyDirections ? /* wgsl */ `fn fv(roughness: f32, strength: f32) -> vec2f {
23
+ ${hasAnisotropyDirections ? /* wgsl */ `fn fb(roughness: f32, strength: f32) -> vec2f {
24
24
  if (strength == 0.0) { return vec2f(roughness, 0.0); }
25
25
  let u = roughness * roughness;
26
26
  let a = u + (1.0 - u) * strength * strength;
@@ -29,55 +29,55 @@ return vec2f(pow((a*a + u*u) * 0.5, 0.25), clamp(1.0 - u/a, 0.0, 1.0));
29
29
  }
30
30
  ` : /* wgsl */ ``}
31
31
 
32
- fn mG(c: vec3f) -> vec3f {
32
+ fn mq(c: vec3f) -> vec3f {
33
33
  return mix(pow(c * 0.9478672986 + 0.0521327014, vec3f(2.4)), c * 0.0773993808, vec3f(c < vec3f(0.04045)));
34
34
  }
35
35
 
36
36
  fn decodeMapColor(idx: i32, c: vec3f) -> vec3f {
37
37
  if (mapInfo[idx + NUM_MAPS * 2].y > 0.5) { return c; }
38
- return mG(c);
38
+ return mq(c);
39
39
  }
40
40
 
41
- fn ah(val: i32) -> vec2f {
41
+ fn af(val: i32) -> vec2f {
42
42
  return vec2f(f32(val >> 8), f32(val & 0xff) / 255.0);
43
43
  }
44
44
 
45
- fn jO(idx: i32) -> vec2f {
45
+ fn jv(idx: i32) -> vec2f {
46
46
  return mapInfo[idx].xy;
47
47
  }
48
48
 
49
- fn lT(idx: i32) -> i32 {
49
+ fn lE(idx: i32) -> i32 {
50
50
  return i32(floor(mapInfo[idx].z));
51
51
  }
52
52
 
53
- fn kt(idx: i32) -> vec2f {
53
+ fn jV(idx: i32) -> vec2f {
54
54
  return vec2f(fract(mapInfo[idx].z), mapInfo[idx].w);
55
55
  }
56
56
 
57
- fn gg(value: f32, mode: f32) -> f32 {
57
+ fn fS(value: f32, mode: f32) -> f32 {
58
58
  if (mode < 0.5) { return fract(value); }
59
59
  if (mode < 1.5) { return clamp(value, 0.0, 1.0); }
60
60
  return 1.0 - abs(1.0 - (value - 2.0 * floor(value * 0.5)));
61
61
  }
62
62
 
63
- fn kZ(idx: i32, uv: vec2f) -> vec2f {
63
+ fn kF(idx: i32, uv: vec2f) -> vec2f {
64
64
  let transform = mapInfo[idx + NUM_MAPS];
65
65
  let modes = mapInfo[idx + NUM_MAPS * 2].zw;
66
66
  let value = uv * transform.xy + transform.zw;
67
- return vec2f(gg(value.x, modes.x), gg(value.y, modes.y));
67
+ return vec2f(fS(value.x, modes.x), fS(value.y, modes.y));
68
68
  }
69
69
 
70
- fn tJ(idx: i32, uv: vec2f) -> vec2f {
71
- let rN = kZ(idx, uv);
72
- let jH = 1.0 / vec2f(textureDimensions(map).xy);
73
- let eo = kt(idx);
74
- let kS = jO(idx) + jH;
75
- let pJ = eo - 0.5 * jH;
76
- let ml = eo + kS - jH;
70
+ fn tK(idx: i32, uv: vec2f) -> vec2f {
71
+ let rJ = kF(idx, uv);
72
+ let jn = 1.0 / vec2f(textureDimensions(map).xy);
73
+ let dX = jV(idx);
74
+ let kx = jv(idx) + jn;
75
+ let po = dX - 0.5 * jn;
76
+ let lS = dX + kx - jn;
77
77
  return clamp(
78
- pJ + rN * kS,
79
- eo,
80
- ml
78
+ po + rJ * kx,
79
+ dX,
80
+ lS
81
81
  );
82
82
  }
83
83
 
@@ -86,28 +86,28 @@ return select(uv, uv1, mapInfo[idx + NUM_MAPS * 2].x > 0.5);
86
86
  }
87
87
 
88
88
  fn sampleMap(idx: i32, uv: vec2f) -> vec4f {
89
- let size = vec2i(round(jO(idx) * vec2f(textureDimensions(map).xy) + vec2f(1.0)));
90
- let dk = kZ(idx, uv) * vec2f(size) - vec2f(0.5);
89
+ let size = vec2i(round(jv(idx) * vec2f(textureDimensions(map).xy) + vec2f(1.0)));
90
+ let cR = kF(idx, uv) * vec2f(size) - vec2f(0.5);
91
91
  let modes = mapInfo[idx + NUM_MAPS * 2].zw;
92
92
 
93
93
 
94
- if ((size.x > 1 && modes.x < 0.5 && (dk.x < 0.0 || dk.x > f32(size.x - 1))) ||
95
- (size.y > 1 && modes.y < 0.5 && (dk.y < 0.0 || dk.y > f32(size.y - 1)))) {
96
- let base = vec2i(floor(dk));
97
- let weight = fract(dk);
98
- let origin = vec2i(round(kt(idx) * vec2f(textureDimensions(map).xy) - vec2f(0.5)));
94
+ if ((size.x > 1 && modes.x < 0.5 && (cR.x < 0.0 || cR.x > f32(size.x - 1))) ||
95
+ (size.y > 1 && modes.y < 0.5 && (cR.y < 0.0 || cR.y > f32(size.y - 1)))) {
96
+ let base = vec2i(floor(cR));
97
+ let weight = fract(cR);
98
+ let origin = vec2i(round(jV(idx) * vec2f(textureDimensions(map).xy) - vec2f(0.5)));
99
99
  return mix(
100
- mix(fe(idx, base, size, origin, modes), fe(idx, base + vec2i(1, 0), size, origin, modes), weight.x),
101
- mix(fe(idx, base + vec2i(0, 1), size, origin, modes), fe(idx, base + vec2i(1, 1), size, origin, modes), weight.x), weight.y);
100
+ mix(eN(idx, base, size, origin, modes), eN(idx, base + vec2i(1, 0), size, origin, modes), weight.x),
101
+ mix(eN(idx, base + vec2i(0, 1), size, origin, modes), eN(idx, base + vec2i(1, 1), size, origin, modes), weight.x), weight.y);
102
102
  }
103
- return textureSampleLevel(map, mapSampler, tJ(idx, uv), lT(idx), 0.0);
103
+ return textureSampleLevel(map, mapSampler, tK(idx, uv), lE(idx), 0.0);
104
104
  }
105
105
 
106
- fn fe(idx: i32, jJ: vec2i, size: vec2i, origin: vec2i, modes: vec2f) -> vec4f {
107
- var p = clamp(jJ, vec2i(0), size - vec2i(1));
108
- if (modes.x < 0.5) { p.x = ((jJ.x % size.x) + size.x) % size.x; }
109
- if (modes.y < 0.5) { p.y = ((jJ.y % size.y) + size.y) % size.y; }
110
- return textureLoad(map, origin + p, lT(idx), 0);
106
+ fn eN(idx: i32, jq: vec2i, size: vec2i, origin: vec2i, modes: vec2f) -> vec4f {
107
+ var p = clamp(jq, vec2i(0), size - vec2i(1));
108
+ if (modes.x < 0.5) { p.x = ((jq.x % size.x) + size.x) % size.x; }
109
+ if (modes.y < 0.5) { p.y = ((jq.y % size.y) + size.y) % size.y; }
110
+ return textureLoad(map, origin + p, lE(idx), 0);
111
111
  }
112
112
 
113
113
 
@@ -135,21 +135,21 @@ return emission;
135
135
  }
136
136
 
137
137
 
138
- fn aN(roughness: f32, anisotropy: f32) -> vec2f {
138
+ fn aL(roughness: f32, anisotropy: f32) -> vec2f {
139
139
  let alpha = roughness * roughness;
140
- let qe = ROUGHNESS_MIN * ROUGHNESS_MIN;
141
- if (anisotropy == 0.0) { return vec2f(max(qe, alpha)); }
142
- let dw = 1.0 - anisotropy;
143
- let tp = alpha * sqrt(2.0 / (1.0 + dw * dw));
144
- return max(vec2f(qe), vec2f(tp, dw * tp));
140
+ let pZ = ROUGHNESS_MIN * ROUGHNESS_MIN;
141
+ if (anisotropy == 0.0) { return vec2f(max(pZ, alpha)); }
142
+ let cY = 1.0 - anisotropy;
143
+ let tp = alpha * sqrt(2.0 / (1.0 + cY * cY));
144
+ return max(vec2f(pZ), vec2f(tp, cY * tp));
145
145
  }
146
146
 
147
- fn lp(instanceIndex: i32) -> vec3f {
147
+ fn kV(instanceIndex: i32) -> vec3f {
148
148
  if (instanceIndex < 0) { return vec3f(1.0); }
149
149
  return instancesBuffer[instanceIndex * ${INSTANCE_VEC4_STRIDE} + 9].xyz;
150
150
  }
151
151
 
152
- fn dg(
152
+ fn getMaterial(
153
153
  ma: ptr<function, OpenPbrResolvedMaterial>,
154
154
  materialIndex: i32,
155
155
  uv: vec2f,
@@ -230,11 +230,11 @@ if (USE_METALLIC_ROUGHNESS_MAPS) {
230
230
 
231
231
  let mrtMapIndex = i32(matData.mrtMapIndex);
232
232
  if (mrtMapIndex >= 0) {
233
- let gc = sampleMap(
233
+ let fO = sampleMap(
234
234
  mrtMapIndex, getMapUvSet(mrtMapIndex, uv, uv1)
235
235
  );
236
- (*ma).baseMetalness *= gc.b;
237
- (*ma).specularRoughness *= gc.g;
236
+ (*ma).baseMetalness *= fO.b;
237
+ (*ma).specularRoughness *= fO.g;
238
238
  }
239
239
  }
240
240
 
@@ -267,16 +267,16 @@ ${hasAnisotropyDirections ? /* wgsl */ `
267
267
  (*ma).coatAnisotropyRotation = matData.coatAnisotropyRotation;
268
268
  if (USE_ANISOTROPY_MAPS && matData.anisotropyMapIndex >= 0.0) {
269
269
  let index = i32(matData.anisotropyMapIndex);
270
- let dk = sampleMap(index, getMapUvSet(index, uv, uv1));
271
- (*ma).specularAnisotropy *= dk.b;
272
- let direction = dk.rg * 2.0 - 1.0;
270
+ let cR = sampleMap(index, getMapUvSet(index, uv, uv1));
271
+ (*ma).specularAnisotropy *= cR.b;
272
+ let direction = cR.rg * 2.0 - 1.0;
273
273
  if (dot(direction, direction) > 1e-4) { (*ma).anisotropyDirection = normalize(direction); }
274
274
  (*ma).anisotropyDirectionEnabled = true;
275
275
  }
276
276
  if (matData.specularAnisotropyModel > 0.5 && (*ma).specularAnisotropy > 0.0) {
277
- let tU = fv(clamp((*ma).specularRoughness, 0.0, 1.0), (*ma).specularAnisotropy);
278
- (*ma).specularRoughness = tU.x;
279
- (*ma).specularAnisotropy = tU.y;
277
+ let tX = fb(clamp((*ma).specularRoughness, 0.0, 1.0), (*ma).specularAnisotropy);
278
+ (*ma).specularRoughness = tX.x;
279
+ (*ma).specularAnisotropy = tX.y;
280
280
  }
281
281
  if ((*ma).anisotropyDirectionEnabled) {
282
282
  let theta = matData.specularAnisotropyRotation;
@@ -288,57 +288,59 @@ let d = (*ma).anisotropyDirection;
288
288
 
289
289
 
290
290
  if ((*ma).coatWeight > 0.0 && (*ma).coatRoughness > 0.0) {
291
- let ih = (*ma).specularRoughness * (*ma).specularRoughness;
292
- let ij = (*ma).coatRoughness * (*ma).coatRoughness;
291
+ let hJ = (*ma).specularRoughness * (*ma).specularRoughness;
292
+ let hK = (*ma).coatRoughness * (*ma).coatRoughness;
293
293
  (*ma).specularRoughness = mix((*ma).specularRoughness,
294
- pow(min(1.0, ih * ih + 2.0 * ij * ij), 0.25), (*ma).coatWeight);
294
+ pow(min(1.0, hJ * hJ + 2.0 * hK * hK), 0.25), (*ma).coatWeight);
295
295
  }
296
296
  ${hasTransmission ? '' : /* wgsl */ `(*ma).transmissionWeight = 0.0;`}
297
297
  ${hasMetalness ? '' : /* wgsl */ `(*ma).baseMetalness = 0.0;`}
298
- let color = lp(instanceIndex) * vertexColor;
298
+ let color = kV(instanceIndex) * vertexColor;
299
299
  (*ma).baseColor *= color;
300
300
  if ((*ma).materialType == UNLIT) { (*ma).emission *= color; }
301
301
 
302
- (*ma).specularRoughness = clamp((*ma).specularRoughness, ROUGHNESS_MIN, 1.0);
302
+ ${caustics ? /* wgsl */ ` (*ma).causticRoughness = (*ma).specularRoughness;
303
+ (*ma).causticNormalMapped = matData.normalMapIndex >= 0.0;
304
+ ` : ''} (*ma).specularRoughness = clamp((*ma).specularRoughness, ROUGHNESS_MIN, 1.0);
303
305
  (*ma).baseMetalness = clamp((*ma).baseMetalness, 0.0, 1.0);
304
- let specularAlpha = aN((*ma).specularRoughness, (*ma).specularAnisotropy);
306
+ let specularAlpha = aL((*ma).specularRoughness, (*ma).specularAnisotropy);
305
307
  (*ma).alphaX = specularAlpha.x;
306
308
  (*ma).alphaY = specularAlpha.y;
307
309
  }
308
310
 
309
- fn pd(materialIndex: i32, uv: vec2f, normal: vec3f, dp1: vec3f, dp2: vec3f, oW: vec2f, oX: vec2f) -> vec3f {
311
+ fn oS(materialIndex: i32, uv: vec2f, normal: vec3f, dp1: vec3f, dp2: vec3f, oM: vec2f, oN: vec2f) -> vec3f {
310
312
  let matData = materialsBuffer[materialIndex];
311
313
  let normalMapIndex = i32(matData.normalMapIndex);
312
314
  if (normalMapIndex >= 0) {
313
315
 
314
316
 
315
317
 
316
- let sb = cross(dp2, normal);
317
- let sa = cross(normal, dp1);
318
- var dpdu = sb * oW.x + sa * oX.x;
319
- var tH = sb * oW.y + sa * oX.y;
320
- let ej = max(dot(dpdu, dpdu), dot(tH, tH));
321
- if (ej > 1e-12) {
322
- let tO = inverseSqrt(ej);
323
- dpdu *= tO;
324
- tH *= tO;
318
+ let rX = cross(dp2, normal);
319
+ let rW = cross(normal, dp1);
320
+ var dpdu = rX * oM.x + rW * oN.x;
321
+ var tI = rX * oM.y + rW * oN.y;
322
+ let dT = max(dot(dpdu, dpdu), dot(tI, tI));
323
+ if (dT > 1e-12) {
324
+ let tQ = inverseSqrt(dT);
325
+ dpdu *= tQ;
326
+ tI *= tQ;
325
327
  }
326
328
  else {
327
329
 
328
330
 
329
- let oo = select(
331
+ let ob = select(
330
332
  vec3f(0.0, 1.0, 0.0),
331
333
  vec3f(0.0, 0.0, 1.0),
332
334
  abs(normal.z) < 0.999
333
335
  );
334
- dpdu = normalize(cross(oo, normal));
335
- tH = cross(normal, dpdu);
336
+ dpdu = normalize(cross(ob, normal));
337
+ tI = cross(normal, dpdu);
336
338
  }
337
339
 
338
340
  var n = 2.0 * sampleMap(normalMapIndex, uv).rgb - 1.0;
339
341
  n = normalize(vec3(n.xy * matData.normalMapScale, n.z));
340
342
 
341
- let tbn = mat3x3(dpdu, tH, normal);
343
+ let tbn = mat3x3(dpdu, tI, normal);
342
344
 
343
345
  return normalize(tbn * n);
344
346
  } else {
@@ -1 +1 @@
1
- {"version":3,"file":"materialBuffer.wgsl.js","sourceRoot":"","sources":["../../../../src/renderer/wgsl/chunks/materialBuffer.wgsl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,qDAAqD;AACrD,sDAAsD;AACtD,kFAAkF;AAElF,OAAO,EACL,0BAA0B,EAC3B,MAAM,4BAA4B,CAAC;AAEpC,MAAM,UAAU,wBAAwB,CAAC,EACvC,uBAAuB,GAAG,IAAI,EAC9B,cAAc,GAAG,KAAK,EACtB,aAAa,GAAG,IAAI,EACpB,eAAe,GAAG,IAAI,EACtB,YAAY,GAAG,IAAI,KAOjB,EAAE;IACJ,MAAM,mBAAmB,GAAG,aAAa;QACvC,CAAC,CAAC,2CAA2C;QAC7C,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,mBAAmB,GAAG,aAAa;QACvC,CAAC,CAAC,UAAU,CAAC;yBACU,0BAA0B,CAAC,MAAM;;;8BAG5B,0BAA0B,CAAC,IAAI;;EAE3D;QACA,CAAC,CAAC,oBAAoB,CAAC;IAEzB,OAAO,UAAU,CAAC;;EAElB,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;;CAOtC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCAuH0B,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+B3D,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAkCc,sBAAsB,CAAC,YAAY;;;oCAG9B,sBAAsB,CAAC,KAAK;;;;;;EAMlE,mBAAmB,CAAC,UAAU,EAAE,MAAM,CAAC;;EAEvC,mBAAmB;;EAEnB,mBAAmB,CAAC,iBAAiB,EAAE,MAAM,CAAC;;;;;;;;;;;;;;EAc9C,mBAAmB,CAAC,cAAc,EAAE,MAAM,CAAC;;EAE3C,mBAAmB,CAAC,cAAc,EAAE,MAAM,CAAC;;EAE3C,qBAAqB,CAAC,MAAM,CAAC;;EAE7B,mBAAmB,CAAC,eAAe,EAAE,MAAM,CAAC;;EAE9C,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;;;CAG7B,CAAC,CAAC,CAAC,EAAE;;EAEF,mBAAmB,CAAC,kBAAkB,EAAE,MAAM,CAAC;;EAE/C,mBAAmB,CAAC,cAAc,EAAE,MAAM,CAAC;;EAE3C,mBAAmB,CAAC,kBAAkB,EAAE,MAAM,CAAC;;EAE/C,mBAAmB,CAAC,mBAAmB,EAAE,MAAM,CAAC;;EAEhD,mBAAmB,CAAC,kBAAkB,EAAE,MAAM,CAAC;;EAEjD,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;CAuBtC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;;;;;;;;;EASb,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,iCAAiC;EACnE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmD9D,CAAC;AACF,CAAC;AAED,MAAM,kBAAkB,GAAG,wBAAwB,EAAE,CAAC;AAEtD,eAAe,kBAAkB,CAAC","sourcesContent":["import { simpleTextureSample, thinFilmTextureSample } from '../../materialTextureSlots.js';\nimport { INSTANCE_VEC4_STRIDE } from '../../bvhAccel.js';\nimport { mapAlphaUsageConstants } from '../../materialConstants.js';\n// Portions adapted from ray-tracing-renderer@0.10.15\n// (https://github.com/hoverinc/ray-tracing-renderer).\n// Copyright (c) 2019 HOVER, MIT license; see LICENSES/RayTracingRenderer-MIT.txt.\n\nimport {\n materialAlphaModeConstants\n} from '../../materialConstants.js';\n\nexport function createMaterialBufferWgsl({\n hasAnisotropyDirections = true,\n hasCoatNormals = false,\n hasSceneAlpha = true,\n hasTransmission = true,\n hasMetalness = true\n}: {\n hasSceneAlpha?: boolean;\n hasAnisotropyDirections?: boolean;\n hasCoatNormals?: boolean;\n hasTransmission?: boolean;\n hasMetalness?: boolean;\n} = {}) {\n const alphaModeAssignment = hasSceneAlpha\n ? '(*ma).alphaMode = i32(matData.alphaMode);'\n : '';\n const alphaModeResolution = hasSceneAlpha\n ? /* wgsl */ `\n if ((*ma).alphaMode == ${materialAlphaModeConstants.opaque}) {\n (*ma).alpha = 1.0;\n }\n else if ((*ma).alphaMode == ${materialAlphaModeConstants.mask}) {\n (*ma).alpha = select(0.0, 1.0, (*ma).alpha >= matData.alphaCutoff);\n }`\n : '(*ma).alpha = 1.0;';\n\n return /* wgsl */ `\n\n${hasAnisotropyDirections ? /* wgsl */ `fn gltf_anisotropy_to_openpbr(roughness: f32, strength: f32) -> vec2f {\n if (strength == 0.0) { return vec2f(roughness, 0.0); }\n let u = roughness * roughness;\n let a = u + (1.0 - u) * strength * strength;\n if (a == 0.0) { return vec2f(0.0); }\n return vec2f(pow((a*a + u*u) * 0.5, 0.25), clamp(1.0 - u/a, 0.0, 1.0));\n}\n` : /* wgsl */ ``}\n\nfn sRGBToLinear(c: vec3f) -> vec3f {\n return mix(pow(c * 0.9478672986 + 0.0521327014, vec3f(2.4)), c * 0.0773993808, vec3f(c < vec3f(0.04045)));\n}\n\nfn decodeMapColor(idx: i32, c: vec3f) -> vec3f {\n if (mapInfo[idx + NUM_MAPS * 2].y > 0.5) { return c; }\n return sRGBToLinear(c);\n}\n\nfn unpackMaterialIndex(val: i32) -> vec2f {\n return vec2f(f32(val >> 8), f32(val & 0xff) / 255.0);\n}\n\nfn getMapSize(idx: i32) -> vec2f {\n return mapInfo[idx].xy;\n}\n\nfn getMapLayer(idx: i32) -> i32 {\n return i32(floor(mapInfo[idx].z));\n}\n\nfn getMapOffset(idx: i32) -> vec2f {\n return vec2f(fract(mapInfo[idx].z), mapInfo[idx].w);\n}\n\nfn wrapMapCoordinate(value: f32, mode: f32) -> f32 {\n if (mode < 0.5) { return fract(value); }\n if (mode < 1.5) { return clamp(value, 0.0, 1.0); }\n return 1.0 - abs(1.0 - (value - 2.0 * floor(value * 0.5)));\n}\n\nfn wrappedMapUv(idx: i32, uv: vec2f) -> vec2f {\n let transform = mapInfo[idx + NUM_MAPS];\n let modes = mapInfo[idx + NUM_MAPS * 2].zw;\n let value = uv * transform.xy + transform.zw;\n return vec2f(wrapMapCoordinate(value.x, modes.x), wrapMapCoordinate(value.y, modes.y));\n}\n\nfn getMapUV(idx: i32, uv: vec2f) -> vec2f {\n let repeatedUv = wrappedMapUv(idx, uv);\n let atlasTexel = 1.0 / vec2f(textureDimensions(map).xy);\n let firstTexelCenter = getMapOffset(idx);\n let sourceExtent = getMapSize(idx) + atlasTexel;\n let sourceOrigin = firstTexelCenter - 0.5 * atlasTexel;\n let lastTexelCenter = firstTexelCenter + sourceExtent - atlasTexel;\n return clamp(\n sourceOrigin + repeatedUv * sourceExtent,\n firstTexelCenter,\n lastTexelCenter\n );\n}\n\nfn getMapUvSet(idx: i32, uv: vec2f, uv1: vec2f) -> vec2f {\n return select(uv, uv1, mapInfo[idx + NUM_MAPS * 2].x > 0.5);\n}\n\nfn sampleMap(idx: i32, uv: vec2f) -> vec4f {\n let size = vec2i(round(getMapSize(idx) * vec2f(textureDimensions(map).xy) + vec2f(1.0)));\n let texel = wrappedMapUv(idx, uv) * vec2f(size) - vec2f(0.5);\n let modes = mapInfo[idx + NUM_MAPS * 2].zw;\n // Repeat filtering must cross the logical image boundary, never another\n // atlas placement. Interior/clamped/mirrored footprints use hardware filtering.\n if ((size.x > 1 && modes.x < 0.5 && (texel.x < 0.0 || texel.x > f32(size.x - 1))) ||\n (size.y > 1 && modes.y < 0.5 && (texel.y < 0.0 || texel.y > f32(size.y - 1)))) {\n let base = vec2i(floor(texel));\n let weight = fract(texel);\n let origin = vec2i(round(getMapOffset(idx) * vec2f(textureDimensions(map).xy) - vec2f(0.5)));\n return mix(\n mix(loadMapTexel(idx, base, size, origin, modes), loadMapTexel(idx, base + vec2i(1, 0), size, origin, modes), weight.x),\n mix(loadMapTexel(idx, base + vec2i(0, 1), size, origin, modes), loadMapTexel(idx, base + vec2i(1, 1), size, origin, modes), weight.x), weight.y);\n }\n return textureSampleLevel(map, mapSampler, getMapUV(idx, uv), getMapLayer(idx), 0.0);\n}\n\nfn loadMapTexel(idx: i32, coordinate: vec2i, size: vec2i, origin: vec2i, modes: vec2f) -> vec4f {\n var p = clamp(coordinate, vec2i(0), size - vec2i(1));\n if (modes.x < 0.5) { p.x = ((coordinate.x % size.x) + size.x) % size.x; }\n if (modes.y < 0.5) { p.y = ((coordinate.y % size.y) + size.y) % size.y; }\n return textureLoad(map, origin + p, getMapLayer(idx), 0);\n}\n\n\nfn getMaterialEmission(materialIndex: i32, uv: vec2f, uv1: vec2f) -> vec3f {\n let matData = materialsBuffer[materialIndex];\n var emission = matData.emission;\n if (USE_EMISSIVE_MAPS) {\n let emissiveMapIndex = i32(matData.emissiveMapIndex);\n if (emissiveMapIndex >= 0) {\n emission *= decodeMapColor(emissiveMapIndex, sampleMap(\n emissiveMapIndex, getMapUvSet(emissiveMapIndex, uv, uv1)\n ).rgb);\n }\n }\n if (USE_COAT_WEIGHT_MAPS && matData.matType == 0.0) {\n let coatWeightMapIndex = i32(matData.coatWeightMapIndex);\n if (coatWeightMapIndex >= 0) {\n let coatWeight = clamp(matData.coatWeight, 0.0, 1.0) * sampleMap(\n coatWeightMapIndex, getMapUvSet(coatWeightMapIndex, uv, uv1)\n ).r;\n emission *= mix(vec3f(1.0), sqrt(max(matData.coatColor, vec3f(0.0))), coatWeight);\n }\n }\n return emission;\n}\n\n// OpenPBR 1.1.1: RMS-preserving GGX anisotropy, shared by base and coat.\nfn openpbr_roughness_to_alpha(roughness: f32, anisotropy: f32) -> vec2f {\n let alpha = roughness * roughness;\n let alphaMin = ROUGHNESS_MIN * ROUGHNESS_MIN;\n if (anisotropy == 0.0) { return vec2f(max(alphaMin, alpha)); }\n let complement = 1.0 - anisotropy;\n let alphaT = alpha * sqrt(2.0 / (1.0 + complement * complement));\n return max(vec2f(alphaMin), vec2f(alphaT, complement * alphaT));\n}\n\nfn getInstanceColor(instanceIndex: i32) -> vec3f {\n if (instanceIndex < 0) { return vec3f(1.0); }\n return instancesBuffer[instanceIndex * ${INSTANCE_VEC4_STRIDE} + 9].xyz;\n}\n\nfn getMaterial(\n ma: ptr<function, OpenPbrResolvedMaterial>,\n materialIndex: i32,\n uv: vec2f,\n uv1: vec2f,\n instanceIndex: i32,\n vertexColor: vec3f\n) {\n let matData = materialsBuffer[materialIndex];\n\n (*ma).baseColor = matData.color;\n (*ma).materialType = i32(matData.matType);\n (*ma).specularRoughness = matData.roughness;\n (*ma).baseMetalness = matData.metallic;\n (*ma).specularAnisotropy = clamp(matData.anisotropy, 0.0, 1.0);\n (*ma).emission = getMaterialEmission(materialIndex, uv, uv1);\n (*ma).inside = false;\n (*ma).specularIor = matData.ior;\n (*ma).transmissionWeight = matData.transmission;\n (*ma).thinWalled = matData.thin > 0.5;\n (*ma).bevel = matData.bevel;\n (*ma).transmissionDispersionScale = matData.dispersion;\n (*ma).dispersionAbbeNumber = max(matData.dispersionAbbeNumber, 1e-6);\n (*ma).mediumExtinction = max(matData.mediumExtinction, vec3f(0.0));\n (*ma).mediumScattering = max(matData.mediumScattering, vec3f(0.0));\n (*ma).mediumAnisotropy = clamp(matData.mediumAnisotropy, -1.0, 1.0);\n (*ma).mediumType = select(0, 1, max(max((*ma).mediumExtinction.x, (*ma).mediumExtinction.y), (*ma).mediumExtinction.z) > 0.0);\n (*ma).alpha = matData.alpha;\n ${alphaModeAssignment}\n\n (*ma).thinFilmThickness = matData.thinFilmThickness * 1000.0;\n (*ma).thinFilmIor = matData.thinFilmIor;\n (*ma).thinFilmWeight = select(0.0, clamp(matData.thinFilmWeight, 0.0, 1.0), HAS_THIN_FILM);\n (*ma).baseWeight = clamp(matData.baseWeight, 0.0, 1.0);\n (*ma).diffuseRoughness = clamp(matData.baseDiffuseRoughness, 0.0, 1.0);\n (*ma).specularWeight = max(matData.specularWeight, 0.0);\n (*ma).specularColor = max(matData.specularColor, vec3f(0.0));\n (*ma).subsurfaceWeight = select(0.0, clamp(matData.subsurfaceWeight, 0.0, 1.0), HAS_SUBSURFACE);\n (*ma).subsurfaceColor = max(matData.subsurfaceColor, vec3f(0.0));\n (*ma).transmissionColor = max(matData.transmissionColor, vec3f(0.0));\n (*ma).fuzzWeight = select(0.0, clamp(matData.fuzzWeight, 0.0, 1.0), HAS_FUZZ);\n (*ma).fuzzColor = max(matData.fuzzColor, vec3f(0.0));\n (*ma).fuzzRoughness = clamp(matData.fuzzRoughness, 0.0, 1.0);\n (*ma).coatWeight = select(0.0, clamp(matData.coatWeight, 0.0, 1.0), HAS_COAT);\n (*ma).coatColor = max(matData.coatColor, vec3f(0.0));\n (*ma).coatRoughness = clamp(matData.coatRoughness, ROUGHNESS_MIN, 1.0);\n (*ma).coatAnisotropy = clamp(matData.coatAnisotropy, 0.0, 1.0);\n (*ma).coatIor = max(matData.coatIor, 1.0);\n (*ma).coatDarkening = clamp(matData.coatDarkening, 0.0, 1.0);\n\n if (USE_DIFFUSE_MAPS) {\n let diffuseMapIndex = i32(matData.diffuseMapIndex);\n if (diffuseMapIndex >= 0) {\n // TODO textureSample is not supported in compute shader.\n let diffuse = sampleMap(\n diffuseMapIndex, getMapUvSet(diffuseMapIndex, uv, uv1)\n );\n // Material factors from THREE / glTF are already linear. Only color\n // textures need decoding from their stored sRGB values.\n (*ma).baseColor *= decodeMapColor(diffuseMapIndex, diffuse.rgb);\n\n // Map alpha to transmission\n if (matData.mapAlphaUsage == ${mapAlphaUsageConstants.transmission}) {\n (*ma).transmissionWeight = 1.0 - diffuse.a;\n }\n else if (matData.mapAlphaUsage == ${mapAlphaUsageConstants.alpha}) {\n (*ma).alpha *= diffuse.a;\n }\n }\n }\n\n ${simpleTextureSample('alphaMap', 'wgsl')}\n\n ${alphaModeResolution}\n\n ${simpleTextureSample('transmissionMap', 'wgsl')}\n\n if (USE_METALLIC_ROUGHNESS_MAPS) {\n // Metallic roughness transmission map index\n let mrtMapIndex = i32(matData.mrtMapIndex);\n if (mrtMapIndex >= 0) {\n let metallicRoughness = sampleMap(\n mrtMapIndex, getMapUvSet(mrtMapIndex, uv, uv1)\n );\n (*ma).baseMetalness *= metallicRoughness.b;\n (*ma).specularRoughness *= metallicRoughness.g;\n }\n }\n\n ${simpleTextureSample('roughnessMap', 'wgsl')}\n\n ${simpleTextureSample('metalnessMap', 'wgsl')}\n\n ${thinFilmTextureSample('wgsl')}\n\n ${simpleTextureSample('coatWeightMap', 'wgsl')}\n\n${hasCoatNormals ? /* wgsl */ `\n // Independent coat shading also applies when the coat has no normal map.\n (*ma).coatNormalEnabled = (*ma).coatWeight > 0.0 && (matData.normalMapIndex >= 0.0 || matData.coatNormalMapIndex >= 0.0);\n` : ''}\n\n ${simpleTextureSample('coatRoughnessMap', 'wgsl')}\n\n ${simpleTextureSample('fuzzColorMap', 'wgsl')}\n\n ${simpleTextureSample('fuzzRoughnessMap', 'wgsl')}\n\n ${simpleTextureSample('specularWeightMap', 'wgsl')}\n\n ${simpleTextureSample('specularColorMap', 'wgsl')}\n\n${hasAnisotropyDirections ? /* wgsl */ `\n (*ma).anisotropyDirection = vec2f(1.0, 0.0);\n (*ma).anisotropyDirectionEnabled = matData.specularAnisotropyRotation != 0.0;\n (*ma).coatAnisotropyRotation = matData.coatAnisotropyRotation;\n if (USE_ANISOTROPY_MAPS && matData.anisotropyMapIndex >= 0.0) {\n let index = i32(matData.anisotropyMapIndex);\n let texel = sampleMap(index, getMapUvSet(index, uv, uv1));\n (*ma).specularAnisotropy *= texel.b;\n let direction = texel.rg * 2.0 - 1.0;\n if (dot(direction, direction) > 1e-4) { (*ma).anisotropyDirection = normalize(direction); }\n (*ma).anisotropyDirectionEnabled = true;\n }\n if (matData.specularAnisotropyModel > 0.5 && (*ma).specularAnisotropy > 0.0) {\n let native = gltf_anisotropy_to_openpbr(clamp((*ma).specularRoughness, 0.0, 1.0), (*ma).specularAnisotropy);\n (*ma).specularRoughness = native.x;\n (*ma).specularAnisotropy = native.y;\n }\n if ((*ma).anisotropyDirectionEnabled) {\n let theta = matData.specularAnisotropyRotation;\n let d = (*ma).anisotropyDirection;\n (*ma).anisotropyDirection = vec2f(cos(theta)*d.x - sin(theta)*d.y, sin(theta)*d.x + cos(theta)*d.y);\n }\n\n` : /* wgsl */ ``}\n // OpenPBR 1.1.1: coat refraction broadens all base microfacet lobes.\n // Keep the zero-coat / smooth-coat paths byte-identical.\n if ((*ma).coatWeight > 0.0 && (*ma).coatRoughness > 0.0) {\n let baseRoughness2 = (*ma).specularRoughness * (*ma).specularRoughness;\n let coatRoughness2 = (*ma).coatRoughness * (*ma).coatRoughness;\n (*ma).specularRoughness = mix((*ma).specularRoughness,\n pow(min(1.0, baseRoughness2 * baseRoughness2 + 2.0 * coatRoughness2 * coatRoughness2), 0.25), (*ma).coatWeight);\n }\n ${hasTransmission ? '' : /* wgsl */ `(*ma).transmissionWeight = 0.0;`}\n ${hasMetalness ? '' : /* wgsl */ `(*ma).baseMetalness = 0.0;`}\n let color = getInstanceColor(instanceIndex) * vertexColor;\n (*ma).baseColor *= color;\n if ((*ma).materialType == UNLIT) { (*ma).emission *= color; }\n\n (*ma).specularRoughness = clamp((*ma).specularRoughness, ROUGHNESS_MIN, 1.0);\n (*ma).baseMetalness = clamp((*ma).baseMetalness, 0.0, 1.0);\n let specularAlpha = openpbr_roughness_to_alpha((*ma).specularRoughness, (*ma).specularAnisotropy);\n (*ma).alphaX = specularAlpha.x;\n (*ma).alphaY = specularAlpha.y;\n}\n\nfn getMatNormal(materialIndex: i32, uv: vec2f, normal: vec3f, dp1: vec3f, dp2: vec3f, duv1: vec2f, duv2: vec2f) -> vec3f {\n let matData = materialsBuffer[materialIndex];\n let normalMapIndex = i32(matData.normalMapIndex);\n if (normalMapIndex >= 0) {\n // http://www.thetenthplanet.de/archives/1180\n // TODO use tangent attribute\n // Compute co-tangent and co-bitangent vectors\n let dp2perp = cross(dp2, normal);\n let dp1perp = cross(normal, dp1);\n var dpdu = dp2perp * duv1.x + dp1perp * duv2.x;\n var dpdv = dp2perp * duv1.y + dp1perp * duv2.y;\n let gradientLengthSquared = max(dot(dpdu, dpdu), dot(dpdv, dpdv));\n if (gradientLengthSquared > 1e-12) {\n let invmax = inverseSqrt(gradientLengthSquared);\n dpdu *= invmax;\n dpdv *= invmax;\n }\n else {\n // Generated/triplanar UVs have no per-vertex UV derivatives. Build a\n // stable fallback basis instead of normalizing two zero vectors.\n let referenceAxis = select(\n vec3f(0.0, 1.0, 0.0),\n vec3f(0.0, 0.0, 1.0),\n abs(normal.z) < 0.999\n );\n dpdu = normalize(cross(referenceAxis, normal));\n dpdv = cross(normal, dpdu);\n }\n\n var n = 2.0 * sampleMap(normalMapIndex, uv).rgb - 1.0;\n n = normalize(vec3(n.xy * matData.normalMapScale, n.z));\n\n let tbn = mat3x3(dpdu, dpdv, normal);\n\n return normalize(tbn * n);\n } else {\n return normal;\n }\n}\n`;\n}\n\nconst materialBufferWgsl = createMaterialBufferWgsl();\n\nexport default materialBufferWgsl;\n"]}
1
+ {"version":3,"file":"materialBuffer.wgsl.js","sourceRoot":"","sources":["../../../../src/renderer/wgsl/chunks/materialBuffer.wgsl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,qDAAqD;AACrD,sDAAsD;AACtD,kFAAkF;AAElF,OAAO,EACL,0BAA0B,EAC3B,MAAM,4BAA4B,CAAC;AAEpC,MAAM,UAAU,wBAAwB,CAAC,EACvC,uBAAuB,GAAG,IAAI,EAC9B,cAAc,GAAG,KAAK,EACtB,aAAa,GAAG,IAAI,EACpB,eAAe,GAAG,IAAI,EAAE,QAAQ,GAAG,KAAK,EACxC,YAAY,GAAG,IAAI,KAOjB,EAAE;IACJ,MAAM,mBAAmB,GAAG,aAAa;QACvC,CAAC,CAAC,2CAA2C;QAC7C,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,mBAAmB,GAAG,aAAa;QACvC,CAAC,CAAC,UAAU,CAAC;yBACU,0BAA0B,CAAC,MAAM;;;8BAG5B,0BAA0B,CAAC,IAAI;;EAE3D;QACA,CAAC,CAAC,oBAAoB,CAAC;IAEzB,OAAO,UAAU,CAAC;;EAElB,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;;CAOtC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCAuH0B,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+B3D,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAkCc,sBAAsB,CAAC,YAAY;;;oCAG9B,sBAAsB,CAAC,KAAK;;;;;;EAMlE,mBAAmB,CAAC,UAAU,EAAE,MAAM,CAAC;;EAEvC,mBAAmB;;EAEnB,mBAAmB,CAAC,iBAAiB,EAAE,MAAM,CAAC;;;;;;;;;;;;;;EAc9C,mBAAmB,CAAC,cAAc,EAAE,MAAM,CAAC;;EAE3C,mBAAmB,CAAC,cAAc,EAAE,MAAM,CAAC;;EAE3C,qBAAqB,CAAC,MAAM,CAAC;;EAE7B,mBAAmB,CAAC,eAAe,EAAE,MAAM,CAAC;;EAE9C,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;;;CAG7B,CAAC,CAAC,CAAC,EAAE;;EAEF,mBAAmB,CAAC,kBAAkB,EAAE,MAAM,CAAC;;EAE/C,mBAAmB,CAAC,cAAc,EAAE,MAAM,CAAC;;EAE3C,mBAAmB,CAAC,kBAAkB,EAAE,MAAM,CAAC;;EAE/C,mBAAmB,CAAC,mBAAmB,EAAE,MAAM,CAAC;;EAEhD,mBAAmB,CAAC,kBAAkB,EAAE,MAAM,CAAC;;EAEjD,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;CAuBtC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;;;;;;;;;EASb,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,iCAAiC;EACnE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,4BAA4B;;;;;EAK7D,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;;CAEvB,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CL,CAAC;AACF,CAAC;AAED,MAAM,kBAAkB,GAAG,wBAAwB,EAAE,CAAC;AAEtD,eAAe,kBAAkB,CAAC","sourcesContent":["import { simpleTextureSample, thinFilmTextureSample } from '../../materialTextureSlots.js';\nimport { INSTANCE_VEC4_STRIDE } from '../../bvhAccel.js';\nimport { mapAlphaUsageConstants } from '../../materialConstants.js';\n// Portions adapted from ray-tracing-renderer@0.10.15\n// (https://github.com/hoverinc/ray-tracing-renderer).\n// Copyright (c) 2019 HOVER, MIT license; see LICENSES/RayTracingRenderer-MIT.txt.\n\nimport {\n materialAlphaModeConstants\n} from '../../materialConstants.js';\n\nexport function createMaterialBufferWgsl({\n hasAnisotropyDirections = true,\n hasCoatNormals = false,\n hasSceneAlpha = true,\n hasTransmission = true, caustics = false,\n hasMetalness = true\n}: {\n hasSceneAlpha?: boolean;\n hasAnisotropyDirections?: boolean;\n hasCoatNormals?: boolean;\n hasTransmission?: boolean; caustics?: boolean;\n hasMetalness?: boolean;\n} = {}) {\n const alphaModeAssignment = hasSceneAlpha\n ? '(*ma).alphaMode = i32(matData.alphaMode);'\n : '';\n const alphaModeResolution = hasSceneAlpha\n ? /* wgsl */ `\n if ((*ma).alphaMode == ${materialAlphaModeConstants.opaque}) {\n (*ma).alpha = 1.0;\n }\n else if ((*ma).alphaMode == ${materialAlphaModeConstants.mask}) {\n (*ma).alpha = select(0.0, 1.0, (*ma).alpha >= matData.alphaCutoff);\n }`\n : '(*ma).alpha = 1.0;';\n\n return /* wgsl */ `\n\n${hasAnisotropyDirections ? /* wgsl */ `fn gltf_anisotropy_to_openpbr(roughness: f32, strength: f32) -> vec2f {\n if (strength == 0.0) { return vec2f(roughness, 0.0); }\n let u = roughness * roughness;\n let a = u + (1.0 - u) * strength * strength;\n if (a == 0.0) { return vec2f(0.0); }\n return vec2f(pow((a*a + u*u) * 0.5, 0.25), clamp(1.0 - u/a, 0.0, 1.0));\n}\n` : /* wgsl */ ``}\n\nfn sRGBToLinear(c: vec3f) -> vec3f {\n return mix(pow(c * 0.9478672986 + 0.0521327014, vec3f(2.4)), c * 0.0773993808, vec3f(c < vec3f(0.04045)));\n}\n\nfn decodeMapColor(idx: i32, c: vec3f) -> vec3f {\n if (mapInfo[idx + NUM_MAPS * 2].y > 0.5) { return c; }\n return sRGBToLinear(c);\n}\n\nfn unpackMaterialIndex(val: i32) -> vec2f {\n return vec2f(f32(val >> 8), f32(val & 0xff) / 255.0);\n}\n\nfn getMapSize(idx: i32) -> vec2f {\n return mapInfo[idx].xy;\n}\n\nfn getMapLayer(idx: i32) -> i32 {\n return i32(floor(mapInfo[idx].z));\n}\n\nfn getMapOffset(idx: i32) -> vec2f {\n return vec2f(fract(mapInfo[idx].z), mapInfo[idx].w);\n}\n\nfn wrapMapCoordinate(value: f32, mode: f32) -> f32 {\n if (mode < 0.5) { return fract(value); }\n if (mode < 1.5) { return clamp(value, 0.0, 1.0); }\n return 1.0 - abs(1.0 - (value - 2.0 * floor(value * 0.5)));\n}\n\nfn wrappedMapUv(idx: i32, uv: vec2f) -> vec2f {\n let transform = mapInfo[idx + NUM_MAPS];\n let modes = mapInfo[idx + NUM_MAPS * 2].zw;\n let value = uv * transform.xy + transform.zw;\n return vec2f(wrapMapCoordinate(value.x, modes.x), wrapMapCoordinate(value.y, modes.y));\n}\n\nfn getMapUV(idx: i32, uv: vec2f) -> vec2f {\n let repeatedUv = wrappedMapUv(idx, uv);\n let atlasTexel = 1.0 / vec2f(textureDimensions(map).xy);\n let firstTexelCenter = getMapOffset(idx);\n let sourceExtent = getMapSize(idx) + atlasTexel;\n let sourceOrigin = firstTexelCenter - 0.5 * atlasTexel;\n let lastTexelCenter = firstTexelCenter + sourceExtent - atlasTexel;\n return clamp(\n sourceOrigin + repeatedUv * sourceExtent,\n firstTexelCenter,\n lastTexelCenter\n );\n}\n\nfn getMapUvSet(idx: i32, uv: vec2f, uv1: vec2f) -> vec2f {\n return select(uv, uv1, mapInfo[idx + NUM_MAPS * 2].x > 0.5);\n}\n\nfn sampleMap(idx: i32, uv: vec2f) -> vec4f {\n let size = vec2i(round(getMapSize(idx) * vec2f(textureDimensions(map).xy) + vec2f(1.0)));\n let texel = wrappedMapUv(idx, uv) * vec2f(size) - vec2f(0.5);\n let modes = mapInfo[idx + NUM_MAPS * 2].zw;\n // Repeat filtering must cross the logical image boundary, never another\n // atlas placement. Interior/clamped/mirrored footprints use hardware filtering.\n if ((size.x > 1 && modes.x < 0.5 && (texel.x < 0.0 || texel.x > f32(size.x - 1))) ||\n (size.y > 1 && modes.y < 0.5 && (texel.y < 0.0 || texel.y > f32(size.y - 1)))) {\n let base = vec2i(floor(texel));\n let weight = fract(texel);\n let origin = vec2i(round(getMapOffset(idx) * vec2f(textureDimensions(map).xy) - vec2f(0.5)));\n return mix(\n mix(loadMapTexel(idx, base, size, origin, modes), loadMapTexel(idx, base + vec2i(1, 0), size, origin, modes), weight.x),\n mix(loadMapTexel(idx, base + vec2i(0, 1), size, origin, modes), loadMapTexel(idx, base + vec2i(1, 1), size, origin, modes), weight.x), weight.y);\n }\n return textureSampleLevel(map, mapSampler, getMapUV(idx, uv), getMapLayer(idx), 0.0);\n}\n\nfn loadMapTexel(idx: i32, coordinate: vec2i, size: vec2i, origin: vec2i, modes: vec2f) -> vec4f {\n var p = clamp(coordinate, vec2i(0), size - vec2i(1));\n if (modes.x < 0.5) { p.x = ((coordinate.x % size.x) + size.x) % size.x; }\n if (modes.y < 0.5) { p.y = ((coordinate.y % size.y) + size.y) % size.y; }\n return textureLoad(map, origin + p, getMapLayer(idx), 0);\n}\n\n\nfn getMaterialEmission(materialIndex: i32, uv: vec2f, uv1: vec2f) -> vec3f {\n let matData = materialsBuffer[materialIndex];\n var emission = matData.emission;\n if (USE_EMISSIVE_MAPS) {\n let emissiveMapIndex = i32(matData.emissiveMapIndex);\n if (emissiveMapIndex >= 0) {\n emission *= decodeMapColor(emissiveMapIndex, sampleMap(\n emissiveMapIndex, getMapUvSet(emissiveMapIndex, uv, uv1)\n ).rgb);\n }\n }\n if (USE_COAT_WEIGHT_MAPS && matData.matType == 0.0) {\n let coatWeightMapIndex = i32(matData.coatWeightMapIndex);\n if (coatWeightMapIndex >= 0) {\n let coatWeight = clamp(matData.coatWeight, 0.0, 1.0) * sampleMap(\n coatWeightMapIndex, getMapUvSet(coatWeightMapIndex, uv, uv1)\n ).r;\n emission *= mix(vec3f(1.0), sqrt(max(matData.coatColor, vec3f(0.0))), coatWeight);\n }\n }\n return emission;\n}\n\n// OpenPBR 1.1.1: RMS-preserving GGX anisotropy, shared by base and coat.\nfn openpbr_roughness_to_alpha(roughness: f32, anisotropy: f32) -> vec2f {\n let alpha = roughness * roughness;\n let alphaMin = ROUGHNESS_MIN * ROUGHNESS_MIN;\n if (anisotropy == 0.0) { return vec2f(max(alphaMin, alpha)); }\n let complement = 1.0 - anisotropy;\n let alphaT = alpha * sqrt(2.0 / (1.0 + complement * complement));\n return max(vec2f(alphaMin), vec2f(alphaT, complement * alphaT));\n}\n\nfn getInstanceColor(instanceIndex: i32) -> vec3f {\n if (instanceIndex < 0) { return vec3f(1.0); }\n return instancesBuffer[instanceIndex * ${INSTANCE_VEC4_STRIDE} + 9].xyz;\n}\n\nfn getMaterial(\n ma: ptr<function, OpenPbrResolvedMaterial>,\n materialIndex: i32,\n uv: vec2f,\n uv1: vec2f,\n instanceIndex: i32,\n vertexColor: vec3f\n) {\n let matData = materialsBuffer[materialIndex];\n\n (*ma).baseColor = matData.color;\n (*ma).materialType = i32(matData.matType);\n (*ma).specularRoughness = matData.roughness;\n (*ma).baseMetalness = matData.metallic;\n (*ma).specularAnisotropy = clamp(matData.anisotropy, 0.0, 1.0);\n (*ma).emission = getMaterialEmission(materialIndex, uv, uv1);\n (*ma).inside = false;\n (*ma).specularIor = matData.ior;\n (*ma).transmissionWeight = matData.transmission;\n (*ma).thinWalled = matData.thin > 0.5;\n (*ma).bevel = matData.bevel;\n (*ma).transmissionDispersionScale = matData.dispersion;\n (*ma).dispersionAbbeNumber = max(matData.dispersionAbbeNumber, 1e-6);\n (*ma).mediumExtinction = max(matData.mediumExtinction, vec3f(0.0));\n (*ma).mediumScattering = max(matData.mediumScattering, vec3f(0.0));\n (*ma).mediumAnisotropy = clamp(matData.mediumAnisotropy, -1.0, 1.0);\n (*ma).mediumType = select(0, 1, max(max((*ma).mediumExtinction.x, (*ma).mediumExtinction.y), (*ma).mediumExtinction.z) > 0.0);\n (*ma).alpha = matData.alpha;\n ${alphaModeAssignment}\n\n (*ma).thinFilmThickness = matData.thinFilmThickness * 1000.0;\n (*ma).thinFilmIor = matData.thinFilmIor;\n (*ma).thinFilmWeight = select(0.0, clamp(matData.thinFilmWeight, 0.0, 1.0), HAS_THIN_FILM);\n (*ma).baseWeight = clamp(matData.baseWeight, 0.0, 1.0);\n (*ma).diffuseRoughness = clamp(matData.baseDiffuseRoughness, 0.0, 1.0);\n (*ma).specularWeight = max(matData.specularWeight, 0.0);\n (*ma).specularColor = max(matData.specularColor, vec3f(0.0));\n (*ma).subsurfaceWeight = select(0.0, clamp(matData.subsurfaceWeight, 0.0, 1.0), HAS_SUBSURFACE);\n (*ma).subsurfaceColor = max(matData.subsurfaceColor, vec3f(0.0));\n (*ma).transmissionColor = max(matData.transmissionColor, vec3f(0.0));\n (*ma).fuzzWeight = select(0.0, clamp(matData.fuzzWeight, 0.0, 1.0), HAS_FUZZ);\n (*ma).fuzzColor = max(matData.fuzzColor, vec3f(0.0));\n (*ma).fuzzRoughness = clamp(matData.fuzzRoughness, 0.0, 1.0);\n (*ma).coatWeight = select(0.0, clamp(matData.coatWeight, 0.0, 1.0), HAS_COAT);\n (*ma).coatColor = max(matData.coatColor, vec3f(0.0));\n (*ma).coatRoughness = clamp(matData.coatRoughness, ROUGHNESS_MIN, 1.0);\n (*ma).coatAnisotropy = clamp(matData.coatAnisotropy, 0.0, 1.0);\n (*ma).coatIor = max(matData.coatIor, 1.0);\n (*ma).coatDarkening = clamp(matData.coatDarkening, 0.0, 1.0);\n\n if (USE_DIFFUSE_MAPS) {\n let diffuseMapIndex = i32(matData.diffuseMapIndex);\n if (diffuseMapIndex >= 0) {\n // TODO textureSample is not supported in compute shader.\n let diffuse = sampleMap(\n diffuseMapIndex, getMapUvSet(diffuseMapIndex, uv, uv1)\n );\n // Material factors from THREE / glTF are already linear. Only color\n // textures need decoding from their stored sRGB values.\n (*ma).baseColor *= decodeMapColor(diffuseMapIndex, diffuse.rgb);\n\n // Map alpha to transmission\n if (matData.mapAlphaUsage == ${mapAlphaUsageConstants.transmission}) {\n (*ma).transmissionWeight = 1.0 - diffuse.a;\n }\n else if (matData.mapAlphaUsage == ${mapAlphaUsageConstants.alpha}) {\n (*ma).alpha *= diffuse.a;\n }\n }\n }\n\n ${simpleTextureSample('alphaMap', 'wgsl')}\n\n ${alphaModeResolution}\n\n ${simpleTextureSample('transmissionMap', 'wgsl')}\n\n if (USE_METALLIC_ROUGHNESS_MAPS) {\n // Metallic roughness transmission map index\n let mrtMapIndex = i32(matData.mrtMapIndex);\n if (mrtMapIndex >= 0) {\n let metallicRoughness = sampleMap(\n mrtMapIndex, getMapUvSet(mrtMapIndex, uv, uv1)\n );\n (*ma).baseMetalness *= metallicRoughness.b;\n (*ma).specularRoughness *= metallicRoughness.g;\n }\n }\n\n ${simpleTextureSample('roughnessMap', 'wgsl')}\n\n ${simpleTextureSample('metalnessMap', 'wgsl')}\n\n ${thinFilmTextureSample('wgsl')}\n\n ${simpleTextureSample('coatWeightMap', 'wgsl')}\n\n${hasCoatNormals ? /* wgsl */ `\n // Independent coat shading also applies when the coat has no normal map.\n (*ma).coatNormalEnabled = (*ma).coatWeight > 0.0 && (matData.normalMapIndex >= 0.0 || matData.coatNormalMapIndex >= 0.0);\n` : ''}\n\n ${simpleTextureSample('coatRoughnessMap', 'wgsl')}\n\n ${simpleTextureSample('fuzzColorMap', 'wgsl')}\n\n ${simpleTextureSample('fuzzRoughnessMap', 'wgsl')}\n\n ${simpleTextureSample('specularWeightMap', 'wgsl')}\n\n ${simpleTextureSample('specularColorMap', 'wgsl')}\n\n${hasAnisotropyDirections ? /* wgsl */ `\n (*ma).anisotropyDirection = vec2f(1.0, 0.0);\n (*ma).anisotropyDirectionEnabled = matData.specularAnisotropyRotation != 0.0;\n (*ma).coatAnisotropyRotation = matData.coatAnisotropyRotation;\n if (USE_ANISOTROPY_MAPS && matData.anisotropyMapIndex >= 0.0) {\n let index = i32(matData.anisotropyMapIndex);\n let texel = sampleMap(index, getMapUvSet(index, uv, uv1));\n (*ma).specularAnisotropy *= texel.b;\n let direction = texel.rg * 2.0 - 1.0;\n if (dot(direction, direction) > 1e-4) { (*ma).anisotropyDirection = normalize(direction); }\n (*ma).anisotropyDirectionEnabled = true;\n }\n if (matData.specularAnisotropyModel > 0.5 && (*ma).specularAnisotropy > 0.0) {\n let native = gltf_anisotropy_to_openpbr(clamp((*ma).specularRoughness, 0.0, 1.0), (*ma).specularAnisotropy);\n (*ma).specularRoughness = native.x;\n (*ma).specularAnisotropy = native.y;\n }\n if ((*ma).anisotropyDirectionEnabled) {\n let theta = matData.specularAnisotropyRotation;\n let d = (*ma).anisotropyDirection;\n (*ma).anisotropyDirection = vec2f(cos(theta)*d.x - sin(theta)*d.y, sin(theta)*d.x + cos(theta)*d.y);\n }\n\n` : /* wgsl */ ``}\n // OpenPBR 1.1.1: coat refraction broadens all base microfacet lobes.\n // Keep the zero-coat / smooth-coat paths byte-identical.\n if ((*ma).coatWeight > 0.0 && (*ma).coatRoughness > 0.0) {\n let baseRoughness2 = (*ma).specularRoughness * (*ma).specularRoughness;\n let coatRoughness2 = (*ma).coatRoughness * (*ma).coatRoughness;\n (*ma).specularRoughness = mix((*ma).specularRoughness,\n pow(min(1.0, baseRoughness2 * baseRoughness2 + 2.0 * coatRoughness2 * coatRoughness2), 0.25), (*ma).coatWeight);\n }\n ${hasTransmission ? '' : /* wgsl */ `(*ma).transmissionWeight = 0.0;`}\n ${hasMetalness ? '' : /* wgsl */ `(*ma).baseMetalness = 0.0;`}\n let color = getInstanceColor(instanceIndex) * vertexColor;\n (*ma).baseColor *= color;\n if ((*ma).materialType == UNLIT) { (*ma).emission *= color; }\n\n${caustics ? /* wgsl */ ` (*ma).causticRoughness = (*ma).specularRoughness;\n (*ma).causticNormalMapped = matData.normalMapIndex >= 0.0;\n` : ''} (*ma).specularRoughness = clamp((*ma).specularRoughness, ROUGHNESS_MIN, 1.0);\n (*ma).baseMetalness = clamp((*ma).baseMetalness, 0.0, 1.0);\n let specularAlpha = openpbr_roughness_to_alpha((*ma).specularRoughness, (*ma).specularAnisotropy);\n (*ma).alphaX = specularAlpha.x;\n (*ma).alphaY = specularAlpha.y;\n}\n\nfn getMatNormal(materialIndex: i32, uv: vec2f, normal: vec3f, dp1: vec3f, dp2: vec3f, duv1: vec2f, duv2: vec2f) -> vec3f {\n let matData = materialsBuffer[materialIndex];\n let normalMapIndex = i32(matData.normalMapIndex);\n if (normalMapIndex >= 0) {\n // http://www.thetenthplanet.de/archives/1180\n // TODO use tangent attribute\n // Compute co-tangent and co-bitangent vectors\n let dp2perp = cross(dp2, normal);\n let dp1perp = cross(normal, dp1);\n var dpdu = dp2perp * duv1.x + dp1perp * duv2.x;\n var dpdv = dp2perp * duv1.y + dp1perp * duv2.y;\n let gradientLengthSquared = max(dot(dpdu, dpdu), dot(dpdv, dpdv));\n if (gradientLengthSquared > 1e-12) {\n let invmax = inverseSqrt(gradientLengthSquared);\n dpdu *= invmax;\n dpdv *= invmax;\n }\n else {\n // Generated/triplanar UVs have no per-vertex UV derivatives. Build a\n // stable fallback basis instead of normalizing two zero vectors.\n let referenceAxis = select(\n vec3f(0.0, 1.0, 0.0),\n vec3f(0.0, 0.0, 1.0),\n abs(normal.z) < 0.999\n );\n dpdu = normalize(cross(referenceAxis, normal));\n dpdv = cross(normal, dpdu);\n }\n\n var n = 2.0 * sampleMap(normalMapIndex, uv).rgb - 1.0;\n n = normalize(vec3(n.xy * matData.normalMapScale, n.z));\n\n let tbn = mat3x3(dpdu, dpdv, normal);\n\n return normalize(tbn * n);\n } else {\n return normal;\n }\n}\n`;\n}\n\nconst materialBufferWgsl = createMaterialBufferWgsl();\n\nexport default materialBufferWgsl;\n"]}