@meimu/mutracer 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/assets/bvh.worker.js +1 -1
  2. package/dist/mutracer.umd.js +4155 -4052
  3. package/docs/api.md +13 -10
  4. package/docs/materials.md +17 -26
  5. package/docs/threejs.md +35 -9
  6. package/docs/viewer.md +36 -3
  7. package/lib/Engine.js +18 -1
  8. package/lib/Engine.js.map +1 -1
  9. package/lib/main.d.ts +1 -1
  10. package/lib/main.js.map +1 -1
  11. package/lib/oidn.d.ts +1 -1
  12. package/lib/oidnBundledWeights.cdn.d.ts +2 -2
  13. package/lib/renderer/MaterialTable.d.ts +1 -0
  14. package/lib/renderer/MaterialTable.js +10 -4
  15. package/lib/renderer/MaterialTable.js.map +1 -1
  16. package/lib/renderer/WGPUBloomPass.js +18 -18
  17. package/lib/renderer/WGPUFullQuadPass.js +6 -6
  18. package/lib/renderer/WGPUJNLMDenoiser.js +69 -69
  19. package/lib/renderer/WGPURayTraceOutput.js +14 -14
  20. package/lib/renderer/WGPURayTracePass.d.ts +2 -0
  21. package/lib/renderer/WGPURayTracePass.js +17 -9
  22. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  23. package/lib/renderer/WGPURenderingPipeline.js +15 -15
  24. package/lib/renderer/WebGLJNLMDenoiser.js +69 -69
  25. package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
  26. package/lib/renderer/WebGLRayTracePass.d.ts +1 -0
  27. package/lib/renderer/WebGLRayTracePass.js +8 -1
  28. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  29. package/lib/renderer/envMapCreation.d.ts +5 -1
  30. package/lib/renderer/envMapCreation.js +42 -5
  31. package/lib/renderer/envMapCreation.js.map +1 -1
  32. package/lib/renderer/geometryUpdates.js +1 -1
  33. package/lib/renderer/geometryUpdates.js.map +1 -1
  34. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +12 -12
  35. package/lib/renderer/glsl/chunks/envMap.glsl.js +66 -54
  36. package/lib/renderer/glsl/chunks/envMap.glsl.js.map +1 -1
  37. package/lib/renderer/glsl/chunks/intersect.glsl.js +323 -315
  38. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
  39. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +154 -121
  40. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
  41. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +434 -434
  42. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js.map +1 -1
  43. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  44. package/lib/renderer/glsl/chunks/random.glsl.js +3 -3
  45. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +42 -41
  46. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  47. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +69 -69
  48. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +84 -84
  49. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
  50. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +12 -12
  51. package/lib/renderer/glsl/chunks/sampling.glsl.js +75 -75
  52. package/lib/renderer/glsl/chunks/sobol.glsl.js +61 -61
  53. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  54. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
  55. package/lib/renderer/glsl/depthQuery.frag.js +5 -5
  56. package/lib/renderer/glsl/depthQuery.frag.js.map +1 -1
  57. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +8 -8
  58. package/lib/renderer/glsl/rayTrace.frag.js +133 -133
  59. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
  60. package/lib/renderer/glsl/shadowCatcher.frag.js +9 -9
  61. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  62. package/lib/renderer/glsl/webglPipeline.frag.js +52 -52
  63. package/lib/renderer/lightsUtil.js +6 -4
  64. package/lib/renderer/lightsUtil.js.map +1 -1
  65. package/lib/renderer/materialChanges.js +1 -1
  66. package/lib/renderer/materialChanges.js.map +1 -1
  67. package/lib/renderer/materialComparison.generated.js +36 -18
  68. package/lib/renderer/materialComparison.generated.js.map +1 -1
  69. package/lib/renderer/prepareMeshBVH.js +2 -2
  70. package/lib/renderer/prepareMeshBVH.js.map +1 -1
  71. package/lib/renderer/sceneChangeDetector.js +4 -1
  72. package/lib/renderer/sceneChangeDetector.js.map +1 -1
  73. package/lib/renderer/sceneLightChanges.js +3 -2
  74. package/lib/renderer/sceneLightChanges.js.map +1 -1
  75. package/lib/renderer/scratchSampling.js +18 -18
  76. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  77. package/lib/renderer/wgsl/chunks/envMap.wgsl.d.ts +1 -1
  78. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +39 -31
  79. package/lib/renderer/wgsl/chunks/envMap.wgsl.js.map +1 -1
  80. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +476 -470
  81. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  82. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +8 -8
  83. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +95 -60
  84. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  85. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +469 -469
  86. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.d.ts +1 -1
  87. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +117 -120
  88. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js.map +1 -1
  89. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  90. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +25 -22
  91. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  92. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +127 -127
  93. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +136 -136
  94. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +6 -6
  95. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +73 -73
  96. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +62 -62
  97. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
  98. package/lib/renderer/wgsl/compose.frag.wgsl.js +105 -105
  99. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  100. package/lib/renderer/wgsl/depthQuery.wgsl.d.ts +1 -1
  101. package/lib/renderer/wgsl/depthQuery.wgsl.js +5 -5
  102. package/lib/renderer/wgsl/depthQuery.wgsl.js.map +1 -1
  103. package/lib/renderer/wgsl/offlineAdaptive.compute.js +28 -28
  104. package/lib/renderer/wgsl/rayTrace.compute.js +251 -248
  105. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  106. package/lib/scene/EnvironmentLight.d.ts +9 -3
  107. package/lib/scene/EnvironmentLight.js +9 -2
  108. package/lib/scene/EnvironmentLight.js.map +1 -1
  109. package/lib/scene/OpenPBRMaterial.d.ts +1 -1
  110. package/lib/scene/OpenPBRMaterial.js +1 -1
  111. package/lib/scene/OpenPBRMaterial.js.map +1 -1
  112. package/lib/scene/Scene.d.ts +4 -0
  113. package/lib/scene/Scene.js.map +1 -1
  114. package/lib/scene/SpotLight.d.ts +2 -2
  115. package/lib/scene/SpotLight.js +1 -1
  116. package/lib/scene/SpotLight.js.map +1 -1
  117. package/lib/scene/Texture.d.ts +17 -6
  118. package/lib/scene/Texture.js +13 -4
  119. package/lib/scene/Texture.js.map +1 -1
  120. package/lib/util/fromTHREE.js +151 -29
  121. package/lib/util/fromTHREE.js.map +1 -1
  122. package/lib/version.d.ts +1 -1
  123. package/lib/version.js +1 -1
  124. package/lib/version.js.map +1 -1
  125. package/package.json +1 -1
@@ -27,9 +27,9 @@ ${shadowCatcherAccumulationWGSL}
27
27
  fn main(@builtin(global_invocation_id) id: vec3u) {
28
28
  let size = params.size;
29
29
  if (id.x >= size.x || id.y >= size.y) { return; }
30
- let tT = id.x + (size.y - 1u - id.y) * size.x;
31
- let n = normalBuffer[tT].a;
32
- let moments = accumulation[tT].moments;
30
+ let ua = id.x + (size.y - 1u - id.y) * size.x;
31
+ let n = normalBuffer[ua].a;
32
+ let moments = accumulation[ua].moments;
33
33
  let mean = moments.x / max(n, 1.0);
34
34
 
35
35
  var variance = -1.0;
@@ -53,28 +53,28 @@ fn main(@builtin(global_invocation_id) id: vec3u) {
53
53
  let size = params.size;
54
54
  if (id.x >= size.x || id.y >= size.y) { return; }
55
55
  let center = rawGuide[id.x + id.y * size.x];
56
- var lk = 0.0;
57
- var iY = 0.0;
58
- var mO = 0.0;
59
- var iS = 0.0;
56
+ var lu = 0.0;
57
+ var jc = 0.0;
58
+ var mY = 0.0;
59
+ var iX = 0.0;
60
60
  for (var dy = -1; dy <= 1; dy++) {
61
61
  for (var dx = -1; dx <= 1; dx++) {
62
62
  let q = clamp(vec2i(id.xy) + vec2i(dx, dy), vec2i(0), vec2i(size) - 1);
63
63
  let value = rawGuide[u32(q.x) + u32(q.y) * size.x];
64
- mO += value.x;
65
- iS += value.x * value.x;
64
+ mY += value.x;
65
+ iX += value.x * value.x;
66
66
  if (value.y >= 0.0) {
67
- lk += value.y;
68
- iY += 1.0;
67
+ lu += value.y;
68
+ jc += 1.0;
69
69
  }
70
70
  }
71
71
  }
72
72
  var variance: f32;
73
73
  if (center.y >= 0.0) {
74
- variance = lk / iY;
74
+ variance = lu / jc;
75
75
  } else {
76
- let lj = mO / 9.0;
77
- variance = max(iS / 9.0 - lj * lj, 0.0) * 9.0 / 8.0;
76
+ let lt = mY / 9.0;
77
+ variance = max(iX / 9.0 - lt * lt, 0.0) * 9.0 / 8.0;
78
78
  }
79
79
  guide[id.x + id.y * size.x] = vec2f(center.x, variance);
80
80
  }
@@ -122,23 +122,23 @@ const INV_NORMAL_BANDWIDTH2 = ${(1 / normalBandwidth ** 2).toFixed(6)};
122
122
 
123
123
  const CENTER_WEIGHT_MIN = 0.01;
124
124
 
125
- fn ha(p: vec2i) -> u32 {
125
+ fn hg(p: vec2i) -> u32 {
126
126
  let q = clamp(p, vec2i(0), vec2i(params.size) - 1);
127
127
  return u32(q.x) + u32(q.y) * params.size.x;
128
128
  }
129
129
 
130
- fn ln(q: vec2i, bs: vec4f, gO: vec3f) -> f32 {
130
+ fn lw(q: vec2i, bs: vec4f, gT: vec3f) -> f32 {
131
131
  let albedo = textureLoad(albedoTex, q, 0);
132
132
 
133
133
 
134
- let oW = max((albedo.rgb + bs.rgb) * 0.5, vec3f(${JNLM_ALBEDO_FLOOR}));
135
- let kU = (albedo.rgb - bs.rgb) / oW;
136
- let iP = albedo.a - bs.a;
137
- let le = textureLoad(normalTex, q, 0).rgb - gO;
134
+ let pf = max((albedo.rgb + bs.rgb) * 0.5, vec3f(${JNLM_ALBEDO_FLOOR}));
135
+ let ld = (albedo.rgb - bs.rgb) / pf;
136
+ let iU = albedo.a - bs.a;
137
+ let lp = textureLoad(normalTex, q, 0).rgb - gT;
138
138
  return max(
139
- dot(kU, kU) * INV_ALBEDO_BANDWIDTH2
140
- + iP * iP * INV_COVERAGE_BANDWIDTH2,
141
- dot(le, le) * INV_NORMAL_BANDWIDTH2
139
+ dot(ld, ld) * INV_ALBEDO_BANDWIDTH2
140
+ + iU * iU * INV_COVERAGE_BANDWIDTH2,
141
+ dot(lp, lp) * INV_NORMAL_BANDWIDTH2
142
142
  );
143
143
  }
144
144
 
@@ -153,36 +153,36 @@ let p = vec2i(id.xy);
153
153
  if (p.x >= size.x || p.y >= size.y) { return; }
154
154
  let step = i32(params.dilation);
155
155
  let bs = textureLoad(albedoTex, p, 0);
156
- let fw = textureLoad(normalTex, p, 0);
157
- let gO = fw.rgb;
158
- let index = ha(p);
156
+ let fD = textureLoad(normalTex, p, 0);
157
+ let gT = fD.rgb;
158
+ let index = hg(p);
159
159
 
160
160
 
161
- if (fw.a <= 0.0 && textureLoad(shadowCatcherTex, p, 0).r <= 0.0) {
161
+ if (fD.a <= 0.0 && textureLoad(shadowCatcherTex, p, 0).r <= 0.0) {
162
162
  outColor[index] = color[index];
163
163
  outGuide[index] = guide[index];
164
164
  return;
165
165
  }
166
166
 
167
- var kW: array<vec2f, PATCH_SIZE>;
167
+ var lf: array<vec2f, PATCH_SIZE>;
168
168
  var k = 0;
169
169
  for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
170
170
  for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
171
- kW[k] = guide[ha(p + vec2i(dx, dy) * step)];
171
+ lf[k] = guide[hg(p + vec2i(dx, dy) * step)];
172
172
  k++;
173
173
  }
174
174
  }
175
175
  let k2 = params.colorSensitivity * params.colorSensitivity;
176
176
 
177
177
  var sum = vec4f(0.0);
178
- let gR = max(bs.rgb, vec3f(${JNLM_ALBEDO_FLOOR}));
179
- var mf = vec3f(0.0);
180
- var gt = vec3f(0.0);
181
- var hn = vec3f(0.0);
182
- var pk = 0.0;
183
- var gv = 0.0;
184
- var nK = 0.0;
185
- var kD = 0.0;
178
+ let gW = max(bs.rgb, vec3f(${JNLM_ALBEDO_FLOOR}));
179
+ var mp = vec3f(0.0);
180
+ var gy = vec3f(0.0);
181
+ var hs = vec3f(0.0);
182
+ var ps = 0.0;
183
+ var gA = 0.0;
184
+ var nU = 0.0;
185
+ var kM = 0.0;
186
186
  for (var sy = -SEARCH_RADIUS; sy <= SEARCH_RADIUS; sy++) {
187
187
  for (var sx = -SEARCH_RADIUS; sx <= SEARCH_RADIUS; sx++) {
188
188
  let q = p + vec2i(sx, sy) * step;
@@ -191,63 +191,63 @@ if (
191
191
  q.x < 0 || q.y < 0 || q.x >= size.x || q.y >= size.y
192
192
  ) { continue; }
193
193
 
194
- let features = ln(q, bs, gO);
194
+ let features = lw(q, bs, gT);
195
195
  if (features > 16.0) { continue; }
196
196
 
197
- var fT = 0.0;
197
+ var fY = 0.0;
198
198
  k = 0;
199
199
  for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
200
200
  for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
201
- let a = kW[k];
202
- let b = guide[ha(q + vec2i(dx, dy) * step)];
203
- let qL = a.x - b.x;
204
- fT += (qL * qL
201
+ let a = lf[k];
202
+ let b = guide[hg(q + vec2i(dx, dy) * step)];
203
+ let qU = a.x - b.x;
204
+ fY += (qU * qU
205
205
  - VARIANCE_CANCELLATION * (a.y + min(a.y, b.y)))
206
206
  / (1e-10 + k2 * (a.y + b.y));
207
207
  k++;
208
208
  }
209
209
  }
210
- fT /= f32(PATCH_SIZE);
210
+ fY /= f32(PATCH_SIZE);
211
211
 
212
- let weight = exp(-max(max(fT, 0.0), features));
213
- let index = ha(q);
212
+ let weight = exp(-max(max(fY, 0.0), features));
213
+ let index = hg(q);
214
214
  let c = color[index];
215
215
  let g = guide[index];
216
216
 
217
- let a = (textureLoad(albedoTex, q, 0).rgb - bs.rgb) / gR;
217
+ let a = (textureLoad(albedoTex, q, 0).rgb - bs.rgb) / gW;
218
218
  let value = premultiplied(c);
219
219
  sum += value * weight;
220
- mf += a * weight;
221
- gt += a * a * weight;
222
- hn += a * value.rgb * weight;
223
- pk += g.x * weight;
224
- gv += g.y * weight * weight;
225
- nK += weight;
226
- kD = max(kD, weight);
220
+ mp += a * weight;
221
+ gy += a * a * weight;
222
+ hs += a * value.rgb * weight;
223
+ ps += g.x * weight;
224
+ gA += g.y * weight * weight;
225
+ nU += weight;
226
+ kM = max(kM, weight);
227
227
  }
228
228
  }
229
229
 
230
230
 
231
231
 
232
232
  let center = color[index];
233
- let kV = guide[index];
234
- let dF = max(kD, CENTER_WEIGHT_MIN);
235
- let totalWeight = nK + dF;
236
- let tF = premultiplied(center);
237
- let mean = (sum + tF * dF) / totalWeight;
233
+ let le = guide[index];
234
+ let dG = max(kM, CENTER_WEIGHT_MIN);
235
+ let totalWeight = nU + dG;
236
+ let tM = premultiplied(center);
237
+ let mean = (sum + tM * dG) / totalWeight;
238
238
 
239
239
 
240
- let ez = mf / totalWeight;
241
- let lo = max(gt / totalWeight - ez * ez, vec3f(0.0));
242
- let qm = hn / totalWeight - ez * mean.rgb;
240
+ let ez = mp / totalWeight;
241
+ let lA = max(gy / totalWeight - ez * ez, vec3f(0.0));
242
+ let qu = hs / totalWeight - ez * mean.rgb;
243
243
 
244
244
 
245
245
 
246
- let qw = bs.rgb + ez * gR;
247
- let oq = mean.rgb * gR / max(qw, vec3f(${JNLM_ALBEDO_FLOOR}));
248
- let vs = clamp(qm / (lo + vec3f(${JNLM_ALBEDO_REGULARIZATION})), vec3f(0.0), oq);
249
- let rs = mean.rgb - vs * ez;
250
- let filtered = vec4f(max(rs, vec3f(0.0)), max(mean.a, 0.0));
246
+ let qE = bs.rgb + ez * gW;
247
+ let oz = mean.rgb * gW / max(qE, vec3f(${JNLM_ALBEDO_FLOOR}));
248
+ let vB = clamp(qu / (lA + vec3f(${JNLM_ALBEDO_REGULARIZATION})), vec3f(0.0), oz);
249
+ let rD = mean.rgb - vB * ez;
250
+ let filtered = vec4f(max(rD, vec3f(0.0)), max(mean.a, 0.0));
251
251
  let rgb = select(
252
252
  center.rgb,
253
253
  filtered.rgb / max(filtered.a, 1e-6),
@@ -255,8 +255,8 @@ filtered.a > 1e-6
255
255
  );
256
256
  outColor[index] = vec4f(rgb, filtered.a);
257
257
  outGuide[index] = vec2f(
258
- (pk + kV.x * dF) / totalWeight,
259
- (gv + kV.y * dF * dF)
258
+ (ps + le.x * dG) / totalWeight,
259
+ (gA + le.y * dG * dG)
260
260
  / (totalWeight * totalWeight)
261
261
  );
262
262
  }
@@ -16,33 +16,33 @@ ${shadowCatcherAccumulationWGSL}
16
16
  override outputWidth: f32;
17
17
  override outputHeight: f32;
18
18
 
19
- struct oU {
19
+ struct pd {
20
20
  ${layers ? `@location(0) foreground: vec4f,
21
21
  @location(1) catcherBackground: vec4f` : `@location(0) color: vec4f,
22
22
  @location(1) normal: vec4f,
23
23
  @location(2) albedo: vec4f${catcher ? ',\n @location(3) shadowCatcher: vec4f' : ''}`}
24
24
  }
25
25
  @fragment
26
- fn main(@builtin(position) fD: vec4f) -> oU {
26
+ fn main(@builtin(position) fH: vec4f) -> pd {
27
27
  let size = vec2u(u32(outputWidth), u32(outputHeight));
28
- let fM = vec2u(u32(fD.x), size.y - u32(fD.y) - 1u);
29
- var idx = fM.x + fM.y * size.x;
28
+ let fQ = vec2u(u32(fH.x), size.y - u32(fH.y) - 1u);
29
+ var idx = fQ.x + fQ.y * size.x;
30
30
 
31
31
 
32
32
 
33
33
 
34
34
  if (sampleCount < 1.0 && normalBuffer[idx].a <= 0.0) {
35
- let uV = max(sampleTileGrid, vec2u(1u));
36
- let uF = min(
37
- ((fM + uV / 2u) / uV) * uV,
38
- ((size - vec2u(1u)) / uV) * uV
35
+ let vc = max(sampleTileGrid, vec2u(1u));
36
+ let uM = min(
37
+ ((fQ + vc / 2u) / vc) * vc,
38
+ ((size - vec2u(1u)) / vc) * vc
39
39
  );
40
- let sz = uF.x + uF.y * size.x;
41
- if (normalBuffer[sz].a > 0.0) {
42
- idx = sz;
40
+ let sH = uM.x + uM.y * size.x;
41
+ if (normalBuffer[sH].a > 0.0) {
42
+ idx = sH;
43
43
  }
44
44
  }
45
- var output: oU;
45
+ var output: pd;
46
46
  if (normalBuffer[idx].a <= 0.0) {
47
47
  ${layers ? `output.foreground = vec4f(0.0);
48
48
  output.catcherBackground = vec4f(0.0);` : `output.color = vec4f(0.0);
@@ -62,12 +62,12 @@ let hit = albedo.a;
62
62
  let total = max(normal.a, 1.0);
63
63
  ${layers ? `
64
64
  let shadow = shadowCatcherBuffer[idx];
65
- let iQ = max(hit - shadow.mask.b, 0.0);
65
+ let iV = max(hit - shadow.mask.b, 0.0);
66
66
 
67
67
 
68
68
  output.foreground = vec4f(
69
69
  (color.rgb - shadow.background.rgb)
70
- / select(total, iQ, iQ > 0.0),
70
+ / select(total, iV, iV > 0.0),
71
71
  clamp((color.a - shadow.mask.g) / total, 0.0, 1.0)
72
72
  );
73
73
  output.catcherBackground = shadow.background / total;
@@ -57,6 +57,8 @@ export declare function makeRayTraceUniform(): {
57
57
  sequenceSeed: Uint32Array<ArrayBuffer>;
58
58
  zSobolLogSPP: Uint32Array<ArrayBuffer>;
59
59
  sampleSequenceOffset: Uint32Array<ArrayBuffer>;
60
+ environmentRotation: Float32Array<ArrayBuffer>;
61
+ backgroundMapTransform: Float32Array<ArrayBuffer>;
60
62
  };
61
63
  };
62
64
  export declare function packAnalyticsLightsToBuffer(lights: AnalyticLight[], texturesIndices: number[], selectionPmfs: number[], iesProfileTexelOffsets?: ArrayLike<number>): Float32Array<ArrayBuffer>;
@@ -24,7 +24,7 @@ import { WGPU_SCENE_FEATURE_BITS, wgpuSceneFeatureFlags } from './WGPUSceneFeatu
24
24
  import { mat4 } from '../math.js';
25
25
  import MaterialTable, { DEFAULT_MAX_TEXTURE_ARRAY_BYTES, materialUsesMedium } from './MaterialTable.js';
26
26
  import { numberArraysEqual } from './util.js';
27
- import { generateBackgroundMapFromSceneBackground } from './envMapCreation.js';
27
+ import { generateBackgroundMapFromSceneBackground, environmentRotation, backgroundMapTransform } from './envMapCreation.js';
28
28
  import rayTraceCompute, { WORKGROUP_SIZE } from './wgsl/rayTrace.compute.js';
29
29
  import { CONSTANT_DIRECTIONAL_LIGHT, CONSTANT_RECT_LIGHT, CONSTANT_SPHERE_LIGHT, CONSTANT_SPOT_LIGHT } from './lightsUtil.js';
30
30
  import { envMapDistribution, environmentMapSourcesMatch } from './envMapDistribution.js';
@@ -89,7 +89,7 @@ export function isWebGPUPipelineSpecializationFailure(...errors) {
89
89
  /** CPU-side views over the `RayTraceUniform` WGSL struct. */
90
90
  export function makeRayTraceUniform() {
91
91
  // Created from https://webgpufundamentals.org/webgpu/lessons/resources/wgsl-offset-computer.html
92
- const RayTraceUniformValues = new ArrayBuffer(176);
92
+ const RayTraceUniformValues = new ArrayBuffer(256);
93
93
  const RayTraceUniformViews = {
94
94
  outputSize: new Float32Array(RayTraceUniformValues, 0, 2),
95
95
  sampleCount: new Float32Array(RayTraceUniformValues, 8, 1),
@@ -119,11 +119,15 @@ export function makeRayTraceUniform() {
119
119
  sceneFeatureFlags: new Uint32Array(RayTraceUniformValues, 152, 1),
120
120
  sequenceSeed: new Uint32Array(RayTraceUniformValues, 156, 1),
121
121
  zSobolLogSPP: new Uint32Array(RayTraceUniformValues, 160, 1),
122
- sampleSequenceOffset: new Uint32Array(RayTraceUniformValues, 164, 1)
122
+ sampleSequenceOffset: new Uint32Array(RayTraceUniformValues, 164, 1),
123
+ environmentRotation: new Float32Array(RayTraceUniformValues, 176, 16),
124
+ backgroundMapTransform: new Float32Array(RayTraceUniformValues, 240, 4)
123
125
  };
124
126
  // Fixed runtime trip bounds discourage thin-film loop unrolling. Keep 4 for
125
127
  // 2 polarizations/substrates and 3 channels, independent of BSDF budgets.
126
128
  RayTraceUniformViews.loopUnrollGuard[0] = 4;
129
+ RayTraceUniformViews.environmentRotation.set(environmentRotation([]));
130
+ RayTraceUniformViews.backgroundMapTransform.set(backgroundMapTransform());
127
131
  RayTraceUniformViews.bevel[0] = 1;
128
132
  RayTraceUniformViews.dispersionWavelengths[0] = 3;
129
133
  return {
@@ -179,7 +183,7 @@ export function packAnalyticsLightsToBuffer(lights, texturesIndices, selectionPm
179
183
  data[(off + 2) * 4 + 3] = light.radius;
180
184
  packVec3(off + 3, [
181
185
  Math.cos((light.outerAngle * Math.PI) / 180),
182
- Math.min(1, Math.max(0, 1 - light.innerAngle / light.outerAngle)),
186
+ Math.cos((Math.min(light.innerAngle, light.outerAngle) * Math.PI) / 180),
183
187
  0
184
188
  ]);
185
189
  }
@@ -792,8 +796,6 @@ class WGPURayTracePass {
792
796
  ...MATERIAL_TEXTURE_DEFINES,
793
797
  'USE_ANISOTROPY_DIRECTIONS',
794
798
  'USE_COAT_NORMAL_FRAMES',
795
- 'COLOR_OFF',
796
- 'USE_VERTEX_COLOR',
797
799
  'HAS_ALPHA_BLEND',
798
800
  'HAS_ALPHA_MASK'
799
801
  ];
@@ -1621,6 +1623,7 @@ ${rayTraceCompute({
1621
1623
  return true;
1622
1624
  }
1623
1625
  setBackground(background) {
1626
+ this._rtUniform.views.backgroundMapTransform.set(backgroundMapTransform(background));
1624
1627
  this._constants.USE_BACKGROUND = !!background;
1625
1628
  const backgroundImage = background && !Array.isArray(background)
1626
1629
  ? generateBackgroundMapFromSceneBackground(background)
@@ -1913,6 +1916,9 @@ ${rayTraceCompute({
1913
1916
  // Retain the atlas uniform capacity when a stage/material is removed.
1914
1917
  // Shrinking the array would rebuild every pipeline again on the next edit.
1915
1918
  const NUM_MAPS = Math.max(Math.ceil(+materialData.defines.NUM_MAPS / 10) * 10, Number(this._constants.NUM_MAPS ?? 0), 20);
1919
+ // Either layer's map requires independent normals, including a smooth
1920
+ // coat over a mapped base. Unmapped materials retain the shared path.
1921
+ const USE_COAT_NORMAL_FRAMES = materials.some(m => m.coatWeight > 0 && (!!m.normalMap || !!m.coatNormalMap));
1916
1922
  Object.assign(this._constants, {
1917
1923
  // Match the atlas UV selector. Keep the second set when any texture
1918
1924
  // needs it; material/texture edits already rebuild these constants.
@@ -1921,9 +1927,8 @@ ${rayTraceCompute({
1921
1927
  // triangle UV differentials rather than this vertex tangent.
1922
1928
  USE_TANGENT: mergedGeometry.tangent != null &&
1923
1929
  materials.some(material => material.specularAnisotropy > 0 || material.coatAnisotropy > 0 || (!!material.coatNormalMap && material.coatWeight > 0)),
1924
- USE_COAT_NORMAL_FRAMES: materials.some(m => !!m.coatNormalMap && m.coatWeight > 0),
1925
- USE_ANISOTROPY_DIRECTIONS: materials.some(m => (!!m.coatNormalMap && m.coatWeight > 0) ||
1926
- m.specularAnisotropy > 0 && (m.specularAnisotropyModel === 'gltf' || !!m.anisotropyMap || m.specularAnisotropyRotation !== 0) ||
1930
+ USE_COAT_NORMAL_FRAMES,
1931
+ USE_ANISOTROPY_DIRECTIONS: USE_COAT_NORMAL_FRAMES || materials.some(m => m.specularAnisotropy > 0 && (m.specularAnisotropyModel === 'gltf' || !!m.anisotropyMap || m.specularAnisotropyRotation !== 0) ||
1927
1932
  m.coatAnisotropy > 0 && m.coatAnisotropyRotation !== 0),
1928
1933
  HAS_MEDIUM,
1929
1934
  HAS_SHADOW_CATCHER: this._hasShadowCatcher,
@@ -2119,6 +2124,8 @@ ${rayTraceCompute({
2119
2124
  for (let i = 0; i < mapUvChannel.length; i++) {
2120
2125
  mapInfoData[numMaps * 8 + i * 4] = mapUvChannel[i];
2121
2126
  mapInfoData[numMaps * 8 + i * 4 + 1] = mapColorLinear[i];
2127
+ mapInfoData[numMaps * 8 + i * 4 + 2] = materialData.bufferData.mapWrap[i * 2];
2128
+ mapInfoData[numMaps * 8 + i * 4 + 3] = materialData.bufferData.mapWrap[i * 2 + 1];
2122
2129
  }
2123
2130
  let mapInfoUniform = this._mapInfoUniform;
2124
2131
  if (!mapInfoUniform || mapInfoUniform.size !== mapInfoData.byteLength) {
@@ -2186,6 +2193,7 @@ ${rayTraceCompute({
2186
2193
  const analyticLights = allAnalyticLights.slice(0, FIXED_LIGHT_COUNT);
2187
2194
  const numAnalyticLights = analyticLights.length;
2188
2195
  const envImage = this._sceneEnvironment.update(lights);
2196
+ this._rtUniform.views.environmentRotation.set(environmentRotation(lights));
2189
2197
  this._rtUniform.views.lightsCount[0] = numAnalyticLights;
2190
2198
  this._setEnvMap(envImage);
2191
2199
  const lightTexturesChanged = this._rectLightTextures.update(analyticLights);