@meimu/mutracer 0.1.3 → 0.1.4

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 (118) hide show
  1. package/dist/assets/bvh.worker.js +1 -1
  2. package/dist/mutracer.umd.js +4114 -4015
  3. package/docs/api.md +11 -9
  4. package/docs/threejs.md +30 -4
  5. package/lib/Engine.js +18 -1
  6. package/lib/Engine.js.map +1 -1
  7. package/lib/main.d.ts +1 -1
  8. package/lib/main.js.map +1 -1
  9. package/lib/oidn.d.ts +1 -1
  10. package/lib/oidnBundledWeights.cdn.d.ts +2 -2
  11. package/lib/renderer/MaterialTable.d.ts +1 -0
  12. package/lib/renderer/MaterialTable.js +10 -4
  13. package/lib/renderer/MaterialTable.js.map +1 -1
  14. package/lib/renderer/WGPUBloomPass.js +18 -18
  15. package/lib/renderer/WGPUFullQuadPass.js +6 -6
  16. package/lib/renderer/WGPUJNLMDenoiser.js +69 -69
  17. package/lib/renderer/WGPURayTraceOutput.js +14 -14
  18. package/lib/renderer/WGPURayTracePass.d.ts +2 -0
  19. package/lib/renderer/WGPURayTracePass.js +12 -6
  20. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  21. package/lib/renderer/WGPURenderingPipeline.js +15 -15
  22. package/lib/renderer/WebGLJNLMDenoiser.js +69 -69
  23. package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
  24. package/lib/renderer/WebGLRayTracePass.d.ts +1 -0
  25. package/lib/renderer/WebGLRayTracePass.js +7 -1
  26. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  27. package/lib/renderer/envMapCreation.d.ts +5 -1
  28. package/lib/renderer/envMapCreation.js +42 -5
  29. package/lib/renderer/envMapCreation.js.map +1 -1
  30. package/lib/renderer/geometryUpdates.js +1 -1
  31. package/lib/renderer/geometryUpdates.js.map +1 -1
  32. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +12 -12
  33. package/lib/renderer/glsl/chunks/envMap.glsl.js +66 -54
  34. package/lib/renderer/glsl/chunks/envMap.glsl.js.map +1 -1
  35. package/lib/renderer/glsl/chunks/intersect.glsl.js +316 -310
  36. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
  37. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +151 -119
  38. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
  39. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +414 -414
  40. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  41. package/lib/renderer/glsl/chunks/random.glsl.js +3 -3
  42. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +40 -39
  43. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  44. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +69 -69
  45. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +78 -78
  46. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +12 -12
  47. package/lib/renderer/glsl/chunks/sampling.glsl.js +75 -75
  48. package/lib/renderer/glsl/chunks/sobol.glsl.js +61 -61
  49. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  50. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
  51. package/lib/renderer/glsl/depthQuery.frag.js +5 -5
  52. package/lib/renderer/glsl/depthQuery.frag.js.map +1 -1
  53. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +8 -8
  54. package/lib/renderer/glsl/rayTrace.frag.js +133 -133
  55. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
  56. package/lib/renderer/glsl/shadowCatcher.frag.js +9 -9
  57. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  58. package/lib/renderer/glsl/webglPipeline.frag.js +52 -52
  59. package/lib/renderer/lightsUtil.js +6 -4
  60. package/lib/renderer/lightsUtil.js.map +1 -1
  61. package/lib/renderer/materialChanges.js +1 -1
  62. package/lib/renderer/materialChanges.js.map +1 -1
  63. package/lib/renderer/materialComparison.generated.js +36 -18
  64. package/lib/renderer/materialComparison.generated.js.map +1 -1
  65. package/lib/renderer/prepareMeshBVH.js +2 -2
  66. package/lib/renderer/prepareMeshBVH.js.map +1 -1
  67. package/lib/renderer/sceneChangeDetector.js +4 -1
  68. package/lib/renderer/sceneChangeDetector.js.map +1 -1
  69. package/lib/renderer/sceneLightChanges.js +3 -2
  70. package/lib/renderer/sceneLightChanges.js.map +1 -1
  71. package/lib/renderer/scratchSampling.js +18 -18
  72. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  73. package/lib/renderer/wgsl/chunks/envMap.wgsl.d.ts +1 -1
  74. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +39 -31
  75. package/lib/renderer/wgsl/chunks/envMap.wgsl.js.map +1 -1
  76. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +475 -469
  77. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  78. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +8 -8
  79. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +93 -59
  80. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  81. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +469 -469
  82. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.d.ts +1 -1
  83. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +117 -120
  84. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js.map +1 -1
  85. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  86. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +25 -22
  87. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  88. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +127 -127
  89. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +136 -136
  90. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +6 -6
  91. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +73 -73
  92. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +62 -62
  93. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
  94. package/lib/renderer/wgsl/compose.frag.wgsl.js +105 -105
  95. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  96. package/lib/renderer/wgsl/depthQuery.wgsl.d.ts +1 -1
  97. package/lib/renderer/wgsl/depthQuery.wgsl.js +5 -5
  98. package/lib/renderer/wgsl/depthQuery.wgsl.js.map +1 -1
  99. package/lib/renderer/wgsl/offlineAdaptive.compute.js +28 -28
  100. package/lib/renderer/wgsl/rayTrace.compute.js +251 -248
  101. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  102. package/lib/scene/EnvironmentLight.d.ts +9 -3
  103. package/lib/scene/EnvironmentLight.js +9 -2
  104. package/lib/scene/EnvironmentLight.js.map +1 -1
  105. package/lib/scene/Scene.d.ts +4 -0
  106. package/lib/scene/Scene.js.map +1 -1
  107. package/lib/scene/SpotLight.d.ts +2 -2
  108. package/lib/scene/SpotLight.js +1 -1
  109. package/lib/scene/SpotLight.js.map +1 -1
  110. package/lib/scene/Texture.d.ts +17 -6
  111. package/lib/scene/Texture.js +13 -4
  112. package/lib/scene/Texture.js.map +1 -1
  113. package/lib/util/fromTHREE.js +151 -29
  114. package/lib/util/fromTHREE.js.map +1 -1
  115. package/lib/version.d.ts +1 -1
  116. package/lib/version.js +1 -1
  117. package/lib/version.js.map +1 -1
  118. package/package.json +1 -1
@@ -32,7 +32,7 @@ return;
32
32
  // So here the code are injected separately.
33
33
  const bounceCodeOnIntelMac = glsl `
34
34
 
35
- for(int vN = 0; vN < BOUNCES; vN++) {{
35
+ for(int vU = 0; vU < BOUNCES; vU++) {{
36
36
  if (aa.abort) {
37
37
  return vec4(aa.li, aa.alpha);
38
38
  }
@@ -40,10 +40,10 @@ bounce(aa, depth, si, mat, outAux);
40
40
  }}
41
41
  `;
42
42
  const bounceCodeOnOther = glsl `
43
- bool uY = !si.isTransparency;
44
- int qF = min(BOUNCES, bounceLimit);
43
+ bool vg = !si.isTransparency;
44
+ int qO = min(BOUNCES, bounceLimit);
45
45
  for(int idx = 0; idx < min(BOUNCES * 3, ${MAX_PATH_EVENTS}); idx++) {
46
- if (uY && idx > qF) {
46
+ if (vg && idx > qO) {
47
47
  aa.abort = true;
48
48
  }
49
49
  if (aa.abort) {
@@ -93,7 +93,7 @@ ${envMap.main}
93
93
  ${samplingGlsl}
94
94
  ${openPbrBsdfGlsl}
95
95
 
96
- float mk;
96
+ float mw;
97
97
  float bf;
98
98
 
99
99
  ${sampleLightGlsl}
@@ -139,18 +139,18 @@ vec4 bg = cx(aa.ray.o, aa.ray.d);
139
139
  bg.rgb = ai(bg.rgb, bf);
140
140
  float cT = aa.scatteringIsDelta ? 1.0
141
141
  : aG(aa.scatteringPdf,
142
- iv(aS(aa.ray.d)) * envLightSelectionPmf);
142
+ iB(cY(aa.ray.d)) * envLightSelectionPmf);
143
143
  aa.li += cT * aa.beta * bg.rgb * bg.a;
144
144
  aa.alpha = max(aa.alpha, bg.a);
145
145
  }
146
146
  else {
147
- vec2 tJ = aS(aa.ray.d);
148
- vec3 emission = textureLinear(envMap, tJ).rgb;
147
+ vec2 tQ = cY(aa.ray.d);
148
+ vec3 emission = textureLinear(envMap, tQ).rgb;
149
149
  emission = ai(emission, bf);
150
150
  aa.li += aa.beta * emission *
151
151
  aG(
152
152
  aa.scatteringPdf,
153
- iv(tJ) * envLightSelectionPmf
153
+ iB(tQ) * envLightSelectionPmf
154
154
  );
155
155
  }
156
156
  #else
@@ -177,10 +177,10 @@ aa.alpha = bg.a;
177
177
  outAux.isBlank = bg.a < 0.01;
178
178
  }
179
179
  else {
180
- Ray cam = hy(v_Texcoord + rS());
181
- bool mC = dot(cam.d, aa.ray.d) > 0.0;
180
+ Ray cam = hC(v_Texcoord + sa());
181
+ bool mM = dot(cam.d, aa.ray.d) > 0.0;
182
182
  if (transmissiveOutputAlphaMin < 1.0) {
183
- if (mC) {
183
+ if (mM) {
184
184
  aa.alpha = max(aa.alpha, bg.a);
185
185
  } else {
186
186
  aa.alpha = 1.0;
@@ -188,7 +188,7 @@ aa.alpha = 1.0;
188
188
  }
189
189
  #if !defined(USE_ENVMAP)
190
190
 
191
- if (mC) {
191
+ if (mM) {
192
192
  aa.li = aa.beta * aG(aa.scatteringPdf, 1.0) * bg.rgb;
193
193
  }
194
194
  #endif
@@ -214,7 +214,7 @@ cH = true;
214
214
  }
215
215
  }
216
216
  if (!cH) {
217
- lR(si, mat, aa);
217
+ mc(si, mat, aa);
218
218
  }
219
219
  else {
220
220
  aa.ray.o = si.position + aa.ray.d * EPS;
@@ -245,8 +245,8 @@ si.albedoSampled = true;
245
245
  #ifdef USE_RR
246
246
  if (depth >= RR_MAX && !cH) {
247
247
 
248
- float oo = max(max(aa.beta.x, aa.beta.y), aa.beta.z);
249
- float q = max(0.0, 1.0 - oo);
248
+ float oz = max(max(aa.beta.x, aa.beta.y), aa.beta.z);
249
+ float q = max(0.0, 1.0 - oz);
250
250
  if (dz(cw(RUSSIAN_ROULETTE)) < q) {
251
251
 
252
252
 
@@ -264,18 +264,18 @@ return;
264
264
  }
265
265
 
266
266
 
267
- cY(aa.ray, si, true);
268
- eT(mat, si.materialIndex, si.uv, si.uv1, si.instanceIndex);
267
+ cZ(aa.ray, si, true);
268
+ eX(mat, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);
269
269
  si.isTransparency = mat.transmissionWeight > 0.001 || mat.subsurfaceWeight > 0.001 || mat.alpha < 0.999;
270
270
 
271
271
 
272
272
 
273
273
 
274
274
  if (dispersionWavelengths == 1 && si.hit && mat.transmissionWeight > 0.001 && mat.transmissionDispersionScale > 0.001) {
275
- bf = mk;
275
+ bf = mw;
276
276
  }
277
277
  if (mat.transmissionWeight > 0.001 && bf > 0.0) {
278
- mat.specularIor = eK(
278
+ mat.specularIor = eN(
279
279
  bf,
280
280
  mat.specularIor,
281
281
  mat.transmissionDispersionScale,
@@ -287,20 +287,20 @@ if (cH) {
287
287
  return;
288
288
  }
289
289
 
290
- bool hu = eo(3u) < mat.alpha;
290
+ bool hy = eo(3u) < mat.alpha;
291
291
  #ifdef NUM_LIGHTS
292
292
 
293
293
  LightSampleRec lightSample;
294
294
  for (int i = 0; i < NUM_LIGHTS; i++) {
295
295
 
296
- Light light = qp(i);
297
- float d = mo(aa.ray, light, lightSample);
298
- bool mt = si.hit && d > distance(si.position, aa.ray.o);
299
- if (d != INF && !(mt && hu)) {
296
+ Light light = qx(i);
297
+ float d = mz(aa.ray, light, lightSample);
298
+ bool mD = si.hit && d > distance(si.position, aa.ray.o);
299
+ if (d != INF && !(mD && hy)) {
300
300
  lightSample.pdf *= light.selectionPmf;
301
- float eW = aG(aa.scatteringPdf, lightSample.pdf);
301
+ float fa = aG(aa.scatteringPdf, lightSample.pdf);
302
302
  lightSample.emission = ai(lightSample.emission, bf);
303
- aa.li += eW * aa.beta * lightSample.emission;
303
+ aa.li += fa * aa.beta * lightSample.emission;
304
304
 
305
305
  aa.alpha = 1.0;
306
306
  aa.abort = true;
@@ -309,7 +309,7 @@ aa.abort = true;
309
309
  #endif
310
310
 
311
311
  #ifdef USE_ENVMAP
312
- if (!(si.hit && hu)) {
312
+ if (!(si.hit && hy)) {
313
313
  if (aa.isNextRefraction) {
314
314
 
315
315
 
@@ -317,20 +317,20 @@ vec4 bg = cx(aa.ray.o, aa.ray.d);
317
317
  bg.rgb = ai(bg.rgb, bf);
318
318
  float cT = aa.scatteringIsDelta ? 1.0
319
319
  : aG(aa.scatteringPdf,
320
- iv(aS(aa.ray.d)) * envLightSelectionPmf);
320
+ iB(cY(aa.ray.d)) * envLightSelectionPmf);
321
321
  aa.li += cT * aa.beta * bg.rgb * bg.a;
322
322
  aa.alpha = max(aa.alpha, bg.a);
323
323
  aa.abort = true;
324
324
  return;
325
325
  }
326
- vec2 uv = aS(aa.ray.d);
326
+ vec2 uv = cY(aa.ray.d);
327
327
  vec3 emission = textureLinear(envMap, uv).rgb;
328
- float eW = aG(
328
+ float fa = aG(
329
329
  aa.scatteringPdf,
330
- iv(uv) * envLightSelectionPmf
330
+ iB(uv) * envLightSelectionPmf
331
331
  );
332
332
  emission = ai(emission, bf);
333
- aa.li += aa.beta * emission * eW;
333
+ aa.li += aa.beta * emission * fa;
334
334
 
335
335
 
336
336
  #if !defined(USE_BACKGROUND)
@@ -345,105 +345,105 @@ depth++;
345
345
  }
346
346
 
347
347
 
348
- vec2 kp(float radius, float xi) {
348
+ vec2 kz(float radius, float xi) {
349
349
  float x = 0.25;
350
- for (int ns = 0; ns < 10; ns++) {
350
+ for (int nH = 0; nH < 10; nH++) {
351
351
  float x2 = x * x;
352
352
  float x3 = x2 * x;
353
- float kG = 1.0 - x;
353
+ float kP = 1.0 - x;
354
354
  float value = 10.0 * x2 - 20.0 * x3 + 15.0 * x2 * x2 -
355
355
  4.0 * x2 * x3 - xi;
356
- float lY = 20.0 * x * kG * kG * kG;
357
- if (abs(value) < 1e-6 || lY == 0.0) break;
358
- x = clamp(x - value / lY, 0.0, 1.0);
356
+ float mk = 20.0 * x * kP * kP * kP;
357
+ if (abs(value) < 1e-6 || mk == 0.0) break;
358
+ x = clamp(x - value / mk, 0.0, 1.0);
359
359
  }
360
- float jj = x * radius;
360
+ float jo = x * radius;
361
361
  return vec2(
362
- jj,
363
- sqrt(max(radius * radius - jj * jj, 0.0))
362
+ jo,
363
+ sqrt(max(radius * radius - jo * jo, 0.0))
364
364
  );
365
365
  }
366
366
 
367
- float iO(float radius, float gs) {
368
- if (gs >= radius) return 0.0;
369
- float nV = radius - gs;
370
- return nV * nV * nV;
367
+ float iT(float radius, float gw) {
368
+ if (gw >= radius) return 0.0;
369
+ float oh = radius - gw;
370
+ return oh * oh * oh;
371
371
  }
372
372
 
373
373
 
374
- vec3 mi(ad source, float radius) {
374
+ vec3 mu(ad source, float radius) {
375
375
  vec3 geometricNormal = source.faceNormal;
376
376
  if (dot(geometricNormal, source.vertexNormal) < 0.0) geometricNormal = -geometricNormal;
377
377
  vec3 tangent;
378
378
  vec3 bitangent;
379
379
  aL(geometricNormal, tangent, bitangent);
380
- vec3 iB = vec3(0.0);
381
-
382
- for (int ia = 0; ia < BEVEL_SAMPLES; ia++) {
383
- vec2 oY = fk(CAMERA_BEVEL_BASE + uint(ia));
384
- float cA = oY.x;
385
- float ox = oY.y;
386
- vec3 di = geometricNormal;
387
- vec3 fE = tangent;
380
+ vec3 iF = vec3(0.0);
381
+
382
+ for (int ig = 0; ig < BEVEL_SAMPLES; ig++) {
383
+ vec2 ph = fo(CAMERA_BEVEL_BASE + uint(ig));
384
+ float cA = ph.x;
385
+ float oG = ph.y;
386
+ vec3 dj = geometricNormal;
387
+ vec3 fH = tangent;
388
388
  vec3 ek = bitangent;
389
- float ga = 0.5;
390
- float hU = 0.25;
391
- float gA = 0.25;
389
+ float ge = 0.5;
390
+ float hY = 0.25;
391
+ float gG = 0.25;
392
392
  if (cA < 0.5) {
393
393
  cA *= 2.0;
394
394
  }
395
395
  else if (cA < 0.75) {
396
- vec3 mA = di;
397
- di = fE;
398
- fE = mA;
399
- ga = 0.25;
400
- hU = 0.5;
396
+ vec3 mK = dj;
397
+ dj = fH;
398
+ fH = mK;
399
+ ge = 0.25;
400
+ hY = 0.5;
401
401
  cA = (cA - 0.5) * 4.0;
402
402
  }
403
403
  else {
404
- vec3 mA = di;
405
- di = ek;
406
- ek = mA;
407
- ga = 0.25;
408
- gA = 0.5;
404
+ vec3 mK = dj;
405
+ dj = ek;
406
+ ek = mK;
407
+ ge = 0.25;
408
+ gG = 0.5;
409
409
  cA = (cA - 0.75) * 4.0;
410
410
  }
411
411
 
412
- vec2 gQ = kp(radius, ox);
412
+ vec2 gU = kz(radius, oG);
413
413
  float phi = TWOPI * cA;
414
- vec3 qn = gQ.x *
415
- (cos(phi) * fE + sin(phi) * ek);
414
+ vec3 qv = gU.x *
415
+ (cos(phi) * fH + sin(phi) * ek);
416
416
  Ray ray;
417
- iw(
417
+ iC(
418
418
  ray,
419
- source.position + di * gQ.y + qn,
420
- -di
419
+ source.position + dj * gU.y + qv,
420
+ -dj
421
421
  );
422
422
  ad hit;
423
- iH(
423
+ iM(
424
424
  ray,
425
425
  hit,
426
426
  source.instanceIndex,
427
- max(2.0 * gQ.y, EPS)
427
+ max(2.0 * gU.y, EPS)
428
428
  );
429
429
  if (!hit.hit) continue;
430
430
 
431
- float kH = ga * abs(dot(di, hit.faceNormal));
432
- float mw = hU * abs(dot(fE, hit.faceNormal));
433
- float jU = gA * abs(dot(ek, hit.faceNormal));
434
- float weight = kH / max(
435
- kH * kH + mw * mw +
436
- jU * jU,
431
+ float kQ = ge * abs(dot(dj, hit.faceNormal));
432
+ float mG = hY * abs(dot(fH, hit.faceNormal));
433
+ float kb = gG * abs(dot(ek, hit.faceNormal));
434
+ float weight = kQ / max(
435
+ kQ * kQ + mG * mG +
436
+ kb * kb,
437
437
  1e-8
438
438
  );
439
- weight *= iO(radius, distance(hit.position, source.position)) /
440
- max(iO(radius, gQ.x), 1e-8);
441
- iB += weight * hit.vertexNormal;
439
+ weight *= iT(radius, distance(hit.position, source.position)) /
440
+ max(iT(radius, gU.x), 1e-8);
441
+ iF += weight * hit.vertexNormal;
442
442
  }
443
443
 
444
- if (dot(iB, iB) <= 1e-12) return source.normal;
445
- vec3 jC = normalize(iB);
446
- vec3 result = source.normal + jC - source.vertexNormal;
444
+ if (dot(iF, iF) <= 1e-12) return source.normal;
445
+ vec3 jH = normalize(iF);
446
+ vec3 result = source.normal + jH - source.vertexNormal;
447
447
  return dot(result, result) > 1e-12 ? normalize(result) : source.normal;
448
448
  }
449
449
 
@@ -463,7 +463,7 @@ ${intelMac ? bounceCodeOnIntelMac : bounceCodeOnOther}
463
463
  return vec4(aa.li, aa.alpha);
464
464
  }
465
465
 
466
- vec4 iz(ad si, Ray ray, J mat, inout RayTraceAuxiliary outAux) {
466
+ vec4 iD(ad si, Ray ray, J mat, inout RayTraceAuxiliary outAux) {
467
467
  float coverage = clamp(mat.alpha, 0.0, 1.0);
468
468
  if (!si.hit || (mat.materialType != STANDARD && mat.materialType != UNLIT) || coverage >= 1.0) {
469
469
  return bw(si, ray, mat, outAux);
@@ -473,49 +473,49 @@ return bw(si, ray, mat, outAux);
473
473
 
474
474
 
475
475
 
476
- Ray nN = ray;
477
- nN.o = si.position + ray.d * (EPS * 0.02);
478
- ad dU = si;
479
- dU.albedoSampled = false;
480
- cY(nN, dU, false);
481
- J nM;
482
- eT(nM, dU.materialIndex, dU.uv, dU.uv1, dU.instanceIndex);
483
- RayTraceAuxiliary gh = outAux;
484
- if (dU.hit && (nM.materialType == STANDARD || nM.materialType == UNLIT)) {
485
- gh.albedo = nM.transmissionWeight > 0.5
476
+ Ray nY = ray;
477
+ nY.o = si.position + ray.d * (EPS * 0.02);
478
+ ad dE = si;
479
+ dE.albedoSampled = false;
480
+ cZ(nY, dE, false);
481
+ J nX;
482
+ eX(nX, dE.materialIndex, dE.uv, dE.uv1, dE.instanceIndex, dE.vertexColor);
483
+ RayTraceAuxiliary gm = outAux;
484
+ if (dE.hit && (nX.materialType == STANDARD || nX.materialType == UNLIT)) {
485
+ gm.albedo = nX.transmissionWeight > 0.5
486
486
  ? vec3(1.0)
487
- : nM.baseColor;
488
- gh.normal = dot(
489
- dU.normal,
490
- dU.position - vec3(viewInv[3])
487
+ : nX.baseColor;
488
+ gm.normal = dot(
489
+ dE.normal,
490
+ dE.position - vec3(viewInv[3])
491
491
  ) > 0.0
492
- ? -dU.normal
493
- : dU.normal;
494
- dU.albedoSampled = nM.transmissionWeight > 0.5;
492
+ ? -dE.normal
493
+ : dE.normal;
494
+ dE.albedoSampled = nX.transmissionWeight > 0.5;
495
495
  }
496
- vec4 back = bw(dU, nN, nM, gh);
496
+ vec4 back = bw(dE, nY, nX, gm);
497
497
  if (coverage <= 0.0) {
498
- outAux = gh;
498
+ outAux = gm;
499
499
  return back;
500
500
  }
501
501
 
502
- ad tk = si;
503
- J tK = mat;
504
- tK.alpha = 1.0;
505
- RayTraceAuxiliary iR = outAux;
506
- vec4 qQ = bw(tk, ray, tK, iR);
507
- outAux.albedo = mix(gh.albedo, iR.albedo, coverage);
508
- vec3 fR = mix(gh.normal, iR.normal, coverage);
509
- outAux.normal = dot(fR, fR) > 1e-12
510
- ? normalize(fR)
502
+ ad tu = si;
503
+ J tR = mat;
504
+ tR.alpha = 1.0;
505
+ RayTraceAuxiliary iW = outAux;
506
+ vec4 qY = bw(tu, ray, tR, iW);
507
+ outAux.albedo = mix(gm.albedo, iW.albedo, coverage);
508
+ vec3 fV = mix(gm.normal, iW.normal, coverage);
509
+ outAux.normal = dot(fV, fV) > 1e-12
510
+ ? normalize(fV)
511
511
  : vec3(0.0);
512
- outAux.isBlank = gh.isBlank && iR.isBlank;
513
- return mix(back, qQ, coverage);
512
+ outAux.isBlank = gm.isBlank && iW.isBlank;
513
+ return mix(back, qY, coverage);
514
514
  }
515
515
 
516
516
 
517
517
 
518
- vec4 mn(Ray ray, out RayTraceAuxiliary outAux) {
518
+ vec4 my(Ray ray, out RayTraceAuxiliary outAux) {
519
519
 
520
520
  ad si;
521
521
  J mat;
@@ -528,13 +528,13 @@ si.mediumScattering = vec3(0.0);
528
528
  si.mediumAnisotropy = 0.0;
529
529
  #endif
530
530
 
531
- cY(ray, si, false);
532
- eT(mat, si.materialIndex, si.uv, si.uv1, si.instanceIndex);
531
+ cZ(ray, si, false);
532
+ eX(mat, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);
533
533
  si.isTransparency = mat.transmissionWeight > 0.001 || mat.subsurfaceWeight > 0.001 || mat.alpha < 0.999;
534
534
 
535
535
  #ifdef HAS_BEVEL
536
536
  if (bevelEnabled && mat.bevel > 0.0) {
537
- si.normal = mi(si, mat.bevel);
537
+ si.normal = mu(si, mat.bevel);
538
538
  }
539
539
  #endif
540
540
 
@@ -551,32 +551,32 @@ si.albedoSampled = mat.transmissionWeight > 0.5;
551
551
  }
552
552
 
553
553
  if (mat.transmissionDispersionScale > 0.001) {
554
- mat.specularIor = eK(
554
+ mat.specularIor = eN(
555
555
  bf,
556
556
  mat.specularIor,
557
557
  mat.transmissionDispersionScale,
558
558
  mat.dispersionAbbeNumber
559
559
  );
560
560
  }
561
- return iz(si, ray, mat, outAux);
561
+ return iD(si, ray, mat, outAux);
562
562
  }
563
563
 
564
564
  void main() {
565
565
 
566
- sk();
567
- ka(v_Texcoord * viewportSize, int(uint(sampleCount) ^ eg(uint(sequenceSeed))));
566
+ su();
567
+ kh(v_Texcoord * viewportSize, int(uint(sampleCount) ^ eg(uint(sequenceSeed))));
568
568
 
569
569
 
570
570
  bf = dispersionWavelengths == 1 ? 0.0 : wavelength;
571
- mk = wavelength;
571
+ mw = wavelength;
572
572
  if (dispersionWavelengths == 1 && wavelength > 0.0) {
573
573
  float channel = floor(dz(CAMERA_WAVELENGTH) * 3.0);
574
- mk = channel < 1.0 ? 650.0 : channel < 2.0 ? 510.0 : 475.0;
574
+ mw = channel < 1.0 ? 650.0 : channel < 2.0 ? 510.0 : 475.0;
575
575
  }
576
576
 
577
577
 
578
578
 
579
- Ray cam = nC();
579
+ Ray cam = nN();
580
580
 
581
581
  RayTraceAuxiliary outAux;
582
582
  outAux.albedo = vec3(0.0);
@@ -584,7 +584,7 @@ outAux.normal = vec3(0.0);
584
584
  outAux.isBlank = false;
585
585
  outAux.isShadowCatcher = false;
586
586
 
587
- vec4 aF = mn(cam, outAux);
587
+ vec4 aF = my(cam, outAux);
588
588
 
589
589
 
590
590
 
@@ -612,10 +612,10 @@ out_albedo = vec4(outAux.albedo, outAux.isBlank ? 0.0 : 1.0);
612
612
  out_normal = vec4(outAux.normal, 1.0);
613
613
 
614
614
 
615
- float jl = dot(aF.rgb, vec3(0.2126, 0.7152, 0.0722));
615
+ float jq = dot(aF.rgb, vec3(0.2126, 0.7152, 0.0722));
616
616
  out_moments = outAux.isShadowCatcher
617
617
  ? vec4(0.0)
618
- : vec4(jl, jl * jl, 1.0, 0.0);
618
+ : vec4(jq, jq * jq, 1.0, 0.0);
619
619
 
620
620
  }`
621
621
  });
@@ -1 +1 @@
1
- {"version":3,"file":"rayTrace.frag.js","sourceRoot":"","sources":["../../../src/renderer/glsl/rayTrace.frag.ts"],"names":[],"mappings":"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","sourcesContent":["import { MAX_PATH_EVENTS } from '../pathLimits.js';\nimport cameraRayGlsl from './chunks/cameraRay.glsl.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 commonGlsl from './chunks/common.glsl.js';\nimport rayTraceCore from './chunks/rayTraceCore.glsl.js';\nimport textureLinear from './chunks/textureLinear.glsl.js';\nimport materialBufferGlsl from './chunks/materialBuffer.glsl.js';\nimport intersect from './chunks/intersect.glsl.js';\nimport randGlsl from './chunks/rand.glsl.js';\nimport random from './chunks/random.glsl.js';\nimport envMap from './chunks/envMap.glsl.js';\nimport sampleMaterialGlsl from './chunks/sampleMaterial.glsl.js';\nimport sampleLightGlsl from './chunks/sampleLight.glsl.js';\nimport { FragmentShader, glsl, Shader } from '../shader.js';\nimport openPbrBsdfGlsl from './chunks/openPbrBsdf.glsl.js';\nimport samplingGlsl from './chunks/sampling.glsl.js';\nimport { isIntelMac } from '../util.js';\nimport uvProjectionGlsl from './chunks/uvProjection.glsl.js';\n\nconst doubleTransmissionCheckCode = glsl`\n#if defined(HAS_TRANSMISSION) || defined(HAS_ALPHA)\n if (!si.isTransparency && BOUNCES < 16 && depth * 2 > BOUNCES) {\n path.abort = true;\n return;\n }\n#endif\n`;\n\n// bounce fix on intel mac\n// The intel mac only have one bounce if the loop is not unrolled\n// But windows will have extremely slow shader compilation if the loop is unrolled\n// So here the code are injected separately.\nconst bounceCodeOnIntelMac = glsl`\n// Mark loop can be unrolled\nfor(int _idx_ = 0; _idx_ < BOUNCES; _idx_++) {{\n if (path.abort) {\n return vec4(path.li, path.alpha);\n }\n bounce(path, depth, si, mat, outAux);\n}}\n`;\nconst bounceCodeOnOther = glsl`\nbool isOpaque = !si.isTransparency;\nint activeBounceLimit = min(BOUNCES, bounceLimit);\nfor(int idx = 0; idx < min(BOUNCES * 3, ${MAX_PATH_EVENTS}); idx++) {\n if (isOpaque && idx > activeBounceLimit) {\n path.abort = true;\n }\n if (path.abort) {\n return vec4(path.li, path.alpha);\n }\n bounce(path, depth, si, mat, outAux);\n}\n`;\n\nexport default function createRayTraceFragmentShader() {\n const intelMac = isIntelMac();\n return new FragmentShader({\n name: 'rayTraceFrag',\n outputs: ['color', 'albedo', 'normal', 'moments'],\n defines: {\n BOUNCES: 2\n },\n uniforms: {\n cameraApertureRadius: Shader.uniform('float', 0),\n cameraFocusDistance: Shader.uniform('float', 10),\n\n viewProjectionInv: Shader.uniform('mat4'),\n viewInv: Shader.uniform('mat4'),\n transmissiveOutputAlphaMin: Shader.uniform('float'),\n openPbrEnergyLut: Shader.uniform('sampler2D'),\n\n viewportSize: Shader.uniform('vec2'),\n\n wavelength: Shader.uniform('float', 0),\n bevelEnabled: Shader.uniform('bool', true),\n dispersionWavelengths: Shader.uniform('int', 3),\n bounceLimit: Shader.uniform('int', 8)\n },\n includes: [rayTraceCore, materialBufferGlsl, intersect, random, envMap],\n main: glsl`\n${commonGlsl}\n\n${randGlsl}\n${random.main}\n\n${textureLinear}\n\n${rayTraceCore.main}\n\n${uvProjectionGlsl}\n\n${materialBufferGlsl.main}\n${intersect.main}\n${envMap.main}\n\n${samplingGlsl}\n${openPbrBsdfGlsl}\n\nfloat heroWavelength;\nfloat pathWavelength;\n\n${sampleLightGlsl}\n${sampleMaterialGlsl}\n\n${cameraRayGlsl}\nstruct RayTraceAuxiliary {\n // Denoising guides and auxiliary pixel classification.\n vec3 albedo;\n vec3 normal;\n bool isBlank;\n // The primary ray hit a shadow catcher, whose sample the catcher pass owns.\n bool isShadowCatcher;\n};\n\nvoid bounce(inout Path path, inout int depth, inout SurfaceInteraction si, inout OpenPbrResolvedMaterial mat, inout RayTraceAuxiliary outAux) {\n samplingBounce = uint(max(depth, 0));\n // The bounce will be doubled on the transmission material.\n // For other materials. We will quite early\n // TODO It is only used on Mac with AMD card. If I enabled it on windows.\n // It will cause shader compilation too slow.\n${intelMac ? doubleTransmissionCheckCode : ''}\n\n bool isShadowCatcher = mat.materialType == SHADOW_CATCHER;\n if (isShadowCatcher) {\n if (path.fromEye) {\n // Match the composed shadow with neutral receiver guides, while keeping\n // background coverage and radiance independent of the invisible ground.\n outAux.albedo = vec3(1.0);\n outAux.normal = dot(si.normal, path.ray.d) > 0.0 ? -si.normal : si.normal;\n si.hit = false;\n outAux.isShadowCatcher = true;\n }\n else {\n // The catcher belongs only to the shadow-mask pass. Keep its default\n // white material out of glossy and transmission reflections.\n#ifdef USE_ENVMAP\n if (path.isNextRefraction) {\n // The invisible catcher can sit between a transmitted camera ray and\n // the grounded skybox. Use the displayed background here instead of\n // terminating early with the raw lighting environment.\n vec4 bg = sampleBackgroundFromRay(path.ray.o, path.ray.d);\n bg.rgb = sampling_spectral_rgb_filter(bg.rgb, pathWavelength);\n float backgroundMisWeight = path.scatteringIsDelta ? 1.0\n : sampling_power_heuristic(path.scatteringPdf,\n envMapPdf(cartesianToEquirect(path.ray.d)) * envLightSelectionPmf);\n path.li += backgroundMisWeight * path.beta * bg.rgb * bg.a;\n path.alpha = max(path.alpha, bg.a);\n }\n else {\n vec2 envUv = cartesianToEquirect(path.ray.d);\n vec3 emission = textureLinear(envMap, envUv).rgb;\n emission = sampling_spectral_rgb_filter(emission, pathWavelength);\n path.li += path.beta * emission *\n sampling_power_heuristic(\n path.scatteringPdf,\n envMapPdf(envUv) * envLightSelectionPmf\n );\n }\n#else\n vec4 bg = sampleBackgroundFromRay(path.ray.o, path.ray.d);\n bg.rgb = sampling_spectral_rgb_filter(bg.rgb, pathWavelength);\n path.li += path.beta * bg.rgb * bg.a;\n#endif\n path.abort = true;\n return;\n }\n }\n\n if (!si.hit) {\n // Sample from background if first ray not hit anything.\n vec4 bg = sampleBackgroundFromRay(path.ray.o, path.ray.d);\n // Dispersion renders one additive pass per RGB wavelength. Background\n // radiance has to be split in the same way as lights and emissive\n // surfaces, otherwise the full skybox is accumulated three times.\n bg.rgb = sampling_spectral_rgb_filter(bg.rgb, pathWavelength);\n if (path.fromEye) {\n path.li = bg.rgb * bg.a;\n path.alpha = bg.a;\n // Only treat as blank pixels when the background is transparent\n outAux.isBlank = bg.a < 0.01;\n }\n else {\n Ray cam = initCameraRay(v_Texcoord + pixelJitter());\n bool towardsCam = dot(cam.d, path.ray.d) > 0.0;\n if (transmissiveOutputAlphaMin < 1.0) {\n if (towardsCam) {\n path.alpha = max(path.alpha, bg.a);\n } else {\n path.alpha = 1.0;\n }\n }\n#if !defined(USE_ENVMAP)\n // TODO treat background as a light source\n if (towardsCam) {\n path.li = path.beta * sampling_power_heuristic(path.scatteringPdf, 1.0) * bg.rgb;\n }\n#endif\n }\n path.abort = true;\n return;\n }\n\n bool sampleIgnored = false;\n if ((mat.materialType == STANDARD || mat.materialType == UNLIT)) {\n if (transmissiveOutputAlphaMin < 1.0) {\n // TODO increase the alpha when there are more bounces.\n float alpha = max(1.0 - mat.transmissionWeight, 1.0 - pow(1.0 - transmissiveOutputAlphaMin, float(depth)));\n path.alpha = max(alpha, path.alpha);\n }\n float alpha = mat.alpha;\n if (alpha < 1.0) {\n // Alpha is sampled as stochastic coverage. An accepted surface branch\n // must use full radiance weight; multiplying by alpha again is biased.\n path.alpha = max(path.alpha, alpha);\n if (hashedSample(3u) > alpha) {\n sampleIgnored = true;\n }\n }\n if (!sampleIgnored) {\n SampleMaterial(si, mat, path);\n }\n else {\n path.ray.o = si.position + path.ray.d * EPS;\n }\n }\n\n if (!si.albedoSampled && !sampleIgnored) {\n // Select denoising guides.\n if ((mat.materialType == STANDARD || mat.materialType == UNLIT) &&\n !(mat.transmissionWeight > 0.5 ||\n (mat.specularRoughness <= 0.02 && mat.baseMetalness > 0.98))) {\n // Alpha-blended decals can be skipped stochastically. In that case keep\n // looking for the first useful rough-surface guide behind the decal,\n // even though it is reached after depth zero.\n outAux.albedo = mat.baseColor;\n outAux.normal = dot(si.normal, si.position - vec3(viewInv[3])) > 0.0\n ? -si.normal\n : si.normal;\n si.albedoSampled = true;\n }\n if (depth > 4) {\n si.albedoSampled = true;\n }\n }\n\n\n // Russian Roulette sampling\n#ifdef USE_RR\n if (depth >= RR_MAX && !sampleIgnored) {\n // Max-component survival (pbrt-v4) avoids over-amplifying saturated paths.\n float maxComponent = max(max(path.beta.x, path.beta.y), path.beta.z);\n float q = max(0.0, 1.0 - maxComponent);\n if (sample1D(bounceDim(RUSSIAN_ROULETTE)) < q) {\n // TODO we force use alpha 1.0 here.\n // To avoid the glass pixels is transparent even if it's on an opaque object.\n path.alpha = 1.0;\n path.abort = true;\n }\n else {\n path.beta /= 1.0 - q;\n }\n }\n#endif\n\n if (path.abort) {\n return;\n }\n\n // Next ray hit\n intersectScene(path.ray, si, true);\n getMaterial(mat, si.materialIndex, si.uv, si.uv1, si.instanceIndex);\n si.isTransparency = mat.transmissionWeight > 0.001 || mat.subsurfaceWeight > 0.001 || mat.alpha < 0.999;\n\n // Dynamic preview only becomes spectral when the primary visible surface\n // actually disperses transmitted light. Direct background and ordinary\n // opaque materials stay full RGB and therefore remain noise-free.\n if (dispersionWavelengths == 1 && si.hit && mat.transmissionWeight > 0.001 && mat.transmissionDispersionScale > 0.001) {\n pathWavelength = heroWavelength;\n }\n if (mat.transmissionWeight > 0.001 && pathWavelength > 0.0) {\n mat.specularIor = sampling_cauchy_ior(\n pathWavelength,\n mat.specularIor,\n mat.transmissionDispersionScale,\n mat.dispersionAbbeNumber\n );\n }\n\n if (sampleIgnored) {\n return;\n }\n\n bool isAlphaOccluded = hashedSample(3u) < mat.alpha;\n#ifdef NUM_LIGHTS\n // Use light if hit the light\n LightSampleRec lightSample;\n for (int i = 0; i < NUM_LIGHTS; i++) {\n // Fetch light Data\n Light light = fetchLight(i);\n float d = intersectLight(path.ray, light, lightSample);\n bool occluded = si.hit && d > distance(si.position, path.ray.o);\n if (d != INF && !(occluded && isAlphaOccluded)) {\n lightSample.pdf *= light.selectionPmf;\n float misWeight = sampling_power_heuristic(path.scatteringPdf, lightSample.pdf);\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathWavelength);\n path.li += misWeight * path.beta * lightSample.emission;\n // TODO set alpha to 1.0 will cause some sharp edges\n path.alpha = 1.0;\n path.abort = true;\n }\n }\n#endif\n\n#ifdef USE_ENVMAP\n if (!(si.hit && isAlphaOccluded)) {\n if (path.isNextRefraction) {\n // Camera-visible transmission must use the displayed background. The\n // raw environment remains the lighting source for non-transmission rays.\n vec4 bg = sampleBackgroundFromRay(path.ray.o, path.ray.d);\n bg.rgb = sampling_spectral_rgb_filter(bg.rgb, pathWavelength);\n float backgroundMisWeight = path.scatteringIsDelta ? 1.0\n : sampling_power_heuristic(path.scatteringPdf,\n envMapPdf(cartesianToEquirect(path.ray.d)) * envLightSelectionPmf);\n path.li += backgroundMisWeight * path.beta * bg.rgb * bg.a;\n path.alpha = max(path.alpha, bg.a);\n path.abort = true;\n return;\n }\n vec2 uv = cartesianToEquirect(path.ray.d);\n vec3 emission = textureLinear(envMap, uv).rgb;\n float misWeight = sampling_power_heuristic(\n path.scatteringPdf,\n envMapPdf(uv) * envLightSelectionPmf\n );\n emission = sampling_spectral_rgb_filter(emission, pathWavelength);\n path.li += path.beta * emission * misWeight;\n\n // TODO force the min alpha to be 1 when showing envmap as background\n #if !defined(USE_BACKGROUND)\n path.alpha = 1.0;\n #endif\n path.abort = true;\n return;\n }\n#endif\n\n depth++;\n}\n\n\nvec2 bevelCubicSample(float radius, float xi) {\n float x = 0.25;\n for (int iteration = 0; iteration < 10; iteration++) {\n float x2 = x * x;\n float x3 = x2 * x;\n float oneMinusX = 1.0 - x;\n float value = 10.0 * x2 - 20.0 * x3 + 15.0 * x2 * x2 -\n 4.0 * x2 * x3 - xi;\n float derivative = 20.0 * x * oneMinusX * oneMinusX * oneMinusX;\n if (abs(value) < 1e-6 || derivative == 0.0) break;\n x = clamp(x - value / derivative, 0.0, 1.0);\n }\n float diskRadius = x * radius;\n return vec2(\n diskRadius,\n sqrt(max(radius * radius - diskRadius * diskRadius, 0.0))\n );\n}\n\nfloat bevelCubicPdf(float radius, float distanceToSource) {\n if (distanceToSource >= radius) return 0.0;\n float falloff = radius - distanceToSource;\n return falloff * falloff * falloff;\n}\n\n// Shader bevel. Usage: docs/materials.md (Renderer extensions)\nvec3 getBevelNormal(SurfaceInteraction source, float radius) {\n vec3 geometricNormal = source.faceNormal;\n if (dot(geometricNormal, source.vertexNormal) < 0.0) geometricNormal = -geometricNormal;\n vec3 tangent;\n vec3 bitangent;\n sampling_orthonormal_basis(geometricNormal, tangent, bitangent);\n vec3 normalSum = vec3(0.0);\n\n for (int sampleIndex = 0; sampleIndex < BEVEL_SAMPLES; sampleIndex++) {\n vec2 bevelRnd = sample2D(CAMERA_BEVEL_BASE + uint(sampleIndex));\n float axisSample = bevelRnd.x;\n float radialSample = bevelRnd.y;\n vec3 diskNormal = geometricNormal;\n vec3 diskTangent = tangent;\n vec3 diskBitangent = bitangent;\n float pickPdfNormal = 0.5;\n float pickPdfTangent = 0.25;\n float pickPdfBitangent = 0.25;\n if (axisSample < 0.5) {\n axisSample *= 2.0;\n }\n else if (axisSample < 0.75) {\n vec3 swapAxis = diskNormal;\n diskNormal = diskTangent;\n diskTangent = swapAxis;\n pickPdfNormal = 0.25;\n pickPdfTangent = 0.5;\n axisSample = (axisSample - 0.5) * 4.0;\n }\n else {\n vec3 swapAxis = diskNormal;\n diskNormal = diskBitangent;\n diskBitangent = swapAxis;\n pickPdfNormal = 0.25;\n pickPdfBitangent = 0.5;\n axisSample = (axisSample - 0.75) * 4.0;\n }\n\n vec2 diskSample = bevelCubicSample(radius, radialSample);\n float phi = TWOPI * axisSample;\n vec3 diskOffset = diskSample.x *\n (cos(phi) * diskTangent + sin(phi) * diskBitangent);\n Ray ray;\n initRay(\n ray,\n source.position + diskNormal * diskSample.y + diskOffset,\n -diskNormal\n );\n SurfaceInteraction hit;\n intersectSceneBevel(\n ray,\n hit,\n source.instanceIndex,\n max(2.0 * diskSample.y, EPS)\n );\n if (!hit.hit) continue;\n\n float pdfNormal = pickPdfNormal * abs(dot(diskNormal, hit.faceNormal));\n float pdfTangent = pickPdfTangent * abs(dot(diskTangent, hit.faceNormal));\n float pdfBitangent = pickPdfBitangent * abs(dot(diskBitangent, hit.faceNormal));\n float weight = pdfNormal / max(\n pdfNormal * pdfNormal + pdfTangent * pdfTangent +\n pdfBitangent * pdfBitangent,\n 1e-8\n );\n weight *= bevelCubicPdf(radius, distance(hit.position, source.position)) /\n max(bevelCubicPdf(radius, diskSample.x), 1e-8);\n normalSum += weight * hit.vertexNormal;\n }\n\n if (dot(normalSum, normalSum) <= 1e-12) return source.normal;\n vec3 bevelVertexNormal = normalize(normalSum);\n vec3 result = source.normal + bevelVertexNormal - source.vertexNormal;\n return dot(result, result) > 1e-12 ? normalize(result) : source.normal;\n}\n\nvec4 integrateOnePathSample(SurfaceInteraction si, Ray ray, OpenPbrResolvedMaterial mat, inout RayTraceAuxiliary outAux) {\n Path path;\n path.ray = ray;\n path.li = vec3(0);\n path.alpha = transmissiveOutputAlphaMin < 1.0 ? 0.0 : 1.0;\n path.beta = vec3(1.0);\n path.fromEye = true;\n path.scatteringPdf = 0.0;\n path.scatteringIsDelta = false;\n path.isNextRefraction = false;\n path.abort = false;\n int depth = 0;\n${intelMac ? bounceCodeOnIntelMac : bounceCodeOnOther}\n return vec4(path.li, path.alpha);\n}\n\nvec4 integrateOnePath(SurfaceInteraction si, Ray ray, OpenPbrResolvedMaterial mat, inout RayTraceAuxiliary outAux) {\n float coverage = clamp(mat.alpha, 0.0, 1.0);\n if (!si.hit || (mat.materialType != STANDARD && mat.materialType != UNLIT) || coverage >= 1.0) {\n return integrateOnePathSample(si, ray, mat, outAux);\n }\n\n // glTF BLEND is source-over opacity, not a physical glass boundary. Split\n // the primary ray so reflected radiance is attenuated by alpha every sample\n // while the complementary branch continues straight to the scene behind it.\n // Secondary alpha hits remain stochastic to avoid exponential path growth.\n Ray backRay = ray;\n backRay.o = si.position + ray.d * (EPS * 0.02);\n SurfaceInteraction backSi = si;\n backSi.albedoSampled = false;\n intersectScene(backRay, backSi, false);\n OpenPbrResolvedMaterial backMat;\n getMaterial(backMat, backSi.materialIndex, backSi.uv, backSi.uv1, backSi.instanceIndex);\n RayTraceAuxiliary backAux = outAux;\n if (backSi.hit && (backMat.materialType == STANDARD || backMat.materialType == UNLIT)) {\n backAux.albedo = backMat.transmissionWeight > 0.5\n ? vec3(1.0)\n : backMat.baseColor;\n backAux.normal = dot(\n backSi.normal,\n backSi.position - vec3(viewInv[3])\n ) > 0.0\n ? -backSi.normal\n : backSi.normal;\n backSi.albedoSampled = backMat.transmissionWeight > 0.5;\n }\n vec4 back = integrateOnePathSample(backSi, backRay, backMat, backAux);\n if (coverage <= 0.0) {\n outAux = backAux;\n return back;\n }\n\n SurfaceInteraction frontSi = si;\n OpenPbrResolvedMaterial frontMat = mat;\n frontMat.alpha = 1.0;\n RayTraceAuxiliary frontAux = outAux;\n vec4 front = integrateOnePathSample(frontSi, ray, frontMat, frontAux);\n outAux.albedo = mix(backAux.albedo, frontAux.albedo, coverage);\n vec3 blendedNormal = mix(backAux.normal, frontAux.normal, coverage);\n outAux.normal = dot(blendedNormal, blendedNormal) > 1e-12\n ? normalize(blendedNormal)\n : vec3(0.0);\n outAux.isBlank = backAux.isBlank && frontAux.isBlank;\n return mix(back, front, coverage);\n}\n\n// Path tracing integrator as described in\n// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Path_Tracing.html#\nvec4 integrator(Ray ray, out RayTraceAuxiliary outAux) {\n\n SurfaceInteraction si;\n OpenPbrResolvedMaterial mat;\n\n si.albedoSampled = false;\n#ifdef HAS_MEDIUM\n si.mediumType = 0;\n si.mediumExtinction = vec3(0.0);\n si.mediumScattering = vec3(0.0);\n si.mediumAnisotropy = 0.0;\n#endif\n\n intersectScene(ray, si, false);\n getMaterial(mat, si.materialIndex, si.uv, si.uv1, si.instanceIndex);\n si.isTransparency = mat.transmissionWeight > 0.001 || mat.subsurfaceWeight > 0.001 || mat.alpha < 0.999;\n\n#ifdef HAS_BEVEL\n if (bevelEnabled && mat.bevel > 0.0) {\n si.normal = getBevelNormal(si, mat.bevel);\n }\n#endif\n\n // Keep a clean first-hit fallback for denoising. Glass retains this stable\n // guide; other delta paths may replace it at their first non-delta hit.\n if (si.hit && (mat.materialType == STANDARD || mat.materialType == UNLIT)) {\n outAux.albedo = mat.transmissionWeight > 0.5 ? vec3(1.0) : mat.baseColor;\n outAux.normal = dot(si.normal, si.position - vec3(viewInv[3])) > 0.0\n ? -si.normal\n : si.normal;\n // A refracted/reflected continuation is stochastic and therefore not a\n // clean OIDN feature. Keep the stable primary glass guide instead.\n si.albedoSampled = mat.transmissionWeight > 0.5;\n }\n\n if (mat.transmissionDispersionScale > 0.001) {\n mat.specularIor = sampling_cauchy_ior(\n pathWavelength,\n mat.specularIor,\n mat.transmissionDispersionScale,\n mat.dispersionAbbeNumber\n );\n }\n return integrateOnePath(si, ray, mat, outAux);\n}\n\nvoid main() {\n\n initRandom();\n rng_initialize(v_Texcoord * viewportSize, int(uint(sampleCount) ^ sampleHash(uint(sequenceSeed))));\n\n\n pathWavelength = dispersionWavelengths == 1 ? 0.0 : wavelength;\n heroWavelength = wavelength;\n if (dispersionWavelengths == 1 && wavelength > 0.0) {\n float channel = floor(sample1D(CAMERA_WAVELENGTH) * 3.0);\n heroWavelength = channel < 1.0 ? 650.0 : channel < 2.0 ? 510.0 : 475.0;\n }\n\n // Thin lens model with depth-of-field\n // http://www.pbr-book.org/3ed-2018/Camera_Models/Projective_Camera_Models.html#TheThinLensModelandDepthofField\n Ray cam = primaryCameraRay();\n\n RayTraceAuxiliary outAux;\n outAux.albedo = vec3(0.0);\n outAux.normal = vec3(0.0);\n outAux.isBlank = false;\n outAux.isShadowCatcher = false;\n\n vec4 liAndAlpha = integrator(cam, outAux);\n\n // Clamp at Integration Level to reduce fireflies.\n // TODO Path level configuration?\n#ifdef CLAMPING\n float clamping = float(CLAMPING);\n liAndAlpha.rgb = clamp(liAndAlpha.rgb, -clamping, clamping);\n#endif\n\n // Each sample will be accumulated three times.\n if (pathWavelength > 0.0) {\n // RGB will be normalized using accumated hit in out_albedo.a\n liAndAlpha.rgb *= 3.0;\n if (dispersionWavelengths != 1) {\n // Full spectral samples use three additive passes. Preview only submits\n // one hero wavelength, so its alpha must not be divided.\n liAndAlpha.a /= 3.0;\n }\n }\n if (!(liAndAlpha.x < INF && liAndAlpha.x > -EPS)) {\n liAndAlpha = vec4(0, 0, 0, 1);\n }\n\n out_color = liAndAlpha;\n out_albedo = vec4(outAux.albedo, outAux.isBlank ? 0.0 : 1.0);\n out_normal = vec4(outAux.normal, 1.0);\n // Moments and count of the built-in denoiser's guide value. The catcher\n // pass accumulates its own samples (see shadowCatcher.frag).\n float guideValue = dot(liAndAlpha.rgb, vec3(0.2126, 0.7152, 0.0722));\n out_moments = outAux.isShadowCatcher\n ? vec4(0.0)\n : vec4(guideValue, guideValue * guideValue, 1.0, 0.0);\n\n}`\n });\n}\n"]}
1
+ {"version":3,"file":"rayTrace.frag.js","sourceRoot":"","sources":["../../../src/renderer/glsl/rayTrace.frag.ts"],"names":[],"mappings":"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","sourcesContent":["import { MAX_PATH_EVENTS } from '../pathLimits.js';\nimport cameraRayGlsl from './chunks/cameraRay.glsl.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 commonGlsl from './chunks/common.glsl.js';\nimport rayTraceCore from './chunks/rayTraceCore.glsl.js';\nimport textureLinear from './chunks/textureLinear.glsl.js';\nimport materialBufferGlsl from './chunks/materialBuffer.glsl.js';\nimport intersect from './chunks/intersect.glsl.js';\nimport randGlsl from './chunks/rand.glsl.js';\nimport random from './chunks/random.glsl.js';\nimport envMap from './chunks/envMap.glsl.js';\nimport sampleMaterialGlsl from './chunks/sampleMaterial.glsl.js';\nimport sampleLightGlsl from './chunks/sampleLight.glsl.js';\nimport { FragmentShader, glsl, Shader } from '../shader.js';\nimport openPbrBsdfGlsl from './chunks/openPbrBsdf.glsl.js';\nimport samplingGlsl from './chunks/sampling.glsl.js';\nimport { isIntelMac } from '../util.js';\nimport uvProjectionGlsl from './chunks/uvProjection.glsl.js';\n\nconst doubleTransmissionCheckCode = glsl`\n#if defined(HAS_TRANSMISSION) || defined(HAS_ALPHA)\n if (!si.isTransparency && BOUNCES < 16 && depth * 2 > BOUNCES) {\n path.abort = true;\n return;\n }\n#endif\n`;\n\n// bounce fix on intel mac\n// The intel mac only have one bounce if the loop is not unrolled\n// But windows will have extremely slow shader compilation if the loop is unrolled\n// So here the code are injected separately.\nconst bounceCodeOnIntelMac = glsl`\n// Mark loop can be unrolled\nfor(int _idx_ = 0; _idx_ < BOUNCES; _idx_++) {{\n if (path.abort) {\n return vec4(path.li, path.alpha);\n }\n bounce(path, depth, si, mat, outAux);\n}}\n`;\nconst bounceCodeOnOther = glsl`\nbool isOpaque = !si.isTransparency;\nint activeBounceLimit = min(BOUNCES, bounceLimit);\nfor(int idx = 0; idx < min(BOUNCES * 3, ${MAX_PATH_EVENTS}); idx++) {\n if (isOpaque && idx > activeBounceLimit) {\n path.abort = true;\n }\n if (path.abort) {\n return vec4(path.li, path.alpha);\n }\n bounce(path, depth, si, mat, outAux);\n}\n`;\n\nexport default function createRayTraceFragmentShader() {\n const intelMac = isIntelMac();\n return new FragmentShader({\n name: 'rayTraceFrag',\n outputs: ['color', 'albedo', 'normal', 'moments'],\n defines: {\n BOUNCES: 2\n },\n uniforms: {\n cameraApertureRadius: Shader.uniform('float', 0),\n cameraFocusDistance: Shader.uniform('float', 10),\n\n viewProjectionInv: Shader.uniform('mat4'),\n viewInv: Shader.uniform('mat4'),\n transmissiveOutputAlphaMin: Shader.uniform('float'),\n openPbrEnergyLut: Shader.uniform('sampler2D'),\n\n viewportSize: Shader.uniform('vec2'),\n\n wavelength: Shader.uniform('float', 0),\n bevelEnabled: Shader.uniform('bool', true),\n dispersionWavelengths: Shader.uniform('int', 3),\n bounceLimit: Shader.uniform('int', 8)\n },\n includes: [rayTraceCore, materialBufferGlsl, intersect, random, envMap],\n main: glsl`\n${commonGlsl}\n\n${randGlsl}\n${random.main}\n\n${textureLinear}\n\n${rayTraceCore.main}\n\n${uvProjectionGlsl}\n\n${materialBufferGlsl.main}\n${intersect.main}\n${envMap.main}\n\n${samplingGlsl}\n${openPbrBsdfGlsl}\n\nfloat heroWavelength;\nfloat pathWavelength;\n\n${sampleLightGlsl}\n${sampleMaterialGlsl}\n\n${cameraRayGlsl}\nstruct RayTraceAuxiliary {\n // Denoising guides and auxiliary pixel classification.\n vec3 albedo;\n vec3 normal;\n bool isBlank;\n // The primary ray hit a shadow catcher, whose sample the catcher pass owns.\n bool isShadowCatcher;\n};\n\nvoid bounce(inout Path path, inout int depth, inout SurfaceInteraction si, inout OpenPbrResolvedMaterial mat, inout RayTraceAuxiliary outAux) {\n samplingBounce = uint(max(depth, 0));\n // The bounce will be doubled on the transmission material.\n // For other materials. We will quite early\n // TODO It is only used on Mac with AMD card. If I enabled it on windows.\n // It will cause shader compilation too slow.\n${intelMac ? doubleTransmissionCheckCode : ''}\n\n bool isShadowCatcher = mat.materialType == SHADOW_CATCHER;\n if (isShadowCatcher) {\n if (path.fromEye) {\n // Match the composed shadow with neutral receiver guides, while keeping\n // background coverage and radiance independent of the invisible ground.\n outAux.albedo = vec3(1.0);\n outAux.normal = dot(si.normal, path.ray.d) > 0.0 ? -si.normal : si.normal;\n si.hit = false;\n outAux.isShadowCatcher = true;\n }\n else {\n // The catcher belongs only to the shadow-mask pass. Keep its default\n // white material out of glossy and transmission reflections.\n#ifdef USE_ENVMAP\n if (path.isNextRefraction) {\n // The invisible catcher can sit between a transmitted camera ray and\n // the grounded skybox. Use the displayed background here instead of\n // terminating early with the raw lighting environment.\n vec4 bg = sampleBackgroundFromRay(path.ray.o, path.ray.d);\n bg.rgb = sampling_spectral_rgb_filter(bg.rgb, pathWavelength);\n float backgroundMisWeight = path.scatteringIsDelta ? 1.0\n : sampling_power_heuristic(path.scatteringPdf,\n envMapPdf(environmentUv(path.ray.d)) * envLightSelectionPmf);\n path.li += backgroundMisWeight * path.beta * bg.rgb * bg.a;\n path.alpha = max(path.alpha, bg.a);\n }\n else {\n vec2 envUv = environmentUv(path.ray.d);\n vec3 emission = textureLinear(envMap, envUv).rgb;\n emission = sampling_spectral_rgb_filter(emission, pathWavelength);\n path.li += path.beta * emission *\n sampling_power_heuristic(\n path.scatteringPdf,\n envMapPdf(envUv) * envLightSelectionPmf\n );\n }\n#else\n vec4 bg = sampleBackgroundFromRay(path.ray.o, path.ray.d);\n bg.rgb = sampling_spectral_rgb_filter(bg.rgb, pathWavelength);\n path.li += path.beta * bg.rgb * bg.a;\n#endif\n path.abort = true;\n return;\n }\n }\n\n if (!si.hit) {\n // Sample from background if first ray not hit anything.\n vec4 bg = sampleBackgroundFromRay(path.ray.o, path.ray.d);\n // Dispersion renders one additive pass per RGB wavelength. Background\n // radiance has to be split in the same way as lights and emissive\n // surfaces, otherwise the full skybox is accumulated three times.\n bg.rgb = sampling_spectral_rgb_filter(bg.rgb, pathWavelength);\n if (path.fromEye) {\n path.li = bg.rgb * bg.a;\n path.alpha = bg.a;\n // Only treat as blank pixels when the background is transparent\n outAux.isBlank = bg.a < 0.01;\n }\n else {\n Ray cam = initCameraRay(v_Texcoord + pixelJitter());\n bool towardsCam = dot(cam.d, path.ray.d) > 0.0;\n if (transmissiveOutputAlphaMin < 1.0) {\n if (towardsCam) {\n path.alpha = max(path.alpha, bg.a);\n } else {\n path.alpha = 1.0;\n }\n }\n#if !defined(USE_ENVMAP)\n // TODO treat background as a light source\n if (towardsCam) {\n path.li = path.beta * sampling_power_heuristic(path.scatteringPdf, 1.0) * bg.rgb;\n }\n#endif\n }\n path.abort = true;\n return;\n }\n\n bool sampleIgnored = false;\n if ((mat.materialType == STANDARD || mat.materialType == UNLIT)) {\n if (transmissiveOutputAlphaMin < 1.0) {\n // TODO increase the alpha when there are more bounces.\n float alpha = max(1.0 - mat.transmissionWeight, 1.0 - pow(1.0 - transmissiveOutputAlphaMin, float(depth)));\n path.alpha = max(alpha, path.alpha);\n }\n float alpha = mat.alpha;\n if (alpha < 1.0) {\n // Alpha is sampled as stochastic coverage. An accepted surface branch\n // must use full radiance weight; multiplying by alpha again is biased.\n path.alpha = max(path.alpha, alpha);\n if (hashedSample(3u) > alpha) {\n sampleIgnored = true;\n }\n }\n if (!sampleIgnored) {\n SampleMaterial(si, mat, path);\n }\n else {\n path.ray.o = si.position + path.ray.d * EPS;\n }\n }\n\n if (!si.albedoSampled && !sampleIgnored) {\n // Select denoising guides.\n if ((mat.materialType == STANDARD || mat.materialType == UNLIT) &&\n !(mat.transmissionWeight > 0.5 ||\n (mat.specularRoughness <= 0.02 && mat.baseMetalness > 0.98))) {\n // Alpha-blended decals can be skipped stochastically. In that case keep\n // looking for the first useful rough-surface guide behind the decal,\n // even though it is reached after depth zero.\n outAux.albedo = mat.baseColor;\n outAux.normal = dot(si.normal, si.position - vec3(viewInv[3])) > 0.0\n ? -si.normal\n : si.normal;\n si.albedoSampled = true;\n }\n if (depth > 4) {\n si.albedoSampled = true;\n }\n }\n\n\n // Russian Roulette sampling\n#ifdef USE_RR\n if (depth >= RR_MAX && !sampleIgnored) {\n // Max-component survival (pbrt-v4) avoids over-amplifying saturated paths.\n float maxComponent = max(max(path.beta.x, path.beta.y), path.beta.z);\n float q = max(0.0, 1.0 - maxComponent);\n if (sample1D(bounceDim(RUSSIAN_ROULETTE)) < q) {\n // TODO we force use alpha 1.0 here.\n // To avoid the glass pixels is transparent even if it's on an opaque object.\n path.alpha = 1.0;\n path.abort = true;\n }\n else {\n path.beta /= 1.0 - q;\n }\n }\n#endif\n\n if (path.abort) {\n return;\n }\n\n // Next ray hit\n intersectScene(path.ray, si, true);\n getMaterial(mat, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);\n si.isTransparency = mat.transmissionWeight > 0.001 || mat.subsurfaceWeight > 0.001 || mat.alpha < 0.999;\n\n // Dynamic preview only becomes spectral when the primary visible surface\n // actually disperses transmitted light. Direct background and ordinary\n // opaque materials stay full RGB and therefore remain noise-free.\n if (dispersionWavelengths == 1 && si.hit && mat.transmissionWeight > 0.001 && mat.transmissionDispersionScale > 0.001) {\n pathWavelength = heroWavelength;\n }\n if (mat.transmissionWeight > 0.001 && pathWavelength > 0.0) {\n mat.specularIor = sampling_cauchy_ior(\n pathWavelength,\n mat.specularIor,\n mat.transmissionDispersionScale,\n mat.dispersionAbbeNumber\n );\n }\n\n if (sampleIgnored) {\n return;\n }\n\n bool isAlphaOccluded = hashedSample(3u) < mat.alpha;\n#ifdef NUM_LIGHTS\n // Use light if hit the light\n LightSampleRec lightSample;\n for (int i = 0; i < NUM_LIGHTS; i++) {\n // Fetch light Data\n Light light = fetchLight(i);\n float d = intersectLight(path.ray, light, lightSample);\n bool occluded = si.hit && d > distance(si.position, path.ray.o);\n if (d != INF && !(occluded && isAlphaOccluded)) {\n lightSample.pdf *= light.selectionPmf;\n float misWeight = sampling_power_heuristic(path.scatteringPdf, lightSample.pdf);\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathWavelength);\n path.li += misWeight * path.beta * lightSample.emission;\n // TODO set alpha to 1.0 will cause some sharp edges\n path.alpha = 1.0;\n path.abort = true;\n }\n }\n#endif\n\n#ifdef USE_ENVMAP\n if (!(si.hit && isAlphaOccluded)) {\n if (path.isNextRefraction) {\n // Camera-visible transmission must use the displayed background. The\n // raw environment remains the lighting source for non-transmission rays.\n vec4 bg = sampleBackgroundFromRay(path.ray.o, path.ray.d);\n bg.rgb = sampling_spectral_rgb_filter(bg.rgb, pathWavelength);\n float backgroundMisWeight = path.scatteringIsDelta ? 1.0\n : sampling_power_heuristic(path.scatteringPdf,\n envMapPdf(environmentUv(path.ray.d)) * envLightSelectionPmf);\n path.li += backgroundMisWeight * path.beta * bg.rgb * bg.a;\n path.alpha = max(path.alpha, bg.a);\n path.abort = true;\n return;\n }\n vec2 uv = environmentUv(path.ray.d);\n vec3 emission = textureLinear(envMap, uv).rgb;\n float misWeight = sampling_power_heuristic(\n path.scatteringPdf,\n envMapPdf(uv) * envLightSelectionPmf\n );\n emission = sampling_spectral_rgb_filter(emission, pathWavelength);\n path.li += path.beta * emission * misWeight;\n\n // TODO force the min alpha to be 1 when showing envmap as background\n #if !defined(USE_BACKGROUND)\n path.alpha = 1.0;\n #endif\n path.abort = true;\n return;\n }\n#endif\n\n depth++;\n}\n\n\nvec2 bevelCubicSample(float radius, float xi) {\n float x = 0.25;\n for (int iteration = 0; iteration < 10; iteration++) {\n float x2 = x * x;\n float x3 = x2 * x;\n float oneMinusX = 1.0 - x;\n float value = 10.0 * x2 - 20.0 * x3 + 15.0 * x2 * x2 -\n 4.0 * x2 * x3 - xi;\n float derivative = 20.0 * x * oneMinusX * oneMinusX * oneMinusX;\n if (abs(value) < 1e-6 || derivative == 0.0) break;\n x = clamp(x - value / derivative, 0.0, 1.0);\n }\n float diskRadius = x * radius;\n return vec2(\n diskRadius,\n sqrt(max(radius * radius - diskRadius * diskRadius, 0.0))\n );\n}\n\nfloat bevelCubicPdf(float radius, float distanceToSource) {\n if (distanceToSource >= radius) return 0.0;\n float falloff = radius - distanceToSource;\n return falloff * falloff * falloff;\n}\n\n// Shader bevel. Usage: docs/materials.md (Renderer extensions)\nvec3 getBevelNormal(SurfaceInteraction source, float radius) {\n vec3 geometricNormal = source.faceNormal;\n if (dot(geometricNormal, source.vertexNormal) < 0.0) geometricNormal = -geometricNormal;\n vec3 tangent;\n vec3 bitangent;\n sampling_orthonormal_basis(geometricNormal, tangent, bitangent);\n vec3 normalSum = vec3(0.0);\n\n for (int sampleIndex = 0; sampleIndex < BEVEL_SAMPLES; sampleIndex++) {\n vec2 bevelRnd = sample2D(CAMERA_BEVEL_BASE + uint(sampleIndex));\n float axisSample = bevelRnd.x;\n float radialSample = bevelRnd.y;\n vec3 diskNormal = geometricNormal;\n vec3 diskTangent = tangent;\n vec3 diskBitangent = bitangent;\n float pickPdfNormal = 0.5;\n float pickPdfTangent = 0.25;\n float pickPdfBitangent = 0.25;\n if (axisSample < 0.5) {\n axisSample *= 2.0;\n }\n else if (axisSample < 0.75) {\n vec3 swapAxis = diskNormal;\n diskNormal = diskTangent;\n diskTangent = swapAxis;\n pickPdfNormal = 0.25;\n pickPdfTangent = 0.5;\n axisSample = (axisSample - 0.5) * 4.0;\n }\n else {\n vec3 swapAxis = diskNormal;\n diskNormal = diskBitangent;\n diskBitangent = swapAxis;\n pickPdfNormal = 0.25;\n pickPdfBitangent = 0.5;\n axisSample = (axisSample - 0.75) * 4.0;\n }\n\n vec2 diskSample = bevelCubicSample(radius, radialSample);\n float phi = TWOPI * axisSample;\n vec3 diskOffset = diskSample.x *\n (cos(phi) * diskTangent + sin(phi) * diskBitangent);\n Ray ray;\n initRay(\n ray,\n source.position + diskNormal * diskSample.y + diskOffset,\n -diskNormal\n );\n SurfaceInteraction hit;\n intersectSceneBevel(\n ray,\n hit,\n source.instanceIndex,\n max(2.0 * diskSample.y, EPS)\n );\n if (!hit.hit) continue;\n\n float pdfNormal = pickPdfNormal * abs(dot(diskNormal, hit.faceNormal));\n float pdfTangent = pickPdfTangent * abs(dot(diskTangent, hit.faceNormal));\n float pdfBitangent = pickPdfBitangent * abs(dot(diskBitangent, hit.faceNormal));\n float weight = pdfNormal / max(\n pdfNormal * pdfNormal + pdfTangent * pdfTangent +\n pdfBitangent * pdfBitangent,\n 1e-8\n );\n weight *= bevelCubicPdf(radius, distance(hit.position, source.position)) /\n max(bevelCubicPdf(radius, diskSample.x), 1e-8);\n normalSum += weight * hit.vertexNormal;\n }\n\n if (dot(normalSum, normalSum) <= 1e-12) return source.normal;\n vec3 bevelVertexNormal = normalize(normalSum);\n vec3 result = source.normal + bevelVertexNormal - source.vertexNormal;\n return dot(result, result) > 1e-12 ? normalize(result) : source.normal;\n}\n\nvec4 integrateOnePathSample(SurfaceInteraction si, Ray ray, OpenPbrResolvedMaterial mat, inout RayTraceAuxiliary outAux) {\n Path path;\n path.ray = ray;\n path.li = vec3(0);\n path.alpha = transmissiveOutputAlphaMin < 1.0 ? 0.0 : 1.0;\n path.beta = vec3(1.0);\n path.fromEye = true;\n path.scatteringPdf = 0.0;\n path.scatteringIsDelta = false;\n path.isNextRefraction = false;\n path.abort = false;\n int depth = 0;\n${intelMac ? bounceCodeOnIntelMac : bounceCodeOnOther}\n return vec4(path.li, path.alpha);\n}\n\nvec4 integrateOnePath(SurfaceInteraction si, Ray ray, OpenPbrResolvedMaterial mat, inout RayTraceAuxiliary outAux) {\n float coverage = clamp(mat.alpha, 0.0, 1.0);\n if (!si.hit || (mat.materialType != STANDARD && mat.materialType != UNLIT) || coverage >= 1.0) {\n return integrateOnePathSample(si, ray, mat, outAux);\n }\n\n // glTF BLEND is source-over opacity, not a physical glass boundary. Split\n // the primary ray so reflected radiance is attenuated by alpha every sample\n // while the complementary branch continues straight to the scene behind it.\n // Secondary alpha hits remain stochastic to avoid exponential path growth.\n Ray backRay = ray;\n backRay.o = si.position + ray.d * (EPS * 0.02);\n SurfaceInteraction backSi = si;\n backSi.albedoSampled = false;\n intersectScene(backRay, backSi, false);\n OpenPbrResolvedMaterial backMat;\n getMaterial(backMat, backSi.materialIndex, backSi.uv, backSi.uv1, backSi.instanceIndex, backSi.vertexColor);\n RayTraceAuxiliary backAux = outAux;\n if (backSi.hit && (backMat.materialType == STANDARD || backMat.materialType == UNLIT)) {\n backAux.albedo = backMat.transmissionWeight > 0.5\n ? vec3(1.0)\n : backMat.baseColor;\n backAux.normal = dot(\n backSi.normal,\n backSi.position - vec3(viewInv[3])\n ) > 0.0\n ? -backSi.normal\n : backSi.normal;\n backSi.albedoSampled = backMat.transmissionWeight > 0.5;\n }\n vec4 back = integrateOnePathSample(backSi, backRay, backMat, backAux);\n if (coverage <= 0.0) {\n outAux = backAux;\n return back;\n }\n\n SurfaceInteraction frontSi = si;\n OpenPbrResolvedMaterial frontMat = mat;\n frontMat.alpha = 1.0;\n RayTraceAuxiliary frontAux = outAux;\n vec4 front = integrateOnePathSample(frontSi, ray, frontMat, frontAux);\n outAux.albedo = mix(backAux.albedo, frontAux.albedo, coverage);\n vec3 blendedNormal = mix(backAux.normal, frontAux.normal, coverage);\n outAux.normal = dot(blendedNormal, blendedNormal) > 1e-12\n ? normalize(blendedNormal)\n : vec3(0.0);\n outAux.isBlank = backAux.isBlank && frontAux.isBlank;\n return mix(back, front, coverage);\n}\n\n// Path tracing integrator as described in\n// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Path_Tracing.html#\nvec4 integrator(Ray ray, out RayTraceAuxiliary outAux) {\n\n SurfaceInteraction si;\n OpenPbrResolvedMaterial mat;\n\n si.albedoSampled = false;\n#ifdef HAS_MEDIUM\n si.mediumType = 0;\n si.mediumExtinction = vec3(0.0);\n si.mediumScattering = vec3(0.0);\n si.mediumAnisotropy = 0.0;\n#endif\n\n intersectScene(ray, si, false);\n getMaterial(mat, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);\n si.isTransparency = mat.transmissionWeight > 0.001 || mat.subsurfaceWeight > 0.001 || mat.alpha < 0.999;\n\n#ifdef HAS_BEVEL\n if (bevelEnabled && mat.bevel > 0.0) {\n si.normal = getBevelNormal(si, mat.bevel);\n }\n#endif\n\n // Keep a clean first-hit fallback for denoising. Glass retains this stable\n // guide; other delta paths may replace it at their first non-delta hit.\n if (si.hit && (mat.materialType == STANDARD || mat.materialType == UNLIT)) {\n outAux.albedo = mat.transmissionWeight > 0.5 ? vec3(1.0) : mat.baseColor;\n outAux.normal = dot(si.normal, si.position - vec3(viewInv[3])) > 0.0\n ? -si.normal\n : si.normal;\n // A refracted/reflected continuation is stochastic and therefore not a\n // clean OIDN feature. Keep the stable primary glass guide instead.\n si.albedoSampled = mat.transmissionWeight > 0.5;\n }\n\n if (mat.transmissionDispersionScale > 0.001) {\n mat.specularIor = sampling_cauchy_ior(\n pathWavelength,\n mat.specularIor,\n mat.transmissionDispersionScale,\n mat.dispersionAbbeNumber\n );\n }\n return integrateOnePath(si, ray, mat, outAux);\n}\n\nvoid main() {\n\n initRandom();\n rng_initialize(v_Texcoord * viewportSize, int(uint(sampleCount) ^ sampleHash(uint(sequenceSeed))));\n\n\n pathWavelength = dispersionWavelengths == 1 ? 0.0 : wavelength;\n heroWavelength = wavelength;\n if (dispersionWavelengths == 1 && wavelength > 0.0) {\n float channel = floor(sample1D(CAMERA_WAVELENGTH) * 3.0);\n heroWavelength = channel < 1.0 ? 650.0 : channel < 2.0 ? 510.0 : 475.0;\n }\n\n // Thin lens model with depth-of-field\n // http://www.pbr-book.org/3ed-2018/Camera_Models/Projective_Camera_Models.html#TheThinLensModelandDepthofField\n Ray cam = primaryCameraRay();\n\n RayTraceAuxiliary outAux;\n outAux.albedo = vec3(0.0);\n outAux.normal = vec3(0.0);\n outAux.isBlank = false;\n outAux.isShadowCatcher = false;\n\n vec4 liAndAlpha = integrator(cam, outAux);\n\n // Clamp at Integration Level to reduce fireflies.\n // TODO Path level configuration?\n#ifdef CLAMPING\n float clamping = float(CLAMPING);\n liAndAlpha.rgb = clamp(liAndAlpha.rgb, -clamping, clamping);\n#endif\n\n // Each sample will be accumulated three times.\n if (pathWavelength > 0.0) {\n // RGB will be normalized using accumated hit in out_albedo.a\n liAndAlpha.rgb *= 3.0;\n if (dispersionWavelengths != 1) {\n // Full spectral samples use three additive passes. Preview only submits\n // one hero wavelength, so its alpha must not be divided.\n liAndAlpha.a /= 3.0;\n }\n }\n if (!(liAndAlpha.x < INF && liAndAlpha.x > -EPS)) {\n liAndAlpha = vec4(0, 0, 0, 1);\n }\n\n out_color = liAndAlpha;\n out_albedo = vec4(outAux.albedo, outAux.isBlank ? 0.0 : 1.0);\n out_normal = vec4(outAux.normal, 1.0);\n // Moments and count of the built-in denoiser's guide value. The catcher\n // pass accumulates its own samples (see shadowCatcher.frag).\n float guideValue = dot(liAndAlpha.rgb, vec3(0.2126, 0.7152, 0.0722));\n out_moments = outAux.isShadowCatcher\n ? vec4(0.0)\n : vec4(guideValue, guideValue * guideValue, 1.0, 0.0);\n\n}`\n });\n}\n"]}