softbox 4.20.0 → 4.22.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.
- package/README.md +12 -3
- package/dist/{ThreePathTracingService-Dze7maGx.js → ThreePathTracingService-CcWLjj2l.js} +312 -313
- package/dist/{ThreePathTracingService-CMw8SvGp.cjs → ThreePathTracingService-Io1vC_FO.cjs} +4 -4
- package/dist/index.d.cts +49 -12
- package/dist/index.d.ts +49 -12
- package/dist/simple-viewer.cjs +95 -3
- package/dist/simple-viewer.es.js +1814 -1582
- package/dist/{unwrap-DdgS2iXe.js → smoothstep-DR5B0_eF.js} +47 -41
- package/dist/{unwrap-CuSMMFPQ.cjs → smoothstep-DUhHZEuB.cjs} +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as e, C as t, D as n,
|
|
2
|
-
import { t as
|
|
3
|
-
import * as
|
|
4
|
-
import { AdditiveBlending as
|
|
1
|
+
import { A as e, C as t, D as n, E as r, M as i, N as a, S as o, T as s, a as c, b as l, j as u, n as d, o as f, t as p, w as m, x as h, y as g } from "./smoothstep-DR5B0_eF.js";
|
|
2
|
+
import { t as _ } from "./Pass-CSHIrJrV.js";
|
|
3
|
+
import * as v from "three";
|
|
4
|
+
import { AdditiveBlending as y, BackSide as b, BufferAttribute as x, BufferGeometry as S, ByteType as C, ClampToEdgeWrapping as w, Clock as ee, Color as T, DataArrayTexture as te, DataTexture as E, DataUtils as D, DoubleSide as ne, EquirectangularReflectionMapping as re, FloatType as O, FrontSide as ie, HalfFloatType as k, IntType as ae, LinearFilter as A, LinearMipMapLinearFilter as oe, Matrix3 as se, Matrix4 as j, Mesh as ce, MeshBasicMaterial as le, NearestFilter as M, NoBlending as N, NoToneMapping as ue, NormalBlending as de, PerspectiveCamera as fe, Quaternion as pe, RGBAFormat as P, RGBAIntegerFormat as me, RGFormat as he, RGIntegerFormat as ge, RedFormat as F, RedIntegerFormat as _e, RepeatWrapping as I, Scene as ve, ShaderMaterial as ye, ShortType as be, Source as xe, Spherical as Se, UnsignedByteType as Ce, UnsignedIntType as L, UnsignedShortType as we, Vector2 as R, Vector3 as z, Vector4 as B, WebGLArrayRenderTarget as Te, WebGLRenderTarget as V } from "three";
|
|
5
5
|
//#region node_modules/three-mesh-bvh/src/webgl/VertexAttributeTexture.js
|
|
6
6
|
function Ee(e) {
|
|
7
7
|
switch (e) {
|
|
@@ -14,8 +14,8 @@ function Ee(e) {
|
|
|
14
14
|
}
|
|
15
15
|
function De(e) {
|
|
16
16
|
switch (e) {
|
|
17
|
-
case 1: return
|
|
18
|
-
case 2: return
|
|
17
|
+
case 1: return F;
|
|
18
|
+
case 2: return he;
|
|
19
19
|
case 3: return P;
|
|
20
20
|
case 4: return P;
|
|
21
21
|
}
|
|
@@ -23,9 +23,9 @@ function De(e) {
|
|
|
23
23
|
function Oe(e) {
|
|
24
24
|
switch (e) {
|
|
25
25
|
case 1: return _e;
|
|
26
|
-
case 2: return
|
|
27
|
-
case 3: return
|
|
28
|
-
case 4: return
|
|
26
|
+
case 2: return ge;
|
|
27
|
+
case 3: return me;
|
|
28
|
+
case 4: return me;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
var ke = class extends E {
|
|
@@ -46,27 +46,27 @@ var ke = class extends E {
|
|
|
46
46
|
case Uint8Array:
|
|
47
47
|
case Uint16Array:
|
|
48
48
|
case Uint32Array:
|
|
49
|
-
l =
|
|
49
|
+
l = L;
|
|
50
50
|
break;
|
|
51
51
|
case Int8Array:
|
|
52
52
|
case Int16Array:
|
|
53
53
|
case Int32Array:
|
|
54
|
-
l =
|
|
54
|
+
l = ae;
|
|
55
55
|
break;
|
|
56
56
|
}
|
|
57
57
|
let d, f, p, m, h = Ee(i);
|
|
58
58
|
switch (l) {
|
|
59
59
|
case O:
|
|
60
|
-
p = 1, f = De(i), o && c === 1 ? (m = s, h += "8", s === Uint8Array ? d = Ce : (d =
|
|
60
|
+
p = 1, f = De(i), o && c === 1 ? (m = s, h += "8", s === Uint8Array ? d = Ce : (d = C, h += "_SNORM")) : (m = Float32Array, h += "32F", d = O);
|
|
61
61
|
break;
|
|
62
|
-
case
|
|
63
|
-
h += c * 8 + "I", p = o ? 2 ** (s.BYTES_PER_ELEMENT * 8 - 1) : 1, f = Oe(i), c === 1 ? (m = Int8Array, d =
|
|
62
|
+
case ae:
|
|
63
|
+
h += c * 8 + "I", p = o ? 2 ** (s.BYTES_PER_ELEMENT * 8 - 1) : 1, f = Oe(i), c === 1 ? (m = Int8Array, d = C) : c === 2 ? (m = Int16Array, d = be) : (m = Int32Array, d = ae);
|
|
64
64
|
break;
|
|
65
|
-
case
|
|
66
|
-
h += c * 8 + "UI", p = o ? 2 ** (s.BYTES_PER_ELEMENT * 8 - 1) : 1, f = Oe(i), c === 1 ? (m = Uint8Array, d = Ce) : c === 2 ? (m = Uint16Array, d = we) : (m = Uint32Array, d =
|
|
65
|
+
case L:
|
|
66
|
+
h += c * 8 + "UI", p = o ? 2 ** (s.BYTES_PER_ELEMENT * 8 - 1) : 1, f = Oe(i), c === 1 ? (m = Uint8Array, d = Ce) : c === 2 ? (m = Uint16Array, d = we) : (m = Uint32Array, d = L);
|
|
67
67
|
break;
|
|
68
68
|
}
|
|
69
|
-
u === 3 && (f === P || f ===
|
|
69
|
+
u === 3 && (f === P || f === me) && (u = 4);
|
|
70
70
|
let g = Math.ceil(Math.sqrt(a)) || 1, _ = u * g * g, v = new m(_), y = e.normalized;
|
|
71
71
|
e.normalized = !1;
|
|
72
72
|
for (let t = 0; t < a; t++) {
|
|
@@ -77,7 +77,7 @@ var ke = class extends E {
|
|
|
77
77
|
}
|
|
78
78
|
}, Ae = class extends ke {
|
|
79
79
|
constructor() {
|
|
80
|
-
super(), this._forcedType =
|
|
80
|
+
super(), this._forcedType = L;
|
|
81
81
|
}
|
|
82
82
|
}, je = class extends ke {
|
|
83
83
|
constructor() {
|
|
@@ -93,8 +93,8 @@ var ke = class extends E {
|
|
|
93
93
|
let n = e._indirectBuffer;
|
|
94
94
|
if (this._cachedIndexAttr === null || this._cachedIndexAttr.count !== n.length) if (t.index) this._cachedIndexAttr = t.index.clone();
|
|
95
95
|
else {
|
|
96
|
-
let e =
|
|
97
|
-
this._cachedIndexAttr = new
|
|
96
|
+
let e = l(h(t));
|
|
97
|
+
this._cachedIndexAttr = new x(e, 1, !1);
|
|
98
98
|
}
|
|
99
99
|
Ne(t, n, this._cachedIndexAttr), this.index.updateFrom(this._cachedIndexAttr);
|
|
100
100
|
} else this.index.updateFrom(t.index);
|
|
@@ -111,22 +111,22 @@ function Ne(e, t, n) {
|
|
|
111
111
|
for (let e = 0; e < 3; e++) r[n + e] = i ? i[a + e] : a + e;
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
function Pe(e,
|
|
115
|
-
let
|
|
116
|
-
if (
|
|
117
|
-
let
|
|
118
|
-
for (let e = 0; e <
|
|
119
|
-
let
|
|
120
|
-
for (let t = 0; t < 3; t++) g[8 * e + 0 + t] =
|
|
121
|
-
if (m(
|
|
122
|
-
let
|
|
123
|
-
v[e * 2 + 0] =
|
|
114
|
+
function Pe(e, i, a) {
|
|
115
|
+
let c = e._roots;
|
|
116
|
+
if (c.length !== 1) throw Error("MeshBVHUniformStruct: Multi-root BVHs not supported.");
|
|
117
|
+
let l = c[0], u = new Uint16Array(l), d = new Uint32Array(l), f = new Float32Array(l), p = l.byteLength / 32, h = 2 * Math.ceil(Math.sqrt(p / 2)), g = new Float32Array(4 * h * h), _ = Math.ceil(Math.sqrt(p)), v = new Uint32Array(2 * _ * _);
|
|
118
|
+
for (let e = 0; e < p; e++) {
|
|
119
|
+
let i = e * 32 / 4, a = i * 2, c = o(i);
|
|
120
|
+
for (let t = 0; t < 3; t++) g[8 * e + 0 + t] = f[c + 0 + t], g[8 * e + 4 + t] = f[c + 3 + t];
|
|
121
|
+
if (m(a, u)) {
|
|
122
|
+
let r = t(a, u), o = s(i, d), c = n | r;
|
|
123
|
+
v[e * 2 + 0] = c, v[e * 2 + 1] = o;
|
|
124
124
|
} else {
|
|
125
|
-
let
|
|
126
|
-
v[e * 2 + 0] =
|
|
125
|
+
let t = d[i + 6], n = r(i, d);
|
|
126
|
+
v[e * 2 + 0] = n, v[e * 2 + 1] = t;
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
|
|
129
|
+
i.image.data = g, i.image.width = h, i.image.height = h, i.format = P, i.type = O, i.internalFormat = "RGBA32F", i.minFilter = M, i.magFilter = M, i.generateMipmaps = !1, i.needsUpdate = !0, i.dispose(), a.image.data = v, a.image.width = _, a.image.height = _, a.format = ge, a.type = L, a.internalFormat = "RG32UI", a.minFilter = M, a.magFilter = M, a.generateMipmaps = !1, a.needsUpdate = !0, a.dispose();
|
|
130
130
|
}
|
|
131
131
|
//#endregion
|
|
132
132
|
//#region node_modules/three-mesh-bvh/src/webgl/glsl/common_functions.glsl.js
|
|
@@ -145,11 +145,11 @@ function Re(e, t, n = 0) {
|
|
|
145
145
|
new i(r.buffer, a, e.array.length).set(e.array);
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
function
|
|
148
|
+
function H(e, t = null) {
|
|
149
149
|
let n = e.array.constructor, r = e.normalized, i = e.itemSize;
|
|
150
|
-
return new
|
|
150
|
+
return new x(new n(i * (t === null ? e.count : t)), i, r);
|
|
151
151
|
}
|
|
152
|
-
function
|
|
152
|
+
function U(e, t) {
|
|
153
153
|
if (!e && !t) return !0;
|
|
154
154
|
if (!!e != !!t) return !1;
|
|
155
155
|
let n = e.count === t.count, r = e.normalized === t.normalized, i = e.array.constructor === t.array.constructor, a = e.itemSize === t.itemSize;
|
|
@@ -185,7 +185,7 @@ function He(e, t, n) {
|
|
|
185
185
|
let r = e.attributes;
|
|
186
186
|
for (let t in r) r[t].count !== n && e.deleteAttribute(t);
|
|
187
187
|
}
|
|
188
|
-
function Ue(e, t = {}, n = new
|
|
188
|
+
function Ue(e, t = {}, n = new S()) {
|
|
189
189
|
let { useGroups: r = !1, forceUpdate: i = !1, skipAssigningAttributes: a = [], overwriteIndex: o = !0 } = t;
|
|
190
190
|
ze(e);
|
|
191
191
|
let s = e[0].index !== null, c = s ? Be(e) : -1, l = Ve(e);
|
|
@@ -198,7 +198,7 @@ function Ue(e, t = {}, n = new x()) {
|
|
|
198
198
|
}
|
|
199
199
|
if (s) {
|
|
200
200
|
let t = !1;
|
|
201
|
-
if (n.index || (n.setIndex(new
|
|
201
|
+
if (n.index || (n.setIndex(new x(new Uint32Array(c), 1, !1)), t = !0), t || o) {
|
|
202
202
|
let r = 0, o = 0, s = n.getIndex();
|
|
203
203
|
for (let n = 0, c = e.length; n < c; n++) {
|
|
204
204
|
let c = e[n], l = c.getIndex();
|
|
@@ -212,7 +212,7 @@ function Ue(e, t = {}, n = new x()) {
|
|
|
212
212
|
let r = !1, o = u[t];
|
|
213
213
|
if (!n.getAttribute(o)) {
|
|
214
214
|
let t = e[0].getAttribute(o);
|
|
215
|
-
n.setAttribute(o,
|
|
215
|
+
n.setAttribute(o, H(t, l)), r = !0;
|
|
216
216
|
}
|
|
217
217
|
let s = 0, c = n.getAttribute(o);
|
|
218
218
|
for (let t = 0, n = e.length; t < n; t++) {
|
|
@@ -233,7 +233,7 @@ function We(e, t, n) {
|
|
|
233
233
|
let s = e.getAttribute("materialIndex");
|
|
234
234
|
if (!s || s.count !== i) {
|
|
235
235
|
let t;
|
|
236
|
-
t = n.length <= 255 ? new Uint8Array(i) : new Uint16Array(i), s = new
|
|
236
|
+
t = n.length <= 255 ? new Uint8Array(i) : new Uint16Array(i), s = new x(t, 1, !1), e.deleteAttribute("materialIndex"), e.setAttribute("materialIndex", s);
|
|
237
237
|
}
|
|
238
238
|
let c = s.array;
|
|
239
239
|
for (let e = 0; e < o.length; e++) {
|
|
@@ -252,20 +252,20 @@ function Ge(e, t) {
|
|
|
252
252
|
}
|
|
253
253
|
if (!e.attributes.normal && t && t.includes("normal") && e.computeVertexNormals(), !e.attributes.uv && t && t.includes("uv")) {
|
|
254
254
|
let t = e.attributes.position.count;
|
|
255
|
-
e.setAttribute("uv", new
|
|
255
|
+
e.setAttribute("uv", new x(new Float32Array(t * 2), 2, !1));
|
|
256
256
|
}
|
|
257
257
|
if (!e.attributes.uv2 && t && t.includes("uv2")) {
|
|
258
258
|
let t = e.attributes.position.count;
|
|
259
|
-
e.setAttribute("uv2", new
|
|
259
|
+
e.setAttribute("uv2", new x(new Float32Array(t * 2), 2, !1));
|
|
260
260
|
}
|
|
261
261
|
if (!e.attributes.tangent && t && t.includes("tangent")) if (e.attributes.uv && e.attributes.normal) e.computeTangents();
|
|
262
262
|
else {
|
|
263
263
|
let t = e.attributes.position.count;
|
|
264
|
-
e.setAttribute("tangent", new
|
|
264
|
+
e.setAttribute("tangent", new x(new Float32Array(t * 4), 4, !1));
|
|
265
265
|
}
|
|
266
266
|
if (!e.attributes.color && t && t.includes("color")) {
|
|
267
267
|
let t = e.attributes.position.count, n = new Float32Array(t * 4);
|
|
268
|
-
n.fill(1), e.setAttribute("color", new
|
|
268
|
+
n.fill(1), e.setAttribute("color", new x(n, 4));
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
//#endregion
|
|
@@ -309,32 +309,32 @@ var Ye = class {
|
|
|
309
309
|
let t = e.geometry, n = (t.index ? t.index.count : t.attributes.position.count) / 3;
|
|
310
310
|
return !(this.matrixWorld.equals(e.matrixWorld) && this.geometryHash === qe(t) && this.skeletonHash === Je(e) && this.primitiveCount === n);
|
|
311
311
|
}
|
|
312
|
-
},
|
|
313
|
-
function
|
|
312
|
+
}, W = /*@__PURE__*/ new z(), G = /*@__PURE__*/ new z(), K = /*@__PURE__*/ new z(), Xe = /*@__PURE__*/ new B(), q = /*@__PURE__*/ new z(), Ze = /*@__PURE__*/ new z(), Qe = /*@__PURE__*/ new B(), $e = /*@__PURE__*/ new B(), et = /*@__PURE__*/ new j(), tt = /*@__PURE__*/ new j();
|
|
313
|
+
function nt(e, t, n) {
|
|
314
314
|
let r = e.skeleton, i = e.geometry, a = r.bones, o = r.boneInverses;
|
|
315
|
-
Qe.fromBufferAttribute(i.attributes.skinIndex, t), $e.fromBufferAttribute(i.attributes.skinWeight, t),
|
|
315
|
+
Qe.fromBufferAttribute(i.attributes.skinIndex, t), $e.fromBufferAttribute(i.attributes.skinWeight, t), et.elements.fill(0);
|
|
316
316
|
for (let e = 0; e < 4; e++) {
|
|
317
317
|
let t = $e.getComponent(e);
|
|
318
318
|
if (t !== 0) {
|
|
319
319
|
let n = Qe.getComponent(e);
|
|
320
|
-
|
|
320
|
+
tt.multiplyMatrices(a[n].matrixWorld, o[n]), it(et, tt, t);
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
|
-
return
|
|
323
|
+
return et.multiply(e.bindMatrix).premultiply(e.bindMatrixInverse), n.transformDirection(et), n;
|
|
324
324
|
}
|
|
325
|
-
function
|
|
326
|
-
|
|
325
|
+
function rt(e, t, n, r, i) {
|
|
326
|
+
q.set(0, 0, 0);
|
|
327
327
|
for (let a = 0, o = e.length; a < o; a++) {
|
|
328
328
|
let o = t[a], s = e[a];
|
|
329
|
-
o !== 0 && (Ze.fromBufferAttribute(s, r), n ?
|
|
329
|
+
o !== 0 && (Ze.fromBufferAttribute(s, r), n ? q.addScaledVector(Ze, o) : q.addScaledVector(Ze.sub(i), o));
|
|
330
330
|
}
|
|
331
|
-
i.add(
|
|
331
|
+
i.add(q);
|
|
332
332
|
}
|
|
333
|
-
function
|
|
333
|
+
function it(e, t, n) {
|
|
334
334
|
let r = e.elements, i = t.elements;
|
|
335
335
|
for (let e = 0, t = i.length; e < t; e++) r[e] += i[e] * n;
|
|
336
336
|
}
|
|
337
|
-
function
|
|
337
|
+
function at(e) {
|
|
338
338
|
let { index: t, attributes: n } = e;
|
|
339
339
|
if (t) for (let e = 0, n = t.count; e < n; e += 3) {
|
|
340
340
|
let n = t.getX(e), r = t.getX(e + 2);
|
|
@@ -349,7 +349,7 @@ function it(e) {
|
|
|
349
349
|
}
|
|
350
350
|
return e;
|
|
351
351
|
}
|
|
352
|
-
function
|
|
352
|
+
function ot(e, t = {}, n = new S()) {
|
|
353
353
|
t = {
|
|
354
354
|
applyWorldTransforms: !0,
|
|
355
355
|
attributes: [],
|
|
@@ -357,19 +357,19 @@ function at(e, t = {}, n = new x()) {
|
|
|
357
357
|
};
|
|
358
358
|
let r = e.geometry, i = t.applyWorldTransforms, a = t.attributes.includes("normal"), o = t.attributes.includes("tangent"), s = r.attributes, c = n.attributes;
|
|
359
359
|
for (let e in n.attributes) (!t.attributes.includes(e) || !(e in r.attributes)) && n.deleteAttribute(e);
|
|
360
|
-
!n.index && r.index && (n.index = r.index.clone()), c.position || n.setAttribute("position",
|
|
361
|
-
let l = s.position, u = a ? s.normal : null, d = o ? s.tangent : null, f = r.morphAttributes.position, p = r.morphAttributes.normal, m = r.morphAttributes.tangent, h = r.morphTargetsRelative, g = e.morphTargetInfluences, _ = new
|
|
360
|
+
!n.index && r.index && (n.index = r.index.clone()), c.position || n.setAttribute("position", H(s.position)), a && !c.normal && s.normal && n.setAttribute("normal", H(s.normal)), o && !c.tangent && s.tangent && n.setAttribute("tangent", H(s.tangent)), U(r.index, n.index), U(s.position, c.position), a && U(s.normal, c.normal), o && U(s.tangent, c.tangent);
|
|
361
|
+
let l = s.position, u = a ? s.normal : null, d = o ? s.tangent : null, f = r.morphAttributes.position, p = r.morphAttributes.normal, m = r.morphAttributes.tangent, h = r.morphTargetsRelative, g = e.morphTargetInfluences, _ = new se();
|
|
362
362
|
_.getNormalMatrix(e.matrixWorld), r.index && n.index.array.set(r.index.array);
|
|
363
|
-
for (let t = 0, n = s.position.count; t < n; t++)
|
|
363
|
+
for (let t = 0, n = s.position.count; t < n; t++) W.fromBufferAttribute(l, t), u && G.fromBufferAttribute(u, t), d && (Xe.fromBufferAttribute(d, t), K.fromBufferAttribute(d, t)), g && (f && rt(f, g, h, t, W), p && rt(p, g, h, t, G), m && rt(m, g, h, t, K)), e.isSkinnedMesh && (e.applyBoneTransform(t, W), u && nt(e, t, G), d && nt(e, t, K)), i && W.applyMatrix4(e.matrixWorld), c.position.setXYZ(t, W.x, W.y, W.z), u && (i && G.applyNormalMatrix(_), c.normal.setXYZ(t, G.x, G.y, G.z)), d && (i && K.transformDirection(e.matrixWorld), c.tangent.setXYZW(t, K.x, K.y, K.z, Xe.w));
|
|
364
364
|
for (let e in t.attributes) {
|
|
365
365
|
let r = t.attributes[e];
|
|
366
|
-
r === "position" || r === "tangent" || r === "normal" || !(r in s) || (c[r] || n.setAttribute(r,
|
|
366
|
+
r === "position" || r === "tangent" || r === "normal" || !(r in s) || (c[r] || n.setAttribute(r, H(s[r])), U(s[r], c[r]), Re(s[r], c[r]));
|
|
367
367
|
}
|
|
368
|
-
return e.matrixWorld.determinant() < 0 &&
|
|
368
|
+
return e.matrixWorld.determinant() < 0 && at(n), n;
|
|
369
369
|
}
|
|
370
370
|
//#endregion
|
|
371
371
|
//#region node_modules/three-gpu-pathtracer/src/core/utils/BakedGeometry.js
|
|
372
|
-
var
|
|
372
|
+
var st = class extends S {
|
|
373
373
|
constructor() {
|
|
374
374
|
super(), this.version = 0, this.hash = null, this._diff = new Ye();
|
|
375
375
|
}
|
|
@@ -377,21 +377,21 @@ var ot = class extends x {
|
|
|
377
377
|
let n = e.geometry;
|
|
378
378
|
for (let e = 0; e < t.length; e++) {
|
|
379
379
|
let r = t[e], i = n.attributes[r], a = this.attributes[r];
|
|
380
|
-
if (i && !
|
|
380
|
+
if (i && !U(i, a)) return !1;
|
|
381
381
|
}
|
|
382
382
|
return !0;
|
|
383
383
|
}
|
|
384
384
|
updateFrom(e, t) {
|
|
385
385
|
let n = this._diff;
|
|
386
|
-
return n.didChange(e) ? (
|
|
386
|
+
return n.didChange(e) ? (ot(e, t, this), n.updateFrom(e), this.version++, this.hash = `${this.uuid}_${this.version}`, !0) : !1;
|
|
387
387
|
}
|
|
388
388
|
};
|
|
389
|
-
function
|
|
389
|
+
function ct(e, t) {
|
|
390
390
|
for (let n = 0, r = e.length; n < r; n++) e[n].traverseVisible((e) => {
|
|
391
391
|
e.isMesh && t(e);
|
|
392
392
|
});
|
|
393
393
|
}
|
|
394
|
-
function
|
|
394
|
+
function lt(e) {
|
|
395
395
|
let t = [];
|
|
396
396
|
for (let n = 0, r = e.length; n < r; n++) {
|
|
397
397
|
let r = e[n];
|
|
@@ -399,16 +399,16 @@ function ct(e) {
|
|
|
399
399
|
}
|
|
400
400
|
return t;
|
|
401
401
|
}
|
|
402
|
-
function
|
|
402
|
+
function ut(e, t, n) {
|
|
403
403
|
if (e.length === 0) {
|
|
404
404
|
t.setIndex(null);
|
|
405
405
|
let e = t.attributes;
|
|
406
406
|
for (let n in e) t.deleteAttribute(n);
|
|
407
|
-
for (let e in n.attributes) t.setAttribute(n.attributes[e], new
|
|
407
|
+
for (let e in n.attributes) t.setAttribute(n.attributes[e], new x(/* @__PURE__ */ new Float32Array(), 4, !1));
|
|
408
408
|
} else Ue(e, n, t);
|
|
409
409
|
for (let e in t.attributes) t.attributes[e].needsUpdate = !0;
|
|
410
410
|
}
|
|
411
|
-
var
|
|
411
|
+
var dt = class {
|
|
412
412
|
constructor(e) {
|
|
413
413
|
this.objects = null, this.useGroups = !0, this.applyWorldTransforms = !0, this.generateMissingAttributes = !0, this.overwriteIndex = !0, this.attributes = [
|
|
414
414
|
"position",
|
|
@@ -421,14 +421,14 @@ var ut = class {
|
|
|
421
421
|
}
|
|
422
422
|
_getDummyMesh() {
|
|
423
423
|
if (!this._dummyMesh) {
|
|
424
|
-
let e = new
|
|
425
|
-
t.setAttribute("position", new
|
|
424
|
+
let e = new le(), t = new S();
|
|
425
|
+
t.setAttribute("position", new x(/* @__PURE__ */ new Float32Array(9), 3)), this._dummyMesh = new ce(t, e);
|
|
426
426
|
}
|
|
427
427
|
return this._dummyMesh;
|
|
428
428
|
}
|
|
429
429
|
_getMeshes() {
|
|
430
430
|
let e = [];
|
|
431
|
-
return
|
|
431
|
+
return ct(this.objects, (t) => {
|
|
432
432
|
e.push(t);
|
|
433
433
|
}), e.sort((e, t) => e.uuid > t.uuid ? 1 : e.uuid < t.uuid ? -1 : 0), e.length === 0 && e.push(this._getDummyMesh()), e;
|
|
434
434
|
}
|
|
@@ -441,7 +441,7 @@ var ut = class {
|
|
|
441
441
|
let a = t[i], o = a.uuid;
|
|
442
442
|
n.delete(o);
|
|
443
443
|
let s = e.get(o);
|
|
444
|
-
(!s || !s.isCompatible(a, this.attributes)) && (s && s.dispose(), s = new
|
|
444
|
+
(!s || !s.isCompatible(a, this.attributes)) && (s && s.dispose(), s = new st(), e.set(o, s)), s.updateFrom(a, r) && this.generateMissingAttributes && Ge(s, this.attributes);
|
|
445
445
|
}
|
|
446
446
|
n.forEach((t) => {
|
|
447
447
|
e.delete(t);
|
|
@@ -450,7 +450,7 @@ var ut = class {
|
|
|
450
450
|
setObjects(e) {
|
|
451
451
|
Array.isArray(e) ? this.objects = [...e] : this.objects = [e];
|
|
452
452
|
}
|
|
453
|
-
generate(e = new
|
|
453
|
+
generate(e = new S()) {
|
|
454
454
|
let { useGroups: t, overwriteIndex: n, _intermediateGeometry: r, _geometryMergeSets: i } = this, a = this._getMeshes(), o = [], s = [], c = i.get(e) || [];
|
|
455
455
|
this._updateIntermediateGeometries();
|
|
456
456
|
let l = !1;
|
|
@@ -461,7 +461,7 @@ var ut = class {
|
|
|
461
461
|
let i = c[e];
|
|
462
462
|
!i || i.uuid !== n.uuid ? (o.push(!1), l = !0) : i.version === n.version ? o.push(!0) : o.push(!1);
|
|
463
463
|
}
|
|
464
|
-
|
|
464
|
+
ut(s, e, {
|
|
465
465
|
useGroups: t,
|
|
466
466
|
forceUpdate: l,
|
|
467
467
|
skipAssigningAttributes: o,
|
|
@@ -473,14 +473,14 @@ var ut = class {
|
|
|
473
473
|
let u = 0;
|
|
474
474
|
return l ? u = 2 : o.includes(!1) && (u = 1), {
|
|
475
475
|
changeType: u,
|
|
476
|
-
materials:
|
|
476
|
+
materials: lt(a),
|
|
477
477
|
geometry: e
|
|
478
478
|
};
|
|
479
479
|
}
|
|
480
480
|
};
|
|
481
481
|
//#endregion
|
|
482
482
|
//#region node_modules/three-gpu-pathtracer/src/core/PathTracingSceneGenerator.js
|
|
483
|
-
function
|
|
483
|
+
function ft(e) {
|
|
484
484
|
let t = /* @__PURE__ */ new Set();
|
|
485
485
|
for (let n = 0, r = e.length; n < r; n++) {
|
|
486
486
|
let r = e[n];
|
|
@@ -491,7 +491,7 @@ function dt(e) {
|
|
|
491
491
|
}
|
|
492
492
|
return Array.from(t);
|
|
493
493
|
}
|
|
494
|
-
function
|
|
494
|
+
function pt(e) {
|
|
495
495
|
let t = [], n = /* @__PURE__ */ new Set();
|
|
496
496
|
for (let r = 0, i = e.length; r < i; r++) e[r].traverse((e) => {
|
|
497
497
|
e.visible && (e.isRectAreaLight || e.isSpotLight || e.isPointLight || e.isDirectionalLight) && (t.push(e), e.iesMap && n.add(e.iesMap));
|
|
@@ -501,7 +501,7 @@ function ft(e) {
|
|
|
501
501
|
iesTextures: Array.from(n).sort((e, t) => e.uuid < t.uuid ? 1 : e.uuid > t.uuid ? -1 : 0)
|
|
502
502
|
};
|
|
503
503
|
}
|
|
504
|
-
var
|
|
504
|
+
var mt = class {
|
|
505
505
|
get initialized() {
|
|
506
506
|
return !!this.bvh;
|
|
507
507
|
}
|
|
@@ -513,7 +513,7 @@ var pt = class {
|
|
|
513
513
|
"color",
|
|
514
514
|
"uv",
|
|
515
515
|
"uv2"
|
|
516
|
-
], this.generateBVH = !0, this.bvh = null, this.geometry = new
|
|
516
|
+
], this.generateBVH = !0, this.bvh = null, this.geometry = new S(), this.staticGeometryGenerator = new dt(e), this._bvhWorker = null, this._pendingGenerate = null, this._buildAsync = !1;
|
|
517
517
|
}
|
|
518
518
|
setObjects(e) {
|
|
519
519
|
this.staticGeometryGenerator.setObjects(e);
|
|
@@ -537,7 +537,7 @@ var pt = class {
|
|
|
537
537
|
e.isSkinnedMesh && e.skeleton && e.skeleton.update();
|
|
538
538
|
});
|
|
539
539
|
});
|
|
540
|
-
let a = t.generate(n), o = a.materials, s =
|
|
540
|
+
let a = t.generate(n), o = a.materials, s = ft(o), { lights: c, iesTextures: l } = pt(i);
|
|
541
541
|
if (a.changeType !== 0 && We(n, o, o), this.generateBVH) {
|
|
542
542
|
if (this.bvh instanceof Promise) throw Error("PathTracingSceneGenerator: BVH is already building asynchronously.");
|
|
543
543
|
if (a.changeType === 2) {
|
|
@@ -548,21 +548,21 @@ var pt = class {
|
|
|
548
548
|
onProgress: e,
|
|
549
549
|
...this.bvhOptions
|
|
550
550
|
};
|
|
551
|
-
this._buildAsync ? this.bvh = this._bvhWorker.generate(n, t) : this.bvh = new
|
|
551
|
+
this._buildAsync ? this.bvh = this._bvhWorker.generate(n, t) : this.bvh = new g(n, t);
|
|
552
552
|
} else a.changeType === 1 && this.bvh.refit();
|
|
553
553
|
}
|
|
554
554
|
return {
|
|
555
555
|
bvhChanged: a.changeType !== 0,
|
|
556
556
|
bvh: this.bvh,
|
|
557
|
-
lights:
|
|
558
|
-
iesTextures:
|
|
557
|
+
lights: c,
|
|
558
|
+
iesTextures: l,
|
|
559
559
|
geometry: n,
|
|
560
560
|
materials: o,
|
|
561
561
|
textures: s,
|
|
562
562
|
objects: i
|
|
563
563
|
};
|
|
564
564
|
}
|
|
565
|
-
},
|
|
565
|
+
}, ht = class extends ye {
|
|
566
566
|
set needsUpdate(e) {
|
|
567
567
|
super.needsUpdate = !0, this.dispatchEvent({ type: "recompilation" });
|
|
568
568
|
}
|
|
@@ -583,7 +583,7 @@ var pt = class {
|
|
|
583
583
|
} else if (this.defines[e] !== t) return this.defines[e] = t, this.needsUpdate = !0, !0;
|
|
584
584
|
return !1;
|
|
585
585
|
}
|
|
586
|
-
},
|
|
586
|
+
}, gt = class extends ht {
|
|
587
587
|
constructor(e) {
|
|
588
588
|
super({
|
|
589
589
|
blending: N,
|
|
@@ -599,7 +599,7 @@ var pt = class {
|
|
|
599
599
|
};
|
|
600
600
|
//#endregion
|
|
601
601
|
//#region node_modules/three-gpu-pathtracer/src/shader/rand/sobol.glsl.js
|
|
602
|
-
function
|
|
602
|
+
function _t(e = 1) {
|
|
603
603
|
let t = "uint";
|
|
604
604
|
return e > 1 && (t = "uvec" + e), `
|
|
605
605
|
${t} sobolReverseBits( ${t} x ) {
|
|
@@ -638,7 +638,7 @@ function gt(e = 1) {
|
|
|
638
638
|
}
|
|
639
639
|
`;
|
|
640
640
|
}
|
|
641
|
-
function
|
|
641
|
+
function vt(e = 1) {
|
|
642
642
|
let t = "uint", n = "float", r = "", i = ".r", a = "1u";
|
|
643
643
|
return e > 1 && (t = "uvec" + e, n = "vec" + e, r = e + "", e === 2 ? (i = ".rg", a = "uvec2( 1u, 2u )") : e === 3 ? (i = ".rgb", a = "uvec3( 1u, 2u, 3u )") : (i = "", a = "uvec4( 1u, 2u, 3u, 4u )")), `
|
|
644
644
|
|
|
@@ -660,16 +660,16 @@ function _t(e = 1) {
|
|
|
660
660
|
}
|
|
661
661
|
`;
|
|
662
662
|
}
|
|
663
|
-
var
|
|
663
|
+
var yt = `
|
|
664
664
|
|
|
665
665
|
// Utils
|
|
666
666
|
const float SOBOL_FACTOR = 1.0 / 16777216.0;
|
|
667
667
|
const uint SOBOL_MAX_POINTS = 256u * 256u;
|
|
668
668
|
|
|
669
|
-
${
|
|
670
|
-
${
|
|
671
|
-
${
|
|
672
|
-
${
|
|
669
|
+
${_t(1)}
|
|
670
|
+
${_t(2)}
|
|
671
|
+
${_t(3)}
|
|
672
|
+
${_t(4)}
|
|
673
673
|
|
|
674
674
|
uint sobolHash( uint x ) {
|
|
675
675
|
|
|
@@ -683,7 +683,7 @@ var vt = `
|
|
|
683
683
|
|
|
684
684
|
}
|
|
685
685
|
|
|
686
|
-
`,
|
|
686
|
+
`, bt = "\n\n const uint SOBOL_DIRECTIONS_1[ 32 ] = uint[ 32 ](\n 0x80000000u, 0xc0000000u, 0xa0000000u, 0xf0000000u,\n 0x88000000u, 0xcc000000u, 0xaa000000u, 0xff000000u,\n 0x80800000u, 0xc0c00000u, 0xa0a00000u, 0xf0f00000u,\n 0x88880000u, 0xcccc0000u, 0xaaaa0000u, 0xffff0000u,\n 0x80008000u, 0xc000c000u, 0xa000a000u, 0xf000f000u,\n 0x88008800u, 0xcc00cc00u, 0xaa00aa00u, 0xff00ff00u,\n 0x80808080u, 0xc0c0c0c0u, 0xa0a0a0a0u, 0xf0f0f0f0u,\n 0x88888888u, 0xccccccccu, 0xaaaaaaaau, 0xffffffffu\n );\n\n const uint SOBOL_DIRECTIONS_2[ 32 ] = uint[ 32 ](\n 0x80000000u, 0xc0000000u, 0x60000000u, 0x90000000u,\n 0xe8000000u, 0x5c000000u, 0x8e000000u, 0xc5000000u,\n 0x68800000u, 0x9cc00000u, 0xee600000u, 0x55900000u,\n 0x80680000u, 0xc09c0000u, 0x60ee0000u, 0x90550000u,\n 0xe8808000u, 0x5cc0c000u, 0x8e606000u, 0xc5909000u,\n 0x6868e800u, 0x9c9c5c00u, 0xeeee8e00u, 0x5555c500u,\n 0x8000e880u, 0xc0005cc0u, 0x60008e60u, 0x9000c590u,\n 0xe8006868u, 0x5c009c9cu, 0x8e00eeeeu, 0xc5005555u\n );\n\n const uint SOBOL_DIRECTIONS_3[ 32 ] = uint[ 32 ](\n 0x80000000u, 0xc0000000u, 0x20000000u, 0x50000000u,\n 0xf8000000u, 0x74000000u, 0xa2000000u, 0x93000000u,\n 0xd8800000u, 0x25400000u, 0x59e00000u, 0xe6d00000u,\n 0x78080000u, 0xb40c0000u, 0x82020000u, 0xc3050000u,\n 0x208f8000u, 0x51474000u, 0xfbea2000u, 0x75d93000u,\n 0xa0858800u, 0x914e5400u, 0xdbe79e00u, 0x25db6d00u,\n 0x58800080u, 0xe54000c0u, 0x79e00020u, 0xb6d00050u,\n 0x800800f8u, 0xc00c0074u, 0x200200a2u, 0x50050093u\n );\n\n const uint SOBOL_DIRECTIONS_4[ 32 ] = uint[ 32 ](\n 0x80000000u, 0x40000000u, 0x20000000u, 0xb0000000u,\n 0xf8000000u, 0xdc000000u, 0x7a000000u, 0x9d000000u,\n 0x5a800000u, 0x2fc00000u, 0xa1600000u, 0xf0b00000u,\n 0xda880000u, 0x6fc40000u, 0x81620000u, 0x40bb0000u,\n 0x22878000u, 0xb3c9c000u, 0xfb65a000u, 0xddb2d000u,\n 0x78022800u, 0x9c0b3c00u, 0x5a0fb600u, 0x2d0ddb00u,\n 0xa2878080u, 0xf3c9c040u, 0xdb65a020u, 0x6db2d0b0u,\n 0x800228f8u, 0x400b3cdcu, 0x200fb67au, 0xb00ddb9du\n );\n\n uint getMaskedSobol( uint index, uint directions[ 32 ] ) {\n\n uint X = 0u;\n for ( int bit = 0; bit < 32; bit ++ ) {\n\n uint mask = ( index >> bit ) & 1u;\n X ^= mask * directions[ bit ];\n\n }\n return X;\n\n }\n\n vec4 generateSobolPoint( uint index ) {\n\n if ( index >= SOBOL_MAX_POINTS ) {\n\n return vec4( 0.0 );\n\n }\n\n // NOTE: this sobol \"direction\" is also available but we can't write out 5 components\n // uint x = index & 0x00ffffffu;\n uint x = sobolReverseBits( getMaskedSobol( index, SOBOL_DIRECTIONS_1 ) ) & 0x00ffffffu;\n uint y = sobolReverseBits( getMaskedSobol( index, SOBOL_DIRECTIONS_2 ) ) & 0x00ffffffu;\n uint z = sobolReverseBits( getMaskedSobol( index, SOBOL_DIRECTIONS_3 ) ) & 0x00ffffffu;\n uint w = sobolReverseBits( getMaskedSobol( index, SOBOL_DIRECTIONS_4 ) ) & 0x00ffffffu;\n\n return vec4( x, y, z, w ) * SOBOL_FACTOR;\n\n }\n\n", xt = `
|
|
687
687
|
|
|
688
688
|
// Seeds
|
|
689
689
|
uniform sampler2D sobolTexture;
|
|
@@ -721,21 +721,21 @@ var vt = `
|
|
|
721
721
|
|
|
722
722
|
}
|
|
723
723
|
|
|
724
|
-
${
|
|
725
|
-
${
|
|
726
|
-
${
|
|
727
|
-
${
|
|
724
|
+
${vt(1)}
|
|
725
|
+
${vt(2)}
|
|
726
|
+
${vt(3)}
|
|
727
|
+
${vt(4)}
|
|
728
728
|
|
|
729
|
-
`,
|
|
729
|
+
`, St = class extends ht {
|
|
730
730
|
constructor() {
|
|
731
731
|
super({
|
|
732
732
|
blending: N,
|
|
733
|
-
uniforms: { resolution: { value: new
|
|
733
|
+
uniforms: { resolution: { value: new R() } },
|
|
734
734
|
vertexShader: "\n\n varying vec2 vUv;\n void main() {\n\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n }\n ",
|
|
735
735
|
fragmentShader: `
|
|
736
736
|
|
|
737
|
-
${vt}
|
|
738
737
|
${yt}
|
|
738
|
+
${bt}
|
|
739
739
|
|
|
740
740
|
varying vec2 vUv;
|
|
741
741
|
uniform vec2 resolution;
|
|
@@ -748,9 +748,9 @@ var vt = `
|
|
|
748
748
|
`
|
|
749
749
|
});
|
|
750
750
|
}
|
|
751
|
-
},
|
|
751
|
+
}, Ct = class {
|
|
752
752
|
generate(e, t = 256) {
|
|
753
|
-
let n = new
|
|
753
|
+
let n = new V(t, t, {
|
|
754
754
|
type: O,
|
|
755
755
|
format: P,
|
|
756
756
|
minFilter: M,
|
|
@@ -758,10 +758,10 @@ var vt = `
|
|
|
758
758
|
generateMipmaps: !1
|
|
759
759
|
}), r = e.getRenderTarget();
|
|
760
760
|
e.setRenderTarget(n);
|
|
761
|
-
let i = new
|
|
761
|
+
let i = new _(new St());
|
|
762
762
|
return i.material.resolution.set(t, t), i.render(e), e.setRenderTarget(r), i.dispose(), n;
|
|
763
763
|
}
|
|
764
|
-
},
|
|
764
|
+
}, wt = class extends fe {
|
|
765
765
|
set bokehSize(e) {
|
|
766
766
|
this.fStop = this.getFocalLength() / e;
|
|
767
767
|
}
|
|
@@ -774,24 +774,24 @@ var vt = `
|
|
|
774
774
|
copy(e, t) {
|
|
775
775
|
return super.copy(e, t), this.fStop = e.fStop, this.apertureBlades = e.apertureBlades, this.apertureRotation = e.apertureRotation, this.focusDistance = e.focusDistance, this.anamorphicRatio = e.anamorphicRatio, this;
|
|
776
776
|
}
|
|
777
|
-
},
|
|
777
|
+
}, Tt = class {
|
|
778
778
|
constructor() {
|
|
779
779
|
this.bokehSize = 0, this.apertureBlades = 0, this.apertureRotation = 0, this.focusDistance = 10, this.anamorphicRatio = 1;
|
|
780
780
|
}
|
|
781
781
|
updateFrom(e) {
|
|
782
|
-
e instanceof
|
|
782
|
+
e instanceof wt ? (this.bokehSize = e.bokehSize, this.apertureBlades = e.apertureBlades, this.apertureRotation = e.apertureRotation, this.focusDistance = e.focusDistance, this.anamorphicRatio = e.anamorphicRatio) : (this.bokehSize = 0, this.apertureRotation = 0, this.apertureBlades = 0, this.focusDistance = 10, this.anamorphicRatio = 1);
|
|
783
783
|
}
|
|
784
784
|
};
|
|
785
785
|
//#endregion
|
|
786
786
|
//#region node_modules/three-gpu-pathtracer/src/utils/TextureUtils.js
|
|
787
|
-
function
|
|
787
|
+
function Et(e) {
|
|
788
788
|
let t = new Uint16Array(e.length);
|
|
789
789
|
for (let n = 0, r = e.length; n < r; ++n) t[n] = D.toHalfFloat(e[n]);
|
|
790
790
|
return t;
|
|
791
791
|
}
|
|
792
792
|
//#endregion
|
|
793
793
|
//#region node_modules/three-gpu-pathtracer/src/uniforms/EquirectHdrInfoUniform.js
|
|
794
|
-
function
|
|
794
|
+
function Dt(e, t, n = 0, r = e.length) {
|
|
795
795
|
let i = n, a = n + r - 1;
|
|
796
796
|
for (; i < a;) {
|
|
797
797
|
let n = i + a >> 1;
|
|
@@ -799,10 +799,10 @@ function Et(e, t, n = 0, r = e.length) {
|
|
|
799
799
|
}
|
|
800
800
|
return i - n;
|
|
801
801
|
}
|
|
802
|
-
function
|
|
802
|
+
function Ot(e, t, n) {
|
|
803
803
|
return .2126 * e + .7152 * t + .0722 * n;
|
|
804
804
|
}
|
|
805
|
-
function
|
|
805
|
+
function kt(e, t = k) {
|
|
806
806
|
let n = e.clone();
|
|
807
807
|
n.source = new xe({ ...n.image });
|
|
808
808
|
let { width: r, height: i, data: a } = n.image, o = a;
|
|
@@ -827,36 +827,36 @@ function Ot(e, t = k) {
|
|
|
827
827
|
}
|
|
828
828
|
return n;
|
|
829
829
|
}
|
|
830
|
-
var
|
|
830
|
+
var At = class {
|
|
831
831
|
constructor() {
|
|
832
|
-
let e = new E(
|
|
832
|
+
let e = new E(Et(new Float32Array([
|
|
833
833
|
0,
|
|
834
834
|
0,
|
|
835
835
|
0,
|
|
836
836
|
0
|
|
837
837
|
])), 1, 1);
|
|
838
|
-
e.type = k, e.format = P, e.minFilter = A, e.magFilter = A, e.wrapS =
|
|
839
|
-
let t = new E(
|
|
840
|
-
t.type = k, t.format =
|
|
841
|
-
let n = new E(
|
|
838
|
+
e.type = k, e.format = P, e.minFilter = A, e.magFilter = A, e.wrapS = I, e.wrapT = I, e.generateMipmaps = !1, e.needsUpdate = !0;
|
|
839
|
+
let t = new E(Et(new Float32Array([0, 1])), 1, 2);
|
|
840
|
+
t.type = k, t.format = F, t.minFilter = A, t.magFilter = A, t.generateMipmaps = !1, t.needsUpdate = !0;
|
|
841
|
+
let n = new E(Et(new Float32Array([
|
|
842
842
|
0,
|
|
843
843
|
0,
|
|
844
844
|
1,
|
|
845
845
|
1
|
|
846
846
|
])), 2, 2);
|
|
847
|
-
n.type = k, n.format =
|
|
847
|
+
n.type = k, n.format = F, n.minFilter = A, n.magFilter = A, n.generateMipmaps = !1, n.needsUpdate = !0, this.map = e, this.marginalWeights = t, this.conditionalWeights = n, this.totalSum = 0;
|
|
848
848
|
}
|
|
849
849
|
dispose() {
|
|
850
850
|
this.marginalWeights.dispose(), this.conditionalWeights.dispose(), this.map.dispose();
|
|
851
851
|
}
|
|
852
852
|
updateFrom(e) {
|
|
853
|
-
let t =
|
|
854
|
-
t.wrapS =
|
|
853
|
+
let t = kt(e);
|
|
854
|
+
t.wrapS = I, t.wrapT = w;
|
|
855
855
|
let { width: n, height: r, data: i } = t.image, a = new Float32Array(n * r), o = new Float32Array(n * r), s = new Float32Array(r), c = new Float32Array(r), l = 0, u = 0;
|
|
856
856
|
for (let e = 0; e < r; e++) {
|
|
857
857
|
let t = 0;
|
|
858
858
|
for (let r = 0; r < n; r++) {
|
|
859
|
-
let s = e * n + r, c =
|
|
859
|
+
let s = e * n + r, c = Ot(D.fromHalfFloat(i[4 * s + 0]), D.fromHalfFloat(i[4 * s + 1]), D.fromHalfFloat(i[4 * s + 2]));
|
|
860
860
|
t += c, l += c, a[s] = c, o[s] = t;
|
|
861
861
|
}
|
|
862
862
|
if (t !== 0) for (let r = e * n, i = e * n + n; r < i; r++) a[r] /= t, o[r] /= t;
|
|
@@ -865,11 +865,11 @@ var kt = class {
|
|
|
865
865
|
if (u !== 0) for (let e = 0, t = s.length; e < t; e++) s[e] /= u, c[e] /= u;
|
|
866
866
|
let d = new Uint16Array(r), f = new Uint16Array(n * r);
|
|
867
867
|
for (let e = 0; e < r; e++) {
|
|
868
|
-
let t =
|
|
868
|
+
let t = Dt(c, (e + 1) / r);
|
|
869
869
|
d[e] = D.toHalfFloat((t + .5) / r);
|
|
870
870
|
}
|
|
871
871
|
for (let e = 0; e < r; e++) for (let t = 0; t < n; t++) {
|
|
872
|
-
let r = e * n + t, i =
|
|
872
|
+
let r = e * n + t, i = Dt(o, (t + 1) / n, e * n, n);
|
|
873
873
|
f[r] = D.toHalfFloat((i + .5) / n);
|
|
874
874
|
}
|
|
875
875
|
this.dispose();
|
|
@@ -884,24 +884,24 @@ var kt = class {
|
|
|
884
884
|
data: f
|
|
885
885
|
}, m.needsUpdate = !0, this.totalSum = l, this.map = t;
|
|
886
886
|
}
|
|
887
|
-
},
|
|
887
|
+
}, jt = 6, Mt = 0, Nt = 1, Pt = 2, Ft = 3, It = 4, J = new z(), Y = new z(), Lt = new j(), X = new pe(), Rt = new z(), Z = new z(), zt = new z(0, 1, 0), Bt = class {
|
|
888
888
|
constructor() {
|
|
889
889
|
let e = new E(/* @__PURE__ */ new Float32Array(4), 1, 1);
|
|
890
|
-
e.format = P, e.type = O, e.wrapS =
|
|
890
|
+
e.format = P, e.type = O, e.wrapS = w, e.wrapT = w, e.generateMipmaps = !1, e.minFilter = M, e.magFilter = M, this.tex = e, this.count = 0;
|
|
891
891
|
}
|
|
892
892
|
updateFrom(e, t = []) {
|
|
893
|
-
let n = this.tex, r = Math.max(e.length *
|
|
893
|
+
let n = this.tex, r = Math.max(e.length * jt, 1), i = Math.ceil(Math.sqrt(r));
|
|
894
894
|
n.image.width !== i && (n.dispose(), n.image.data = new Float32Array(i * i * 4), n.image.width = i, n.image.height = i);
|
|
895
895
|
let a = n.image.data;
|
|
896
896
|
for (let n = 0, r = e.length; n < r; n++) {
|
|
897
|
-
let r = e[n], i = n *
|
|
898
|
-
for (let e = 0; e <
|
|
897
|
+
let r = e[n], i = n * jt * 4, o = 0;
|
|
898
|
+
for (let e = 0; e < jt * 4; e++) a[i + e] = 0;
|
|
899
899
|
r.getWorldPosition(Y), a[i + o++] = Y.x, a[i + o++] = Y.y, a[i + o++] = Y.z;
|
|
900
|
-
let s =
|
|
901
|
-
if (r.isRectAreaLight && r.isCircular ? s =
|
|
900
|
+
let s = Mt;
|
|
901
|
+
if (r.isRectAreaLight && r.isCircular ? s = Nt : r.isSpotLight ? s = Pt : r.isDirectionalLight ? s = Ft : r.isPointLight && (s = It), a[i + o++] = s, a[i + o++] = r.color.r, a[i + o++] = r.color.g, a[i + o++] = r.color.b, a[i + o++] = r.intensity, r.getWorldQuaternion(X), r.isRectAreaLight) J.set(r.width, 0, 0).applyQuaternion(X), a[i + o++] = J.x, a[i + o++] = J.y, a[i + o++] = J.z, o++, Y.set(0, r.height, 0).applyQuaternion(X), a[i + o++] = Y.x, a[i + o++] = Y.y, a[i + o++] = Y.z, a[i + o++] = J.cross(Y).length() * (r.isCircular ? Math.PI / 4 : 1);
|
|
902
902
|
else if (r.isSpotLight) {
|
|
903
903
|
let e = r.radius || 0;
|
|
904
|
-
|
|
904
|
+
Rt.setFromMatrixPosition(r.matrixWorld), Z.setFromMatrixPosition(r.target.matrixWorld), Lt.lookAt(Rt, Z, zt), X.setFromRotationMatrix(Lt), J.set(1, 0, 0).applyQuaternion(X), a[i + o++] = J.x, a[i + o++] = J.y, a[i + o++] = J.z, o++, Y.set(0, 1, 0).applyQuaternion(X), a[i + o++] = Y.x, a[i + o++] = Y.y, a[i + o++] = Y.z, a[i + o++] = Math.PI * e * e, a[i + o++] = e, a[i + o++] = r.decay, a[i + o++] = r.distance, a[i + o++] = Math.cos(r.angle), a[i + o++] = Math.cos(r.angle * (1 - r.penumbra)), a[i + o++] = r.iesMap ? t.indexOf(r.iesMap) : -1;
|
|
905
905
|
} else if (r.isPointLight) {
|
|
906
906
|
let e = J.setFromMatrixPosition(r.matrixWorld);
|
|
907
907
|
a[i + o++] = e.x, a[i + o++] = e.y, a[i + o++] = e.z, o++, o += 4, o += 1, a[i + o++] = r.decay, a[i + o++] = r.distance;
|
|
@@ -917,7 +917,7 @@ var kt = class {
|
|
|
917
917
|
};
|
|
918
918
|
//#endregion
|
|
919
919
|
//#region node_modules/three-gpu-pathtracer/src/uniforms/FloatAttributeTextureArray.js
|
|
920
|
-
function
|
|
920
|
+
function Vt(e, t, n, r, i) {
|
|
921
921
|
if (t > r) throw Error();
|
|
922
922
|
let a = e.length / t, o = e.constructor.BYTES_PER_ELEMENT * 8, s = 1;
|
|
923
923
|
switch (e.constructor) {
|
|
@@ -937,7 +937,7 @@ function Bt(e, t, n, r, i) {
|
|
|
937
937
|
for (let o = 0; o < r; o++) n[i + a + o] = t >= o + 1 ? e[c + o] / s : 0;
|
|
938
938
|
}
|
|
939
939
|
}
|
|
940
|
-
var
|
|
940
|
+
var Ht = class extends te {
|
|
941
941
|
constructor() {
|
|
942
942
|
super(), this._textures = [], this.type = O, this.format = P, this.internalFormat = "RGBA32F";
|
|
943
943
|
}
|
|
@@ -947,7 +947,7 @@ var Vt = class extends T {
|
|
|
947
947
|
let r = n.image, i = this.image;
|
|
948
948
|
if (r.width !== i.width || r.height !== i.height) throw Error("FloatAttributeTextureArray: Attribute must be the same dimensions when updating single layer.");
|
|
949
949
|
let { width: a, height: o, data: s } = i, c = a * o * 4 * e, l = t.itemSize;
|
|
950
|
-
l === 3 && (l = 4),
|
|
950
|
+
l === 3 && (l = 4), Vt(n.image.data, l, s, 4, c), this.dispose(), this.needsUpdate = !0;
|
|
951
951
|
}
|
|
952
952
|
setAttributes(e) {
|
|
953
953
|
let t = e[0].count, n = e.length;
|
|
@@ -964,11 +964,11 @@ var Vt = class extends T {
|
|
|
964
964
|
let { data: o, width: s, height: c } = a;
|
|
965
965
|
for (let t = 0, i = n; t < i; t++) {
|
|
966
966
|
let n = r[t], i = s * c * 4 * t, a = e[t].itemSize;
|
|
967
|
-
a === 3 && (a = 4),
|
|
967
|
+
a === 3 && (a = 4), Vt(n.image.data, a, o, 4, i);
|
|
968
968
|
}
|
|
969
969
|
this.dispose(), this.needsUpdate = !0;
|
|
970
970
|
}
|
|
971
|
-
},
|
|
971
|
+
}, Ut = class extends Ht {
|
|
972
972
|
updateNormalAttribute(e) {
|
|
973
973
|
this.updateAttribute(0, e);
|
|
974
974
|
}
|
|
@@ -992,25 +992,25 @@ var Vt = class extends T {
|
|
|
992
992
|
};
|
|
993
993
|
//#endregion
|
|
994
994
|
//#region node_modules/three-gpu-pathtracer/src/core/utils/sceneUpdateUtils.js
|
|
995
|
-
function
|
|
995
|
+
function Wt(e, t) {
|
|
996
996
|
return e.uuid < t.uuid ? 1 : e.uuid > t.uuid ? -1 : 0;
|
|
997
997
|
}
|
|
998
|
-
function
|
|
998
|
+
function Gt(e) {
|
|
999
999
|
return `${e.source.uuid}:${e.colorSpace}`;
|
|
1000
1000
|
}
|
|
1001
|
-
function
|
|
1001
|
+
function Kt(e) {
|
|
1002
1002
|
let t = /* @__PURE__ */ new Set(), n = [];
|
|
1003
1003
|
for (let r = 0, i = e.length; r < i; r++) {
|
|
1004
|
-
let i = e[r], a =
|
|
1004
|
+
let i = e[r], a = Gt(i);
|
|
1005
1005
|
t.has(a) || (t.add(a), n.push(i));
|
|
1006
1006
|
}
|
|
1007
1007
|
return n;
|
|
1008
1008
|
}
|
|
1009
|
-
function
|
|
1009
|
+
function qt(e) {
|
|
1010
1010
|
let t = e.map((e) => e.iesMap || null).filter((e) => e), n = new Set(t);
|
|
1011
|
-
return Array.from(n).sort(
|
|
1011
|
+
return Array.from(n).sort(Wt);
|
|
1012
1012
|
}
|
|
1013
|
-
function
|
|
1013
|
+
function Jt(e) {
|
|
1014
1014
|
let t = /* @__PURE__ */ new Set();
|
|
1015
1015
|
for (let n = 0, r = e.length; n < r; n++) {
|
|
1016
1016
|
let r = e[n];
|
|
@@ -1019,17 +1019,17 @@ function qt(e) {
|
|
|
1019
1019
|
n && n.isTexture && t.add(n);
|
|
1020
1020
|
}
|
|
1021
1021
|
}
|
|
1022
|
-
return
|
|
1022
|
+
return Kt(Array.from(t)).sort(Wt);
|
|
1023
1023
|
}
|
|
1024
|
-
function
|
|
1024
|
+
function Yt(e) {
|
|
1025
1025
|
let t = [];
|
|
1026
1026
|
return e.traverse((e) => {
|
|
1027
1027
|
e.visible && (e.isRectAreaLight || e.isSpotLight || e.isPointLight || e.isDirectionalLight) && t.push(e);
|
|
1028
|
-
}), t.sort(
|
|
1028
|
+
}), t.sort(Wt);
|
|
1029
1029
|
}
|
|
1030
1030
|
//#endregion
|
|
1031
1031
|
//#region node_modules/three-gpu-pathtracer/src/uniforms/MaterialsTexture.js
|
|
1032
|
-
var
|
|
1032
|
+
var Xt = 45, Zt = Xt * 4, Qt = class {
|
|
1033
1033
|
constructor() {
|
|
1034
1034
|
this._features = {};
|
|
1035
1035
|
}
|
|
@@ -1042,14 +1042,14 @@ var Yt = 45, Xt = Yt * 4, Zt = class {
|
|
|
1042
1042
|
reset() {
|
|
1043
1043
|
this._features = {};
|
|
1044
1044
|
}
|
|
1045
|
-
},
|
|
1045
|
+
}, $t = class extends E {
|
|
1046
1046
|
constructor() {
|
|
1047
|
-
super(/* @__PURE__ */ new Float32Array(4), 1, 1), this.format = P, this.type = O, this.wrapS =
|
|
1047
|
+
super(/* @__PURE__ */ new Float32Array(4), 1, 1), this.format = P, this.type = O, this.wrapS = w, this.wrapT = w, this.minFilter = M, this.magFilter = M, this.generateMipmaps = !1, this.features = new Qt();
|
|
1048
1048
|
}
|
|
1049
1049
|
updateFrom(e, t) {
|
|
1050
1050
|
function n(e, t, n = -1) {
|
|
1051
1051
|
if (t in e && e[t]) {
|
|
1052
|
-
let n =
|
|
1052
|
+
let n = Gt(e[t]);
|
|
1053
1053
|
return u[n];
|
|
1054
1054
|
} else return n;
|
|
1055
1055
|
}
|
|
@@ -1065,8 +1065,8 @@ var Yt = 45, Xt = Yt * 4, Zt = class {
|
|
|
1065
1065
|
}
|
|
1066
1066
|
return 8;
|
|
1067
1067
|
}
|
|
1068
|
-
let a = 0, o = e.length *
|
|
1069
|
-
for (let e = 0, n = t.length; e < n; e++) u[
|
|
1068
|
+
let a = 0, o = e.length * Xt, s = Math.ceil(Math.sqrt(o)) || 1, { image: c, features: l } = this, u = {};
|
|
1069
|
+
for (let e = 0, n = t.length; e < n; e++) u[Gt(t[e])] = e;
|
|
1070
1070
|
c.width !== s && (this.dispose(), c.data = new Float32Array(s * s * 4), c.width = s, c.height = s);
|
|
1071
1071
|
let d = c.data;
|
|
1072
1072
|
l.reset();
|
|
@@ -1074,8 +1074,8 @@ var Yt = 45, Xt = Yt * 4, Zt = class {
|
|
|
1074
1074
|
let o = e[t];
|
|
1075
1075
|
if (o.isFogVolumeMaterial) {
|
|
1076
1076
|
l.setUsed("FOG");
|
|
1077
|
-
for (let e = 0; e <
|
|
1078
|
-
d[a + 0 + 0] = o.color.r, d[a + 0 + 1] = o.color.g, d[a + 0 + 2] = o.color.b, d[a + 8 + 3] = r(o, "emissiveIntensity", 0), d[a + 12 + 0] = o.emissive.r, d[a + 12 + 1] = o.emissive.g, d[a + 12 + 2] = o.emissive.b, d[a + 52 + 1] = o.density, d[a + 52 + 3] = 0, d[a + 56 + 2] = 4, a +=
|
|
1077
|
+
for (let e = 0; e < Zt; e++) d[a + e] = 0;
|
|
1078
|
+
d[a + 0 + 0] = o.color.r, d[a + 0 + 1] = o.color.g, d[a + 0 + 2] = o.color.b, d[a + 8 + 3] = r(o, "emissiveIntensity", 0), d[a + 12 + 0] = o.emissive.r, d[a + 12 + 1] = o.emissive.g, d[a + 12 + 2] = o.emissive.b, d[a + 52 + 1] = o.density, d[a + 52 + 3] = 0, d[a + 56 + 2] = 4, a += Zt;
|
|
1079
1079
|
continue;
|
|
1080
1080
|
}
|
|
1081
1081
|
d[a++] = o.color.r, d[a++] = o.color.g, d[a++] = o.color.b, d[a++] = n(o, "map"), d[a++] = r(o, "metalness", 0), d[a++] = n(o, "metalnessMap"), d[a++] = r(o, "roughness", 0), d[a++] = n(o, "roughnessMap"), d[a++] = r(o, "ior", 1.5), d[a++] = r(o, "transmission", 0), d[a++] = n(o, "transmissionMap"), d[a++] = r(o, "emissiveIntensity", 0), "emissive" in o ? (d[a++] = o.emissive.r, d[a++] = o.emissive.g, d[a++] = o.emissive.b) : (d[a++] = 0, d[a++] = 0, d[a++] = 0), d[a++] = n(o, "emissiveMap"), d[a++] = n(o, "normalMap"), "normalScale" in o ? (d[a++] = o.normalScale.x, d[a++] = o.normalScale.y) : (d[a++] = 1, d[a++] = 1), d[a++] = r(o, "clearcoat", 0), d[a++] = n(o, "clearcoatMap"), d[a++] = r(o, "clearcoatRoughness", 0), d[a++] = n(o, "clearcoatRoughnessMap"), d[a++] = n(o, "clearcoatNormalMap"), "clearcoatNormalScale" in o ? (d[a++] = o.clearcoatNormalScale.x, d[a++] = o.clearcoatNormalScale.y) : (d[a++] = 1, d[a++] = 1), a++, d[a++] = r(o, "sheen", 0), "sheenColor" in o ? (d[a++] = o.sheenColor.r, d[a++] = o.sheenColor.g, d[a++] = o.sheenColor.b) : (d[a++] = 0, d[a++] = 0, d[a++] = 0), d[a++] = n(o, "sheenColorMap"), d[a++] = r(o, "sheenRoughness", 0), d[a++] = n(o, "sheenRoughnessMap"), d[a++] = n(o, "iridescenceMap"), d[a++] = n(o, "iridescenceThicknessMap"), d[a++] = r(o, "iridescence", 0), d[a++] = r(o, "iridescenceIOR", 1.3);
|
|
@@ -1084,13 +1084,13 @@ var Yt = 45, Xt = Yt * 4, Zt = class {
|
|
|
1084
1084
|
let c = r(o, "thickness", 0) === 0 && r(o, "attenuationDistance", Infinity) === Infinity;
|
|
1085
1085
|
if (d[a++] = Number(c), a++, "attenuationColor" in o ? (d[a++] = o.attenuationColor.r, d[a++] = o.attenuationColor.g, d[a++] = o.attenuationColor.b) : (d[a++] = 1, d[a++] = 1, d[a++] = 1), d[a++] = r(o, "attenuationDistance", Infinity), d[a++] = n(o, "alphaMap"), d[a++] = o.opacity, d[a++] = o.alphaTest, !c && o.transmission > 0) d[a++] = 0;
|
|
1086
1086
|
else switch (o.side) {
|
|
1087
|
-
case
|
|
1087
|
+
case ie:
|
|
1088
1088
|
d[a++] = 1;
|
|
1089
1089
|
break;
|
|
1090
|
-
case
|
|
1090
|
+
case b:
|
|
1091
1091
|
d[a++] = -1;
|
|
1092
1092
|
break;
|
|
1093
|
-
case
|
|
1093
|
+
case ne:
|
|
1094
1094
|
d[a++] = 0;
|
|
1095
1095
|
break;
|
|
1096
1096
|
}
|
|
@@ -1099,47 +1099,47 @@ var Yt = 45, Xt = Yt * 4, Zt = class {
|
|
|
1099
1099
|
let f = Ke(d.buffer);
|
|
1100
1100
|
return this.hash === f ? !1 : (this.hash = f, this.needsUpdate = !0, !0);
|
|
1101
1101
|
}
|
|
1102
|
-
},
|
|
1103
|
-
function
|
|
1102
|
+
}, en = new T();
|
|
1103
|
+
function tn(e) {
|
|
1104
1104
|
return e ? `${e.uuid}:${e.version}` : null;
|
|
1105
1105
|
}
|
|
1106
|
-
function
|
|
1106
|
+
function nn(e, t) {
|
|
1107
1107
|
for (let n in t) n in e && (e[n] = t[n]);
|
|
1108
1108
|
}
|
|
1109
|
-
var
|
|
1109
|
+
var rn = class extends Te {
|
|
1110
1110
|
constructor(e, t, n) {
|
|
1111
1111
|
let r = {
|
|
1112
1112
|
format: P,
|
|
1113
1113
|
type: Ce,
|
|
1114
1114
|
minFilter: A,
|
|
1115
1115
|
magFilter: A,
|
|
1116
|
-
wrapS:
|
|
1117
|
-
wrapT:
|
|
1116
|
+
wrapS: I,
|
|
1117
|
+
wrapT: I,
|
|
1118
1118
|
generateMipmaps: !1,
|
|
1119
1119
|
...n
|
|
1120
1120
|
};
|
|
1121
|
-
super(e, t, 1, r),
|
|
1121
|
+
super(e, t, 1, r), nn(this.texture, r), this.texture.setTextures = (...e) => {
|
|
1122
1122
|
this.setTextures(...e);
|
|
1123
1123
|
}, this.hashes = [null];
|
|
1124
|
-
let i = new
|
|
1124
|
+
let i = new _(new an());
|
|
1125
1125
|
this.fsQuad = i;
|
|
1126
1126
|
}
|
|
1127
1127
|
setTextures(e, t, n = this.width, r = this.height) {
|
|
1128
1128
|
let i = e.getRenderTarget(), a = e.toneMapping, o = e.getClearAlpha();
|
|
1129
|
-
e.getClearColor(
|
|
1129
|
+
e.getClearColor(en);
|
|
1130
1130
|
let s = t.length || 1;
|
|
1131
|
-
(n !== this.width || r !== this.height || this.depth !== s) && (this.setSize(n, r, s), this.hashes = Array(s).fill(null)), e.setClearColor(0, 0), e.toneMapping =
|
|
1131
|
+
(n !== this.width || r !== this.height || this.depth !== s) && (this.setSize(n, r, s), this.hashes = Array(s).fill(null)), e.setClearColor(0, 0), e.toneMapping = ue;
|
|
1132
1132
|
let c = this.fsQuad, l = this.hashes, u = !1;
|
|
1133
1133
|
for (let n = 0, r = s; n < r; n++) {
|
|
1134
|
-
let r = t[n], i =
|
|
1134
|
+
let r = t[n], i = tn(r);
|
|
1135
1135
|
r && (l[n] !== i || r.isWebGLRenderTarget) && (r.matrixAutoUpdate = !1, r.matrix.identity(), c.material.map = r, e.setRenderTarget(this, n), c.render(e), r.updateMatrix(), r.matrixAutoUpdate = !0, l[n] = i, u = !0);
|
|
1136
1136
|
}
|
|
1137
|
-
return c.material.map = null, e.setClearColor(
|
|
1137
|
+
return c.material.map = null, e.setClearColor(en, o), e.setRenderTarget(i), e.toneMapping = a, u;
|
|
1138
1138
|
}
|
|
1139
1139
|
dispose() {
|
|
1140
1140
|
super.dispose(), this.fsQuad.dispose();
|
|
1141
1141
|
}
|
|
1142
|
-
},
|
|
1142
|
+
}, an = class extends ye {
|
|
1143
1143
|
get map() {
|
|
1144
1144
|
return this.uniforms.map.value;
|
|
1145
1145
|
}
|
|
@@ -1156,14 +1156,14 @@ var nn = class extends Te {
|
|
|
1156
1156
|
};
|
|
1157
1157
|
//#endregion
|
|
1158
1158
|
//#region node_modules/three-gpu-pathtracer/src/uniforms/stratified/StratifiedSampler.js
|
|
1159
|
-
function
|
|
1159
|
+
function on(e, t = Math.random()) {
|
|
1160
1160
|
for (let n = e.length - 1; n > 0; n--) {
|
|
1161
1161
|
let r = Math.floor(t() * (n + 1)), i = e[n];
|
|
1162
1162
|
e[n] = e[r], e[r] = i;
|
|
1163
1163
|
}
|
|
1164
1164
|
return e;
|
|
1165
1165
|
}
|
|
1166
|
-
var
|
|
1166
|
+
var sn = class {
|
|
1167
1167
|
constructor(e, t, n = Math.random) {
|
|
1168
1168
|
let r = e ** t, i = new Uint16Array(r), a = r;
|
|
1169
1169
|
for (let e = 0; e < r; e++) i[e] = e;
|
|
@@ -1174,19 +1174,19 @@ var on = class {
|
|
|
1174
1174
|
a = 0;
|
|
1175
1175
|
}, this.next = function() {
|
|
1176
1176
|
let { samples: r } = this;
|
|
1177
|
-
a >= i.length && (
|
|
1177
|
+
a >= i.length && (on(i, n), this.reshuffle());
|
|
1178
1178
|
let o = i[a++];
|
|
1179
1179
|
for (let i = 0; i < t; i++) r[i] = (o % e + n()) / e, o = Math.floor(o / e);
|
|
1180
1180
|
return r;
|
|
1181
1181
|
};
|
|
1182
1182
|
}
|
|
1183
|
-
},
|
|
1183
|
+
}, cn = class {
|
|
1184
1184
|
constructor(e, t, n = Math.random) {
|
|
1185
1185
|
let r = 0;
|
|
1186
1186
|
for (let e of t) r += e;
|
|
1187
1187
|
let i = new Float32Array(r), a = [], o = 0;
|
|
1188
1188
|
for (let r of t) {
|
|
1189
|
-
let t = new
|
|
1189
|
+
let t = new sn(e, r, n);
|
|
1190
1190
|
t.samples = new Float32Array(i.buffer, o, t.samples.length), o += t.samples.length * 4, a.push(t);
|
|
1191
1191
|
}
|
|
1192
1192
|
this.samples = i, this.strataCount = e, this.next = function() {
|
|
@@ -1198,7 +1198,7 @@ var on = class {
|
|
|
1198
1198
|
for (let e of a) e.reset();
|
|
1199
1199
|
};
|
|
1200
1200
|
}
|
|
1201
|
-
},
|
|
1201
|
+
}, ln = class {
|
|
1202
1202
|
constructor(e = 0) {
|
|
1203
1203
|
this.m = 2147483648, this.a = 1103515245, this.c = 12345, this.seed = e;
|
|
1204
1204
|
}
|
|
@@ -1208,14 +1208,14 @@ var on = class {
|
|
|
1208
1208
|
nextFloat() {
|
|
1209
1209
|
return this.nextInt() / (this.m - 1);
|
|
1210
1210
|
}
|
|
1211
|
-
},
|
|
1211
|
+
}, un = class extends E {
|
|
1212
1212
|
constructor(e = 1, t = 1, n = 8) {
|
|
1213
|
-
super(/* @__PURE__ */ new Float32Array(1), 1, 1, P, O), this.minFilter = M, this.magFilter = M, this.strata = n, this.sampler = null, this.generator = new
|
|
1213
|
+
super(/* @__PURE__ */ new Float32Array(1), 1, 1, P, O), this.minFilter = M, this.magFilter = M, this.strata = n, this.sampler = null, this.generator = new ln(), this.stableNoise = !1, this.random = () => this.stableNoise ? this.generator.nextFloat() : Math.random(), this.init(e, t, n);
|
|
1214
1214
|
}
|
|
1215
1215
|
init(e = this.image.height, t = this.image.width, n = this.strata) {
|
|
1216
1216
|
let { image: r } = this;
|
|
1217
1217
|
if (r.width === t && r.height === e && this.sampler !== null) return;
|
|
1218
|
-
let i = new
|
|
1218
|
+
let i = new cn(n, Array(e * t).fill(4), this.random);
|
|
1219
1219
|
r.width = t, r.height = e, r.data = i.samples, this.sampler = i, this.dispose(), this.next();
|
|
1220
1220
|
}
|
|
1221
1221
|
next() {
|
|
@@ -1227,19 +1227,19 @@ var on = class {
|
|
|
1227
1227
|
};
|
|
1228
1228
|
//#endregion
|
|
1229
1229
|
//#region node_modules/three-gpu-pathtracer/src/textures/blueNoise/utils.js
|
|
1230
|
-
function
|
|
1230
|
+
function dn(e, t = Math.random) {
|
|
1231
1231
|
for (let n = e.length - 1; n > 0; n--) {
|
|
1232
1232
|
let r = ~~((t() - 1e-6) * n), i = e[n];
|
|
1233
1233
|
e[n] = e[r], e[r] = i;
|
|
1234
1234
|
}
|
|
1235
1235
|
}
|
|
1236
|
-
function
|
|
1236
|
+
function fn(e, t) {
|
|
1237
1237
|
e.fill(0);
|
|
1238
1238
|
for (let n = 0; n < t; n++) e[n] = 1;
|
|
1239
1239
|
}
|
|
1240
1240
|
//#endregion
|
|
1241
1241
|
//#region node_modules/three-gpu-pathtracer/src/textures/blueNoise/BlueNoiseSamples.js
|
|
1242
|
-
var
|
|
1242
|
+
var pn = class {
|
|
1243
1243
|
constructor(e) {
|
|
1244
1244
|
this.count = 0, this.size = -1, this.sigma = -1, this.radius = -1, this.lookupTable = null, this.score = null, this.binaryPattern = null, this.resize(e), this.setSigma(1.5);
|
|
1245
1245
|
}
|
|
@@ -1305,15 +1305,15 @@ var fn = class {
|
|
|
1305
1305
|
copy(e) {
|
|
1306
1306
|
this.resize(e.size), this.score.set(e.score), this.binaryPattern.set(e.binaryPattern), this.setSigma(e.sigma), this.count = e.count;
|
|
1307
1307
|
}
|
|
1308
|
-
},
|
|
1308
|
+
}, mn = class {
|
|
1309
1309
|
constructor() {
|
|
1310
|
-
this.random = Math.random, this.sigma = 1.5, this.size = 64, this.majorityPointsRatio = .1, this.samples = new
|
|
1310
|
+
this.random = Math.random, this.sigma = 1.5, this.size = 64, this.majorityPointsRatio = .1, this.samples = new pn(1), this.savedSamples = new pn(1);
|
|
1311
1311
|
}
|
|
1312
1312
|
generate() {
|
|
1313
1313
|
let { samples: e, savedSamples: t, sigma: n, majorityPointsRatio: r, size: i } = this;
|
|
1314
1314
|
e.resize(i), e.setSigma(n);
|
|
1315
1315
|
let a = Math.floor(i * i * r), o = e.binaryPattern;
|
|
1316
|
-
|
|
1316
|
+
fn(o, a), dn(o, this.random);
|
|
1317
1317
|
for (let t = 0, n = o.length; t < n; t++) o[t] === 1 && e.addPointIndex(t);
|
|
1318
1318
|
for (;;) {
|
|
1319
1319
|
let t = e.findCluster();
|
|
@@ -1349,24 +1349,24 @@ var fn = class {
|
|
|
1349
1349
|
};
|
|
1350
1350
|
//#endregion
|
|
1351
1351
|
//#region node_modules/three-gpu-pathtracer/src/textures/BlueNoiseTexture.js
|
|
1352
|
-
function
|
|
1352
|
+
function hn(e) {
|
|
1353
1353
|
return e >= 3 ? 4 : e;
|
|
1354
1354
|
}
|
|
1355
|
-
function
|
|
1355
|
+
function gn(e) {
|
|
1356
1356
|
switch (e) {
|
|
1357
|
-
case 1: return
|
|
1358
|
-
case 2: return
|
|
1357
|
+
case 1: return F;
|
|
1358
|
+
case 2: return he;
|
|
1359
1359
|
default: return P;
|
|
1360
1360
|
}
|
|
1361
1361
|
}
|
|
1362
|
-
var
|
|
1362
|
+
var _n = class extends E {
|
|
1363
1363
|
constructor(e = 64, t = 1) {
|
|
1364
1364
|
super(/* @__PURE__ */ new Float32Array(4), 1, 1, P, O), this.minFilter = M, this.magFilter = M, this.size = e, this.channels = t, this.update();
|
|
1365
1365
|
}
|
|
1366
1366
|
update() {
|
|
1367
|
-
let e = this.channels, t = this.size, n = new
|
|
1367
|
+
let e = this.channels, t = this.size, n = new mn();
|
|
1368
1368
|
n.channels = e, n.size = t;
|
|
1369
|
-
let r =
|
|
1369
|
+
let r = hn(e), i = gn(r);
|
|
1370
1370
|
(this.image.width !== t || i !== this.format) && (this.image.width = t, this.image.height = t, this.image.data = new Float32Array(t ** 2 * r), this.format = i, this.dispose());
|
|
1371
1371
|
let a = this.image.data;
|
|
1372
1372
|
for (let t = 0, i = e; t < i; t++) {
|
|
@@ -1378,7 +1378,7 @@ var gn = class extends E {
|
|
|
1378
1378
|
}
|
|
1379
1379
|
this.needsUpdate = !0;
|
|
1380
1380
|
}
|
|
1381
|
-
}, _n = "\n\n struct PhysicalCamera {\n\n float focusDistance;\n float anamorphicRatio;\n float bokehSize;\n int apertureBlades;\n float apertureRotation;\n\n };\n\n", vn = "\n\n struct EquirectHdrInfo {\n\n sampler2D marginalWeights;\n sampler2D conditionalWeights;\n sampler2D map;\n\n float totalSum;\n\n };\n\n", yn = "\n\n #define RECT_AREA_LIGHT_TYPE 0\n #define CIRC_AREA_LIGHT_TYPE 1\n #define SPOT_LIGHT_TYPE 2\n #define DIR_LIGHT_TYPE 3\n #define POINT_LIGHT_TYPE 4\n\n struct LightsInfo {\n\n sampler2D tex;\n uint count;\n\n };\n\n struct Light {\n\n vec3 position;\n int type;\n\n vec3 color;\n float intensity;\n\n vec3 u;\n vec3 v;\n float area;\n\n // spot light fields\n float radius;\n float near;\n float decay;\n float distance;\n float coneCos;\n float penumbraCos;\n int iesProfile;\n\n };\n\n Light readLightInfo( sampler2D tex, uint index ) {\n\n uint i = index * 6u;\n\n vec4 s0 = texelFetch1D( tex, i + 0u );\n vec4 s1 = texelFetch1D( tex, i + 1u );\n vec4 s2 = texelFetch1D( tex, i + 2u );\n vec4 s3 = texelFetch1D( tex, i + 3u );\n\n Light l;\n l.position = s0.rgb;\n l.type = int( round( s0.a ) );\n\n l.color = s1.rgb;\n l.intensity = s1.a;\n\n l.u = s2.rgb;\n l.v = s3.rgb;\n l.area = s3.a;\n\n if ( l.type == SPOT_LIGHT_TYPE || l.type == POINT_LIGHT_TYPE ) {\n\n vec4 s4 = texelFetch1D( tex, i + 4u );\n vec4 s5 = texelFetch1D( tex, i + 5u );\n l.radius = s4.r;\n l.decay = s4.g;\n l.distance = s4.b;\n l.coneCos = s4.a;\n\n l.penumbraCos = s5.r;\n l.iesProfile = int( round( s5.g ) );\n\n } else {\n\n l.radius = 0.0;\n l.decay = 0.0;\n l.distance = 0.0;\n\n l.coneCos = 0.0;\n l.penumbraCos = 0.0;\n l.iesProfile = - 1;\n\n }\n\n return l;\n\n }\n\n", bn = "\n\n struct Material {\n\n vec3 color;\n int map;\n\n float metalness;\n int metalnessMap;\n\n float roughness;\n int roughnessMap;\n\n float ior;\n float transmission;\n int transmissionMap;\n\n float emissiveIntensity;\n vec3 emissive;\n int emissiveMap;\n\n int normalMap;\n vec2 normalScale;\n\n float clearcoat;\n int clearcoatMap;\n int clearcoatNormalMap;\n vec2 clearcoatNormalScale;\n float clearcoatRoughness;\n int clearcoatRoughnessMap;\n\n int iridescenceMap;\n int iridescenceThicknessMap;\n float iridescence;\n float iridescenceIor;\n float iridescenceThicknessMinimum;\n float iridescenceThicknessMaximum;\n\n vec3 specularColor;\n int specularColorMap;\n\n float specularIntensity;\n int specularIntensityMap;\n bool thinFilm;\n\n vec3 attenuationColor;\n float attenuationDistance;\n\n int alphaMap;\n\n bool castShadow;\n float opacity;\n float alphaTest;\n\n float side;\n bool matte;\n\n float sheen;\n vec3 sheenColor;\n int sheenColorMap;\n float sheenRoughness;\n int sheenRoughnessMap;\n\n bool vertexColors;\n bool flatShading;\n bool transparent;\n bool fogVolume;\n\n mat3 mapTransform;\n mat3 metalnessMapTransform;\n mat3 roughnessMapTransform;\n mat3 transmissionMapTransform;\n mat3 emissiveMapTransform;\n mat3 normalMapTransform;\n mat3 clearcoatMapTransform;\n mat3 clearcoatNormalMapTransform;\n mat3 clearcoatRoughnessMapTransform;\n mat3 sheenColorMapTransform;\n mat3 sheenRoughnessMapTransform;\n mat3 iridescenceMapTransform;\n mat3 iridescenceThicknessMapTransform;\n mat3 specularColorMapTransform;\n mat3 specularIntensityMapTransform;\n\n };\n\n mat3 readTextureTransform( sampler2D tex, uint index ) {\n\n mat3 textureTransform;\n\n vec4 row1 = texelFetch1D( tex, index );\n vec4 row2 = texelFetch1D( tex, index + 1u );\n\n textureTransform[0] = vec3(row1.r, row2.r, 0.0);\n textureTransform[1] = vec3(row1.g, row2.g, 0.0);\n textureTransform[2] = vec3(row1.b, row2.b, 1.0);\n\n return textureTransform;\n\n }\n\n Material readMaterialInfo( sampler2D tex, uint index ) {\n\n uint i = index * 45u;\n\n vec4 s0 = texelFetch1D( tex, i + 0u );\n vec4 s1 = texelFetch1D( tex, i + 1u );\n vec4 s2 = texelFetch1D( tex, i + 2u );\n vec4 s3 = texelFetch1D( tex, i + 3u );\n vec4 s4 = texelFetch1D( tex, i + 4u );\n vec4 s5 = texelFetch1D( tex, i + 5u );\n vec4 s6 = texelFetch1D( tex, i + 6u );\n vec4 s7 = texelFetch1D( tex, i + 7u );\n vec4 s8 = texelFetch1D( tex, i + 8u );\n vec4 s9 = texelFetch1D( tex, i + 9u );\n vec4 s10 = texelFetch1D( tex, i + 10u );\n vec4 s11 = texelFetch1D( tex, i + 11u );\n vec4 s12 = texelFetch1D( tex, i + 12u );\n vec4 s13 = texelFetch1D( tex, i + 13u );\n vec4 s14 = texelFetch1D( tex, i + 14u );\n\n Material m;\n m.color = s0.rgb;\n m.map = int( round( s0.a ) );\n\n m.metalness = s1.r;\n m.metalnessMap = int( round( s1.g ) );\n m.roughness = s1.b;\n m.roughnessMap = int( round( s1.a ) );\n\n m.ior = s2.r;\n m.transmission = s2.g;\n m.transmissionMap = int( round( s2.b ) );\n m.emissiveIntensity = s2.a;\n\n m.emissive = s3.rgb;\n m.emissiveMap = int( round( s3.a ) );\n\n m.normalMap = int( round( s4.r ) );\n m.normalScale = s4.gb;\n\n m.clearcoat = s4.a;\n m.clearcoatMap = int( round( s5.r ) );\n m.clearcoatRoughness = s5.g;\n m.clearcoatRoughnessMap = int( round( s5.b ) );\n m.clearcoatNormalMap = int( round( s5.a ) );\n m.clearcoatNormalScale = s6.rg;\n\n m.sheen = s6.a;\n m.sheenColor = s7.rgb;\n m.sheenColorMap = int( round( s7.a ) );\n m.sheenRoughness = s8.r;\n m.sheenRoughnessMap = int( round( s8.g ) );\n\n m.iridescenceMap = int( round( s8.b ) );\n m.iridescenceThicknessMap = int( round( s8.a ) );\n m.iridescence = s9.r;\n m.iridescenceIor = s9.g;\n m.iridescenceThicknessMinimum = s9.b;\n m.iridescenceThicknessMaximum = s9.a;\n\n m.specularColor = s10.rgb;\n m.specularColorMap = int( round( s10.a ) );\n\n m.specularIntensity = s11.r;\n m.specularIntensityMap = int( round( s11.g ) );\n m.thinFilm = bool( s11.b );\n\n m.attenuationColor = s12.rgb;\n m.attenuationDistance = s12.a;\n\n m.alphaMap = int( round( s13.r ) );\n\n m.opacity = s13.g;\n m.alphaTest = s13.b;\n m.side = s13.a;\n\n m.matte = bool( s14.r );\n m.castShadow = bool( s14.g );\n m.vertexColors = bool( int( s14.b ) & 1 );\n m.flatShading = bool( int( s14.b ) & 2 );\n m.fogVolume = bool( int( s14.b ) & 4 );\n m.transparent = bool( s14.a );\n\n uint firstTextureTransformIdx = i + 15u;\n\n // mat3( 1.0 ) is an identity matrix\n m.mapTransform = m.map == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx );\n m.metalnessMapTransform = m.metalnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 2u );\n m.roughnessMapTransform = m.roughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 4u );\n m.transmissionMapTransform = m.transmissionMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 6u );\n m.emissiveMapTransform = m.emissiveMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 8u );\n m.normalMapTransform = m.normalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 10u );\n m.clearcoatMapTransform = m.clearcoatMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 12u );\n m.clearcoatNormalMapTransform = m.clearcoatNormalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 14u );\n m.clearcoatRoughnessMapTransform = m.clearcoatRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 16u );\n m.sheenColorMapTransform = m.sheenColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 18u );\n m.sheenRoughnessMapTransform = m.sheenRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 20u );\n m.iridescenceMapTransform = m.iridescenceMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 22u );\n m.iridescenceThicknessMapTransform = m.iridescenceThicknessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 24u );\n m.specularColorMapTransform = m.specularColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 26u );\n m.specularIntensityMapTransform = m.specularIntensityMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 28u );\n\n return m;\n\n }\n\n", xn = "\n\n struct SurfaceRecord {\n\n // surface type\n bool volumeParticle;\n\n // geometry\n vec3 faceNormal;\n bool frontFace;\n vec3 normal;\n mat3 normalBasis;\n mat3 normalInvBasis;\n\n // cached properties\n float eta;\n float f0;\n\n // material\n float roughness;\n float filteredRoughness;\n float metalness;\n vec3 color;\n vec3 emission;\n\n // transmission\n float ior;\n float transmission;\n bool thinFilm;\n vec3 attenuationColor;\n float attenuationDistance;\n\n // clearcoat\n vec3 clearcoatNormal;\n mat3 clearcoatBasis;\n mat3 clearcoatInvBasis;\n float clearcoat;\n float clearcoatRoughness;\n float filteredClearcoatRoughness;\n\n // sheen\n float sheen;\n vec3 sheenColor;\n float sheenRoughness;\n\n // iridescence\n float iridescence;\n float iridescenceIor;\n float iridescenceThickness;\n\n // specular\n vec3 specularColor;\n float specularIntensity;\n };\n\n struct ScatterRecord {\n float specularPdf;\n float pdf;\n vec3 direction;\n vec3 color;\n };\n\n", Sn = "\n\n // samples the the given environment map in the given direction\n vec3 sampleEquirectColor( sampler2D envMap, vec3 direction ) {\n\n return texture2D( envMap, equirectDirectionToUv( direction ) ).rgb;\n\n }\n\n // gets the pdf of the given direction to sample\n float equirectDirectionPdf( vec3 direction ) {\n\n vec2 uv = equirectDirectionToUv( direction );\n float theta = uv.y * PI;\n float sinTheta = sin( theta );\n if ( sinTheta == 0.0 ) {\n\n return 0.0;\n\n }\n\n return 1.0 / ( 2.0 * PI * PI * sinTheta );\n\n }\n\n // samples the color given env map with CDF and returns the pdf of the direction\n float sampleEquirect( vec3 direction, inout vec3 color ) {\n\n float totalSum = envMapInfo.totalSum;\n if ( totalSum == 0.0 ) {\n\n color = vec3( 0.0 );\n return 1.0;\n\n }\n\n vec2 uv = equirectDirectionToUv( direction );\n color = texture2D( envMapInfo.map, uv ).rgb;\n\n float lum = luminance( color );\n ivec2 resolution = textureSize( envMapInfo.map, 0 );\n float pdf = lum / totalSum;\n\n return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );\n\n }\n\n // samples a direction of the envmap with color and retrieves pdf\n float sampleEquirectProbability( vec2 r, inout vec3 color, inout vec3 direction ) {\n\n // sample env map cdf\n float v = texture2D( envMapInfo.marginalWeights, vec2( r.x, 0.0 ) ).x;\n float u = texture2D( envMapInfo.conditionalWeights, vec2( r.y, v ) ).x;\n vec2 uv = vec2( u, v );\n\n vec3 derivedDirection = equirectUvToDirection( uv );\n direction = derivedDirection;\n color = texture2D( envMapInfo.map, uv ).rgb;\n\n float totalSum = envMapInfo.totalSum;\n float lum = luminance( color );\n ivec2 resolution = textureSize( envMapInfo.map, 0 );\n float pdf = lum / totalSum;\n\n return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );\n\n }\n", Cn = "\n\n float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\n return smoothstep( coneCosine, penumbraCosine, angleCosine );\n\n }\n\n float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\n // based upon Frostbite 3 Moving to Physically-based Rendering\n // page 32, equation 26: E[window1]\n // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf\n float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), EPSILON );\n\n if ( cutoffDistance > 0.0 ) {\n\n distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\n }\n\n return distanceFalloff;\n\n }\n\n float getPhotometricAttenuation( sampler2DArray iesProfiles, int iesProfile, vec3 posToLight, vec3 lightDir, vec3 u, vec3 v ) {\n\n float cosTheta = dot( posToLight, lightDir );\n float angle = acos( cosTheta ) / PI;\n\n return texture2D( iesProfiles, vec3( angle, 0.0, iesProfile ) ).r;\n\n }\n\n struct LightRecord {\n\n float dist;\n vec3 direction;\n float pdf;\n vec3 emission;\n int type;\n\n };\n\n bool intersectLightAtIndex( sampler2D lights, vec3 rayOrigin, vec3 rayDirection, uint l, inout LightRecord lightRec ) {\n\n bool didHit = false;\n Light light = readLightInfo( lights, l );\n\n vec3 u = light.u;\n vec3 v = light.v;\n\n // check for backface\n vec3 normal = normalize( cross( u, v ) );\n if ( dot( normal, rayDirection ) > 0.0 ) {\n\n u *= 1.0 / dot( u, u );\n v *= 1.0 / dot( v, v );\n\n float dist;\n\n // MIS / light intersection is not supported for punctual lights.\n if(\n ( light.type == RECT_AREA_LIGHT_TYPE && intersectsRectangle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) ) ||\n ( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )\n ) {\n\n float cosTheta = dot( rayDirection, normal );\n didHit = true;\n lightRec.dist = dist;\n lightRec.pdf = ( dist * dist ) / ( light.area * cosTheta );\n lightRec.emission = light.color * light.intensity;\n lightRec.direction = rayDirection;\n lightRec.type = light.type;\n\n }\n\n }\n\n return didHit;\n\n }\n\n LightRecord randomAreaLightSample( Light light, vec3 rayOrigin, vec2 ruv ) {\n\n vec3 randomPos;\n if( light.type == RECT_AREA_LIGHT_TYPE ) {\n\n // rectangular area light\n randomPos = light.position + light.u * ( ruv.x - 0.5 ) + light.v * ( ruv.y - 0.5 );\n\n } else if( light.type == CIRC_AREA_LIGHT_TYPE ) {\n\n // circular area light\n float r = 0.5 * sqrt( ruv.x );\n float theta = ruv.y * 2.0 * PI;\n float x = r * cos( theta );\n float y = r * sin( theta );\n\n randomPos = light.position + light.u * x + light.v * y;\n\n }\n\n vec3 toLight = randomPos - rayOrigin;\n float lightDistSq = dot( toLight, toLight );\n float dist = sqrt( lightDistSq );\n vec3 direction = toLight / dist;\n vec3 lightNormal = normalize( cross( light.u, light.v ) );\n\n LightRecord lightRec;\n lightRec.type = light.type;\n lightRec.emission = light.color * light.intensity;\n lightRec.dist = dist;\n lightRec.direction = direction;\n\n // TODO: the denominator is potentially zero\n lightRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );\n\n return lightRec;\n\n }\n\n LightRecord randomSpotLightSample( Light light, sampler2DArray iesProfiles, vec3 rayOrigin, vec2 ruv ) {\n\n float radius = light.radius * sqrt( ruv.x );\n float theta = ruv.y * 2.0 * PI;\n float x = radius * cos( theta );\n float y = radius * sin( theta );\n\n vec3 u = light.u;\n vec3 v = light.v;\n vec3 normal = normalize( cross( u, v ) );\n\n float angle = acos( light.coneCos );\n float angleTan = tan( angle );\n float startDistance = light.radius / max( angleTan, EPSILON );\n\n vec3 randomPos = light.position - normal * startDistance + u * x + v * y;\n vec3 toLight = randomPos - rayOrigin;\n float lightDistSq = dot( toLight, toLight );\n float dist = sqrt( lightDistSq );\n\n vec3 direction = toLight / max( dist, EPSILON );\n float cosTheta = dot( direction, normal );\n\n float spotAttenuation = light.iesProfile != - 1 ?\n getPhotometricAttenuation( iesProfiles, light.iesProfile, direction, normal, u, v ) :\n getSpotAttenuation( light.coneCos, light.penumbraCos, cosTheta );\n\n float distanceAttenuation = getDistanceAttenuation( dist, light.distance, light.decay );\n LightRecord lightRec;\n lightRec.type = light.type;\n lightRec.dist = dist;\n lightRec.direction = direction;\n lightRec.emission = light.color * light.intensity * distanceAttenuation * spotAttenuation;\n lightRec.pdf = 1.0;\n\n return lightRec;\n\n }\n\n LightRecord randomLightSample( sampler2D lights, sampler2DArray iesProfiles, uint lightCount, vec3 rayOrigin, vec3 ruv ) {\n\n LightRecord result;\n\n // pick a random light\n uint l = uint( ruv.x * float( lightCount ) );\n Light light = readLightInfo( lights, l );\n\n if ( light.type == SPOT_LIGHT_TYPE ) {\n\n result = randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );\n\n } else if ( light.type == POINT_LIGHT_TYPE ) {\n\n vec3 lightRay = light.u - rayOrigin;\n float lightDist = length( lightRay );\n float cutoffDistance = light.distance;\n float distanceFalloff = 1.0 / max( pow( lightDist, light.decay ), 0.01 );\n if ( cutoffDistance > 0.0 ) {\n\n distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDist / cutoffDistance ) ) );\n\n }\n\n LightRecord rec;\n rec.direction = normalize( lightRay );\n rec.dist = length( lightRay );\n rec.pdf = 1.0;\n rec.emission = light.color * light.intensity * distanceFalloff;\n rec.type = light.type;\n result = rec;\n\n } else if ( light.type == DIR_LIGHT_TYPE ) {\n\n LightRecord rec;\n rec.dist = 1e10;\n rec.direction = light.u;\n rec.pdf = 1.0;\n rec.emission = light.color * light.intensity;\n rec.type = light.type;\n\n result = rec;\n\n } else {\n\n // sample the light\n result = randomAreaLightSample( light, rayOrigin, ruv.yz );\n\n }\n\n return result;\n\n }\n\n", wn = "\n\n vec3 sampleHemisphere( vec3 n, vec2 uv ) {\n\n // https://www.rorydriscoll.com/2009/01/07/better-sampling/\n // https://graphics.pixar.com/library/OrthonormalB/paper.pdf\n float sign = n.z == 0.0 ? 1.0 : sign( n.z );\n float a = - 1.0 / ( sign + n.z );\n float b = n.x * n.y * a;\n vec3 b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );\n vec3 b2 = vec3( b, sign + n.y * n.y * a, - n.y );\n\n float r = sqrt( uv.x );\n float theta = 2.0 * PI * uv.y;\n float x = r * cos( theta );\n float y = r * sin( theta );\n return x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;\n\n }\n\n vec2 sampleTriangle( vec2 a, vec2 b, vec2 c, vec2 r ) {\n\n // get the edges of the triangle and the diagonal across the\n // center of the parallelogram\n vec2 e1 = a - b;\n vec2 e2 = c - b;\n vec2 diag = normalize( e1 + e2 );\n\n // pick the point in the parallelogram\n if ( r.x + r.y > 1.0 ) {\n\n r = vec2( 1.0 ) - r;\n\n }\n\n return e1 * r.x + e2 * r.y;\n\n }\n\n vec2 sampleCircle( vec2 uv ) {\n\n float angle = 2.0 * PI * uv.x;\n float radius = sqrt( uv.y );\n return vec2( cos( angle ), sin( angle ) ) * radius;\n\n }\n\n vec3 sampleSphere( vec2 uv ) {\n\n float u = ( uv.x - 0.5 ) * 2.0;\n float t = uv.y * PI * 2.0;\n float f = sqrt( 1.0 - u * u );\n\n return vec3( f * cos( t ), f * sin( t ), u );\n\n }\n\n vec2 sampleRegularPolygon( int sides, vec3 uvw ) {\n\n sides = max( sides, 3 );\n\n vec3 r = uvw;\n float anglePerSegment = 2.0 * PI / float( sides );\n float segment = floor( float( sides ) * r.x );\n\n float angle1 = anglePerSegment * segment;\n float angle2 = angle1 + anglePerSegment;\n vec2 a = vec2( sin( angle1 ), cos( angle1 ) );\n vec2 b = vec2( 0.0, 0.0 );\n vec2 c = vec2( sin( angle2 ), cos( angle2 ) );\n\n return sampleTriangle( a, b, c, r.yz );\n\n }\n\n // samples an aperture shape with the given number of sides. 0 means circle\n vec2 sampleAperture( int blades, vec3 uvw ) {\n\n return blades == 0 ?\n sampleCircle( uvw.xy ) :\n sampleRegularPolygon( blades, uvw );\n\n }\n\n\n", Tn = "\n\n bool totalInternalReflection( float cosTheta, float eta ) {\n\n float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );\n return eta * sinTheta > 1.0;\n\n }\n\n // https://google.github.io/filament/Filament.md.html#materialsystem/diffusebrdf\n float schlickFresnel( float cosine, float f0 ) {\n\n return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n }\n\n vec3 schlickFresnel( float cosine, vec3 f0 ) {\n\n return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n }\n\n vec3 schlickFresnel( float cosine, vec3 f0, vec3 f90 ) {\n\n return f0 + ( f90 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n }\n\n float dielectricFresnel( float cosThetaI, float eta ) {\n\n // https://schuttejoe.github.io/post/disneybsdf/\n float ni = eta;\n float nt = 1.0;\n\n // Check for total internal reflection\n float sinThetaISq = 1.0f - cosThetaI * cosThetaI;\n float sinThetaTSq = eta * eta * sinThetaISq;\n if( sinThetaTSq >= 1.0 ) {\n\n return 1.0;\n\n }\n\n float sinThetaT = sqrt( sinThetaTSq );\n\n float cosThetaT = sqrt( max( 0.0, 1.0f - sinThetaT * sinThetaT ) );\n float rParallel = ( ( nt * cosThetaI ) - ( ni * cosThetaT ) ) / ( ( nt * cosThetaI ) + ( ni * cosThetaT ) );\n float rPerpendicular = ( ( ni * cosThetaI ) - ( nt * cosThetaT ) ) / ( ( ni * cosThetaI ) + ( nt * cosThetaT ) );\n return ( rParallel * rParallel + rPerpendicular * rPerpendicular ) / 2.0;\n\n }\n\n // https://raytracing.github.io/books/RayTracingInOneWeekend.html#dielectrics/schlickapproximation\n float iorRatioToF0( float eta ) {\n\n return pow( ( 1.0 - eta ) / ( 1.0 + eta ), 2.0 );\n\n }\n\n vec3 evaluateFresnel( float cosTheta, float eta, vec3 f0, vec3 f90 ) {\n\n if ( totalInternalReflection( cosTheta, eta ) ) {\n\n return f90;\n\n }\n\n return schlickFresnel( cosTheta, f0, f90 );\n\n }\n\n // TODO: disney fresnel was removed and replaced with this fresnel function to better align with\n // the glTF but is causing blown out pixels. Should be revisited\n // float evaluateFresnelWeight( float cosTheta, float eta, float f0 ) {\n\n // if ( totalInternalReflection( cosTheta, eta ) ) {\n\n // return 1.0;\n\n // }\n\n // return schlickFresnel( cosTheta, f0 );\n\n // }\n\n // https://schuttejoe.github.io/post/disneybsdf/\n float disneyFresnel( vec3 wo, vec3 wi, vec3 wh, float f0, float eta, float metalness ) {\n\n float dotHV = dot( wo, wh );\n if ( totalInternalReflection( dotHV, eta ) ) {\n\n return 1.0;\n\n }\n\n float dotHL = dot( wi, wh );\n float dielectricFresnel = dielectricFresnel( abs( dotHV ), eta );\n float metallicFresnel = schlickFresnel( dotHL, f0 );\n\n return mix( dielectricFresnel, metallicFresnel, metalness );\n\n }\n\n", En = "\n\n // Fast arccos approximation used to remove banding artifacts caused by numerical errors in acos.\n // This is a cubic Lagrange interpolating polynomial for x = [-1, -1/2, 0, 1/2, 1].\n // For more information see: https://github.com/gkjohnson/three-gpu-pathtracer/pull/171#issuecomment-1152275248\n float acosApprox( float x ) {\n\n x = clamp( x, -1.0, 1.0 );\n return ( - 0.69813170079773212 * x * x - 0.87266462599716477 ) * x + 1.5707963267948966;\n\n }\n\n // An acos with input values bound to the range [-1, 1].\n float acosSafe( float x ) {\n\n return acos( clamp( x, -1.0, 1.0 ) );\n\n }\n\n float saturateCos( float val ) {\n\n return clamp( val, 0.001, 1.0 );\n\n }\n\n float square( float t ) {\n\n return t * t;\n\n }\n\n vec2 square( vec2 t ) {\n\n return t * t;\n\n }\n\n vec3 square( vec3 t ) {\n\n return t * t;\n\n }\n\n vec4 square( vec4 t ) {\n\n return t * t;\n\n }\n\n vec2 rotateVector( vec2 v, float t ) {\n\n float ac = cos( t );\n float as = sin( t );\n return vec2(\n v.x * ac - v.y * as,\n v.x * as + v.y * ac\n );\n\n }\n\n // forms a basis with the normal vector as Z\n mat3 getBasisFromNormal( vec3 normal ) {\n\n vec3 other;\n if ( abs( normal.x ) > 0.5 ) {\n\n other = vec3( 0.0, 1.0, 0.0 );\n\n } else {\n\n other = vec3( 1.0, 0.0, 0.0 );\n\n }\n\n vec3 ortho = normalize( cross( normal, other ) );\n vec3 ortho2 = normalize( cross( normal, ortho ) );\n return mat3( ortho2, ortho, normal );\n\n }\n\n", Dn = "\n\n // Finds the point where the ray intersects the plane defined by u and v and checks if this point\n // falls in the bounds of the rectangle on that same plane.\n // Plane intersection: https://lousodrome.net/blog/light/2020/07/03/intersection-of-a-ray-and-a-plane/\n bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {\n\n float t = dot( center - rayOrigin, normal ) / dot( rayDirection, normal );\n\n if ( t > EPSILON ) {\n\n vec3 p = rayOrigin + rayDirection * t;\n vec3 vi = p - center;\n\n // check if p falls inside the rectangle\n float a1 = dot( u, vi );\n if ( abs( a1 ) <= 0.5 ) {\n\n float a2 = dot( v, vi );\n if ( abs( a2 ) <= 0.5 ) {\n\n dist = t;\n return true;\n\n }\n\n }\n\n }\n\n return false;\n\n }\n\n // Finds the point where the ray intersects the plane defined by u and v and checks if this point\n // falls in the bounds of the circle on that same plane. See above URL for a description of the plane intersection algorithm.\n bool intersectsCircle( vec3 position, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {\n\n float t = dot( position - rayOrigin, normal ) / dot( rayDirection, normal );\n\n if ( t > EPSILON ) {\n\n vec3 hit = rayOrigin + rayDirection * t;\n vec3 vi = hit - position;\n\n float a1 = dot( u, vi );\n float a2 = dot( v, vi );\n\n if( length( vec2( a1, a2 ) ) <= 0.5 ) {\n\n dist = t;\n return true;\n\n }\n\n }\n\n return false;\n\n }\n\n", On = "\n\n // add texel fetch functions for texture arrays\n vec4 texelFetch1D( sampler2DArray tex, int layer, uint index ) {\n\n uint width = uint( textureSize( tex, 0 ).x );\n uvec2 uv;\n uv.x = index % width;\n uv.y = index / width;\n\n return texelFetch( tex, ivec3( uv, layer ), 0 );\n\n }\n\n vec4 textureSampleBarycoord( sampler2DArray tex, int layer, vec3 barycoord, uvec3 faceIndices ) {\n\n return\n barycoord.x * texelFetch1D( tex, layer, faceIndices.x ) +\n barycoord.y * texelFetch1D( tex, layer, faceIndices.y ) +\n barycoord.z * texelFetch1D( tex, layer, faceIndices.z );\n\n }\n\n", kn = "\n\n // TODO: possibly this should be renamed something related to material or path tracing logic\n\n #ifndef RAY_OFFSET\n #define RAY_OFFSET 1e-4\n #endif\n\n // adjust the hit point by the surface normal by a factor of some offset and the\n // maximum component-wise value of the current point to accommodate floating point\n // error as values increase.\n vec3 stepRayOrigin( vec3 rayOrigin, vec3 rayDirection, vec3 offset, float dist ) {\n\n vec3 point = rayOrigin + rayDirection * dist;\n vec3 absPoint = abs( point );\n float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );\n return point + offset * ( maxPoint + 1.0 ) * RAY_OFFSET;\n\n }\n\n // https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation\n vec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {\n\n vec3 ot = - log( attColor ) / attDist;\n return exp( - ot * dist );\n\n }\n\n vec3 getHalfVector( vec3 wi, vec3 wo, float eta ) {\n\n // get the half vector - assuming if the light incident vector is on the other side\n // of the that it's transmissive.\n vec3 h;\n if ( wi.z > 0.0 ) {\n\n h = normalize( wi + wo );\n\n } else {\n\n // Scale by the ior ratio to retrieve the appropriate half vector\n // From Section 2.2 on computing the transmission half vector:\n // https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf\n h = normalize( wi + wo * eta );\n\n }\n\n h *= sign( h.z );\n return h;\n\n }\n\n vec3 getHalfVector( vec3 a, vec3 b ) {\n\n return normalize( a + b );\n\n }\n\n // The discrepancy between interpolated surface normal and geometry normal can cause issues when a ray\n // is cast that is on the top side of the geometry normal plane but below the surface normal plane. If\n // we find a ray like that we ignore it to avoid artifacts.\n // This function returns if the direction is on the same side of both planes.\n bool isDirectionValid( vec3 direction, vec3 surfaceNormal, vec3 geometryNormal ) {\n\n bool aboveSurfaceNormal = dot( direction, surfaceNormal ) > 0.0;\n bool aboveGeometryNormal = dot( direction, geometryNormal ) > 0.0;\n return aboveSurfaceNormal == aboveGeometryNormal;\n\n }\n\n // ray sampling x and z are swapped to align with expected background view\n vec2 equirectDirectionToUv( vec3 direction ) {\n\n // from Spherical.setFromCartesianCoords\n vec2 uv = vec2( atan( direction.z, direction.x ), acos( direction.y ) );\n uv /= vec2( 2.0 * PI, PI );\n\n // apply adjustments to get values in range [0, 1] and y right side up\n uv.x += 0.5;\n uv.y = 1.0 - uv.y;\n return uv;\n\n }\n\n vec3 equirectUvToDirection( vec2 uv ) {\n\n // undo above adjustments\n uv.x -= 0.5;\n uv.y = 1.0 - uv.y;\n\n // from Vector3.setFromSphericalCoords\n float theta = uv.x * 2.0 * PI;\n float phi = uv.y * PI;\n\n float sinPhi = sin( phi );\n\n return vec3( sinPhi * cos( theta ), cos( phi ), sinPhi * sin( theta ) );\n\n }\n\n // power heuristic for multiple importance sampling\n float misHeuristic( float a, float b ) {\n\n float aa = a * a;\n float bb = b * b;\n return aa / ( aa + bb );\n\n }\n\n // tentFilter from Peter Shirley's 'Realistic Ray Tracing (2nd Edition)' book, pg. 60\n // erichlof/THREE.js-PathTracing-Renderer/\n float tentFilter( float x ) {\n\n return x < 0.5 ? sqrt( 2.0 * x ) - 1.0 : 1.0 - sqrt( 2.0 - ( 2.0 * x ) );\n\n }\n", An = "\n\n // https://www.shadertoy.com/view/wltcRS\n uvec4 WHITE_NOISE_SEED;\n\n void rng_initialize( vec2 p, int frame ) {\n\n // white noise seed\n WHITE_NOISE_SEED = uvec4( p, uint( frame ), uint( p.x ) + uint( p.y ) );\n\n }\n\n // https://www.pcg-random.org/\n void pcg4d( inout uvec4 v ) {\n\n v = v * 1664525u + 1013904223u;\n v.x += v.y * v.w;\n v.y += v.z * v.x;\n v.z += v.x * v.y;\n v.w += v.y * v.z;\n v = v ^ ( v >> 16u );\n v.x += v.y*v.w;\n v.y += v.z*v.x;\n v.z += v.x*v.y;\n v.w += v.y*v.z;\n\n }\n\n // returns [ 0, 1 ]\n float pcgRand() {\n\n pcg4d( WHITE_NOISE_SEED );\n return float( WHITE_NOISE_SEED.x ) / float( 0xffffffffu );\n\n }\n\n vec2 pcgRand2() {\n\n pcg4d( WHITE_NOISE_SEED );\n return vec2( WHITE_NOISE_SEED.xy ) / float(0xffffffffu);\n\n }\n\n vec3 pcgRand3() {\n\n pcg4d( WHITE_NOISE_SEED );\n return vec3( WHITE_NOISE_SEED.xyz ) / float( 0xffffffffu );\n\n }\n\n vec4 pcgRand4() {\n\n pcg4d( WHITE_NOISE_SEED );\n return vec4( WHITE_NOISE_SEED ) / float( 0xffffffffu );\n\n }\n", jn = "\n\n uniform sampler2D stratifiedTexture;\n uniform sampler2D stratifiedOffsetTexture;\n\n uint sobolPixelIndex = 0u;\n uint sobolPathIndex = 0u;\n uint sobolBounceIndex = 0u;\n vec4 pixelSeed = vec4( 0 );\n\n vec4 rand4( int v ) {\n\n ivec2 uv = ivec2( v, sobolBounceIndex );\n vec4 stratifiedSample = texelFetch( stratifiedTexture, uv, 0 );\n return fract( stratifiedSample + pixelSeed.r ); // blue noise + stratified samples\n\n }\n\n vec3 rand3( int v ) {\n\n return rand4( v ).xyz;\n\n }\n\n vec2 rand2( int v ) {\n\n return rand4( v ).xy;\n\n }\n\n float rand( int v ) {\n\n return rand4( v ).x;\n\n }\n\n void rng_initialize( vec2 screenCoord, int frame ) {\n\n // tile the small noise texture across the entire screen\n ivec2 noiseSize = ivec2( textureSize( stratifiedOffsetTexture, 0 ) );\n ivec2 pixel = ivec2( screenCoord.xy ) % noiseSize;\n vec2 pixelWidth = 1.0 / vec2( noiseSize );\n vec2 uv = vec2( pixel ) * pixelWidth + pixelWidth * 0.5;\n\n // note that using \"texelFetch\" here seems to break Android for some reason\n pixelSeed = texture( stratifiedOffsetTexture, uv );\n\n }\n\n", Mn = "\n\n // diffuse\n float diffuseEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n // https://schuttejoe.github.io/post/disneybsdf/\n float fl = schlickFresnel( wi.z, 0.0 );\n float fv = schlickFresnel( wo.z, 0.0 );\n\n float metalFactor = ( 1.0 - surf.metalness );\n float transFactor = ( 1.0 - surf.transmission );\n float rr = 0.5 + 2.0 * surf.roughness * fl * fl;\n float retro = rr * ( fl + fv + fl * fv * ( rr - 1.0f ) );\n float lambert = ( 1.0f - 0.5f * fl ) * ( 1.0f - 0.5f * fv );\n\n // TODO: subsurface approx?\n\n // float F = evaluateFresnelWeight( dot( wo, wh ), surf.eta, surf.f0 );\n float F = disneyFresnel( wo, wi, wh, surf.f0, surf.eta, surf.metalness );\n color = ( 1.0 - F ) * transFactor * metalFactor * wi.z * surf.color * ( retro + lambert ) / PI;\n\n return wi.z / PI;\n\n }\n\n vec3 diffuseDirection( vec3 wo, SurfaceRecord surf ) {\n\n vec3 lightDirection = sampleSphere( rand2( 11 ) );\n lightDirection.z += 1.0;\n lightDirection = normalize( lightDirection );\n\n return lightDirection;\n\n }\n\n // specular\n float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n // if roughness is set to 0 then D === NaN which results in black pixels\n float metalness = surf.metalness;\n float roughness = surf.filteredRoughness;\n\n float eta = surf.eta;\n float f0 = surf.f0;\n\n vec3 f0Color = mix( f0 * surf.specularColor * surf.specularIntensity, surf.color, surf.metalness );\n vec3 f90Color = vec3( mix( surf.specularIntensity, 1.0, surf.metalness ) );\n vec3 F = evaluateFresnel( dot( wo, wh ), eta, f0Color, f90Color );\n\n vec3 iridescenceF = evalIridescence( 1.0, surf.iridescenceIor, dot( wi, wh ), surf.iridescenceThickness, f0Color );\n F = mix( F, iridescenceF, surf.iridescence );\n\n // PDF\n // See 14.1.1 Microfacet BxDFs in https://www.pbr-book.org/\n float incidentTheta = acos( wo.z );\n float G = ggxShadowMaskG2( wi, wo, roughness );\n float D = ggxDistribution( wh, roughness );\n float G1 = ggxShadowMaskG1( incidentTheta, roughness );\n float ggxPdf = D * G1 * max( 0.0, abs( dot( wo, wh ) ) ) / abs ( wo.z );\n\n color = wi.z * F * G * D / ( 4.0 * abs( wi.z * wo.z ) );\n return ggxPdf / ( 4.0 * dot( wo, wh ) );\n\n }\n\n vec3 specularDirection( vec3 wo, SurfaceRecord surf ) {\n\n // sample ggx vndf distribution which gives a new normal\n float roughness = surf.filteredRoughness;\n vec3 halfVector = ggxDirection(\n wo,\n vec2( roughness ),\n rand2( 12 )\n );\n\n // apply to new ray by reflecting off the new normal\n return - reflect( wo, halfVector );\n\n }\n\n\n // transmission\n /*\n float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n // See section 4.2 in https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf\n\n float filteredRoughness = surf.filteredRoughness;\n float eta = surf.eta;\n bool frontFace = surf.frontFace;\n bool thinFilm = surf.thinFilm;\n\n color = surf.transmission * surf.color;\n\n float denom = pow( eta * dot( wi, wh ) + dot( wo, wh ), 2.0 );\n return ggxPDF( wo, wh, filteredRoughness ) / denom;\n\n }\n\n vec3 transmissionDirection( vec3 wo, SurfaceRecord surf ) {\n\n float filteredRoughness = surf.filteredRoughness;\n float eta = surf.eta;\n bool frontFace = surf.frontFace;\n\n // sample ggx vndf distribution which gives a new normal\n vec3 halfVector = ggxDirection(\n wo,\n vec2( filteredRoughness ),\n rand2( 13 )\n );\n\n vec3 lightDirection = refract( normalize( - wo ), halfVector, eta );\n if ( surf.thinFilm ) {\n\n lightDirection = - refract( normalize( - lightDirection ), - vec3( 0.0, 0.0, 1.0 ), 1.0 / eta );\n\n }\n\n return normalize( lightDirection );\n\n }\n */\n\n // TODO: This is just using a basic cosine-weighted specular distribution with an\n // incorrect PDF value at the moment. Update it to correctly use a GGX distribution\n float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n color = surf.transmission * surf.color;\n\n // PDF\n // float F = evaluateFresnelWeight( dot( wo, wh ), surf.eta, surf.f0 );\n // float F = disneyFresnel( wo, wi, wh, surf.f0, surf.eta, surf.metalness );\n // if ( F >= 1.0 ) {\n\n // return 0.0;\n\n // }\n\n // return 1.0 / ( 1.0 - F );\n\n // reverted to previous to transmission. The above was causing black pixels\n float eta = surf.eta;\n float f0 = surf.f0;\n float cosTheta = min( wo.z, 1.0 );\n float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );\n float reflectance = schlickFresnel( cosTheta, f0 );\n bool cannotRefract = eta * sinTheta > 1.0;\n if ( cannotRefract ) {\n\n return 0.0;\n\n }\n\n return 1.0 / ( 1.0 - reflectance );\n\n }\n\n vec3 transmissionDirection( vec3 wo, SurfaceRecord surf ) {\n\n float roughness = surf.filteredRoughness;\n float eta = surf.eta;\n vec3 halfVector = normalize( vec3( 0.0, 0.0, 1.0 ) + sampleSphere( rand2( 13 ) ) * roughness );\n vec3 lightDirection = refract( normalize( - wo ), halfVector, eta );\n\n if ( surf.thinFilm ) {\n\n lightDirection = - refract( normalize( - lightDirection ), - vec3( 0.0, 0.0, 1.0 ), 1.0 / eta );\n\n }\n return normalize( lightDirection );\n\n }\n\n // clearcoat\n float clearcoatEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n float ior = 1.5;\n float f0 = iorRatioToF0( ior );\n bool frontFace = surf.frontFace;\n float roughness = surf.filteredClearcoatRoughness;\n\n float eta = frontFace ? 1.0 / ior : ior;\n float G = ggxShadowMaskG2( wi, wo, roughness );\n float D = ggxDistribution( wh, roughness );\n float F = schlickFresnel( dot( wi, wh ), f0 );\n\n float fClearcoat = F * D * G / ( 4.0 * abs( wi.z * wo.z ) );\n color = color * ( 1.0 - surf.clearcoat * F ) + fClearcoat * surf.clearcoat * wi.z;\n\n // PDF\n // See equation (27) in http://jcgt.org/published/0003/02/03/\n return ggxPDF( wo, wh, roughness ) / ( 4.0 * dot( wi, wh ) );\n\n }\n\n vec3 clearcoatDirection( vec3 wo, SurfaceRecord surf ) {\n\n // sample ggx vndf distribution which gives a new normal\n float roughness = surf.filteredClearcoatRoughness;\n vec3 halfVector = ggxDirection(\n wo,\n vec2( roughness ),\n rand2( 14 )\n );\n\n // apply to new ray by reflecting off the new normal\n return - reflect( wo, halfVector );\n\n }\n\n // sheen\n vec3 sheenColor( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf ) {\n\n float cosThetaO = saturateCos( wo.z );\n float cosThetaI = saturateCos( wi.z );\n float cosThetaH = wh.z;\n\n float D = velvetD( cosThetaH, surf.sheenRoughness );\n float G = velvetG( cosThetaO, cosThetaI, surf.sheenRoughness );\n\n // See equation (1) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n vec3 color = surf.sheenColor;\n color *= D * G / ( 4.0 * abs( cosThetaO * cosThetaI ) );\n color *= wi.z;\n\n return color;\n\n }\n\n // bsdf\n void getLobeWeights(\n vec3 wo, vec3 wi, vec3 wh, vec3 clearcoatWo, SurfaceRecord surf,\n inout float diffuseWeight, inout float specularWeight, inout float transmissionWeight, inout float clearcoatWeight\n ) {\n\n float metalness = surf.metalness;\n float transmission = surf.transmission;\n // float fEstimate = evaluateFresnelWeight( dot( wo, wh ), surf.eta, surf.f0 );\n float fEstimate = disneyFresnel( wo, wi, wh, surf.f0, surf.eta, surf.metalness );\n\n float transSpecularProb = mix( max( 0.25, fEstimate ), 1.0, metalness );\n float diffSpecularProb = 0.5 + 0.5 * metalness;\n\n diffuseWeight = ( 1.0 - transmission ) * ( 1.0 - diffSpecularProb );\n specularWeight = transmission * transSpecularProb + ( 1.0 - transmission ) * diffSpecularProb;\n transmissionWeight = transmission * ( 1.0 - transSpecularProb );\n clearcoatWeight = surf.clearcoat * schlickFresnel( clearcoatWo.z, 0.04 );\n\n float totalWeight = diffuseWeight + specularWeight + transmissionWeight + clearcoatWeight;\n diffuseWeight /= totalWeight;\n specularWeight /= totalWeight;\n transmissionWeight /= totalWeight;\n clearcoatWeight /= totalWeight;\n }\n\n float bsdfEval(\n vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRecord surf,\n float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight, inout float specularPdf, inout vec3 color\n ) {\n\n float metalness = surf.metalness;\n float transmission = surf.transmission;\n\n float spdf = 0.0;\n float dpdf = 0.0;\n float tpdf = 0.0;\n float cpdf = 0.0;\n color = vec3( 0.0 );\n\n vec3 halfVector = getHalfVector( wi, wo, surf.eta );\n\n // diffuse\n if ( diffuseWeight > 0.0 && wi.z > 0.0 ) {\n\n dpdf = diffuseEval( wo, wi, halfVector, surf, color );\n color *= 1.0 - surf.transmission;\n\n }\n\n // ggx specular\n if ( specularWeight > 0.0 && wi.z > 0.0 ) {\n\n vec3 outColor;\n spdf = specularEval( wo, wi, getHalfVector( wi, wo ), surf, outColor );\n color += outColor;\n\n }\n\n // transmission\n if ( transmissionWeight > 0.0 && wi.z < 0.0 ) {\n\n tpdf = transmissionEval( wo, wi, halfVector, surf, color );\n\n }\n\n // sheen\n color *= mix( 1.0, sheenAlbedoScaling( wo, wi, surf ), surf.sheen );\n color += sheenColor( wo, wi, halfVector, surf ) * surf.sheen;\n\n // clearcoat\n if ( clearcoatWi.z >= 0.0 && clearcoatWeight > 0.0 ) {\n\n vec3 clearcoatHalfVector = getHalfVector( clearcoatWo, clearcoatWi );\n cpdf = clearcoatEval( clearcoatWo, clearcoatWi, clearcoatHalfVector, surf, color );\n\n }\n\n float pdf =\n dpdf * diffuseWeight\n + spdf * specularWeight\n + tpdf * transmissionWeight\n + cpdf * clearcoatWeight;\n\n // retrieve specular rays for the shadows flag\n specularPdf = spdf * specularWeight + cpdf * clearcoatWeight;\n\n return pdf;\n\n }\n\n float bsdfResult( vec3 worldWo, vec3 worldWi, SurfaceRecord surf, inout vec3 color ) {\n\n if ( surf.volumeParticle ) {\n\n color = surf.color / ( 4.0 * PI );\n return 1.0 / ( 4.0 * PI );\n\n }\n\n vec3 wo = normalize( surf.normalInvBasis * worldWo );\n vec3 wi = normalize( surf.normalInvBasis * worldWi );\n\n vec3 clearcoatWo = normalize( surf.clearcoatInvBasis * worldWo );\n vec3 clearcoatWi = normalize( surf.clearcoatInvBasis * worldWi );\n\n vec3 wh = getHalfVector( wo, wi, surf.eta );\n float diffuseWeight;\n float specularWeight;\n float transmissionWeight;\n float clearcoatWeight;\n getLobeWeights( wo, wi, wh, clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );\n\n float specularPdf;\n return bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight, specularPdf, color );\n\n }\n\n ScatterRecord bsdfSample( vec3 worldWo, SurfaceRecord surf ) {\n\n if ( surf.volumeParticle ) {\n\n ScatterRecord sampleRec;\n sampleRec.specularPdf = 0.0;\n sampleRec.pdf = 1.0 / ( 4.0 * PI );\n sampleRec.direction = sampleSphere( rand2( 16 ) );\n sampleRec.color = surf.color / ( 4.0 * PI );\n return sampleRec;\n\n }\n\n vec3 wo = normalize( surf.normalInvBasis * worldWo );\n vec3 clearcoatWo = normalize( surf.clearcoatInvBasis * worldWo );\n mat3 normalBasis = surf.normalBasis;\n mat3 invBasis = surf.normalInvBasis;\n mat3 clearcoatNormalBasis = surf.clearcoatBasis;\n mat3 clearcoatInvBasis = surf.clearcoatInvBasis;\n\n float diffuseWeight;\n float specularWeight;\n float transmissionWeight;\n float clearcoatWeight;\n // using normal and basically-reflected ray since we don't have proper half vector here\n getLobeWeights( wo, wo, vec3( 0, 0, 1 ), clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );\n\n float pdf[4];\n pdf[0] = diffuseWeight;\n pdf[1] = specularWeight;\n pdf[2] = transmissionWeight;\n pdf[3] = clearcoatWeight;\n\n float cdf[4];\n cdf[0] = pdf[0];\n cdf[1] = pdf[1] + cdf[0];\n cdf[2] = pdf[2] + cdf[1];\n cdf[3] = pdf[3] + cdf[2];\n\n if( cdf[3] != 0.0 ) {\n\n float invMaxCdf = 1.0 / cdf[3];\n cdf[0] *= invMaxCdf;\n cdf[1] *= invMaxCdf;\n cdf[2] *= invMaxCdf;\n cdf[3] *= invMaxCdf;\n\n } else {\n\n cdf[0] = 1.0;\n cdf[1] = 0.0;\n cdf[2] = 0.0;\n cdf[3] = 0.0;\n\n }\n\n vec3 wi;\n vec3 clearcoatWi;\n\n float r = rand( 15 );\n if ( r <= cdf[0] ) { // diffuse\n\n wi = diffuseDirection( wo, surf );\n clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );\n\n } else if ( r <= cdf[1] ) { // specular\n\n wi = specularDirection( wo, surf );\n clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );\n\n } else if ( r <= cdf[2] ) { // transmission / refraction\n\n wi = transmissionDirection( wo, surf );\n clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );\n\n } else if ( r <= cdf[3] ) { // clearcoat\n\n clearcoatWi = clearcoatDirection( clearcoatWo, surf );\n wi = normalize( invBasis * normalize( clearcoatNormalBasis * clearcoatWi ) );\n\n }\n\n ScatterRecord result;\n result.pdf = bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight, result.specularPdf, result.color );\n result.direction = normalize( surf.normalBasis * wi );\n\n return result;\n\n }\n\n", Nn = "\n\n // returns the hit distance given the material density\n float intersectFogVolume( Material material, float u ) {\n\n // https://raytracing.github.io/books/RayTracingTheNextWeek.html#volumes/constantdensitymediums\n return material.opacity == 0.0 ? INFINITY : ( - 1.0 / material.opacity ) * log( u );\n\n }\n\n ScatterRecord sampleFogVolume( SurfaceRecord surf, vec2 uv ) {\n\n ScatterRecord sampleRec;\n sampleRec.specularPdf = 0.0;\n sampleRec.pdf = 1.0 / ( 2.0 * PI );\n sampleRec.direction = sampleSphere( uv );\n sampleRec.color = surf.color;\n return sampleRec;\n\n }\n\n", Pn = "\n\n // The GGX functions provide sampling and distribution information for normals as output so\n // in order to get probability of scatter direction the half vector must be computed and provided.\n // [0] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf\n // [1] https://hal.archives-ouvertes.fr/hal-01509746/document\n // [2] http://jcgt.org/published/0007/04/01/\n // [4] http://jcgt.org/published/0003/02/03/\n\n // trowbridge-reitz === GGX === GTR\n\n vec3 ggxDirection( vec3 incidentDir, vec2 roughness, vec2 uv ) {\n\n // TODO: try GGXVNDF implementation from reference [2], here. Needs to update ggxDistribution\n // function below, as well\n\n // Implementation from reference [1]\n // stretch view\n vec3 V = normalize( vec3( roughness * incidentDir.xy, incidentDir.z ) );\n\n // orthonormal basis\n vec3 T1 = ( V.z < 0.9999 ) ? normalize( cross( V, vec3( 0.0, 0.0, 1.0 ) ) ) : vec3( 1.0, 0.0, 0.0 );\n vec3 T2 = cross( T1, V );\n\n // sample point with polar coordinates (r, phi)\n float a = 1.0 / ( 1.0 + V.z );\n float r = sqrt( uv.x );\n float phi = ( uv.y < a ) ? uv.y / a * PI : PI + ( uv.y - a ) / ( 1.0 - a ) * PI;\n float P1 = r * cos( phi );\n float P2 = r * sin( phi ) * ( ( uv.y < a ) ? 1.0 : V.z );\n\n // compute normal\n vec3 N = P1 * T1 + P2 * T2 + V * sqrt( max( 0.0, 1.0 - P1 * P1 - P2 * P2 ) );\n\n // unstretch\n N = normalize( vec3( roughness * N.xy, max( 0.0, N.z ) ) );\n\n return N;\n\n }\n\n // Below are PDF and related functions for use in a Monte Carlo path tracer\n // as specified in Appendix B of the following paper\n // See equation (34) from reference [0]\n float ggxLamda( float theta, float roughness ) {\n\n float tanTheta = tan( theta );\n float tanTheta2 = tanTheta * tanTheta;\n float alpha2 = roughness * roughness;\n\n float numerator = - 1.0 + sqrt( 1.0 + alpha2 * tanTheta2 );\n return numerator / 2.0;\n\n }\n\n // See equation (34) from reference [0]\n float ggxShadowMaskG1( float theta, float roughness ) {\n\n return 1.0 / ( 1.0 + ggxLamda( theta, roughness ) );\n\n }\n\n // See equation (125) from reference [4]\n float ggxShadowMaskG2( vec3 wi, vec3 wo, float roughness ) {\n\n float incidentTheta = acos( wi.z );\n float scatterTheta = acos( wo.z );\n return 1.0 / ( 1.0 + ggxLamda( incidentTheta, roughness ) + ggxLamda( scatterTheta, roughness ) );\n\n }\n\n // See equation (33) from reference [0]\n float ggxDistribution( vec3 halfVector, float roughness ) {\n\n float a2 = roughness * roughness;\n a2 = max( EPSILON, a2 );\n float cosTheta = halfVector.z;\n float cosTheta4 = pow( cosTheta, 4.0 );\n\n if ( cosTheta == 0.0 ) return 0.0;\n\n float theta = acosSafe( halfVector.z );\n float tanTheta = tan( theta );\n float tanTheta2 = pow( tanTheta, 2.0 );\n\n float denom = PI * cosTheta4 * pow( a2 + tanTheta2, 2.0 );\n return ( a2 / denom );\n\n }\n\n // See equation (3) from reference [2]\n float ggxPDF( vec3 wi, vec3 halfVector, float roughness ) {\n\n float incidentTheta = acos( wi.z );\n float D = ggxDistribution( halfVector, roughness );\n float G1 = ggxShadowMaskG1( incidentTheta, roughness );\n\n return D * G1 * max( 0.0, dot( wi, halfVector ) ) / wi.z;\n\n }\n\n", Fn = "\n\n // XYZ to sRGB color space\n const mat3 XYZ_TO_REC709 = mat3(\n 3.2404542, -0.9692660, 0.0556434,\n -1.5371385, 1.8760108, -0.2040259,\n -0.4985314, 0.0415560, 1.0572252\n );\n\n vec3 fresnel0ToIor( vec3 fresnel0 ) {\n\n vec3 sqrtF0 = sqrt( fresnel0 );\n return ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\n }\n\n // Conversion FO/IOR\n vec3 iorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\n return square( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\n }\n\n // ior is a value between 1.0 and 3.0. 1.0 is air interface\n float iorToFresnel0( float transmittedIor, float incidentIor ) {\n\n return square( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ) );\n\n }\n\n // Fresnel equations for dielectric/dielectric interfaces. See https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html\n vec3 evalSensitivity( float OPD, vec3 shift ) {\n\n float phase = 2.0 * PI * OPD * 1.0e-9;\n\n vec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n vec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n vec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\n vec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - square( phase ) * var );\n xyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * square( phase ) );\n xyz /= 1.0685e-7;\n\n vec3 srgb = XYZ_TO_REC709 * xyz;\n return srgb;\n\n }\n\n // See Section 4. Analytic Spectral Integration, A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence, https://hal.archives-ouvertes.fr/hal-01518344/document\n vec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\n vec3 I;\n\n // Force iridescenceIor -> outsideIOR when thinFilmThickness -> 0.0\n float iridescenceIor = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\n // Evaluate the cosTheta on the base layer (Snell law)\n float sinTheta2Sq = square( outsideIOR / iridescenceIor ) * ( 1.0 - square( cosTheta1 ) );\n\n // Handle TIR:\n float cosTheta2Sq = 1.0 - sinTheta2Sq;\n if ( cosTheta2Sq < 0.0 ) {\n\n return vec3( 1.0 );\n\n }\n\n float cosTheta2 = sqrt( cosTheta2Sq );\n\n // First interface\n float R0 = iorToFresnel0( iridescenceIor, outsideIOR );\n float R12 = schlickFresnel( cosTheta1, R0 );\n float R21 = R12;\n float T121 = 1.0 - R12;\n float phi12 = 0.0;\n if ( iridescenceIor < outsideIOR ) {\n\n phi12 = PI;\n\n }\n\n float phi21 = PI - phi12;\n\n // Second interface\n vec3 baseIOR = fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) ); // guard against 1.0\n vec3 R1 = iorToFresnel0( baseIOR, iridescenceIor );\n vec3 R23 = schlickFresnel( cosTheta2, R1 );\n vec3 phi23 = vec3( 0.0 );\n if ( baseIOR[0] < iridescenceIor ) {\n\n phi23[ 0 ] = PI;\n\n }\n\n if ( baseIOR[1] < iridescenceIor ) {\n\n phi23[ 1 ] = PI;\n\n }\n\n if ( baseIOR[2] < iridescenceIor ) {\n\n phi23[ 2 ] = PI;\n\n }\n\n // Phase shift\n float OPD = 2.0 * iridescenceIor * thinFilmThickness * cosTheta2;\n vec3 phi = vec3( phi21 ) + phi23;\n\n // Compound terms\n vec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n vec3 r123 = sqrt( R123 );\n vec3 Rs = square( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\n // Reflectance term for m = 0 (DC term amplitude)\n vec3 C0 = R12 + Rs;\n I = C0;\n\n // Reflectance term for m > 0 (pairs of diracs)\n vec3 Cm = Rs - T121;\n for ( int m = 1; m <= 2; ++ m ) {\n\n Cm *= r123;\n vec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n I += Cm * Sm;\n\n }\n\n // Since out of gamut colors might be produced, negative color values are clamped to 0.\n return max( I, vec3( 0.0 ) );\n\n }\n\n", In = "\n\n // See equation (2) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n float velvetD( float cosThetaH, float roughness ) {\n\n float alpha = max( roughness, 0.07 );\n alpha = alpha * alpha;\n\n float invAlpha = 1.0 / alpha;\n\n float sqrCosThetaH = cosThetaH * cosThetaH;\n float sinThetaH = max( 1.0 - sqrCosThetaH, 0.001 );\n\n return ( 2.0 + invAlpha ) * pow( sinThetaH, 0.5 * invAlpha ) / ( 2.0 * PI );\n\n }\n\n float velvetParamsInterpolate( int i, float oneMinusAlphaSquared ) {\n\n const float p0[5] = float[5]( 25.3245, 3.32435, 0.16801, -1.27393, -4.85967 );\n const float p1[5] = float[5]( 21.5473, 3.82987, 0.19823, -1.97760, -4.32054 );\n\n return mix( p1[i], p0[i], oneMinusAlphaSquared );\n\n }\n\n float velvetL( float x, float alpha ) {\n\n float oneMinusAlpha = 1.0 - alpha;\n float oneMinusAlphaSquared = oneMinusAlpha * oneMinusAlpha;\n\n float a = velvetParamsInterpolate( 0, oneMinusAlphaSquared );\n float b = velvetParamsInterpolate( 1, oneMinusAlphaSquared );\n float c = velvetParamsInterpolate( 2, oneMinusAlphaSquared );\n float d = velvetParamsInterpolate( 3, oneMinusAlphaSquared );\n float e = velvetParamsInterpolate( 4, oneMinusAlphaSquared );\n\n return a / ( 1.0 + b * pow( abs( x ), c ) ) + d * x + e;\n\n }\n\n // See equation (3) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n float velvetLambda( float cosTheta, float alpha ) {\n\n return abs( cosTheta ) < 0.5 ? exp( velvetL( cosTheta, alpha ) ) : exp( 2.0 * velvetL( 0.5, alpha ) - velvetL( 1.0 - cosTheta, alpha ) );\n\n }\n\n // See Section 3, Shadowing Term, in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n float velvetG( float cosThetaO, float cosThetaI, float roughness ) {\n\n float alpha = max( roughness, 0.07 );\n alpha = alpha * alpha;\n\n return 1.0 / ( 1.0 + velvetLambda( cosThetaO, alpha ) + velvetLambda( cosThetaI, alpha ) );\n\n }\n\n float directionalAlbedoSheen( float cosTheta, float alpha ) {\n\n cosTheta = saturate( cosTheta );\n\n float c = 1.0 - cosTheta;\n float c3 = c * c * c;\n\n return 0.65584461 * c3 + 1.0 / ( 4.16526551 + exp( -7.97291361 * sqrt( alpha ) + 6.33516894 ) );\n\n }\n\n float sheenAlbedoScaling( vec3 wo, vec3 wi, SurfaceRecord surf ) {\n\n float alpha = max( surf.sheenRoughness, 0.07 );\n alpha = alpha * alpha;\n\n float maxSheenColor = max( max( surf.sheenColor.r, surf.sheenColor.g ), surf.sheenColor.b );\n\n float eWo = directionalAlbedoSheen( saturateCos( wo.z ), alpha );\n float eWi = directionalAlbedoSheen( saturateCos( wi.z ), alpha );\n\n return min( 1.0 - maxSheenColor * eWo, 1.0 - maxSheenColor * eWi );\n\n }\n\n // See Section 5, Layering, in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n float sheenAlbedoScaling( vec3 wo, SurfaceRecord surf ) {\n\n float alpha = max( surf.sheenRoughness, 0.07 );\n alpha = alpha * alpha;\n\n float maxSheenColor = max( max( surf.sheenColor.r, surf.sheenColor.g ), surf.sheenColor.b );\n\n float eWo = directionalAlbedoSheen( saturateCos( wo.z ), alpha );\n\n return 1.0 - maxSheenColor * eWo;\n\n }\n\n", Ln = "\n\n#ifndef FOG_CHECK_ITERATIONS\n#define FOG_CHECK_ITERATIONS 30\n#endif\n\n// returns whether the given material is a fog material or not\nbool isMaterialFogVolume( sampler2D materials, uint materialIndex ) {\n\n uint i = materialIndex * 45u;\n vec4 s14 = texelFetch1D( materials, i + 14u );\n return bool( int( s14.b ) & 4 );\n\n}\n\n// returns true if we're within the first fog volume we hit\nbool bvhIntersectFogVolumeHit(\n vec3 rayOrigin, vec3 rayDirection,\n usampler2D materialIndexAttribute, sampler2D materials,\n inout Material material\n) {\n\n material.fogVolume = false;\n\n for ( int i = 0; i < FOG_CHECK_ITERATIONS; i ++ ) {\n\n // find nearest hit\n uvec4 faceIndices = uvec4( 0u );\n vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );\n vec3 barycoord = vec3( 0.0 );\n float side = 1.0;\n float dist = 0.0;\n bool hit = bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );\n if ( hit ) {\n\n // if it's a fog volume return whether we hit the front or back face\n uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;\n if ( isMaterialFogVolume( materials, materialIndex ) ) {\n\n material = readMaterialInfo( materials, materialIndex );\n return side == - 1.0;\n\n } else {\n\n // move the ray forward\n rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );\n\n }\n\n } else {\n\n return false;\n\n }\n\n }\n\n return false;\n\n}\n\n", Rn = "\n\n // step through multiple surface hits and accumulate color attenuation based on transmissive surfaces\n // returns true if a solid surface was hit\n bool attenuateHit(\n RenderState state,\n Ray ray, float rayDist,\n out vec3 color\n ) {\n\n // store the original bounce index so we can reset it after\n uint originalBounceIndex = sobolBounceIndex;\n\n int traversals = state.traversals;\n int transmissiveTraversals = state.transmissiveTraversals;\n bool isShadowRay = state.isShadowRay;\n Material fogMaterial = state.fogMaterial;\n\n vec3 startPoint = ray.origin;\n\n // hit results\n SurfaceHit surfaceHit;\n\n color = vec3( 1.0 );\n\n bool result = true;\n for ( int i = 0; i < traversals; i ++ ) {\n\n sobolBounceIndex ++;\n\n int hitType = traceScene( ray, fogMaterial, surfaceHit );\n\n if ( hitType == FOG_HIT ) {\n\n result = true;\n break;\n\n } else if ( hitType == SURFACE_HIT ) {\n\n float totalDist = distance( startPoint, ray.origin + ray.direction * surfaceHit.dist );\n if ( totalDist > rayDist ) {\n\n result = false;\n break;\n\n }\n\n // TODO: attenuate the contribution based on the PDF of the resulting ray including refraction values\n // Should be able to work using the material BSDF functions which will take into account specularity, etc.\n // TODO: should we account for emissive surfaces here?\n\n uint materialIndex = uTexelFetch1D( materialIndexAttribute, surfaceHit.faceIndices.x ).r;\n Material material = readMaterialInfo( materials, materialIndex );\n\n // adjust the ray to the new surface\n bool isEntering = surfaceHit.side == 1.0;\n ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );\n\n #if FEATURE_FOG\n\n if ( material.fogVolume ) {\n\n fogMaterial = material;\n fogMaterial.fogVolume = surfaceHit.side == 1.0;\n i -= sign( transmissiveTraversals );\n transmissiveTraversals --;\n continue;\n\n }\n\n #endif\n\n if ( ! material.castShadow && isShadowRay ) {\n\n continue;\n\n }\n\n vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, surfaceHit.barycoord, surfaceHit.faceIndices.xyz ).xy;\n vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, surfaceHit.barycoord, surfaceHit.faceIndices.xyz );\n\n // albedo\n vec4 albedo = vec4( material.color, material.opacity );\n if ( material.map != - 1 ) {\n\n vec3 uvPrime = material.mapTransform * vec3( uv, 1 );\n albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );\n\n }\n\n if ( material.vertexColors ) {\n\n albedo *= vertexColor;\n\n }\n\n // alphaMap\n if ( material.alphaMap != - 1 ) {\n\n albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;\n\n }\n\n // transmission\n float transmission = material.transmission;\n if ( material.transmissionMap != - 1 ) {\n\n vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );\n transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;\n\n }\n\n // metalness\n float metalness = material.metalness;\n if ( material.metalnessMap != - 1 ) {\n\n vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );\n metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;\n\n }\n\n float alphaTest = material.alphaTest;\n bool useAlphaTest = alphaTest != 0.0;\n float transmissionFactor = ( 1.0 - metalness ) * transmission;\n if (\n transmissionFactor < rand( 9 ) && ! (\n // material sidedness\n material.side != 0.0 && surfaceHit.side == material.side\n\n // alpha test\n || useAlphaTest && albedo.a < alphaTest\n\n // opacity\n || material.transparent && ! useAlphaTest && albedo.a < rand( 10 )\n )\n ) {\n\n result = true;\n break;\n\n }\n\n if ( surfaceHit.side == 1.0 && isEntering ) {\n\n // only attenuate by surface color on the way in\n color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );\n\n } else if ( surfaceHit.side == - 1.0 ) {\n\n // attenuate by medium once we hit the opposite side of the model\n color *= transmissionAttenuation( surfaceHit.dist, material.attenuationColor, material.attenuationDistance );\n\n }\n\n bool isTransmissiveRay = dot( ray.direction, surfaceHit.faceNormal * surfaceHit.side ) < 0.0;\n if ( ( isTransmissiveRay || isEntering ) && transmissiveTraversals > 0 ) {\n\n i -= sign( transmissiveTraversals );\n transmissiveTraversals --;\n\n }\n\n } else {\n\n result = false;\n break;\n\n }\n\n }\n\n // reset the bounce index\n sobolBounceIndex = originalBounceIndex;\n return result;\n\n }\n\n", zn = "\n\n vec3 ndcToRayOrigin( vec2 coord ) {\n\n vec4 rayOrigin4 = cameraWorldMatrix * invProjectionMatrix * vec4( coord, - 1.0, 1.0 );\n return rayOrigin4.xyz / rayOrigin4.w;\n }\n\n Ray getCameraRay() {\n\n vec2 ssd = vec2( 1.0 ) / resolution;\n\n // Jitter the camera ray by finding a uv coordinate at a random sample\n // around this pixel's UV coordinate for AA\n vec2 ruv = rand2( 0 );\n vec2 jitteredUv = vUv + vec2( tentFilter( ruv.x ) * ssd.x, tentFilter( ruv.y ) * ssd.y );\n Ray ray;\n\n #if CAMERA_TYPE == 2\n\n // Equirectangular projection\n vec4 rayDirection4 = vec4( equirectUvToDirection( jitteredUv ), 0.0 );\n vec4 rayOrigin4 = vec4( 0.0, 0.0, 0.0, 1.0 );\n\n rayDirection4 = cameraWorldMatrix * rayDirection4;\n rayOrigin4 = cameraWorldMatrix * rayOrigin4;\n\n ray.direction = normalize( rayDirection4.xyz );\n ray.origin = rayOrigin4.xyz / rayOrigin4.w;\n\n #else\n\n // get [- 1, 1] normalized device coordinates\n vec2 ndc = 2.0 * jitteredUv - vec2( 1.0 );\n ray.origin = ndcToRayOrigin( ndc );\n\n #if CAMERA_TYPE == 1\n\n // Orthographic projection\n ray.direction = ( cameraWorldMatrix * vec4( 0.0, 0.0, - 1.0, 0.0 ) ).xyz;\n ray.direction = normalize( ray.direction );\n\n #else\n\n // Perspective projection\n ray.direction = normalize( mat3( cameraWorldMatrix ) * ( invProjectionMatrix * vec4( ndc, 0.0, 1.0 ) ).xyz );\n\n #endif\n\n #endif\n\n #if FEATURE_DOF\n {\n\n // depth of field\n vec3 focalPoint = ray.origin + normalize( ray.direction ) * physicalCamera.focusDistance;\n\n // get the aperture sample\n // if blades === 0 then we assume a circle\n vec3 shapeUVW= rand3( 1 );\n int blades = physicalCamera.apertureBlades;\n float anamorphicRatio = physicalCamera.anamorphicRatio;\n vec2 apertureSample = blades == 0 ? sampleCircle( shapeUVW.xy ) : sampleRegularPolygon( blades, shapeUVW );\n apertureSample *= physicalCamera.bokehSize * 0.5 * 1e-3;\n\n // rotate the aperture shape\n apertureSample =\n rotateVector( apertureSample, physicalCamera.apertureRotation ) *\n saturate( vec2( anamorphicRatio, 1.0 / anamorphicRatio ) );\n\n // create the new ray\n ray.origin += ( cameraWorldMatrix * vec4( apertureSample, 0.0, 0.0 ) ).xyz;\n ray.direction = focalPoint - ray.origin;\n\n }\n #endif\n\n ray.direction = normalize( ray.direction );\n\n return ray;\n\n }\n\n", Bn = "\n\n vec3 directLightContribution( vec3 worldWo, SurfaceRecord surf, RenderState state, vec3 rayOrigin ) {\n\n vec3 result = vec3( 0.0 );\n\n // uniformly pick a light or environment map\n if( lightsDenom != 0.0 && rand( 5 ) < float( lights.count ) / lightsDenom ) {\n\n // sample a light or environment\n LightRecord lightRec = randomLightSample( lights.tex, iesProfiles, lights.count, rayOrigin, rand3( 6 ) );\n\n bool isSampleBelowSurface = ! surf.volumeParticle && dot( surf.faceNormal, lightRec.direction ) < 0.0;\n if ( isSampleBelowSurface ) {\n\n lightRec.pdf = 0.0;\n\n }\n\n // check if a ray could even reach the light area\n Ray lightRay;\n lightRay.origin = rayOrigin;\n lightRay.direction = lightRec.direction;\n vec3 attenuatedColor;\n if (\n lightRec.pdf > 0.0 &&\n isDirectionValid( lightRec.direction, surf.normal, surf.faceNormal ) &&\n ! attenuateHit( state, lightRay, lightRec.dist, attenuatedColor )\n ) {\n\n // get the material pdf\n vec3 sampleColor;\n float lightMaterialPdf = bsdfResult( worldWo, lightRec.direction, surf, sampleColor );\n bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );\n if ( lightMaterialPdf > 0.0 && isValidSampleColor ) {\n\n // weight the direct light contribution\n float lightPdf = lightRec.pdf / lightsDenom;\n float misWeight = lightRec.type == SPOT_LIGHT_TYPE || lightRec.type == DIR_LIGHT_TYPE || lightRec.type == POINT_LIGHT_TYPE ? 1.0 : misHeuristic( lightPdf, lightMaterialPdf );\n result = attenuatedColor * lightRec.emission * state.throughputColor * sampleColor * misWeight / lightPdf;\n\n }\n\n }\n\n } else if ( envMapInfo.totalSum != 0.0 && environmentIntensity != 0.0 ) {\n\n // find a sample in the environment map to include in the contribution\n vec3 envColor, envDirection;\n float envPdf = sampleEquirectProbability( rand2( 7 ), envColor, envDirection );\n envDirection = invEnvRotation3x3 * envDirection;\n\n // this env sampling is not set up for transmissive sampling and yields overly bright\n // results so we ignore the sample in this case.\n // TODO: this should be improved but how? The env samples could traverse a few layers?\n bool isSampleBelowSurface = ! surf.volumeParticle && dot( surf.faceNormal, envDirection ) < 0.0;\n if ( isSampleBelowSurface ) {\n\n envPdf = 0.0;\n\n }\n\n // check if a ray could even reach the surface\n Ray envRay;\n envRay.origin = rayOrigin;\n envRay.direction = envDirection;\n vec3 attenuatedColor;\n if (\n envPdf > 0.0 &&\n isDirectionValid( envDirection, surf.normal, surf.faceNormal ) &&\n ! attenuateHit( state, envRay, INFINITY, attenuatedColor )\n ) {\n\n // get the material pdf\n vec3 sampleColor;\n float envMaterialPdf = bsdfResult( worldWo, envDirection, surf, sampleColor );\n bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );\n if ( envMaterialPdf > 0.0 && isValidSampleColor ) {\n\n // weight the direct light contribution\n envPdf /= lightsDenom;\n float misWeight = misHeuristic( envPdf, envMaterialPdf );\n result = attenuatedColor * environmentIntensity * envColor * state.throughputColor * sampleColor * misWeight / envPdf;\n\n }\n\n }\n\n }\n\n // Function changed to have a single return statement to potentially help with crashes on Mac OS.\n // See issue #470\n return result;\n\n }\n\n", Vn = "\n\n #define SKIP_SURFACE 0\n #define HIT_SURFACE 1\n int getSurfaceRecord(\n Material material, SurfaceHit surfaceHit, sampler2DArray attributesArray,\n float accumulatedRoughness,\n inout SurfaceRecord surf\n ) {\n\n if ( material.fogVolume ) {\n\n vec3 normal = vec3( 0, 0, 1 );\n\n SurfaceRecord fogSurface;\n fogSurface.volumeParticle = true;\n fogSurface.color = material.color;\n fogSurface.emission = material.emissiveIntensity * material.emissive;\n fogSurface.normal = normal;\n fogSurface.faceNormal = normal;\n fogSurface.clearcoatNormal = normal;\n\n surf = fogSurface;\n return HIT_SURFACE;\n\n }\n\n // uv coord for textures\n vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, surfaceHit.barycoord, surfaceHit.faceIndices.xyz ).xy;\n vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, surfaceHit.barycoord, surfaceHit.faceIndices.xyz );\n\n // albedo\n vec4 albedo = vec4( material.color, material.opacity );\n if ( material.map != - 1 ) {\n\n vec3 uvPrime = material.mapTransform * vec3( uv, 1 );\n albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );\n\n }\n\n if ( material.vertexColors ) {\n\n albedo *= vertexColor;\n\n }\n\n // alphaMap\n if ( material.alphaMap != - 1 ) {\n\n albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;\n\n }\n\n // possibly skip this sample if it's transparent, alpha test is enabled, or we hit the wrong material side\n // and it's single sided.\n // - alpha test is disabled when it === 0\n // - the material sidedness test is complicated because we want light to pass through the back side but still\n // be able to see the front side. This boolean checks if the side we hit is the front side on the first ray\n // and we're rendering the other then we skip it. Do the opposite on subsequent bounces to get incoming light.\n float alphaTest = material.alphaTest;\n bool useAlphaTest = alphaTest != 0.0;\n if (\n // material sidedness\n material.side != 0.0 && surfaceHit.side != material.side\n\n // alpha test\n || useAlphaTest && albedo.a < alphaTest\n\n // opacity\n || material.transparent && ! useAlphaTest && albedo.a < rand( 3 )\n ) {\n\n return SKIP_SURFACE;\n\n }\n\n // fetch the interpolated smooth normal\n vec3 normal = normalize( textureSampleBarycoord(\n attributesArray,\n ATTR_NORMAL,\n surfaceHit.barycoord,\n surfaceHit.faceIndices.xyz\n ).xyz );\n\n // roughness\n float roughness = material.roughness;\n if ( material.roughnessMap != - 1 ) {\n\n vec3 uvPrime = material.roughnessMapTransform * vec3( uv, 1 );\n roughness *= texture2D( textures, vec3( uvPrime.xy, material.roughnessMap ) ).g;\n\n }\n\n // metalness\n float metalness = material.metalness;\n if ( material.metalnessMap != - 1 ) {\n\n vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );\n metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;\n\n }\n\n // emission\n vec3 emission = material.emissiveIntensity * material.emissive;\n if ( material.emissiveMap != - 1 ) {\n\n vec3 uvPrime = material.emissiveMapTransform * vec3( uv, 1 );\n emission *= texture2D( textures, vec3( uvPrime.xy, material.emissiveMap ) ).xyz;\n\n }\n\n // transmission\n float transmission = material.transmission;\n if ( material.transmissionMap != - 1 ) {\n\n vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );\n transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;\n\n }\n\n // normal\n if ( material.flatShading ) {\n\n // if we're rendering a flat shaded object then use the face normals - the face normal\n // is provided based on the side the ray hits the mesh so flip it to align with the\n // interpolated vertex normals.\n normal = surfaceHit.faceNormal * surfaceHit.side;\n\n }\n\n vec3 baseNormal = normal;\n if ( material.normalMap != - 1 ) {\n\n vec4 tangentSample = textureSampleBarycoord(\n attributesArray,\n ATTR_TANGENT,\n surfaceHit.barycoord,\n surfaceHit.faceIndices.xyz\n );\n\n // some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate\n // resulting in NaNs and slow path tracing.\n if ( length( tangentSample.xyz ) > 0.0 ) {\n\n vec3 tangent = normalize( tangentSample.xyz );\n vec3 bitangent = normalize( cross( normal, tangent ) * tangentSample.w );\n mat3 vTBN = mat3( tangent, bitangent, normal );\n\n vec3 uvPrime = material.normalMapTransform * vec3( uv, 1 );\n vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.normalMap ) ).xyz * 2.0 - 1.0;\n texNormal.xy *= material.normalScale;\n normal = vTBN * texNormal;\n\n }\n\n }\n\n normal *= surfaceHit.side;\n\n // clearcoat\n float clearcoat = material.clearcoat;\n if ( material.clearcoatMap != - 1 ) {\n\n vec3 uvPrime = material.clearcoatMapTransform * vec3( uv, 1 );\n clearcoat *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatMap ) ).r;\n\n }\n\n // clearcoatRoughness\n float clearcoatRoughness = material.clearcoatRoughness;\n if ( material.clearcoatRoughnessMap != - 1 ) {\n\n vec3 uvPrime = material.clearcoatRoughnessMapTransform * vec3( uv, 1 );\n clearcoatRoughness *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatRoughnessMap ) ).g;\n\n }\n\n // clearcoatNormal\n vec3 clearcoatNormal = baseNormal;\n if ( material.clearcoatNormalMap != - 1 ) {\n\n vec4 tangentSample = textureSampleBarycoord(\n attributesArray,\n ATTR_TANGENT,\n surfaceHit.barycoord,\n surfaceHit.faceIndices.xyz\n );\n\n // some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate\n // resulting in NaNs and slow path tracing.\n if ( length( tangentSample.xyz ) > 0.0 ) {\n\n vec3 tangent = normalize( tangentSample.xyz );\n vec3 bitangent = normalize( cross( clearcoatNormal, tangent ) * tangentSample.w );\n mat3 vTBN = mat3( tangent, bitangent, clearcoatNormal );\n\n vec3 uvPrime = material.clearcoatNormalMapTransform * vec3( uv, 1 );\n vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.clearcoatNormalMap ) ).xyz * 2.0 - 1.0;\n texNormal.xy *= material.clearcoatNormalScale;\n clearcoatNormal = vTBN * texNormal;\n\n }\n\n }\n\n clearcoatNormal *= surfaceHit.side;\n\n // sheenColor\n vec3 sheenColor = material.sheenColor;\n if ( material.sheenColorMap != - 1 ) {\n\n vec3 uvPrime = material.sheenColorMapTransform * vec3( uv, 1 );\n sheenColor *= texture2D( textures, vec3( uvPrime.xy, material.sheenColorMap ) ).rgb;\n\n }\n\n // sheenRoughness\n float sheenRoughness = material.sheenRoughness;\n if ( material.sheenRoughnessMap != - 1 ) {\n\n vec3 uvPrime = material.sheenRoughnessMapTransform * vec3( uv, 1 );\n sheenRoughness *= texture2D( textures, vec3( uvPrime.xy, material.sheenRoughnessMap ) ).a;\n\n }\n\n // iridescence\n float iridescence = material.iridescence;\n if ( material.iridescenceMap != - 1 ) {\n\n vec3 uvPrime = material.iridescenceMapTransform * vec3( uv, 1 );\n iridescence *= texture2D( textures, vec3( uvPrime.xy, material.iridescenceMap ) ).r;\n\n }\n\n // iridescence thickness\n float iridescenceThickness = material.iridescenceThicknessMaximum;\n if ( material.iridescenceThicknessMap != - 1 ) {\n\n vec3 uvPrime = material.iridescenceThicknessMapTransform * vec3( uv, 1 );\n float iridescenceThicknessSampled = texture2D( textures, vec3( uvPrime.xy, material.iridescenceThicknessMap ) ).g;\n iridescenceThickness = mix( material.iridescenceThicknessMinimum, material.iridescenceThicknessMaximum, iridescenceThicknessSampled );\n\n }\n\n iridescence = iridescenceThickness == 0.0 ? 0.0 : iridescence;\n\n // specular color\n vec3 specularColor = material.specularColor;\n if ( material.specularColorMap != - 1 ) {\n\n vec3 uvPrime = material.specularColorMapTransform * vec3( uv, 1 );\n specularColor *= texture2D( textures, vec3( uvPrime.xy, material.specularColorMap ) ).rgb;\n\n }\n\n // specular intensity\n float specularIntensity = material.specularIntensity;\n if ( material.specularIntensityMap != - 1 ) {\n\n vec3 uvPrime = material.specularIntensityMapTransform * vec3( uv, 1 );\n specularIntensity *= texture2D( textures, vec3( uvPrime.xy, material.specularIntensityMap ) ).a;\n\n }\n\n surf.volumeParticle = false;\n\n surf.faceNormal = surfaceHit.faceNormal;\n surf.normal = normal;\n\n surf.metalness = metalness;\n surf.color = albedo.rgb;\n surf.emission = emission;\n\n surf.ior = material.ior;\n surf.transmission = transmission;\n surf.thinFilm = material.thinFilm;\n surf.attenuationColor = material.attenuationColor;\n surf.attenuationDistance = material.attenuationDistance;\n\n surf.clearcoatNormal = clearcoatNormal;\n surf.clearcoat = clearcoat;\n\n surf.sheen = material.sheen;\n surf.sheenColor = sheenColor;\n\n surf.iridescence = iridescence;\n surf.iridescenceIor = material.iridescenceIor;\n surf.iridescenceThickness = iridescenceThickness;\n\n surf.specularColor = specularColor;\n surf.specularIntensity = specularIntensity;\n\n // apply perceptual roughness factor from gltf. sheen perceptual roughness is\n // applied by its brdf function\n // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces\n surf.roughness = roughness * roughness;\n surf.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness;\n surf.sheenRoughness = sheenRoughness;\n\n // frontFace is used to determine transmissive properties and PDF. If no transmission is used\n // then we can just always assume this is a front face.\n surf.frontFace = surfaceHit.side == 1.0 || transmission == 0.0;\n surf.eta = material.thinFilm || surf.frontFace ? 1.0 / material.ior : material.ior;\n surf.f0 = iorRatioToF0( surf.eta );\n\n // Compute the filtered roughness value to use during specular reflection computations.\n // The accumulated roughness value is scaled by a user setting and a \"magic value\" of 5.0.\n // If we're exiting something transmissive then scale the factor down significantly so we can retain\n // sharp internal reflections\n surf.filteredRoughness = applyFilteredGlossy( surf.roughness, accumulatedRoughness );\n surf.filteredClearcoatRoughness = applyFilteredGlossy( surf.clearcoatRoughness, accumulatedRoughness );\n\n // get the normal frames\n surf.normalBasis = getBasisFromNormal( surf.normal );\n surf.normalInvBasis = inverse( surf.normalBasis );\n\n surf.clearcoatBasis = getBasisFromNormal( surf.clearcoatNormal );\n surf.clearcoatInvBasis = inverse( surf.clearcoatBasis );\n\n return HIT_SURFACE;\n\n }\n", Hn = "\n\n struct Ray {\n\n vec3 origin;\n vec3 direction;\n\n };\n\n struct SurfaceHit {\n\n uvec4 faceIndices;\n vec3 barycoord;\n vec3 faceNormal;\n float side;\n float dist;\n\n };\n\n struct RenderState {\n\n bool firstRay;\n bool transmissiveRay;\n bool isShadowRay;\n float accumulatedRoughness;\n int transmissiveTraversals;\n int traversals;\n uint depth;\n vec3 throughputColor;\n Material fogMaterial;\n\n };\n\n RenderState initRenderState() {\n\n RenderState result;\n result.firstRay = true;\n result.transmissiveRay = true;\n result.isShadowRay = false;\n result.accumulatedRoughness = 0.0;\n result.transmissiveTraversals = 0;\n result.traversals = 0;\n result.throughputColor = vec3( 1.0 );\n result.depth = 0u;\n result.fogMaterial.fogVolume = false;\n return result;\n\n }\n\n", Un = "\n\n #define NO_HIT 0\n #define SURFACE_HIT 1\n #define LIGHT_HIT 2\n #define FOG_HIT 3\n\n // Passing the global variable 'lights' into this function caused shader program errors.\n // So global variables like 'lights' and 'bvh' were moved out of the function parameters.\n // For more information, refer to: https://github.com/gkjohnson/three-gpu-pathtracer/pull/457\n int traceScene(\n Ray ray, Material fogMaterial, inout SurfaceHit surfaceHit\n ) {\n\n int result = NO_HIT;\n bool hit = bvhIntersectFirstHit( bvh, ray.origin, ray.direction, surfaceHit.faceIndices, surfaceHit.faceNormal, surfaceHit.barycoord, surfaceHit.side, surfaceHit.dist );\n\n #if FEATURE_FOG\n\n if ( fogMaterial.fogVolume ) {\n\n // offset the distance so we don't run into issues with particles on the same surface\n // as other objects\n float particleDist = intersectFogVolume( fogMaterial, rand( 1 ) );\n if ( particleDist + RAY_OFFSET < surfaceHit.dist ) {\n\n surfaceHit.side = 1.0;\n surfaceHit.faceNormal = normalize( - ray.direction );\n surfaceHit.dist = particleDist;\n return FOG_HIT;\n\n }\n\n }\n\n #endif\n\n if ( hit ) {\n\n result = SURFACE_HIT;\n\n }\n\n return result;\n\n }\n\n", Wn = class extends mt {
|
|
1381
|
+
}, vn = "\n\n struct PhysicalCamera {\n\n float focusDistance;\n float anamorphicRatio;\n float bokehSize;\n int apertureBlades;\n float apertureRotation;\n\n };\n\n", yn = "\n\n struct EquirectHdrInfo {\n\n sampler2D marginalWeights;\n sampler2D conditionalWeights;\n sampler2D map;\n\n float totalSum;\n\n };\n\n", bn = "\n\n #define RECT_AREA_LIGHT_TYPE 0\n #define CIRC_AREA_LIGHT_TYPE 1\n #define SPOT_LIGHT_TYPE 2\n #define DIR_LIGHT_TYPE 3\n #define POINT_LIGHT_TYPE 4\n\n struct LightsInfo {\n\n sampler2D tex;\n uint count;\n\n };\n\n struct Light {\n\n vec3 position;\n int type;\n\n vec3 color;\n float intensity;\n\n vec3 u;\n vec3 v;\n float area;\n\n // spot light fields\n float radius;\n float near;\n float decay;\n float distance;\n float coneCos;\n float penumbraCos;\n int iesProfile;\n\n };\n\n Light readLightInfo( sampler2D tex, uint index ) {\n\n uint i = index * 6u;\n\n vec4 s0 = texelFetch1D( tex, i + 0u );\n vec4 s1 = texelFetch1D( tex, i + 1u );\n vec4 s2 = texelFetch1D( tex, i + 2u );\n vec4 s3 = texelFetch1D( tex, i + 3u );\n\n Light l;\n l.position = s0.rgb;\n l.type = int( round( s0.a ) );\n\n l.color = s1.rgb;\n l.intensity = s1.a;\n\n l.u = s2.rgb;\n l.v = s3.rgb;\n l.area = s3.a;\n\n if ( l.type == SPOT_LIGHT_TYPE || l.type == POINT_LIGHT_TYPE ) {\n\n vec4 s4 = texelFetch1D( tex, i + 4u );\n vec4 s5 = texelFetch1D( tex, i + 5u );\n l.radius = s4.r;\n l.decay = s4.g;\n l.distance = s4.b;\n l.coneCos = s4.a;\n\n l.penumbraCos = s5.r;\n l.iesProfile = int( round( s5.g ) );\n\n } else {\n\n l.radius = 0.0;\n l.decay = 0.0;\n l.distance = 0.0;\n\n l.coneCos = 0.0;\n l.penumbraCos = 0.0;\n l.iesProfile = - 1;\n\n }\n\n return l;\n\n }\n\n", xn = "\n\n struct Material {\n\n vec3 color;\n int map;\n\n float metalness;\n int metalnessMap;\n\n float roughness;\n int roughnessMap;\n\n float ior;\n float transmission;\n int transmissionMap;\n\n float emissiveIntensity;\n vec3 emissive;\n int emissiveMap;\n\n int normalMap;\n vec2 normalScale;\n\n float clearcoat;\n int clearcoatMap;\n int clearcoatNormalMap;\n vec2 clearcoatNormalScale;\n float clearcoatRoughness;\n int clearcoatRoughnessMap;\n\n int iridescenceMap;\n int iridescenceThicknessMap;\n float iridescence;\n float iridescenceIor;\n float iridescenceThicknessMinimum;\n float iridescenceThicknessMaximum;\n\n vec3 specularColor;\n int specularColorMap;\n\n float specularIntensity;\n int specularIntensityMap;\n bool thinFilm;\n\n vec3 attenuationColor;\n float attenuationDistance;\n\n int alphaMap;\n\n bool castShadow;\n float opacity;\n float alphaTest;\n\n float side;\n bool matte;\n\n float sheen;\n vec3 sheenColor;\n int sheenColorMap;\n float sheenRoughness;\n int sheenRoughnessMap;\n\n bool vertexColors;\n bool flatShading;\n bool transparent;\n bool fogVolume;\n\n mat3 mapTransform;\n mat3 metalnessMapTransform;\n mat3 roughnessMapTransform;\n mat3 transmissionMapTransform;\n mat3 emissiveMapTransform;\n mat3 normalMapTransform;\n mat3 clearcoatMapTransform;\n mat3 clearcoatNormalMapTransform;\n mat3 clearcoatRoughnessMapTransform;\n mat3 sheenColorMapTransform;\n mat3 sheenRoughnessMapTransform;\n mat3 iridescenceMapTransform;\n mat3 iridescenceThicknessMapTransform;\n mat3 specularColorMapTransform;\n mat3 specularIntensityMapTransform;\n\n };\n\n mat3 readTextureTransform( sampler2D tex, uint index ) {\n\n mat3 textureTransform;\n\n vec4 row1 = texelFetch1D( tex, index );\n vec4 row2 = texelFetch1D( tex, index + 1u );\n\n textureTransform[0] = vec3(row1.r, row2.r, 0.0);\n textureTransform[1] = vec3(row1.g, row2.g, 0.0);\n textureTransform[2] = vec3(row1.b, row2.b, 1.0);\n\n return textureTransform;\n\n }\n\n Material readMaterialInfo( sampler2D tex, uint index ) {\n\n uint i = index * 45u;\n\n vec4 s0 = texelFetch1D( tex, i + 0u );\n vec4 s1 = texelFetch1D( tex, i + 1u );\n vec4 s2 = texelFetch1D( tex, i + 2u );\n vec4 s3 = texelFetch1D( tex, i + 3u );\n vec4 s4 = texelFetch1D( tex, i + 4u );\n vec4 s5 = texelFetch1D( tex, i + 5u );\n vec4 s6 = texelFetch1D( tex, i + 6u );\n vec4 s7 = texelFetch1D( tex, i + 7u );\n vec4 s8 = texelFetch1D( tex, i + 8u );\n vec4 s9 = texelFetch1D( tex, i + 9u );\n vec4 s10 = texelFetch1D( tex, i + 10u );\n vec4 s11 = texelFetch1D( tex, i + 11u );\n vec4 s12 = texelFetch1D( tex, i + 12u );\n vec4 s13 = texelFetch1D( tex, i + 13u );\n vec4 s14 = texelFetch1D( tex, i + 14u );\n\n Material m;\n m.color = s0.rgb;\n m.map = int( round( s0.a ) );\n\n m.metalness = s1.r;\n m.metalnessMap = int( round( s1.g ) );\n m.roughness = s1.b;\n m.roughnessMap = int( round( s1.a ) );\n\n m.ior = s2.r;\n m.transmission = s2.g;\n m.transmissionMap = int( round( s2.b ) );\n m.emissiveIntensity = s2.a;\n\n m.emissive = s3.rgb;\n m.emissiveMap = int( round( s3.a ) );\n\n m.normalMap = int( round( s4.r ) );\n m.normalScale = s4.gb;\n\n m.clearcoat = s4.a;\n m.clearcoatMap = int( round( s5.r ) );\n m.clearcoatRoughness = s5.g;\n m.clearcoatRoughnessMap = int( round( s5.b ) );\n m.clearcoatNormalMap = int( round( s5.a ) );\n m.clearcoatNormalScale = s6.rg;\n\n m.sheen = s6.a;\n m.sheenColor = s7.rgb;\n m.sheenColorMap = int( round( s7.a ) );\n m.sheenRoughness = s8.r;\n m.sheenRoughnessMap = int( round( s8.g ) );\n\n m.iridescenceMap = int( round( s8.b ) );\n m.iridescenceThicknessMap = int( round( s8.a ) );\n m.iridescence = s9.r;\n m.iridescenceIor = s9.g;\n m.iridescenceThicknessMinimum = s9.b;\n m.iridescenceThicknessMaximum = s9.a;\n\n m.specularColor = s10.rgb;\n m.specularColorMap = int( round( s10.a ) );\n\n m.specularIntensity = s11.r;\n m.specularIntensityMap = int( round( s11.g ) );\n m.thinFilm = bool( s11.b );\n\n m.attenuationColor = s12.rgb;\n m.attenuationDistance = s12.a;\n\n m.alphaMap = int( round( s13.r ) );\n\n m.opacity = s13.g;\n m.alphaTest = s13.b;\n m.side = s13.a;\n\n m.matte = bool( s14.r );\n m.castShadow = bool( s14.g );\n m.vertexColors = bool( int( s14.b ) & 1 );\n m.flatShading = bool( int( s14.b ) & 2 );\n m.fogVolume = bool( int( s14.b ) & 4 );\n m.transparent = bool( s14.a );\n\n uint firstTextureTransformIdx = i + 15u;\n\n // mat3( 1.0 ) is an identity matrix\n m.mapTransform = m.map == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx );\n m.metalnessMapTransform = m.metalnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 2u );\n m.roughnessMapTransform = m.roughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 4u );\n m.transmissionMapTransform = m.transmissionMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 6u );\n m.emissiveMapTransform = m.emissiveMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 8u );\n m.normalMapTransform = m.normalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 10u );\n m.clearcoatMapTransform = m.clearcoatMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 12u );\n m.clearcoatNormalMapTransform = m.clearcoatNormalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 14u );\n m.clearcoatRoughnessMapTransform = m.clearcoatRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 16u );\n m.sheenColorMapTransform = m.sheenColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 18u );\n m.sheenRoughnessMapTransform = m.sheenRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 20u );\n m.iridescenceMapTransform = m.iridescenceMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 22u );\n m.iridescenceThicknessMapTransform = m.iridescenceThicknessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 24u );\n m.specularColorMapTransform = m.specularColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 26u );\n m.specularIntensityMapTransform = m.specularIntensityMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 28u );\n\n return m;\n\n }\n\n", Sn = "\n\n struct SurfaceRecord {\n\n // surface type\n bool volumeParticle;\n\n // geometry\n vec3 faceNormal;\n bool frontFace;\n vec3 normal;\n mat3 normalBasis;\n mat3 normalInvBasis;\n\n // cached properties\n float eta;\n float f0;\n\n // material\n float roughness;\n float filteredRoughness;\n float metalness;\n vec3 color;\n vec3 emission;\n\n // transmission\n float ior;\n float transmission;\n bool thinFilm;\n vec3 attenuationColor;\n float attenuationDistance;\n\n // clearcoat\n vec3 clearcoatNormal;\n mat3 clearcoatBasis;\n mat3 clearcoatInvBasis;\n float clearcoat;\n float clearcoatRoughness;\n float filteredClearcoatRoughness;\n\n // sheen\n float sheen;\n vec3 sheenColor;\n float sheenRoughness;\n\n // iridescence\n float iridescence;\n float iridescenceIor;\n float iridescenceThickness;\n\n // specular\n vec3 specularColor;\n float specularIntensity;\n };\n\n struct ScatterRecord {\n float specularPdf;\n float pdf;\n vec3 direction;\n vec3 color;\n };\n\n", Cn = "\n\n // samples the the given environment map in the given direction\n vec3 sampleEquirectColor( sampler2D envMap, vec3 direction ) {\n\n return texture2D( envMap, equirectDirectionToUv( direction ) ).rgb;\n\n }\n\n // gets the pdf of the given direction to sample\n float equirectDirectionPdf( vec3 direction ) {\n\n vec2 uv = equirectDirectionToUv( direction );\n float theta = uv.y * PI;\n float sinTheta = sin( theta );\n if ( sinTheta == 0.0 ) {\n\n return 0.0;\n\n }\n\n return 1.0 / ( 2.0 * PI * PI * sinTheta );\n\n }\n\n // samples the color given env map with CDF and returns the pdf of the direction\n float sampleEquirect( vec3 direction, inout vec3 color ) {\n\n float totalSum = envMapInfo.totalSum;\n if ( totalSum == 0.0 ) {\n\n color = vec3( 0.0 );\n return 1.0;\n\n }\n\n vec2 uv = equirectDirectionToUv( direction );\n color = texture2D( envMapInfo.map, uv ).rgb;\n\n float lum = luminance( color );\n ivec2 resolution = textureSize( envMapInfo.map, 0 );\n float pdf = lum / totalSum;\n\n return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );\n\n }\n\n // samples a direction of the envmap with color and retrieves pdf\n float sampleEquirectProbability( vec2 r, inout vec3 color, inout vec3 direction ) {\n\n // sample env map cdf\n float v = texture2D( envMapInfo.marginalWeights, vec2( r.x, 0.0 ) ).x;\n float u = texture2D( envMapInfo.conditionalWeights, vec2( r.y, v ) ).x;\n vec2 uv = vec2( u, v );\n\n vec3 derivedDirection = equirectUvToDirection( uv );\n direction = derivedDirection;\n color = texture2D( envMapInfo.map, uv ).rgb;\n\n float totalSum = envMapInfo.totalSum;\n float lum = luminance( color );\n ivec2 resolution = textureSize( envMapInfo.map, 0 );\n float pdf = lum / totalSum;\n\n return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );\n\n }\n", wn = "\n\n float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\n return smoothstep( coneCosine, penumbraCosine, angleCosine );\n\n }\n\n float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\n // based upon Frostbite 3 Moving to Physically-based Rendering\n // page 32, equation 26: E[window1]\n // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf\n float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), EPSILON );\n\n if ( cutoffDistance > 0.0 ) {\n\n distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\n }\n\n return distanceFalloff;\n\n }\n\n float getPhotometricAttenuation( sampler2DArray iesProfiles, int iesProfile, vec3 posToLight, vec3 lightDir, vec3 u, vec3 v ) {\n\n float cosTheta = dot( posToLight, lightDir );\n float angle = acos( cosTheta ) / PI;\n\n return texture2D( iesProfiles, vec3( angle, 0.0, iesProfile ) ).r;\n\n }\n\n struct LightRecord {\n\n float dist;\n vec3 direction;\n float pdf;\n vec3 emission;\n int type;\n\n };\n\n bool intersectLightAtIndex( sampler2D lights, vec3 rayOrigin, vec3 rayDirection, uint l, inout LightRecord lightRec ) {\n\n bool didHit = false;\n Light light = readLightInfo( lights, l );\n\n vec3 u = light.u;\n vec3 v = light.v;\n\n // check for backface\n vec3 normal = normalize( cross( u, v ) );\n if ( dot( normal, rayDirection ) > 0.0 ) {\n\n u *= 1.0 / dot( u, u );\n v *= 1.0 / dot( v, v );\n\n float dist;\n\n // MIS / light intersection is not supported for punctual lights.\n if(\n ( light.type == RECT_AREA_LIGHT_TYPE && intersectsRectangle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) ) ||\n ( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )\n ) {\n\n float cosTheta = dot( rayDirection, normal );\n didHit = true;\n lightRec.dist = dist;\n lightRec.pdf = ( dist * dist ) / ( light.area * cosTheta );\n lightRec.emission = light.color * light.intensity;\n lightRec.direction = rayDirection;\n lightRec.type = light.type;\n\n }\n\n }\n\n return didHit;\n\n }\n\n LightRecord randomAreaLightSample( Light light, vec3 rayOrigin, vec2 ruv ) {\n\n vec3 randomPos;\n if( light.type == RECT_AREA_LIGHT_TYPE ) {\n\n // rectangular area light\n randomPos = light.position + light.u * ( ruv.x - 0.5 ) + light.v * ( ruv.y - 0.5 );\n\n } else if( light.type == CIRC_AREA_LIGHT_TYPE ) {\n\n // circular area light\n float r = 0.5 * sqrt( ruv.x );\n float theta = ruv.y * 2.0 * PI;\n float x = r * cos( theta );\n float y = r * sin( theta );\n\n randomPos = light.position + light.u * x + light.v * y;\n\n }\n\n vec3 toLight = randomPos - rayOrigin;\n float lightDistSq = dot( toLight, toLight );\n float dist = sqrt( lightDistSq );\n vec3 direction = toLight / dist;\n vec3 lightNormal = normalize( cross( light.u, light.v ) );\n\n LightRecord lightRec;\n lightRec.type = light.type;\n lightRec.emission = light.color * light.intensity;\n lightRec.dist = dist;\n lightRec.direction = direction;\n\n // TODO: the denominator is potentially zero\n lightRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );\n\n return lightRec;\n\n }\n\n LightRecord randomSpotLightSample( Light light, sampler2DArray iesProfiles, vec3 rayOrigin, vec2 ruv ) {\n\n float radius = light.radius * sqrt( ruv.x );\n float theta = ruv.y * 2.0 * PI;\n float x = radius * cos( theta );\n float y = radius * sin( theta );\n\n vec3 u = light.u;\n vec3 v = light.v;\n vec3 normal = normalize( cross( u, v ) );\n\n float angle = acos( light.coneCos );\n float angleTan = tan( angle );\n float startDistance = light.radius / max( angleTan, EPSILON );\n\n vec3 randomPos = light.position - normal * startDistance + u * x + v * y;\n vec3 toLight = randomPos - rayOrigin;\n float lightDistSq = dot( toLight, toLight );\n float dist = sqrt( lightDistSq );\n\n vec3 direction = toLight / max( dist, EPSILON );\n float cosTheta = dot( direction, normal );\n\n float spotAttenuation = light.iesProfile != - 1 ?\n getPhotometricAttenuation( iesProfiles, light.iesProfile, direction, normal, u, v ) :\n getSpotAttenuation( light.coneCos, light.penumbraCos, cosTheta );\n\n float distanceAttenuation = getDistanceAttenuation( dist, light.distance, light.decay );\n LightRecord lightRec;\n lightRec.type = light.type;\n lightRec.dist = dist;\n lightRec.direction = direction;\n lightRec.emission = light.color * light.intensity * distanceAttenuation * spotAttenuation;\n lightRec.pdf = 1.0;\n\n return lightRec;\n\n }\n\n LightRecord randomLightSample( sampler2D lights, sampler2DArray iesProfiles, uint lightCount, vec3 rayOrigin, vec3 ruv ) {\n\n LightRecord result;\n\n // pick a random light\n uint l = uint( ruv.x * float( lightCount ) );\n Light light = readLightInfo( lights, l );\n\n if ( light.type == SPOT_LIGHT_TYPE ) {\n\n result = randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );\n\n } else if ( light.type == POINT_LIGHT_TYPE ) {\n\n vec3 lightRay = light.u - rayOrigin;\n float lightDist = length( lightRay );\n float cutoffDistance = light.distance;\n float distanceFalloff = 1.0 / max( pow( lightDist, light.decay ), 0.01 );\n if ( cutoffDistance > 0.0 ) {\n\n distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDist / cutoffDistance ) ) );\n\n }\n\n LightRecord rec;\n rec.direction = normalize( lightRay );\n rec.dist = length( lightRay );\n rec.pdf = 1.0;\n rec.emission = light.color * light.intensity * distanceFalloff;\n rec.type = light.type;\n result = rec;\n\n } else if ( light.type == DIR_LIGHT_TYPE ) {\n\n LightRecord rec;\n rec.dist = 1e10;\n rec.direction = light.u;\n rec.pdf = 1.0;\n rec.emission = light.color * light.intensity;\n rec.type = light.type;\n\n result = rec;\n\n } else {\n\n // sample the light\n result = randomAreaLightSample( light, rayOrigin, ruv.yz );\n\n }\n\n return result;\n\n }\n\n", Tn = "\n\n vec3 sampleHemisphere( vec3 n, vec2 uv ) {\n\n // https://www.rorydriscoll.com/2009/01/07/better-sampling/\n // https://graphics.pixar.com/library/OrthonormalB/paper.pdf\n float sign = n.z == 0.0 ? 1.0 : sign( n.z );\n float a = - 1.0 / ( sign + n.z );\n float b = n.x * n.y * a;\n vec3 b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );\n vec3 b2 = vec3( b, sign + n.y * n.y * a, - n.y );\n\n float r = sqrt( uv.x );\n float theta = 2.0 * PI * uv.y;\n float x = r * cos( theta );\n float y = r * sin( theta );\n return x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;\n\n }\n\n vec2 sampleTriangle( vec2 a, vec2 b, vec2 c, vec2 r ) {\n\n // get the edges of the triangle and the diagonal across the\n // center of the parallelogram\n vec2 e1 = a - b;\n vec2 e2 = c - b;\n vec2 diag = normalize( e1 + e2 );\n\n // pick the point in the parallelogram\n if ( r.x + r.y > 1.0 ) {\n\n r = vec2( 1.0 ) - r;\n\n }\n\n return e1 * r.x + e2 * r.y;\n\n }\n\n vec2 sampleCircle( vec2 uv ) {\n\n float angle = 2.0 * PI * uv.x;\n float radius = sqrt( uv.y );\n return vec2( cos( angle ), sin( angle ) ) * radius;\n\n }\n\n vec3 sampleSphere( vec2 uv ) {\n\n float u = ( uv.x - 0.5 ) * 2.0;\n float t = uv.y * PI * 2.0;\n float f = sqrt( 1.0 - u * u );\n\n return vec3( f * cos( t ), f * sin( t ), u );\n\n }\n\n vec2 sampleRegularPolygon( int sides, vec3 uvw ) {\n\n sides = max( sides, 3 );\n\n vec3 r = uvw;\n float anglePerSegment = 2.0 * PI / float( sides );\n float segment = floor( float( sides ) * r.x );\n\n float angle1 = anglePerSegment * segment;\n float angle2 = angle1 + anglePerSegment;\n vec2 a = vec2( sin( angle1 ), cos( angle1 ) );\n vec2 b = vec2( 0.0, 0.0 );\n vec2 c = vec2( sin( angle2 ), cos( angle2 ) );\n\n return sampleTriangle( a, b, c, r.yz );\n\n }\n\n // samples an aperture shape with the given number of sides. 0 means circle\n vec2 sampleAperture( int blades, vec3 uvw ) {\n\n return blades == 0 ?\n sampleCircle( uvw.xy ) :\n sampleRegularPolygon( blades, uvw );\n\n }\n\n\n", En = "\n\n bool totalInternalReflection( float cosTheta, float eta ) {\n\n float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );\n return eta * sinTheta > 1.0;\n\n }\n\n // https://google.github.io/filament/Filament.md.html#materialsystem/diffusebrdf\n float schlickFresnel( float cosine, float f0 ) {\n\n return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n }\n\n vec3 schlickFresnel( float cosine, vec3 f0 ) {\n\n return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n }\n\n vec3 schlickFresnel( float cosine, vec3 f0, vec3 f90 ) {\n\n return f0 + ( f90 - f0 ) * pow( 1.0 - cosine, 5.0 );\n\n }\n\n float dielectricFresnel( float cosThetaI, float eta ) {\n\n // https://schuttejoe.github.io/post/disneybsdf/\n float ni = eta;\n float nt = 1.0;\n\n // Check for total internal reflection\n float sinThetaISq = 1.0f - cosThetaI * cosThetaI;\n float sinThetaTSq = eta * eta * sinThetaISq;\n if( sinThetaTSq >= 1.0 ) {\n\n return 1.0;\n\n }\n\n float sinThetaT = sqrt( sinThetaTSq );\n\n float cosThetaT = sqrt( max( 0.0, 1.0f - sinThetaT * sinThetaT ) );\n float rParallel = ( ( nt * cosThetaI ) - ( ni * cosThetaT ) ) / ( ( nt * cosThetaI ) + ( ni * cosThetaT ) );\n float rPerpendicular = ( ( ni * cosThetaI ) - ( nt * cosThetaT ) ) / ( ( ni * cosThetaI ) + ( nt * cosThetaT ) );\n return ( rParallel * rParallel + rPerpendicular * rPerpendicular ) / 2.0;\n\n }\n\n // https://raytracing.github.io/books/RayTracingInOneWeekend.html#dielectrics/schlickapproximation\n float iorRatioToF0( float eta ) {\n\n return pow( ( 1.0 - eta ) / ( 1.0 + eta ), 2.0 );\n\n }\n\n vec3 evaluateFresnel( float cosTheta, float eta, vec3 f0, vec3 f90 ) {\n\n if ( totalInternalReflection( cosTheta, eta ) ) {\n\n return f90;\n\n }\n\n return schlickFresnel( cosTheta, f0, f90 );\n\n }\n\n // TODO: disney fresnel was removed and replaced with this fresnel function to better align with\n // the glTF but is causing blown out pixels. Should be revisited\n // float evaluateFresnelWeight( float cosTheta, float eta, float f0 ) {\n\n // if ( totalInternalReflection( cosTheta, eta ) ) {\n\n // return 1.0;\n\n // }\n\n // return schlickFresnel( cosTheta, f0 );\n\n // }\n\n // https://schuttejoe.github.io/post/disneybsdf/\n float disneyFresnel( vec3 wo, vec3 wi, vec3 wh, float f0, float eta, float metalness ) {\n\n float dotHV = dot( wo, wh );\n if ( totalInternalReflection( dotHV, eta ) ) {\n\n return 1.0;\n\n }\n\n float dotHL = dot( wi, wh );\n float dielectricFresnel = dielectricFresnel( abs( dotHV ), eta );\n float metallicFresnel = schlickFresnel( dotHL, f0 );\n\n return mix( dielectricFresnel, metallicFresnel, metalness );\n\n }\n\n", Dn = "\n\n // Fast arccos approximation used to remove banding artifacts caused by numerical errors in acos.\n // This is a cubic Lagrange interpolating polynomial for x = [-1, -1/2, 0, 1/2, 1].\n // For more information see: https://github.com/gkjohnson/three-gpu-pathtracer/pull/171#issuecomment-1152275248\n float acosApprox( float x ) {\n\n x = clamp( x, -1.0, 1.0 );\n return ( - 0.69813170079773212 * x * x - 0.87266462599716477 ) * x + 1.5707963267948966;\n\n }\n\n // An acos with input values bound to the range [-1, 1].\n float acosSafe( float x ) {\n\n return acos( clamp( x, -1.0, 1.0 ) );\n\n }\n\n float saturateCos( float val ) {\n\n return clamp( val, 0.001, 1.0 );\n\n }\n\n float square( float t ) {\n\n return t * t;\n\n }\n\n vec2 square( vec2 t ) {\n\n return t * t;\n\n }\n\n vec3 square( vec3 t ) {\n\n return t * t;\n\n }\n\n vec4 square( vec4 t ) {\n\n return t * t;\n\n }\n\n vec2 rotateVector( vec2 v, float t ) {\n\n float ac = cos( t );\n float as = sin( t );\n return vec2(\n v.x * ac - v.y * as,\n v.x * as + v.y * ac\n );\n\n }\n\n // forms a basis with the normal vector as Z\n mat3 getBasisFromNormal( vec3 normal ) {\n\n vec3 other;\n if ( abs( normal.x ) > 0.5 ) {\n\n other = vec3( 0.0, 1.0, 0.0 );\n\n } else {\n\n other = vec3( 1.0, 0.0, 0.0 );\n\n }\n\n vec3 ortho = normalize( cross( normal, other ) );\n vec3 ortho2 = normalize( cross( normal, ortho ) );\n return mat3( ortho2, ortho, normal );\n\n }\n\n", On = "\n\n // Finds the point where the ray intersects the plane defined by u and v and checks if this point\n // falls in the bounds of the rectangle on that same plane.\n // Plane intersection: https://lousodrome.net/blog/light/2020/07/03/intersection-of-a-ray-and-a-plane/\n bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {\n\n float t = dot( center - rayOrigin, normal ) / dot( rayDirection, normal );\n\n if ( t > EPSILON ) {\n\n vec3 p = rayOrigin + rayDirection * t;\n vec3 vi = p - center;\n\n // check if p falls inside the rectangle\n float a1 = dot( u, vi );\n if ( abs( a1 ) <= 0.5 ) {\n\n float a2 = dot( v, vi );\n if ( abs( a2 ) <= 0.5 ) {\n\n dist = t;\n return true;\n\n }\n\n }\n\n }\n\n return false;\n\n }\n\n // Finds the point where the ray intersects the plane defined by u and v and checks if this point\n // falls in the bounds of the circle on that same plane. See above URL for a description of the plane intersection algorithm.\n bool intersectsCircle( vec3 position, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {\n\n float t = dot( position - rayOrigin, normal ) / dot( rayDirection, normal );\n\n if ( t > EPSILON ) {\n\n vec3 hit = rayOrigin + rayDirection * t;\n vec3 vi = hit - position;\n\n float a1 = dot( u, vi );\n float a2 = dot( v, vi );\n\n if( length( vec2( a1, a2 ) ) <= 0.5 ) {\n\n dist = t;\n return true;\n\n }\n\n }\n\n return false;\n\n }\n\n", kn = "\n\n // add texel fetch functions for texture arrays\n vec4 texelFetch1D( sampler2DArray tex, int layer, uint index ) {\n\n uint width = uint( textureSize( tex, 0 ).x );\n uvec2 uv;\n uv.x = index % width;\n uv.y = index / width;\n\n return texelFetch( tex, ivec3( uv, layer ), 0 );\n\n }\n\n vec4 textureSampleBarycoord( sampler2DArray tex, int layer, vec3 barycoord, uvec3 faceIndices ) {\n\n return\n barycoord.x * texelFetch1D( tex, layer, faceIndices.x ) +\n barycoord.y * texelFetch1D( tex, layer, faceIndices.y ) +\n barycoord.z * texelFetch1D( tex, layer, faceIndices.z );\n\n }\n\n", An = "\n\n // TODO: possibly this should be renamed something related to material or path tracing logic\n\n #ifndef RAY_OFFSET\n #define RAY_OFFSET 1e-4\n #endif\n\n // adjust the hit point by the surface normal by a factor of some offset and the\n // maximum component-wise value of the current point to accommodate floating point\n // error as values increase.\n vec3 stepRayOrigin( vec3 rayOrigin, vec3 rayDirection, vec3 offset, float dist ) {\n\n vec3 point = rayOrigin + rayDirection * dist;\n vec3 absPoint = abs( point );\n float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );\n return point + offset * ( maxPoint + 1.0 ) * RAY_OFFSET;\n\n }\n\n // https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation\n vec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {\n\n vec3 ot = - log( attColor ) / attDist;\n return exp( - ot * dist );\n\n }\n\n vec3 getHalfVector( vec3 wi, vec3 wo, float eta ) {\n\n // get the half vector - assuming if the light incident vector is on the other side\n // of the that it's transmissive.\n vec3 h;\n if ( wi.z > 0.0 ) {\n\n h = normalize( wi + wo );\n\n } else {\n\n // Scale by the ior ratio to retrieve the appropriate half vector\n // From Section 2.2 on computing the transmission half vector:\n // https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf\n h = normalize( wi + wo * eta );\n\n }\n\n h *= sign( h.z );\n return h;\n\n }\n\n vec3 getHalfVector( vec3 a, vec3 b ) {\n\n return normalize( a + b );\n\n }\n\n // The discrepancy between interpolated surface normal and geometry normal can cause issues when a ray\n // is cast that is on the top side of the geometry normal plane but below the surface normal plane. If\n // we find a ray like that we ignore it to avoid artifacts.\n // This function returns if the direction is on the same side of both planes.\n bool isDirectionValid( vec3 direction, vec3 surfaceNormal, vec3 geometryNormal ) {\n\n bool aboveSurfaceNormal = dot( direction, surfaceNormal ) > 0.0;\n bool aboveGeometryNormal = dot( direction, geometryNormal ) > 0.0;\n return aboveSurfaceNormal == aboveGeometryNormal;\n\n }\n\n // ray sampling x and z are swapped to align with expected background view\n vec2 equirectDirectionToUv( vec3 direction ) {\n\n // from Spherical.setFromCartesianCoords\n vec2 uv = vec2( atan( direction.z, direction.x ), acos( direction.y ) );\n uv /= vec2( 2.0 * PI, PI );\n\n // apply adjustments to get values in range [0, 1] and y right side up\n uv.x += 0.5;\n uv.y = 1.0 - uv.y;\n return uv;\n\n }\n\n vec3 equirectUvToDirection( vec2 uv ) {\n\n // undo above adjustments\n uv.x -= 0.5;\n uv.y = 1.0 - uv.y;\n\n // from Vector3.setFromSphericalCoords\n float theta = uv.x * 2.0 * PI;\n float phi = uv.y * PI;\n\n float sinPhi = sin( phi );\n\n return vec3( sinPhi * cos( theta ), cos( phi ), sinPhi * sin( theta ) );\n\n }\n\n // power heuristic for multiple importance sampling\n float misHeuristic( float a, float b ) {\n\n float aa = a * a;\n float bb = b * b;\n return aa / ( aa + bb );\n\n }\n\n // tentFilter from Peter Shirley's 'Realistic Ray Tracing (2nd Edition)' book, pg. 60\n // erichlof/THREE.js-PathTracing-Renderer/\n float tentFilter( float x ) {\n\n return x < 0.5 ? sqrt( 2.0 * x ) - 1.0 : 1.0 - sqrt( 2.0 - ( 2.0 * x ) );\n\n }\n", jn = "\n\n // https://www.shadertoy.com/view/wltcRS\n uvec4 WHITE_NOISE_SEED;\n\n void rng_initialize( vec2 p, int frame ) {\n\n // white noise seed\n WHITE_NOISE_SEED = uvec4( p, uint( frame ), uint( p.x ) + uint( p.y ) );\n\n }\n\n // https://www.pcg-random.org/\n void pcg4d( inout uvec4 v ) {\n\n v = v * 1664525u + 1013904223u;\n v.x += v.y * v.w;\n v.y += v.z * v.x;\n v.z += v.x * v.y;\n v.w += v.y * v.z;\n v = v ^ ( v >> 16u );\n v.x += v.y*v.w;\n v.y += v.z*v.x;\n v.z += v.x*v.y;\n v.w += v.y*v.z;\n\n }\n\n // returns [ 0, 1 ]\n float pcgRand() {\n\n pcg4d( WHITE_NOISE_SEED );\n return float( WHITE_NOISE_SEED.x ) / float( 0xffffffffu );\n\n }\n\n vec2 pcgRand2() {\n\n pcg4d( WHITE_NOISE_SEED );\n return vec2( WHITE_NOISE_SEED.xy ) / float(0xffffffffu);\n\n }\n\n vec3 pcgRand3() {\n\n pcg4d( WHITE_NOISE_SEED );\n return vec3( WHITE_NOISE_SEED.xyz ) / float( 0xffffffffu );\n\n }\n\n vec4 pcgRand4() {\n\n pcg4d( WHITE_NOISE_SEED );\n return vec4( WHITE_NOISE_SEED ) / float( 0xffffffffu );\n\n }\n", Mn = "\n\n uniform sampler2D stratifiedTexture;\n uniform sampler2D stratifiedOffsetTexture;\n\n uint sobolPixelIndex = 0u;\n uint sobolPathIndex = 0u;\n uint sobolBounceIndex = 0u;\n vec4 pixelSeed = vec4( 0 );\n\n vec4 rand4( int v ) {\n\n ivec2 uv = ivec2( v, sobolBounceIndex );\n vec4 stratifiedSample = texelFetch( stratifiedTexture, uv, 0 );\n return fract( stratifiedSample + pixelSeed.r ); // blue noise + stratified samples\n\n }\n\n vec3 rand3( int v ) {\n\n return rand4( v ).xyz;\n\n }\n\n vec2 rand2( int v ) {\n\n return rand4( v ).xy;\n\n }\n\n float rand( int v ) {\n\n return rand4( v ).x;\n\n }\n\n void rng_initialize( vec2 screenCoord, int frame ) {\n\n // tile the small noise texture across the entire screen\n ivec2 noiseSize = ivec2( textureSize( stratifiedOffsetTexture, 0 ) );\n ivec2 pixel = ivec2( screenCoord.xy ) % noiseSize;\n vec2 pixelWidth = 1.0 / vec2( noiseSize );\n vec2 uv = vec2( pixel ) * pixelWidth + pixelWidth * 0.5;\n\n // note that using \"texelFetch\" here seems to break Android for some reason\n pixelSeed = texture( stratifiedOffsetTexture, uv );\n\n }\n\n", Nn = "\n\n // diffuse\n float diffuseEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n // https://schuttejoe.github.io/post/disneybsdf/\n float fl = schlickFresnel( wi.z, 0.0 );\n float fv = schlickFresnel( wo.z, 0.0 );\n\n float metalFactor = ( 1.0 - surf.metalness );\n float transFactor = ( 1.0 - surf.transmission );\n float rr = 0.5 + 2.0 * surf.roughness * fl * fl;\n float retro = rr * ( fl + fv + fl * fv * ( rr - 1.0f ) );\n float lambert = ( 1.0f - 0.5f * fl ) * ( 1.0f - 0.5f * fv );\n\n // TODO: subsurface approx?\n\n // float F = evaluateFresnelWeight( dot( wo, wh ), surf.eta, surf.f0 );\n float F = disneyFresnel( wo, wi, wh, surf.f0, surf.eta, surf.metalness );\n color = ( 1.0 - F ) * transFactor * metalFactor * wi.z * surf.color * ( retro + lambert ) / PI;\n\n return wi.z / PI;\n\n }\n\n vec3 diffuseDirection( vec3 wo, SurfaceRecord surf ) {\n\n vec3 lightDirection = sampleSphere( rand2( 11 ) );\n lightDirection.z += 1.0;\n lightDirection = normalize( lightDirection );\n\n return lightDirection;\n\n }\n\n // specular\n float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n // if roughness is set to 0 then D === NaN which results in black pixels\n float metalness = surf.metalness;\n float roughness = surf.filteredRoughness;\n\n float eta = surf.eta;\n float f0 = surf.f0;\n\n vec3 f0Color = mix( f0 * surf.specularColor * surf.specularIntensity, surf.color, surf.metalness );\n vec3 f90Color = vec3( mix( surf.specularIntensity, 1.0, surf.metalness ) );\n vec3 F = evaluateFresnel( dot( wo, wh ), eta, f0Color, f90Color );\n\n vec3 iridescenceF = evalIridescence( 1.0, surf.iridescenceIor, dot( wi, wh ), surf.iridescenceThickness, f0Color );\n F = mix( F, iridescenceF, surf.iridescence );\n\n // PDF\n // See 14.1.1 Microfacet BxDFs in https://www.pbr-book.org/\n float incidentTheta = acos( wo.z );\n float G = ggxShadowMaskG2( wi, wo, roughness );\n float D = ggxDistribution( wh, roughness );\n float G1 = ggxShadowMaskG1( incidentTheta, roughness );\n float ggxPdf = D * G1 * max( 0.0, abs( dot( wo, wh ) ) ) / abs ( wo.z );\n\n color = wi.z * F * G * D / ( 4.0 * abs( wi.z * wo.z ) );\n return ggxPdf / ( 4.0 * dot( wo, wh ) );\n\n }\n\n vec3 specularDirection( vec3 wo, SurfaceRecord surf ) {\n\n // sample ggx vndf distribution which gives a new normal\n float roughness = surf.filteredRoughness;\n vec3 halfVector = ggxDirection(\n wo,\n vec2( roughness ),\n rand2( 12 )\n );\n\n // apply to new ray by reflecting off the new normal\n return - reflect( wo, halfVector );\n\n }\n\n\n // transmission\n /*\n float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n // See section 4.2 in https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf\n\n float filteredRoughness = surf.filteredRoughness;\n float eta = surf.eta;\n bool frontFace = surf.frontFace;\n bool thinFilm = surf.thinFilm;\n\n color = surf.transmission * surf.color;\n\n float denom = pow( eta * dot( wi, wh ) + dot( wo, wh ), 2.0 );\n return ggxPDF( wo, wh, filteredRoughness ) / denom;\n\n }\n\n vec3 transmissionDirection( vec3 wo, SurfaceRecord surf ) {\n\n float filteredRoughness = surf.filteredRoughness;\n float eta = surf.eta;\n bool frontFace = surf.frontFace;\n\n // sample ggx vndf distribution which gives a new normal\n vec3 halfVector = ggxDirection(\n wo,\n vec2( filteredRoughness ),\n rand2( 13 )\n );\n\n vec3 lightDirection = refract( normalize( - wo ), halfVector, eta );\n if ( surf.thinFilm ) {\n\n lightDirection = - refract( normalize( - lightDirection ), - vec3( 0.0, 0.0, 1.0 ), 1.0 / eta );\n\n }\n\n return normalize( lightDirection );\n\n }\n */\n\n // TODO: This is just using a basic cosine-weighted specular distribution with an\n // incorrect PDF value at the moment. Update it to correctly use a GGX distribution\n float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n color = surf.transmission * surf.color;\n\n // PDF\n // float F = evaluateFresnelWeight( dot( wo, wh ), surf.eta, surf.f0 );\n // float F = disneyFresnel( wo, wi, wh, surf.f0, surf.eta, surf.metalness );\n // if ( F >= 1.0 ) {\n\n // return 0.0;\n\n // }\n\n // return 1.0 / ( 1.0 - F );\n\n // reverted to previous to transmission. The above was causing black pixels\n float eta = surf.eta;\n float f0 = surf.f0;\n float cosTheta = min( wo.z, 1.0 );\n float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );\n float reflectance = schlickFresnel( cosTheta, f0 );\n bool cannotRefract = eta * sinTheta > 1.0;\n if ( cannotRefract ) {\n\n return 0.0;\n\n }\n\n return 1.0 / ( 1.0 - reflectance );\n\n }\n\n vec3 transmissionDirection( vec3 wo, SurfaceRecord surf ) {\n\n float roughness = surf.filteredRoughness;\n float eta = surf.eta;\n vec3 halfVector = normalize( vec3( 0.0, 0.0, 1.0 ) + sampleSphere( rand2( 13 ) ) * roughness );\n vec3 lightDirection = refract( normalize( - wo ), halfVector, eta );\n\n if ( surf.thinFilm ) {\n\n lightDirection = - refract( normalize( - lightDirection ), - vec3( 0.0, 0.0, 1.0 ), 1.0 / eta );\n\n }\n return normalize( lightDirection );\n\n }\n\n // clearcoat\n float clearcoatEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {\n\n float ior = 1.5;\n float f0 = iorRatioToF0( ior );\n bool frontFace = surf.frontFace;\n float roughness = surf.filteredClearcoatRoughness;\n\n float eta = frontFace ? 1.0 / ior : ior;\n float G = ggxShadowMaskG2( wi, wo, roughness );\n float D = ggxDistribution( wh, roughness );\n float F = schlickFresnel( dot( wi, wh ), f0 );\n\n float fClearcoat = F * D * G / ( 4.0 * abs( wi.z * wo.z ) );\n color = color * ( 1.0 - surf.clearcoat * F ) + fClearcoat * surf.clearcoat * wi.z;\n\n // PDF\n // See equation (27) in http://jcgt.org/published/0003/02/03/\n return ggxPDF( wo, wh, roughness ) / ( 4.0 * dot( wi, wh ) );\n\n }\n\n vec3 clearcoatDirection( vec3 wo, SurfaceRecord surf ) {\n\n // sample ggx vndf distribution which gives a new normal\n float roughness = surf.filteredClearcoatRoughness;\n vec3 halfVector = ggxDirection(\n wo,\n vec2( roughness ),\n rand2( 14 )\n );\n\n // apply to new ray by reflecting off the new normal\n return - reflect( wo, halfVector );\n\n }\n\n // sheen\n vec3 sheenColor( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf ) {\n\n float cosThetaO = saturateCos( wo.z );\n float cosThetaI = saturateCos( wi.z );\n float cosThetaH = wh.z;\n\n float D = velvetD( cosThetaH, surf.sheenRoughness );\n float G = velvetG( cosThetaO, cosThetaI, surf.sheenRoughness );\n\n // See equation (1) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n vec3 color = surf.sheenColor;\n color *= D * G / ( 4.0 * abs( cosThetaO * cosThetaI ) );\n color *= wi.z;\n\n return color;\n\n }\n\n // bsdf\n void getLobeWeights(\n vec3 wo, vec3 wi, vec3 wh, vec3 clearcoatWo, SurfaceRecord surf,\n inout float diffuseWeight, inout float specularWeight, inout float transmissionWeight, inout float clearcoatWeight\n ) {\n\n float metalness = surf.metalness;\n float transmission = surf.transmission;\n // float fEstimate = evaluateFresnelWeight( dot( wo, wh ), surf.eta, surf.f0 );\n float fEstimate = disneyFresnel( wo, wi, wh, surf.f0, surf.eta, surf.metalness );\n\n float transSpecularProb = mix( max( 0.25, fEstimate ), 1.0, metalness );\n float diffSpecularProb = 0.5 + 0.5 * metalness;\n\n diffuseWeight = ( 1.0 - transmission ) * ( 1.0 - diffSpecularProb );\n specularWeight = transmission * transSpecularProb + ( 1.0 - transmission ) * diffSpecularProb;\n transmissionWeight = transmission * ( 1.0 - transSpecularProb );\n clearcoatWeight = surf.clearcoat * schlickFresnel( clearcoatWo.z, 0.04 );\n\n float totalWeight = diffuseWeight + specularWeight + transmissionWeight + clearcoatWeight;\n diffuseWeight /= totalWeight;\n specularWeight /= totalWeight;\n transmissionWeight /= totalWeight;\n clearcoatWeight /= totalWeight;\n }\n\n float bsdfEval(\n vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRecord surf,\n float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight, inout float specularPdf, inout vec3 color\n ) {\n\n float metalness = surf.metalness;\n float transmission = surf.transmission;\n\n float spdf = 0.0;\n float dpdf = 0.0;\n float tpdf = 0.0;\n float cpdf = 0.0;\n color = vec3( 0.0 );\n\n vec3 halfVector = getHalfVector( wi, wo, surf.eta );\n\n // diffuse\n if ( diffuseWeight > 0.0 && wi.z > 0.0 ) {\n\n dpdf = diffuseEval( wo, wi, halfVector, surf, color );\n color *= 1.0 - surf.transmission;\n\n }\n\n // ggx specular\n if ( specularWeight > 0.0 && wi.z > 0.0 ) {\n\n vec3 outColor;\n spdf = specularEval( wo, wi, getHalfVector( wi, wo ), surf, outColor );\n color += outColor;\n\n }\n\n // transmission\n if ( transmissionWeight > 0.0 && wi.z < 0.0 ) {\n\n tpdf = transmissionEval( wo, wi, halfVector, surf, color );\n\n }\n\n // sheen\n color *= mix( 1.0, sheenAlbedoScaling( wo, wi, surf ), surf.sheen );\n color += sheenColor( wo, wi, halfVector, surf ) * surf.sheen;\n\n // clearcoat\n if ( clearcoatWi.z >= 0.0 && clearcoatWeight > 0.0 ) {\n\n vec3 clearcoatHalfVector = getHalfVector( clearcoatWo, clearcoatWi );\n cpdf = clearcoatEval( clearcoatWo, clearcoatWi, clearcoatHalfVector, surf, color );\n\n }\n\n float pdf =\n dpdf * diffuseWeight\n + spdf * specularWeight\n + tpdf * transmissionWeight\n + cpdf * clearcoatWeight;\n\n // retrieve specular rays for the shadows flag\n specularPdf = spdf * specularWeight + cpdf * clearcoatWeight;\n\n return pdf;\n\n }\n\n float bsdfResult( vec3 worldWo, vec3 worldWi, SurfaceRecord surf, inout vec3 color ) {\n\n if ( surf.volumeParticle ) {\n\n color = surf.color / ( 4.0 * PI );\n return 1.0 / ( 4.0 * PI );\n\n }\n\n vec3 wo = normalize( surf.normalInvBasis * worldWo );\n vec3 wi = normalize( surf.normalInvBasis * worldWi );\n\n vec3 clearcoatWo = normalize( surf.clearcoatInvBasis * worldWo );\n vec3 clearcoatWi = normalize( surf.clearcoatInvBasis * worldWi );\n\n vec3 wh = getHalfVector( wo, wi, surf.eta );\n float diffuseWeight;\n float specularWeight;\n float transmissionWeight;\n float clearcoatWeight;\n getLobeWeights( wo, wi, wh, clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );\n\n float specularPdf;\n return bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight, specularPdf, color );\n\n }\n\n ScatterRecord bsdfSample( vec3 worldWo, SurfaceRecord surf ) {\n\n if ( surf.volumeParticle ) {\n\n ScatterRecord sampleRec;\n sampleRec.specularPdf = 0.0;\n sampleRec.pdf = 1.0 / ( 4.0 * PI );\n sampleRec.direction = sampleSphere( rand2( 16 ) );\n sampleRec.color = surf.color / ( 4.0 * PI );\n return sampleRec;\n\n }\n\n vec3 wo = normalize( surf.normalInvBasis * worldWo );\n vec3 clearcoatWo = normalize( surf.clearcoatInvBasis * worldWo );\n mat3 normalBasis = surf.normalBasis;\n mat3 invBasis = surf.normalInvBasis;\n mat3 clearcoatNormalBasis = surf.clearcoatBasis;\n mat3 clearcoatInvBasis = surf.clearcoatInvBasis;\n\n float diffuseWeight;\n float specularWeight;\n float transmissionWeight;\n float clearcoatWeight;\n // using normal and basically-reflected ray since we don't have proper half vector here\n getLobeWeights( wo, wo, vec3( 0, 0, 1 ), clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );\n\n float pdf[4];\n pdf[0] = diffuseWeight;\n pdf[1] = specularWeight;\n pdf[2] = transmissionWeight;\n pdf[3] = clearcoatWeight;\n\n float cdf[4];\n cdf[0] = pdf[0];\n cdf[1] = pdf[1] + cdf[0];\n cdf[2] = pdf[2] + cdf[1];\n cdf[3] = pdf[3] + cdf[2];\n\n if( cdf[3] != 0.0 ) {\n\n float invMaxCdf = 1.0 / cdf[3];\n cdf[0] *= invMaxCdf;\n cdf[1] *= invMaxCdf;\n cdf[2] *= invMaxCdf;\n cdf[3] *= invMaxCdf;\n\n } else {\n\n cdf[0] = 1.0;\n cdf[1] = 0.0;\n cdf[2] = 0.0;\n cdf[3] = 0.0;\n\n }\n\n vec3 wi;\n vec3 clearcoatWi;\n\n float r = rand( 15 );\n if ( r <= cdf[0] ) { // diffuse\n\n wi = diffuseDirection( wo, surf );\n clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );\n\n } else if ( r <= cdf[1] ) { // specular\n\n wi = specularDirection( wo, surf );\n clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );\n\n } else if ( r <= cdf[2] ) { // transmission / refraction\n\n wi = transmissionDirection( wo, surf );\n clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );\n\n } else if ( r <= cdf[3] ) { // clearcoat\n\n clearcoatWi = clearcoatDirection( clearcoatWo, surf );\n wi = normalize( invBasis * normalize( clearcoatNormalBasis * clearcoatWi ) );\n\n }\n\n ScatterRecord result;\n result.pdf = bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight, result.specularPdf, result.color );\n result.direction = normalize( surf.normalBasis * wi );\n\n return result;\n\n }\n\n", Pn = "\n\n // returns the hit distance given the material density\n float intersectFogVolume( Material material, float u ) {\n\n // https://raytracing.github.io/books/RayTracingTheNextWeek.html#volumes/constantdensitymediums\n return material.opacity == 0.0 ? INFINITY : ( - 1.0 / material.opacity ) * log( u );\n\n }\n\n ScatterRecord sampleFogVolume( SurfaceRecord surf, vec2 uv ) {\n\n ScatterRecord sampleRec;\n sampleRec.specularPdf = 0.0;\n sampleRec.pdf = 1.0 / ( 2.0 * PI );\n sampleRec.direction = sampleSphere( uv );\n sampleRec.color = surf.color;\n return sampleRec;\n\n }\n\n", Fn = "\n\n // The GGX functions provide sampling and distribution information for normals as output so\n // in order to get probability of scatter direction the half vector must be computed and provided.\n // [0] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf\n // [1] https://hal.archives-ouvertes.fr/hal-01509746/document\n // [2] http://jcgt.org/published/0007/04/01/\n // [4] http://jcgt.org/published/0003/02/03/\n\n // trowbridge-reitz === GGX === GTR\n\n vec3 ggxDirection( vec3 incidentDir, vec2 roughness, vec2 uv ) {\n\n // TODO: try GGXVNDF implementation from reference [2], here. Needs to update ggxDistribution\n // function below, as well\n\n // Implementation from reference [1]\n // stretch view\n vec3 V = normalize( vec3( roughness * incidentDir.xy, incidentDir.z ) );\n\n // orthonormal basis\n vec3 T1 = ( V.z < 0.9999 ) ? normalize( cross( V, vec3( 0.0, 0.0, 1.0 ) ) ) : vec3( 1.0, 0.0, 0.0 );\n vec3 T2 = cross( T1, V );\n\n // sample point with polar coordinates (r, phi)\n float a = 1.0 / ( 1.0 + V.z );\n float r = sqrt( uv.x );\n float phi = ( uv.y < a ) ? uv.y / a * PI : PI + ( uv.y - a ) / ( 1.0 - a ) * PI;\n float P1 = r * cos( phi );\n float P2 = r * sin( phi ) * ( ( uv.y < a ) ? 1.0 : V.z );\n\n // compute normal\n vec3 N = P1 * T1 + P2 * T2 + V * sqrt( max( 0.0, 1.0 - P1 * P1 - P2 * P2 ) );\n\n // unstretch\n N = normalize( vec3( roughness * N.xy, max( 0.0, N.z ) ) );\n\n return N;\n\n }\n\n // Below are PDF and related functions for use in a Monte Carlo path tracer\n // as specified in Appendix B of the following paper\n // See equation (34) from reference [0]\n float ggxLamda( float theta, float roughness ) {\n\n float tanTheta = tan( theta );\n float tanTheta2 = tanTheta * tanTheta;\n float alpha2 = roughness * roughness;\n\n float numerator = - 1.0 + sqrt( 1.0 + alpha2 * tanTheta2 );\n return numerator / 2.0;\n\n }\n\n // See equation (34) from reference [0]\n float ggxShadowMaskG1( float theta, float roughness ) {\n\n return 1.0 / ( 1.0 + ggxLamda( theta, roughness ) );\n\n }\n\n // See equation (125) from reference [4]\n float ggxShadowMaskG2( vec3 wi, vec3 wo, float roughness ) {\n\n float incidentTheta = acos( wi.z );\n float scatterTheta = acos( wo.z );\n return 1.0 / ( 1.0 + ggxLamda( incidentTheta, roughness ) + ggxLamda( scatterTheta, roughness ) );\n\n }\n\n // See equation (33) from reference [0]\n float ggxDistribution( vec3 halfVector, float roughness ) {\n\n float a2 = roughness * roughness;\n a2 = max( EPSILON, a2 );\n float cosTheta = halfVector.z;\n float cosTheta4 = pow( cosTheta, 4.0 );\n\n if ( cosTheta == 0.0 ) return 0.0;\n\n float theta = acosSafe( halfVector.z );\n float tanTheta = tan( theta );\n float tanTheta2 = pow( tanTheta, 2.0 );\n\n float denom = PI * cosTheta4 * pow( a2 + tanTheta2, 2.0 );\n return ( a2 / denom );\n\n }\n\n // See equation (3) from reference [2]\n float ggxPDF( vec3 wi, vec3 halfVector, float roughness ) {\n\n float incidentTheta = acos( wi.z );\n float D = ggxDistribution( halfVector, roughness );\n float G1 = ggxShadowMaskG1( incidentTheta, roughness );\n\n return D * G1 * max( 0.0, dot( wi, halfVector ) ) / wi.z;\n\n }\n\n", In = "\n\n // XYZ to sRGB color space\n const mat3 XYZ_TO_REC709 = mat3(\n 3.2404542, -0.9692660, 0.0556434,\n -1.5371385, 1.8760108, -0.2040259,\n -0.4985314, 0.0415560, 1.0572252\n );\n\n vec3 fresnel0ToIor( vec3 fresnel0 ) {\n\n vec3 sqrtF0 = sqrt( fresnel0 );\n return ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\n }\n\n // Conversion FO/IOR\n vec3 iorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\n return square( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\n }\n\n // ior is a value between 1.0 and 3.0. 1.0 is air interface\n float iorToFresnel0( float transmittedIor, float incidentIor ) {\n\n return square( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ) );\n\n }\n\n // Fresnel equations for dielectric/dielectric interfaces. See https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html\n vec3 evalSensitivity( float OPD, vec3 shift ) {\n\n float phase = 2.0 * PI * OPD * 1.0e-9;\n\n vec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n vec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n vec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\n vec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - square( phase ) * var );\n xyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * square( phase ) );\n xyz /= 1.0685e-7;\n\n vec3 srgb = XYZ_TO_REC709 * xyz;\n return srgb;\n\n }\n\n // See Section 4. Analytic Spectral Integration, A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence, https://hal.archives-ouvertes.fr/hal-01518344/document\n vec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\n vec3 I;\n\n // Force iridescenceIor -> outsideIOR when thinFilmThickness -> 0.0\n float iridescenceIor = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\n // Evaluate the cosTheta on the base layer (Snell law)\n float sinTheta2Sq = square( outsideIOR / iridescenceIor ) * ( 1.0 - square( cosTheta1 ) );\n\n // Handle TIR:\n float cosTheta2Sq = 1.0 - sinTheta2Sq;\n if ( cosTheta2Sq < 0.0 ) {\n\n return vec3( 1.0 );\n\n }\n\n float cosTheta2 = sqrt( cosTheta2Sq );\n\n // First interface\n float R0 = iorToFresnel0( iridescenceIor, outsideIOR );\n float R12 = schlickFresnel( cosTheta1, R0 );\n float R21 = R12;\n float T121 = 1.0 - R12;\n float phi12 = 0.0;\n if ( iridescenceIor < outsideIOR ) {\n\n phi12 = PI;\n\n }\n\n float phi21 = PI - phi12;\n\n // Second interface\n vec3 baseIOR = fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) ); // guard against 1.0\n vec3 R1 = iorToFresnel0( baseIOR, iridescenceIor );\n vec3 R23 = schlickFresnel( cosTheta2, R1 );\n vec3 phi23 = vec3( 0.0 );\n if ( baseIOR[0] < iridescenceIor ) {\n\n phi23[ 0 ] = PI;\n\n }\n\n if ( baseIOR[1] < iridescenceIor ) {\n\n phi23[ 1 ] = PI;\n\n }\n\n if ( baseIOR[2] < iridescenceIor ) {\n\n phi23[ 2 ] = PI;\n\n }\n\n // Phase shift\n float OPD = 2.0 * iridescenceIor * thinFilmThickness * cosTheta2;\n vec3 phi = vec3( phi21 ) + phi23;\n\n // Compound terms\n vec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n vec3 r123 = sqrt( R123 );\n vec3 Rs = square( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\n // Reflectance term for m = 0 (DC term amplitude)\n vec3 C0 = R12 + Rs;\n I = C0;\n\n // Reflectance term for m > 0 (pairs of diracs)\n vec3 Cm = Rs - T121;\n for ( int m = 1; m <= 2; ++ m ) {\n\n Cm *= r123;\n vec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n I += Cm * Sm;\n\n }\n\n // Since out of gamut colors might be produced, negative color values are clamped to 0.\n return max( I, vec3( 0.0 ) );\n\n }\n\n", Ln = "\n\n // See equation (2) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n float velvetD( float cosThetaH, float roughness ) {\n\n float alpha = max( roughness, 0.07 );\n alpha = alpha * alpha;\n\n float invAlpha = 1.0 / alpha;\n\n float sqrCosThetaH = cosThetaH * cosThetaH;\n float sinThetaH = max( 1.0 - sqrCosThetaH, 0.001 );\n\n return ( 2.0 + invAlpha ) * pow( sinThetaH, 0.5 * invAlpha ) / ( 2.0 * PI );\n\n }\n\n float velvetParamsInterpolate( int i, float oneMinusAlphaSquared ) {\n\n const float p0[5] = float[5]( 25.3245, 3.32435, 0.16801, -1.27393, -4.85967 );\n const float p1[5] = float[5]( 21.5473, 3.82987, 0.19823, -1.97760, -4.32054 );\n\n return mix( p1[i], p0[i], oneMinusAlphaSquared );\n\n }\n\n float velvetL( float x, float alpha ) {\n\n float oneMinusAlpha = 1.0 - alpha;\n float oneMinusAlphaSquared = oneMinusAlpha * oneMinusAlpha;\n\n float a = velvetParamsInterpolate( 0, oneMinusAlphaSquared );\n float b = velvetParamsInterpolate( 1, oneMinusAlphaSquared );\n float c = velvetParamsInterpolate( 2, oneMinusAlphaSquared );\n float d = velvetParamsInterpolate( 3, oneMinusAlphaSquared );\n float e = velvetParamsInterpolate( 4, oneMinusAlphaSquared );\n\n return a / ( 1.0 + b * pow( abs( x ), c ) ) + d * x + e;\n\n }\n\n // See equation (3) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n float velvetLambda( float cosTheta, float alpha ) {\n\n return abs( cosTheta ) < 0.5 ? exp( velvetL( cosTheta, alpha ) ) : exp( 2.0 * velvetL( 0.5, alpha ) - velvetL( 1.0 - cosTheta, alpha ) );\n\n }\n\n // See Section 3, Shadowing Term, in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n float velvetG( float cosThetaO, float cosThetaI, float roughness ) {\n\n float alpha = max( roughness, 0.07 );\n alpha = alpha * alpha;\n\n return 1.0 / ( 1.0 + velvetLambda( cosThetaO, alpha ) + velvetLambda( cosThetaI, alpha ) );\n\n }\n\n float directionalAlbedoSheen( float cosTheta, float alpha ) {\n\n cosTheta = saturate( cosTheta );\n\n float c = 1.0 - cosTheta;\n float c3 = c * c * c;\n\n return 0.65584461 * c3 + 1.0 / ( 4.16526551 + exp( -7.97291361 * sqrt( alpha ) + 6.33516894 ) );\n\n }\n\n float sheenAlbedoScaling( vec3 wo, vec3 wi, SurfaceRecord surf ) {\n\n float alpha = max( surf.sheenRoughness, 0.07 );\n alpha = alpha * alpha;\n\n float maxSheenColor = max( max( surf.sheenColor.r, surf.sheenColor.g ), surf.sheenColor.b );\n\n float eWo = directionalAlbedoSheen( saturateCos( wo.z ), alpha );\n float eWi = directionalAlbedoSheen( saturateCos( wi.z ), alpha );\n\n return min( 1.0 - maxSheenColor * eWo, 1.0 - maxSheenColor * eWi );\n\n }\n\n // See Section 5, Layering, in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf\n float sheenAlbedoScaling( vec3 wo, SurfaceRecord surf ) {\n\n float alpha = max( surf.sheenRoughness, 0.07 );\n alpha = alpha * alpha;\n\n float maxSheenColor = max( max( surf.sheenColor.r, surf.sheenColor.g ), surf.sheenColor.b );\n\n float eWo = directionalAlbedoSheen( saturateCos( wo.z ), alpha );\n\n return 1.0 - maxSheenColor * eWo;\n\n }\n\n", Rn = "\n\n#ifndef FOG_CHECK_ITERATIONS\n#define FOG_CHECK_ITERATIONS 30\n#endif\n\n// returns whether the given material is a fog material or not\nbool isMaterialFogVolume( sampler2D materials, uint materialIndex ) {\n\n uint i = materialIndex * 45u;\n vec4 s14 = texelFetch1D( materials, i + 14u );\n return bool( int( s14.b ) & 4 );\n\n}\n\n// returns true if we're within the first fog volume we hit\nbool bvhIntersectFogVolumeHit(\n vec3 rayOrigin, vec3 rayDirection,\n usampler2D materialIndexAttribute, sampler2D materials,\n inout Material material\n) {\n\n material.fogVolume = false;\n\n for ( int i = 0; i < FOG_CHECK_ITERATIONS; i ++ ) {\n\n // find nearest hit\n uvec4 faceIndices = uvec4( 0u );\n vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );\n vec3 barycoord = vec3( 0.0 );\n float side = 1.0;\n float dist = 0.0;\n bool hit = bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );\n if ( hit ) {\n\n // if it's a fog volume return whether we hit the front or back face\n uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;\n if ( isMaterialFogVolume( materials, materialIndex ) ) {\n\n material = readMaterialInfo( materials, materialIndex );\n return side == - 1.0;\n\n } else {\n\n // move the ray forward\n rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );\n\n }\n\n } else {\n\n return false;\n\n }\n\n }\n\n return false;\n\n}\n\n", zn = "\n\n // step through multiple surface hits and accumulate color attenuation based on transmissive surfaces\n // returns true if a solid surface was hit\n bool attenuateHit(\n RenderState state,\n Ray ray, float rayDist,\n out vec3 color\n ) {\n\n // store the original bounce index so we can reset it after\n uint originalBounceIndex = sobolBounceIndex;\n\n int traversals = state.traversals;\n int transmissiveTraversals = state.transmissiveTraversals;\n bool isShadowRay = state.isShadowRay;\n Material fogMaterial = state.fogMaterial;\n\n vec3 startPoint = ray.origin;\n\n // hit results\n SurfaceHit surfaceHit;\n\n color = vec3( 1.0 );\n\n bool result = true;\n for ( int i = 0; i < traversals; i ++ ) {\n\n sobolBounceIndex ++;\n\n int hitType = traceScene( ray, fogMaterial, surfaceHit );\n\n if ( hitType == FOG_HIT ) {\n\n result = true;\n break;\n\n } else if ( hitType == SURFACE_HIT ) {\n\n float totalDist = distance( startPoint, ray.origin + ray.direction * surfaceHit.dist );\n if ( totalDist > rayDist ) {\n\n result = false;\n break;\n\n }\n\n // TODO: attenuate the contribution based on the PDF of the resulting ray including refraction values\n // Should be able to work using the material BSDF functions which will take into account specularity, etc.\n // TODO: should we account for emissive surfaces here?\n\n uint materialIndex = uTexelFetch1D( materialIndexAttribute, surfaceHit.faceIndices.x ).r;\n Material material = readMaterialInfo( materials, materialIndex );\n\n // adjust the ray to the new surface\n bool isEntering = surfaceHit.side == 1.0;\n ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );\n\n #if FEATURE_FOG\n\n if ( material.fogVolume ) {\n\n fogMaterial = material;\n fogMaterial.fogVolume = surfaceHit.side == 1.0;\n i -= sign( transmissiveTraversals );\n transmissiveTraversals --;\n continue;\n\n }\n\n #endif\n\n if ( ! material.castShadow && isShadowRay ) {\n\n continue;\n\n }\n\n vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, surfaceHit.barycoord, surfaceHit.faceIndices.xyz ).xy;\n vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, surfaceHit.barycoord, surfaceHit.faceIndices.xyz );\n\n // albedo\n vec4 albedo = vec4( material.color, material.opacity );\n if ( material.map != - 1 ) {\n\n vec3 uvPrime = material.mapTransform * vec3( uv, 1 );\n albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );\n\n }\n\n if ( material.vertexColors ) {\n\n albedo *= vertexColor;\n\n }\n\n // alphaMap\n if ( material.alphaMap != - 1 ) {\n\n albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;\n\n }\n\n // transmission\n float transmission = material.transmission;\n if ( material.transmissionMap != - 1 ) {\n\n vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );\n transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;\n\n }\n\n // metalness\n float metalness = material.metalness;\n if ( material.metalnessMap != - 1 ) {\n\n vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );\n metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;\n\n }\n\n float alphaTest = material.alphaTest;\n bool useAlphaTest = alphaTest != 0.0;\n float transmissionFactor = ( 1.0 - metalness ) * transmission;\n if (\n transmissionFactor < rand( 9 ) && ! (\n // material sidedness\n material.side != 0.0 && surfaceHit.side == material.side\n\n // alpha test\n || useAlphaTest && albedo.a < alphaTest\n\n // opacity\n || material.transparent && ! useAlphaTest && albedo.a < rand( 10 )\n )\n ) {\n\n result = true;\n break;\n\n }\n\n if ( surfaceHit.side == 1.0 && isEntering ) {\n\n // only attenuate by surface color on the way in\n color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );\n\n } else if ( surfaceHit.side == - 1.0 ) {\n\n // attenuate by medium once we hit the opposite side of the model\n color *= transmissionAttenuation( surfaceHit.dist, material.attenuationColor, material.attenuationDistance );\n\n }\n\n bool isTransmissiveRay = dot( ray.direction, surfaceHit.faceNormal * surfaceHit.side ) < 0.0;\n if ( ( isTransmissiveRay || isEntering ) && transmissiveTraversals > 0 ) {\n\n i -= sign( transmissiveTraversals );\n transmissiveTraversals --;\n\n }\n\n } else {\n\n result = false;\n break;\n\n }\n\n }\n\n // reset the bounce index\n sobolBounceIndex = originalBounceIndex;\n return result;\n\n }\n\n", Bn = "\n\n vec3 ndcToRayOrigin( vec2 coord ) {\n\n vec4 rayOrigin4 = cameraWorldMatrix * invProjectionMatrix * vec4( coord, - 1.0, 1.0 );\n return rayOrigin4.xyz / rayOrigin4.w;\n }\n\n Ray getCameraRay() {\n\n vec2 ssd = vec2( 1.0 ) / resolution;\n\n // Jitter the camera ray by finding a uv coordinate at a random sample\n // around this pixel's UV coordinate for AA\n vec2 ruv = rand2( 0 );\n vec2 jitteredUv = vUv + vec2( tentFilter( ruv.x ) * ssd.x, tentFilter( ruv.y ) * ssd.y );\n Ray ray;\n\n #if CAMERA_TYPE == 2\n\n // Equirectangular projection\n vec4 rayDirection4 = vec4( equirectUvToDirection( jitteredUv ), 0.0 );\n vec4 rayOrigin4 = vec4( 0.0, 0.0, 0.0, 1.0 );\n\n rayDirection4 = cameraWorldMatrix * rayDirection4;\n rayOrigin4 = cameraWorldMatrix * rayOrigin4;\n\n ray.direction = normalize( rayDirection4.xyz );\n ray.origin = rayOrigin4.xyz / rayOrigin4.w;\n\n #else\n\n // get [- 1, 1] normalized device coordinates\n vec2 ndc = 2.0 * jitteredUv - vec2( 1.0 );\n ray.origin = ndcToRayOrigin( ndc );\n\n #if CAMERA_TYPE == 1\n\n // Orthographic projection\n ray.direction = ( cameraWorldMatrix * vec4( 0.0, 0.0, - 1.0, 0.0 ) ).xyz;\n ray.direction = normalize( ray.direction );\n\n #else\n\n // Perspective projection\n ray.direction = normalize( mat3( cameraWorldMatrix ) * ( invProjectionMatrix * vec4( ndc, 0.0, 1.0 ) ).xyz );\n\n #endif\n\n #endif\n\n #if FEATURE_DOF\n {\n\n // depth of field\n vec3 focalPoint = ray.origin + normalize( ray.direction ) * physicalCamera.focusDistance;\n\n // get the aperture sample\n // if blades === 0 then we assume a circle\n vec3 shapeUVW= rand3( 1 );\n int blades = physicalCamera.apertureBlades;\n float anamorphicRatio = physicalCamera.anamorphicRatio;\n vec2 apertureSample = blades == 0 ? sampleCircle( shapeUVW.xy ) : sampleRegularPolygon( blades, shapeUVW );\n apertureSample *= physicalCamera.bokehSize * 0.5 * 1e-3;\n\n // rotate the aperture shape\n apertureSample =\n rotateVector( apertureSample, physicalCamera.apertureRotation ) *\n saturate( vec2( anamorphicRatio, 1.0 / anamorphicRatio ) );\n\n // create the new ray\n ray.origin += ( cameraWorldMatrix * vec4( apertureSample, 0.0, 0.0 ) ).xyz;\n ray.direction = focalPoint - ray.origin;\n\n }\n #endif\n\n ray.direction = normalize( ray.direction );\n\n return ray;\n\n }\n\n", Vn = "\n\n vec3 directLightContribution( vec3 worldWo, SurfaceRecord surf, RenderState state, vec3 rayOrigin ) {\n\n vec3 result = vec3( 0.0 );\n\n // uniformly pick a light or environment map\n if( lightsDenom != 0.0 && rand( 5 ) < float( lights.count ) / lightsDenom ) {\n\n // sample a light or environment\n LightRecord lightRec = randomLightSample( lights.tex, iesProfiles, lights.count, rayOrigin, rand3( 6 ) );\n\n bool isSampleBelowSurface = ! surf.volumeParticle && dot( surf.faceNormal, lightRec.direction ) < 0.0;\n if ( isSampleBelowSurface ) {\n\n lightRec.pdf = 0.0;\n\n }\n\n // check if a ray could even reach the light area\n Ray lightRay;\n lightRay.origin = rayOrigin;\n lightRay.direction = lightRec.direction;\n vec3 attenuatedColor;\n if (\n lightRec.pdf > 0.0 &&\n isDirectionValid( lightRec.direction, surf.normal, surf.faceNormal ) &&\n ! attenuateHit( state, lightRay, lightRec.dist, attenuatedColor )\n ) {\n\n // get the material pdf\n vec3 sampleColor;\n float lightMaterialPdf = bsdfResult( worldWo, lightRec.direction, surf, sampleColor );\n bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );\n if ( lightMaterialPdf > 0.0 && isValidSampleColor ) {\n\n // weight the direct light contribution\n float lightPdf = lightRec.pdf / lightsDenom;\n float misWeight = lightRec.type == SPOT_LIGHT_TYPE || lightRec.type == DIR_LIGHT_TYPE || lightRec.type == POINT_LIGHT_TYPE ? 1.0 : misHeuristic( lightPdf, lightMaterialPdf );\n result = attenuatedColor * lightRec.emission * state.throughputColor * sampleColor * misWeight / lightPdf;\n\n }\n\n }\n\n } else if ( envMapInfo.totalSum != 0.0 && environmentIntensity != 0.0 ) {\n\n // find a sample in the environment map to include in the contribution\n vec3 envColor, envDirection;\n float envPdf = sampleEquirectProbability( rand2( 7 ), envColor, envDirection );\n envDirection = invEnvRotation3x3 * envDirection;\n\n // this env sampling is not set up for transmissive sampling and yields overly bright\n // results so we ignore the sample in this case.\n // TODO: this should be improved but how? The env samples could traverse a few layers?\n bool isSampleBelowSurface = ! surf.volumeParticle && dot( surf.faceNormal, envDirection ) < 0.0;\n if ( isSampleBelowSurface ) {\n\n envPdf = 0.0;\n\n }\n\n // check if a ray could even reach the surface\n Ray envRay;\n envRay.origin = rayOrigin;\n envRay.direction = envDirection;\n vec3 attenuatedColor;\n if (\n envPdf > 0.0 &&\n isDirectionValid( envDirection, surf.normal, surf.faceNormal ) &&\n ! attenuateHit( state, envRay, INFINITY, attenuatedColor )\n ) {\n\n // get the material pdf\n vec3 sampleColor;\n float envMaterialPdf = bsdfResult( worldWo, envDirection, surf, sampleColor );\n bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );\n if ( envMaterialPdf > 0.0 && isValidSampleColor ) {\n\n // weight the direct light contribution\n envPdf /= lightsDenom;\n float misWeight = misHeuristic( envPdf, envMaterialPdf );\n result = attenuatedColor * environmentIntensity * envColor * state.throughputColor * sampleColor * misWeight / envPdf;\n\n }\n\n }\n\n }\n\n // Function changed to have a single return statement to potentially help with crashes on Mac OS.\n // See issue #470\n return result;\n\n }\n\n", Hn = "\n\n #define SKIP_SURFACE 0\n #define HIT_SURFACE 1\n int getSurfaceRecord(\n Material material, SurfaceHit surfaceHit, sampler2DArray attributesArray,\n float accumulatedRoughness,\n inout SurfaceRecord surf\n ) {\n\n if ( material.fogVolume ) {\n\n vec3 normal = vec3( 0, 0, 1 );\n\n SurfaceRecord fogSurface;\n fogSurface.volumeParticle = true;\n fogSurface.color = material.color;\n fogSurface.emission = material.emissiveIntensity * material.emissive;\n fogSurface.normal = normal;\n fogSurface.faceNormal = normal;\n fogSurface.clearcoatNormal = normal;\n\n surf = fogSurface;\n return HIT_SURFACE;\n\n }\n\n // uv coord for textures\n vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, surfaceHit.barycoord, surfaceHit.faceIndices.xyz ).xy;\n vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, surfaceHit.barycoord, surfaceHit.faceIndices.xyz );\n\n // albedo\n vec4 albedo = vec4( material.color, material.opacity );\n if ( material.map != - 1 ) {\n\n vec3 uvPrime = material.mapTransform * vec3( uv, 1 );\n albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );\n\n }\n\n if ( material.vertexColors ) {\n\n albedo *= vertexColor;\n\n }\n\n // alphaMap\n if ( material.alphaMap != - 1 ) {\n\n albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;\n\n }\n\n // possibly skip this sample if it's transparent, alpha test is enabled, or we hit the wrong material side\n // and it's single sided.\n // - alpha test is disabled when it === 0\n // - the material sidedness test is complicated because we want light to pass through the back side but still\n // be able to see the front side. This boolean checks if the side we hit is the front side on the first ray\n // and we're rendering the other then we skip it. Do the opposite on subsequent bounces to get incoming light.\n float alphaTest = material.alphaTest;\n bool useAlphaTest = alphaTest != 0.0;\n if (\n // material sidedness\n material.side != 0.0 && surfaceHit.side != material.side\n\n // alpha test\n || useAlphaTest && albedo.a < alphaTest\n\n // opacity\n || material.transparent && ! useAlphaTest && albedo.a < rand( 3 )\n ) {\n\n return SKIP_SURFACE;\n\n }\n\n // fetch the interpolated smooth normal\n vec3 normal = normalize( textureSampleBarycoord(\n attributesArray,\n ATTR_NORMAL,\n surfaceHit.barycoord,\n surfaceHit.faceIndices.xyz\n ).xyz );\n\n // roughness\n float roughness = material.roughness;\n if ( material.roughnessMap != - 1 ) {\n\n vec3 uvPrime = material.roughnessMapTransform * vec3( uv, 1 );\n roughness *= texture2D( textures, vec3( uvPrime.xy, material.roughnessMap ) ).g;\n\n }\n\n // metalness\n float metalness = material.metalness;\n if ( material.metalnessMap != - 1 ) {\n\n vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );\n metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;\n\n }\n\n // emission\n vec3 emission = material.emissiveIntensity * material.emissive;\n if ( material.emissiveMap != - 1 ) {\n\n vec3 uvPrime = material.emissiveMapTransform * vec3( uv, 1 );\n emission *= texture2D( textures, vec3( uvPrime.xy, material.emissiveMap ) ).xyz;\n\n }\n\n // transmission\n float transmission = material.transmission;\n if ( material.transmissionMap != - 1 ) {\n\n vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );\n transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;\n\n }\n\n // normal\n if ( material.flatShading ) {\n\n // if we're rendering a flat shaded object then use the face normals - the face normal\n // is provided based on the side the ray hits the mesh so flip it to align with the\n // interpolated vertex normals.\n normal = surfaceHit.faceNormal * surfaceHit.side;\n\n }\n\n vec3 baseNormal = normal;\n if ( material.normalMap != - 1 ) {\n\n vec4 tangentSample = textureSampleBarycoord(\n attributesArray,\n ATTR_TANGENT,\n surfaceHit.barycoord,\n surfaceHit.faceIndices.xyz\n );\n\n // some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate\n // resulting in NaNs and slow path tracing.\n if ( length( tangentSample.xyz ) > 0.0 ) {\n\n vec3 tangent = normalize( tangentSample.xyz );\n vec3 bitangent = normalize( cross( normal, tangent ) * tangentSample.w );\n mat3 vTBN = mat3( tangent, bitangent, normal );\n\n vec3 uvPrime = material.normalMapTransform * vec3( uv, 1 );\n vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.normalMap ) ).xyz * 2.0 - 1.0;\n texNormal.xy *= material.normalScale;\n normal = vTBN * texNormal;\n\n }\n\n }\n\n normal *= surfaceHit.side;\n\n // clearcoat\n float clearcoat = material.clearcoat;\n if ( material.clearcoatMap != - 1 ) {\n\n vec3 uvPrime = material.clearcoatMapTransform * vec3( uv, 1 );\n clearcoat *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatMap ) ).r;\n\n }\n\n // clearcoatRoughness\n float clearcoatRoughness = material.clearcoatRoughness;\n if ( material.clearcoatRoughnessMap != - 1 ) {\n\n vec3 uvPrime = material.clearcoatRoughnessMapTransform * vec3( uv, 1 );\n clearcoatRoughness *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatRoughnessMap ) ).g;\n\n }\n\n // clearcoatNormal\n vec3 clearcoatNormal = baseNormal;\n if ( material.clearcoatNormalMap != - 1 ) {\n\n vec4 tangentSample = textureSampleBarycoord(\n attributesArray,\n ATTR_TANGENT,\n surfaceHit.barycoord,\n surfaceHit.faceIndices.xyz\n );\n\n // some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate\n // resulting in NaNs and slow path tracing.\n if ( length( tangentSample.xyz ) > 0.0 ) {\n\n vec3 tangent = normalize( tangentSample.xyz );\n vec3 bitangent = normalize( cross( clearcoatNormal, tangent ) * tangentSample.w );\n mat3 vTBN = mat3( tangent, bitangent, clearcoatNormal );\n\n vec3 uvPrime = material.clearcoatNormalMapTransform * vec3( uv, 1 );\n vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.clearcoatNormalMap ) ).xyz * 2.0 - 1.0;\n texNormal.xy *= material.clearcoatNormalScale;\n clearcoatNormal = vTBN * texNormal;\n\n }\n\n }\n\n clearcoatNormal *= surfaceHit.side;\n\n // sheenColor\n vec3 sheenColor = material.sheenColor;\n if ( material.sheenColorMap != - 1 ) {\n\n vec3 uvPrime = material.sheenColorMapTransform * vec3( uv, 1 );\n sheenColor *= texture2D( textures, vec3( uvPrime.xy, material.sheenColorMap ) ).rgb;\n\n }\n\n // sheenRoughness\n float sheenRoughness = material.sheenRoughness;\n if ( material.sheenRoughnessMap != - 1 ) {\n\n vec3 uvPrime = material.sheenRoughnessMapTransform * vec3( uv, 1 );\n sheenRoughness *= texture2D( textures, vec3( uvPrime.xy, material.sheenRoughnessMap ) ).a;\n\n }\n\n // iridescence\n float iridescence = material.iridescence;\n if ( material.iridescenceMap != - 1 ) {\n\n vec3 uvPrime = material.iridescenceMapTransform * vec3( uv, 1 );\n iridescence *= texture2D( textures, vec3( uvPrime.xy, material.iridescenceMap ) ).r;\n\n }\n\n // iridescence thickness\n float iridescenceThickness = material.iridescenceThicknessMaximum;\n if ( material.iridescenceThicknessMap != - 1 ) {\n\n vec3 uvPrime = material.iridescenceThicknessMapTransform * vec3( uv, 1 );\n float iridescenceThicknessSampled = texture2D( textures, vec3( uvPrime.xy, material.iridescenceThicknessMap ) ).g;\n iridescenceThickness = mix( material.iridescenceThicknessMinimum, material.iridescenceThicknessMaximum, iridescenceThicknessSampled );\n\n }\n\n iridescence = iridescenceThickness == 0.0 ? 0.0 : iridescence;\n\n // specular color\n vec3 specularColor = material.specularColor;\n if ( material.specularColorMap != - 1 ) {\n\n vec3 uvPrime = material.specularColorMapTransform * vec3( uv, 1 );\n specularColor *= texture2D( textures, vec3( uvPrime.xy, material.specularColorMap ) ).rgb;\n\n }\n\n // specular intensity\n float specularIntensity = material.specularIntensity;\n if ( material.specularIntensityMap != - 1 ) {\n\n vec3 uvPrime = material.specularIntensityMapTransform * vec3( uv, 1 );\n specularIntensity *= texture2D( textures, vec3( uvPrime.xy, material.specularIntensityMap ) ).a;\n\n }\n\n surf.volumeParticle = false;\n\n surf.faceNormal = surfaceHit.faceNormal;\n surf.normal = normal;\n\n surf.metalness = metalness;\n surf.color = albedo.rgb;\n surf.emission = emission;\n\n surf.ior = material.ior;\n surf.transmission = transmission;\n surf.thinFilm = material.thinFilm;\n surf.attenuationColor = material.attenuationColor;\n surf.attenuationDistance = material.attenuationDistance;\n\n surf.clearcoatNormal = clearcoatNormal;\n surf.clearcoat = clearcoat;\n\n surf.sheen = material.sheen;\n surf.sheenColor = sheenColor;\n\n surf.iridescence = iridescence;\n surf.iridescenceIor = material.iridescenceIor;\n surf.iridescenceThickness = iridescenceThickness;\n\n surf.specularColor = specularColor;\n surf.specularIntensity = specularIntensity;\n\n // apply perceptual roughness factor from gltf. sheen perceptual roughness is\n // applied by its brdf function\n // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces\n surf.roughness = roughness * roughness;\n surf.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness;\n surf.sheenRoughness = sheenRoughness;\n\n // frontFace is used to determine transmissive properties and PDF. If no transmission is used\n // then we can just always assume this is a front face.\n surf.frontFace = surfaceHit.side == 1.0 || transmission == 0.0;\n surf.eta = material.thinFilm || surf.frontFace ? 1.0 / material.ior : material.ior;\n surf.f0 = iorRatioToF0( surf.eta );\n\n // Compute the filtered roughness value to use during specular reflection computations.\n // The accumulated roughness value is scaled by a user setting and a \"magic value\" of 5.0.\n // If we're exiting something transmissive then scale the factor down significantly so we can retain\n // sharp internal reflections\n surf.filteredRoughness = applyFilteredGlossy( surf.roughness, accumulatedRoughness );\n surf.filteredClearcoatRoughness = applyFilteredGlossy( surf.clearcoatRoughness, accumulatedRoughness );\n\n // get the normal frames\n surf.normalBasis = getBasisFromNormal( surf.normal );\n surf.normalInvBasis = inverse( surf.normalBasis );\n\n surf.clearcoatBasis = getBasisFromNormal( surf.clearcoatNormal );\n surf.clearcoatInvBasis = inverse( surf.clearcoatBasis );\n\n return HIT_SURFACE;\n\n }\n", Un = "\n\n struct Ray {\n\n vec3 origin;\n vec3 direction;\n\n };\n\n struct SurfaceHit {\n\n uvec4 faceIndices;\n vec3 barycoord;\n vec3 faceNormal;\n float side;\n float dist;\n\n };\n\n struct RenderState {\n\n bool firstRay;\n bool transmissiveRay;\n bool isShadowRay;\n float accumulatedRoughness;\n int transmissiveTraversals;\n int traversals;\n uint depth;\n vec3 throughputColor;\n Material fogMaterial;\n\n };\n\n RenderState initRenderState() {\n\n RenderState result;\n result.firstRay = true;\n result.transmissiveRay = true;\n result.isShadowRay = false;\n result.accumulatedRoughness = 0.0;\n result.transmissiveTraversals = 0;\n result.traversals = 0;\n result.throughputColor = vec3( 1.0 );\n result.depth = 0u;\n result.fogMaterial.fogVolume = false;\n return result;\n\n }\n\n", Wn = "\n\n #define NO_HIT 0\n #define SURFACE_HIT 1\n #define LIGHT_HIT 2\n #define FOG_HIT 3\n\n // Passing the global variable 'lights' into this function caused shader program errors.\n // So global variables like 'lights' and 'bvh' were moved out of the function parameters.\n // For more information, refer to: https://github.com/gkjohnson/three-gpu-pathtracer/pull/457\n int traceScene(\n Ray ray, Material fogMaterial, inout SurfaceHit surfaceHit\n ) {\n\n int result = NO_HIT;\n bool hit = bvhIntersectFirstHit( bvh, ray.origin, ray.direction, surfaceHit.faceIndices, surfaceHit.faceNormal, surfaceHit.barycoord, surfaceHit.side, surfaceHit.dist );\n\n #if FEATURE_FOG\n\n if ( fogMaterial.fogVolume ) {\n\n // offset the distance so we don't run into issues with particles on the same surface\n // as other objects\n float particleDist = intersectFogVolume( fogMaterial, rand( 1 ) );\n if ( particleDist + RAY_OFFSET < surfaceHit.dist ) {\n\n surfaceHit.side = 1.0;\n surfaceHit.faceNormal = normalize( - ray.direction );\n surfaceHit.dist = particleDist;\n return FOG_HIT;\n\n }\n\n }\n\n #endif\n\n if ( hit ) {\n\n result = SURFACE_HIT;\n\n }\n\n return result;\n\n }\n\n", Gn = class extends ht {
|
|
1382
1382
|
onBeforeRender() {
|
|
1383
1383
|
this.setDefine("FEATURE_DOF", this.physicalCamera.bokehSize === 0 ? 0 : 1), this.setDefine("FEATURE_BACKGROUND_MAP", +!!this.backgroundMap), this.setDefine("FEATURE_FOG", +!!this.materials.features.isUsed("FOG"));
|
|
1384
1384
|
}
|
|
@@ -1401,28 +1401,28 @@ var gn = class extends E {
|
|
|
1401
1401
|
ATTR_COLOR: 3
|
|
1402
1402
|
},
|
|
1403
1403
|
uniforms: {
|
|
1404
|
-
resolution: { value: new
|
|
1404
|
+
resolution: { value: new R() },
|
|
1405
1405
|
opacity: { value: 1 },
|
|
1406
1406
|
bounces: { value: 10 },
|
|
1407
1407
|
transmissiveBounces: { value: 10 },
|
|
1408
1408
|
filterGlossyFactor: { value: 0 },
|
|
1409
|
-
physicalCamera: { value: new
|
|
1409
|
+
physicalCamera: { value: new Tt() },
|
|
1410
1410
|
cameraWorldMatrix: { value: new j() },
|
|
1411
1411
|
invProjectionMatrix: { value: new j() },
|
|
1412
1412
|
bvh: { value: new Me() },
|
|
1413
|
-
attributesArray: { value: new
|
|
1413
|
+
attributesArray: { value: new Ut() },
|
|
1414
1414
|
materialIndexAttribute: { value: new Ae() },
|
|
1415
|
-
materials: { value: new
|
|
1416
|
-
textures: { value: new
|
|
1417
|
-
lights: { value: new
|
|
1418
|
-
iesProfiles: { value: new
|
|
1415
|
+
materials: { value: new $t() },
|
|
1416
|
+
textures: { value: new rn().texture },
|
|
1417
|
+
lights: { value: new Bt() },
|
|
1418
|
+
iesProfiles: { value: new rn(360, 180, {
|
|
1419
1419
|
type: k,
|
|
1420
|
-
wrapS:
|
|
1421
|
-
wrapT:
|
|
1420
|
+
wrapS: w,
|
|
1421
|
+
wrapT: w
|
|
1422
1422
|
}).texture },
|
|
1423
1423
|
environmentIntensity: { value: 1 },
|
|
1424
1424
|
environmentRotation: { value: new j() },
|
|
1425
|
-
envMapInfo: { value: new
|
|
1425
|
+
envMapInfo: { value: new At() },
|
|
1426
1426
|
backgroundBlur: { value: 0 },
|
|
1427
1427
|
backgroundMap: { value: null },
|
|
1428
1428
|
backgroundAlpha: { value: 1 },
|
|
@@ -1430,8 +1430,8 @@ var gn = class extends E {
|
|
|
1430
1430
|
backgroundRotation: { value: new j() },
|
|
1431
1431
|
seed: { value: 0 },
|
|
1432
1432
|
sobolTexture: { value: null },
|
|
1433
|
-
stratifiedTexture: { value: new
|
|
1434
|
-
stratifiedOffsetTexture: { value: new
|
|
1433
|
+
stratifiedTexture: { value: new un() },
|
|
1434
|
+
stratifiedOffsetTexture: { value: new _n(64, 1) }
|
|
1435
1435
|
},
|
|
1436
1436
|
vertexShader: "\n\n varying vec2 vUv;\n void main() {\n\n vec4 mvPosition = vec4( position, 1.0 );\n mvPosition = modelViewMatrix * mvPosition;\n gl_Position = projectionMatrix * mvPosition;\n\n vUv = uv;\n\n }\n\n ",
|
|
1437
1437
|
fragmentShader: `
|
|
@@ -1450,22 +1450,22 @@ var gn = class extends E {
|
|
|
1450
1450
|
${Ie}
|
|
1451
1451
|
|
|
1452
1452
|
// uniform structs
|
|
1453
|
-
${_n}
|
|
1454
|
-
${yn}
|
|
1455
1453
|
${vn}
|
|
1456
1454
|
${bn}
|
|
1455
|
+
${yn}
|
|
1457
1456
|
${xn}
|
|
1457
|
+
${Sn}
|
|
1458
1458
|
|
|
1459
1459
|
// random
|
|
1460
1460
|
#if RANDOM_TYPE == 2 // Stratified List
|
|
1461
1461
|
|
|
1462
|
-
${
|
|
1462
|
+
${Mn}
|
|
1463
1463
|
|
|
1464
1464
|
#elif RANDOM_TYPE == 1 // Sobol
|
|
1465
1465
|
|
|
1466
|
-
${
|
|
1467
|
-
${
|
|
1468
|
-
${
|
|
1466
|
+
${jn}
|
|
1467
|
+
${yt}
|
|
1468
|
+
${xt}
|
|
1469
1469
|
|
|
1470
1470
|
#define rand(v) sobol(v)
|
|
1471
1471
|
#define rand2(v) sobol2(v)
|
|
@@ -1474,7 +1474,7 @@ var gn = class extends E {
|
|
|
1474
1474
|
|
|
1475
1475
|
#else // PCG
|
|
1476
1476
|
|
|
1477
|
-
${
|
|
1477
|
+
${jn}
|
|
1478
1478
|
|
|
1479
1479
|
// Using the sobol functions seems to break the the compiler on MacOS
|
|
1480
1480
|
// - specifically the "sobolReverseBits" function.
|
|
@@ -1490,11 +1490,11 @@ var gn = class extends E {
|
|
|
1490
1490
|
#endif
|
|
1491
1491
|
|
|
1492
1492
|
// common
|
|
1493
|
-
${On}
|
|
1494
|
-
${Tn}
|
|
1495
1493
|
${kn}
|
|
1496
1494
|
${En}
|
|
1495
|
+
${An}
|
|
1497
1496
|
${Dn}
|
|
1497
|
+
${On}
|
|
1498
1498
|
|
|
1499
1499
|
// environment
|
|
1500
1500
|
uniform EquirectHdrInfo envMapInfo;
|
|
@@ -1550,16 +1550,16 @@ var gn = class extends E {
|
|
|
1550
1550
|
float lightsDenom;
|
|
1551
1551
|
|
|
1552
1552
|
// sampling
|
|
1553
|
-
${
|
|
1554
|
-
${Sn}
|
|
1553
|
+
${Tn}
|
|
1555
1554
|
${Cn}
|
|
1555
|
+
${wn}
|
|
1556
1556
|
|
|
1557
|
+
${Rn}
|
|
1558
|
+
${Fn}
|
|
1557
1559
|
${Ln}
|
|
1558
|
-
${Pn}
|
|
1559
1560
|
${In}
|
|
1560
|
-
${
|
|
1561
|
+
${Pn}
|
|
1561
1562
|
${Nn}
|
|
1562
|
-
${Mn}
|
|
1563
1563
|
|
|
1564
1564
|
float applyFilteredGlossy( float roughness, float accumulatedRoughness ) {
|
|
1565
1565
|
|
|
@@ -1591,12 +1591,12 @@ var gn = class extends E {
|
|
|
1591
1591
|
|
|
1592
1592
|
}
|
|
1593
1593
|
|
|
1594
|
-
${Hn}
|
|
1595
|
-
${zn}
|
|
1596
1594
|
${Un}
|
|
1597
|
-
${Rn}
|
|
1598
1595
|
${Bn}
|
|
1596
|
+
${Wn}
|
|
1597
|
+
${zn}
|
|
1599
1598
|
${Vn}
|
|
1599
|
+
${Hn}
|
|
1600
1600
|
|
|
1601
1601
|
void main() {
|
|
1602
1602
|
|
|
@@ -1894,13 +1894,13 @@ var gn = class extends E {
|
|
|
1894
1894
|
};
|
|
1895
1895
|
//#endregion
|
|
1896
1896
|
//#region node_modules/three-gpu-pathtracer/src/core/PathTracingRenderer.js
|
|
1897
|
-
function*
|
|
1898
|
-
let { _renderer: e, _fsQuad: t, _blendQuad: n, _primaryTarget: r, _blendTargets: i, _sobolTarget: a, _subframe: o, alpha: s, material: c } = this, l = new
|
|
1897
|
+
function* Kn() {
|
|
1898
|
+
let { _renderer: e, _fsQuad: t, _blendQuad: n, _primaryTarget: r, _blendTargets: i, _sobolTarget: a, _subframe: o, alpha: s, material: c } = this, l = new B(), u = new B(), d = n.material, [f, p] = i;
|
|
1899
1899
|
for (;;) {
|
|
1900
|
-
s ? (d.opacity = this._opacityFactor / (this.samples + 1), c.blending = N, c.opacity = 1) : (c.opacity = this._opacityFactor / (this.samples + 1), c.blending =
|
|
1900
|
+
s ? (d.opacity = this._opacityFactor / (this.samples + 1), c.blending = N, c.opacity = 1) : (c.opacity = this._opacityFactor / (this.samples + 1), c.blending = de);
|
|
1901
1901
|
let [i, m, h, g] = o, _ = r.width, v = r.height;
|
|
1902
1902
|
c.resolution.set(_ * h, v * g), c.sobolTexture = a.texture, c.stratifiedTexture.init(20, c.bounces + c.transmissiveBounces + 5), c.stratifiedTexture.next(), c.seed++;
|
|
1903
|
-
let y = this.tiles.x || 1, b = this.tiles.y || 1, x = y * b, S = Math.ceil(_ * h), C = Math.ceil(v * g),
|
|
1903
|
+
let y = this.tiles.x || 1, b = this.tiles.y || 1, x = y * b, S = Math.ceil(_ * h), C = Math.ceil(v * g), w = Math.floor(i * _), ee = Math.floor(m * v), T = Math.ceil(S / y), te = Math.ceil(C / b);
|
|
1904
1904
|
for (let i = 0; i < b; i++) for (let a = 0; a < y; a++) {
|
|
1905
1905
|
let o = e.getRenderTarget(), c = e.autoClear, m = e.getScissorTest();
|
|
1906
1906
|
e.getScissor(l), e.getViewport(u);
|
|
@@ -1910,12 +1910,12 @@ function* Gn() {
|
|
|
1910
1910
|
h = e % y, g = ~~(e / y), this._currentTile = e + 1;
|
|
1911
1911
|
}
|
|
1912
1912
|
let _ = b - g - 1;
|
|
1913
|
-
r.scissor.set(
|
|
1913
|
+
r.scissor.set(w + h * T, ee + _ * te, Math.min(T, S - h * T), Math.min(te, C - _ * te)), r.viewport.set(w, ee, S, C), e.setRenderTarget(r), e.setScissorTest(!0), e.autoClear = !1, t.render(e), e.setViewport(u), e.setScissor(l), e.setScissorTest(m), e.setRenderTarget(o), e.autoClear = c, s && (d.target1 = f.texture, d.target2 = r.texture, e.setRenderTarget(p), n.render(e), e.setRenderTarget(o)), this.samples += 1 / x, a === y - 1 && i === b - 1 && (this.samples = Math.round(this.samples)), yield;
|
|
1914
1914
|
}
|
|
1915
1915
|
[f, p] = [p, f];
|
|
1916
1916
|
}
|
|
1917
1917
|
}
|
|
1918
|
-
var
|
|
1918
|
+
var qn = new T(), Jn = class {
|
|
1919
1919
|
get material() {
|
|
1920
1920
|
return this._fsQuad.material;
|
|
1921
1921
|
}
|
|
@@ -1935,17 +1935,17 @@ var Kn = new w(), qn = class {
|
|
|
1935
1935
|
return !!this._compilePromise;
|
|
1936
1936
|
}
|
|
1937
1937
|
constructor(e) {
|
|
1938
|
-
this.camera = null, this.tiles = new
|
|
1938
|
+
this.camera = null, this.tiles = new R(3, 3), this.stableNoise = !1, this.stableTiles = !0, this.samples = 0, this._subframe = new B(0, 0, 1, 1), this._opacityFactor = 1, this._renderer = e, this._alpha = !1, this._fsQuad = new _(new Gn()), this._blendQuad = new _(new gt()), this._task = null, this._currentTile = 0, this._compilePromise = null, this._sobolTarget = new Ct().generate(e), this._primaryTarget = new V(1, 1, {
|
|
1939
1939
|
format: P,
|
|
1940
1940
|
type: O,
|
|
1941
1941
|
magFilter: M,
|
|
1942
1942
|
minFilter: M
|
|
1943
|
-
}), this._blendTargets = [new
|
|
1943
|
+
}), this._blendTargets = [new V(1, 1, {
|
|
1944
1944
|
format: P,
|
|
1945
1945
|
type: O,
|
|
1946
1946
|
magFilter: M,
|
|
1947
1947
|
minFilter: M
|
|
1948
|
-
}), new
|
|
1948
|
+
}), new V(1, 1, {
|
|
1949
1949
|
format: P,
|
|
1950
1950
|
type: O,
|
|
1951
1951
|
magFilter: M,
|
|
@@ -1977,39 +1977,39 @@ var Kn = new w(), qn = class {
|
|
|
1977
1977
|
}
|
|
1978
1978
|
reset() {
|
|
1979
1979
|
let { _renderer: e, _primaryTarget: t, _blendTargets: n } = this, r = e.getRenderTarget(), i = e.getClearAlpha();
|
|
1980
|
-
e.getClearColor(
|
|
1980
|
+
e.getClearColor(qn), e.setRenderTarget(t), e.setClearColor(0, 0), e.clearColor(), e.setRenderTarget(n[0]), e.setClearColor(0, 0), e.clearColor(), e.setRenderTarget(n[1]), e.setClearColor(0, 0), e.clearColor(), e.setClearColor(qn, i), e.setRenderTarget(r), this.samples = 0, this._task = null, this.material.stratifiedTexture.stableNoise = this.stableNoise, this.stableNoise && (this.material.seed = 0, this.material.stratifiedTexture.reset());
|
|
1981
1981
|
}
|
|
1982
1982
|
update() {
|
|
1983
|
-
this.material.onBeforeRender(), !this.isCompiling && (this._task ||=
|
|
1983
|
+
this.material.onBeforeRender(), !this.isCompiling && (this._task ||= Kn.call(this), this._task.next());
|
|
1984
1984
|
}
|
|
1985
|
-
}, Q = new
|
|
1985
|
+
}, Q = new R(), Yn = new R(), Xn = new Se(), Zn = new T(), Qn = class extends E {
|
|
1986
1986
|
constructor(e = 512, t = 512) {
|
|
1987
|
-
super(new Float32Array(e * t * 4), e, t, P, O,
|
|
1987
|
+
super(new Float32Array(e * t * 4), e, t, P, O, re, I, w, A, A), this.generationCallback = null;
|
|
1988
1988
|
}
|
|
1989
1989
|
update() {
|
|
1990
1990
|
this.dispose(), this.needsUpdate = !0;
|
|
1991
1991
|
let { data: e, width: t, height: n } = this.image;
|
|
1992
1992
|
for (let r = 0; r < t; r++) for (let i = 0; i < n; i++) {
|
|
1993
|
-
|
|
1993
|
+
Yn.set(t, n), Q.set(r / t, i / n), Q.x -= .5, Q.y = 1 - Q.y, Xn.theta = Q.x * 2 * Math.PI, Xn.phi = Q.y * Math.PI, Xn.radius = 1, this.generationCallback(Xn, Q, Yn, Zn);
|
|
1994
1994
|
let a = 4 * (i * t + r);
|
|
1995
|
-
e[a + 0] =
|
|
1995
|
+
e[a + 0] = Zn.r, e[a + 1] = Zn.g, e[a + 2] = Zn.b, e[a + 3] = 1;
|
|
1996
1996
|
}
|
|
1997
1997
|
}
|
|
1998
1998
|
copy(e) {
|
|
1999
1999
|
return super.copy(e), this.generationCallback = e.generationCallback, this;
|
|
2000
2000
|
}
|
|
2001
|
-
},
|
|
2001
|
+
}, $n = new z(), er = class extends Qn {
|
|
2002
2002
|
constructor(e = 512) {
|
|
2003
|
-
super(e, e), this.topColor = new
|
|
2004
|
-
|
|
2005
|
-
let i =
|
|
2003
|
+
super(e, e), this.topColor = new T().set(16777215), this.bottomColor = new T().set(0), this.exponent = 2, this.generationCallback = (e, t, n, r) => {
|
|
2004
|
+
$n.setFromSpherical(e);
|
|
2005
|
+
let i = $n.y * .5 + .5;
|
|
2006
2006
|
r.lerpColors(this.bottomColor, this.topColor, i ** this.exponent);
|
|
2007
2007
|
};
|
|
2008
2008
|
}
|
|
2009
2009
|
copy(e) {
|
|
2010
2010
|
return super.copy(e), this.topColor.copy(e.topColor), this.bottomColor.copy(e.bottomColor), this;
|
|
2011
2011
|
}
|
|
2012
|
-
},
|
|
2012
|
+
}, tr = class extends ye {
|
|
2013
2013
|
get map() {
|
|
2014
2014
|
return this.uniforms.map.value;
|
|
2015
2015
|
}
|
|
@@ -2032,7 +2032,7 @@ var Kn = new w(), qn = class {
|
|
|
2032
2032
|
fragmentShader: "\n uniform sampler2D map;\n uniform float opacity;\n varying vec2 vUv;\n\n vec4 clampedTexelFatch( sampler2D map, ivec2 px, int lod ) {\n\n vec4 res = texelFetch( map, ivec2( px.x, px.y ), 0 );\n\n #if defined( TONE_MAPPING )\n\n res.xyz = toneMapping( res.xyz );\n\n #endif\n\n return linearToOutputTexel( res );\n\n }\n\n void main() {\n\n vec2 size = vec2( textureSize( map, 0 ) );\n vec2 pxUv = vUv * size;\n vec2 pxCurr = floor( pxUv );\n vec2 pxFrac = fract( pxUv ) - 0.5;\n vec2 pxOffset;\n pxOffset.x = pxFrac.x > 0.0 ? 1.0 : - 1.0;\n pxOffset.y = pxFrac.y > 0.0 ? 1.0 : - 1.0;\n\n vec2 pxNext = clamp( pxOffset + pxCurr, vec2( 0.0 ), size - 1.0 );\n vec2 alpha = abs( pxFrac );\n\n vec4 p1 = mix(\n clampedTexelFatch( map, ivec2( pxCurr.x, pxCurr.y ), 0 ),\n clampedTexelFatch( map, ivec2( pxNext.x, pxCurr.y ), 0 ),\n alpha.x\n );\n\n vec4 p2 = mix(\n clampedTexelFatch( map, ivec2( pxCurr.x, pxNext.y ), 0 ),\n clampedTexelFatch( map, ivec2( pxNext.x, pxNext.y ), 0 ),\n alpha.x\n );\n\n gl_FragColor = mix( p1, p2, alpha.y );\n gl_FragColor.a *= opacity;\n #include <premultiplied_alpha_fragment>\n\n }\n "
|
|
2033
2033
|
}), this.setValues(e);
|
|
2034
2034
|
}
|
|
2035
|
-
},
|
|
2035
|
+
}, nr = class extends ye {
|
|
2036
2036
|
constructor() {
|
|
2037
2037
|
super({
|
|
2038
2038
|
uniforms: {
|
|
@@ -2050,7 +2050,7 @@ var Kn = new w(), qn = class {
|
|
|
2050
2050
|
#include <common>
|
|
2051
2051
|
#include <cube_uv_reflection_fragment>
|
|
2052
2052
|
|
|
2053
|
-
${
|
|
2053
|
+
${An}
|
|
2054
2054
|
|
|
2055
2055
|
void main() {
|
|
2056
2056
|
|
|
@@ -2061,15 +2061,15 @@ var Kn = new w(), qn = class {
|
|
|
2061
2061
|
}`
|
|
2062
2062
|
}), this.depthWrite = !1, this.depthTest = !1;
|
|
2063
2063
|
}
|
|
2064
|
-
},
|
|
2064
|
+
}, rr = class {
|
|
2065
2065
|
constructor(e) {
|
|
2066
|
-
this._renderer = e, this._quad = new
|
|
2066
|
+
this._renderer = e, this._quad = new _(new nr());
|
|
2067
2067
|
}
|
|
2068
2068
|
generate(e, t = null, n = null) {
|
|
2069
2069
|
if (!e.isCubeTexture) throw Error("CubeToEquirectMaterial: Source can only be cube textures.");
|
|
2070
2070
|
let r = e.images[0], i = this._renderer, a = this._quad;
|
|
2071
2071
|
t === null && (t = 4 * r.height), n === null && (n = 2 * r.height);
|
|
2072
|
-
let o = new
|
|
2072
|
+
let o = new V(t, n, {
|
|
2073
2073
|
type: O,
|
|
2074
2074
|
colorSpace: r.colorSpace
|
|
2075
2075
|
}), s = r.height, c = Math.log2(s) - 2, l = 1 / s, u = 1 / (3 * Math.max(2 ** c, 112));
|
|
@@ -2080,7 +2080,7 @@ var Kn = new w(), qn = class {
|
|
|
2080
2080
|
i.readRenderTargetPixels(o, 0, 0, t, n, m), o.dispose();
|
|
2081
2081
|
for (let e = 0, t = m.length; e < t; e++) p[e] = D.toHalfFloat(m[e]);
|
|
2082
2082
|
let h = new E(p, t, n, P, k);
|
|
2083
|
-
return h.minFilter =
|
|
2083
|
+
return h.minFilter = oe, h.magFilter = A, h.wrapS = I, h.wrapT = I, h.mapping = re, h.needsUpdate = !0, h;
|
|
2084
2084
|
}
|
|
2085
2085
|
dispose() {
|
|
2086
2086
|
this._quad.dispose();
|
|
@@ -2088,10 +2088,10 @@ var Kn = new w(), qn = class {
|
|
|
2088
2088
|
};
|
|
2089
2089
|
//#endregion
|
|
2090
2090
|
//#region node_modules/three-gpu-pathtracer/src/core/WebGLPathTracer.js
|
|
2091
|
-
function
|
|
2091
|
+
function ir(e) {
|
|
2092
2092
|
return e.extensions.get("EXT_float_blend");
|
|
2093
2093
|
}
|
|
2094
|
-
var $ = new
|
|
2094
|
+
var $ = new R(), ar = class {
|
|
2095
2095
|
get multipleImportanceSampling() {
|
|
2096
2096
|
return !!this._pathTracer.material.defines.FEATURE_MIS;
|
|
2097
2097
|
}
|
|
@@ -2135,17 +2135,17 @@ var $ = new L(), ir = class {
|
|
|
2135
2135
|
return !!this._pathTracer.isCompiling;
|
|
2136
2136
|
}
|
|
2137
2137
|
constructor(e) {
|
|
2138
|
-
this._renderer = e, this._generator = new
|
|
2138
|
+
this._renderer = e, this._generator = new mt(), this._pathTracer = new Jn(e), this._queueReset = !1, this._clock = new ee(), this._compilePromise = null, this._lowResPathTracer = new Jn(e), this._lowResPathTracer.tiles.set(1, 1), this._quad = new _(new tr({
|
|
2139
2139
|
map: null,
|
|
2140
2140
|
transparent: !0,
|
|
2141
2141
|
blending: N,
|
|
2142
2142
|
premultipliedAlpha: e.getContextAttributes().premultipliedAlpha
|
|
2143
|
-
})), this._materials = null, this._previousEnvironment = null, this._previousBackground = null, this._internalBackground = null, this.renderDelay = 100, this.minSamples = 5, this.fadeDuration = 500, this.enablePathTracing = !0, this.pausePathTracing = !1, this.dynamicLowRes = !1, this.lowResScale = .25, this.renderScale = 1, this.synchronizeRenderSize = !0, this.rasterizeScene = !0, this.renderToCanvas = !0, this.textureSize = new
|
|
2143
|
+
})), this._materials = null, this._previousEnvironment = null, this._previousBackground = null, this._internalBackground = null, this.renderDelay = 100, this.minSamples = 5, this.fadeDuration = 500, this.enablePathTracing = !0, this.pausePathTracing = !1, this.dynamicLowRes = !1, this.lowResScale = .25, this.renderScale = 1, this.synchronizeRenderSize = !0, this.rasterizeScene = !0, this.renderToCanvas = !0, this.textureSize = new R(1024, 1024), this.rasterizeSceneCallback = (e, t) => {
|
|
2144
2144
|
this._renderer.render(e, t);
|
|
2145
2145
|
}, this.renderToCanvasCallback = (e, t, n) => {
|
|
2146
2146
|
let r = t.autoClear;
|
|
2147
2147
|
t.autoClear = !1, n.render(t), t.autoClear = r;
|
|
2148
|
-
}, this.setScene(new ve(), new
|
|
2148
|
+
}, this.setScene(new ve(), new fe());
|
|
2149
2149
|
}
|
|
2150
2150
|
setBVHWorker(e) {
|
|
2151
2151
|
this._generator.setBVHWorker(e);
|
|
@@ -2172,28 +2172,28 @@ var $ = new L(), ir = class {
|
|
|
2172
2172
|
e.updateMatrixWorld(), this._pathTracer.setCamera(e), this._lowResPathTracer.setCamera(e), this.reset();
|
|
2173
2173
|
}
|
|
2174
2174
|
updateMaterials() {
|
|
2175
|
-
let e = this._pathTracer.material, t = this._renderer, n = this._materials, r = this.textureSize, i =
|
|
2175
|
+
let e = this._pathTracer.material, t = this._renderer, n = this._materials, r = this.textureSize, i = Jt(n);
|
|
2176
2176
|
e.textures.setTextures(t, i, r.x, r.y), e.materials.updateFrom(n, i), this.reset();
|
|
2177
2177
|
}
|
|
2178
2178
|
updateLights() {
|
|
2179
|
-
let e = this.scene, t = this._renderer, n = this._pathTracer.material, r =
|
|
2179
|
+
let e = this.scene, t = this._renderer, n = this._pathTracer.material, r = Yt(e), i = qt(r);
|
|
2180
2180
|
n.lights.updateFrom(r, i), n.iesProfiles.setTextures(t, i), this.reset();
|
|
2181
2181
|
}
|
|
2182
2182
|
updateEnvironment() {
|
|
2183
2183
|
let e = this.scene, t = this._pathTracer.material;
|
|
2184
2184
|
if (this._internalBackground &&= (this._internalBackground.dispose(), null), t.backgroundBlur = e.backgroundBlurriness, t.backgroundIntensity = e.backgroundIntensity ?? 1, t.backgroundRotation.makeRotationFromEuler(e.backgroundRotation).invert(), e.background === null) t.backgroundMap = null, t.backgroundAlpha = 0;
|
|
2185
2185
|
else if (e.background.isColor) {
|
|
2186
|
-
this._colorBackground = this._colorBackground || new
|
|
2186
|
+
this._colorBackground = this._colorBackground || new er(16);
|
|
2187
2187
|
let n = this._colorBackground;
|
|
2188
2188
|
n.topColor.equals(e.background) || (n.topColor.set(e.background), n.bottomColor.set(e.background), n.update()), t.backgroundMap = n, t.backgroundAlpha = 1;
|
|
2189
2189
|
} else if (e.background.isCubeTexture) {
|
|
2190
2190
|
if (e.background !== this._previousBackground) {
|
|
2191
|
-
let n = new
|
|
2191
|
+
let n = new rr(this._renderer).generate(e.background);
|
|
2192
2192
|
this._internalBackground = n, t.backgroundMap = n, t.backgroundAlpha = 1;
|
|
2193
2193
|
}
|
|
2194
2194
|
} else t.backgroundMap = e.background, t.backgroundAlpha = 1;
|
|
2195
2195
|
if (t.environmentIntensity = e.environmentIntensity ?? 1, t.environmentRotation.makeRotationFromEuler(e.environmentRotation).invert(), this._previousEnvironment !== e.environment) if (e.environment !== null) if (e.environment.isCubeTexture) {
|
|
2196
|
-
let n = new
|
|
2196
|
+
let n = new rr(this._renderer).generate(e.environment);
|
|
2197
2197
|
t.envMapInfo.updateFrom(n);
|
|
2198
2198
|
} else t.envMapInfo.updateFrom(e.environment);
|
|
2199
2199
|
else t.environmentIntensity = 0;
|
|
@@ -2209,7 +2209,7 @@ var $ = new L(), ir = class {
|
|
|
2209
2209
|
let e = this._lowResPathTracer, t = this._pathTracer, n = this._renderer, r = this._clock, i = this._quad;
|
|
2210
2210
|
this._updateScale(), this._queueReset && (t.reset(), e.reset(), this._queueReset = !1, i.material.opacity = 0, r.start());
|
|
2211
2211
|
let a = r.getDelta() * 1e3, o = r.getElapsedTime() * 1e3;
|
|
2212
|
-
if (!this.pausePathTracing && this.enablePathTracing && this.renderDelay <= o && !this.isCompiling && t.update(), t.alpha = t.material.backgroundAlpha !== 1 || !
|
|
2212
|
+
if (!this.pausePathTracing && this.enablePathTracing && this.renderDelay <= o && !this.isCompiling && t.update(), t.alpha = t.material.backgroundAlpha !== 1 || !ir(n), e.alpha = t.alpha, this.renderToCanvas) {
|
|
2213
2213
|
let n = this._renderer, r = this.minSamples;
|
|
2214
2214
|
if (o >= this.renderDelay && this.samples >= this.minSamples && (this.fadeDuration === 0 ? i.material.opacity = 1 : i.material.opacity = Math.min(i.material.opacity + a / this.fadeDuration, 1)), !this.enablePathTracing || this.samples < r || i.material.opacity < 1) {
|
|
2215
2215
|
if (this.dynamicLowRes && !this.isCompiling) {
|
|
@@ -2219,7 +2219,7 @@ var $ = new L(), ir = class {
|
|
|
2219
2219
|
}
|
|
2220
2220
|
(!this.dynamicLowRes && this.rasterizeScene || this.dynamicLowRes && this.isCompiling) && this.rasterizeSceneCallback(this.scene, this.camera);
|
|
2221
2221
|
}
|
|
2222
|
-
this.enablePathTracing && i.material.opacity > 0 && (i.material.opacity < 1 && (i.material.blending = this.dynamicLowRes ?
|
|
2222
|
+
this.enablePathTracing && i.material.opacity > 0 && (i.material.opacity < 1 && (i.material.blending = this.dynamicLowRes ? y : de), i.material.map = t.target.texture, this.renderToCanvasCallback(t.target, n, i), i.material.blending = N);
|
|
2223
2223
|
}
|
|
2224
2224
|
}
|
|
2225
2225
|
reset() {
|
|
@@ -2238,7 +2238,7 @@ var $ = new L(), ir = class {
|
|
|
2238
2238
|
}
|
|
2239
2239
|
}
|
|
2240
2240
|
}
|
|
2241
|
-
},
|
|
2241
|
+
}, or = class t {
|
|
2242
2242
|
ingestSceneWithoutShadowHelpers(e, t) {
|
|
2243
2243
|
let n = [], r = [];
|
|
2244
2244
|
e.traverse((e) => {
|
|
@@ -2259,11 +2259,11 @@ var $ = new L(), ir = class {
|
|
|
2259
2259
|
r.drawImage(t, 0, 0);
|
|
2260
2260
|
let i = r.getImageData(0, 0, n.width, n.height), a = new Float32Array(i.data.length);
|
|
2261
2261
|
for (let e = 0; e < i.data.length; e++) a[e] = i.data[e] / 255;
|
|
2262
|
-
let o = new
|
|
2262
|
+
let o = new v.DataTexture(a, n.width, n.height, v.RGBAFormat, v.FloatType);
|
|
2263
2263
|
return o.mapping = e.mapping, o.wrapS = e.wrapS, o.wrapT = e.wrapT, o.magFilter = e.magFilter, o.minFilter = e.minFilter, o.anisotropy = e.anisotropy, o.needsUpdate = !0, o;
|
|
2264
2264
|
}
|
|
2265
2265
|
getThreeRenderer() {
|
|
2266
|
-
return
|
|
2266
|
+
return c(this.renderer);
|
|
2267
2267
|
}
|
|
2268
2268
|
static {
|
|
2269
2269
|
this.CAMERA_SETTLE_MS = 200;
|
|
@@ -2281,7 +2281,7 @@ var $ = new L(), ir = class {
|
|
|
2281
2281
|
this.FADE_RELEASE_FRACTION = .5;
|
|
2282
2282
|
}
|
|
2283
2283
|
constructor() {
|
|
2284
|
-
this.pathTracer = null, this.enabled = !1, this.renderer = null, this.sampleCount = 0, this.createAttempts = 0, this.maxCreateAttempts = 10, this.sceneInitialized = !1, this.environmentWaitFrames = 0, this.maxEnvironmentWaitFrames = 300, this.disposed = !1, this.convertedEnvTexture = null, this.convertedEnvSourceUuid = null, this.resumable = !1, this.lastCameraMoveTime = -Infinity, this.cameraDirty = !1, this.events = new
|
|
2284
|
+
this.pathTracer = null, this.enabled = !1, this.renderer = null, this.sampleCount = 0, this.createAttempts = 0, this.maxCreateAttempts = 10, this.sceneInitialized = !1, this.environmentWaitFrames = 0, this.maxEnvironmentWaitFrames = 300, this.disposed = !1, this.convertedEnvTexture = null, this.convertedEnvSourceUuid = null, this.resumable = !1, this.lastCameraMoveTime = -Infinity, this.cameraDirty = !1, this.events = new e(), this.rasterFadeTarget = null, this.fadeQuad = null, this.fadeToneMapping = null, this.fadeSupported = !0, this.settings = {
|
|
2285
2285
|
samples: 300,
|
|
2286
2286
|
bounces: 4,
|
|
2287
2287
|
transmissiveBounces: 2,
|
|
@@ -2291,20 +2291,20 @@ var $ = new L(), ir = class {
|
|
|
2291
2291
|
enablePathTracing: !0
|
|
2292
2292
|
};
|
|
2293
2293
|
}
|
|
2294
|
-
async initialize(
|
|
2294
|
+
async initialize(e) {
|
|
2295
2295
|
try {
|
|
2296
|
-
return this.renderer =
|
|
2297
|
-
} catch (
|
|
2298
|
-
return
|
|
2296
|
+
return this.renderer = e.renderer, this.enabled = e.enabled, this.isSupported() ? u.ok(void 0) : u.err(new a("Path tracing is not supported in this environment", i.PATH_TRACING_INIT_FAILED, { reason: "WebGL2 or required extensions not available" }));
|
|
2297
|
+
} catch (e) {
|
|
2298
|
+
return u.err(new a("Failed to initialize path tracing", i.PATH_TRACING_INIT_FAILED, { originalError: e }));
|
|
2299
2299
|
}
|
|
2300
2300
|
}
|
|
2301
2301
|
createPathTracer() {
|
|
2302
|
-
if (this.disposed) return
|
|
2302
|
+
if (this.disposed) return u.err(new a("Instance is disposed", i.INVALID_STATE));
|
|
2303
2303
|
try {
|
|
2304
|
-
let
|
|
2305
|
-
return
|
|
2306
|
-
} catch (
|
|
2307
|
-
return
|
|
2304
|
+
let e = this.getThreeRenderer();
|
|
2305
|
+
return e ? (this.pathTracer = new ar(e), this.pathTracer.tiles && "set" in this.pathTracer.tiles && this.pathTracer.tiles.set(1, 1), this.pathTracer.bounces = this.settings.bounces, this.settings.transmissiveBounces !== void 0 && (this.pathTracer.transmissiveBounces = this.settings.transmissiveBounces), this.pathTracer.renderScale = this.settings.renderScale, this.pathTracer.dynamicLowRes = this.settings.dynamicLowRes, this.pathTracer.lowResScale = this.settings.lowResScale, e.setRenderTarget(null), u.ok(void 0)) : u.err(new a("Renderer not ready, will retry", i.RENDERER_NOT_INITIALIZED));
|
|
2306
|
+
} catch (e) {
|
|
2307
|
+
return u.err(new a("Failed to create path tracer", i.PATH_TRACING_INIT_FAILED, { originalError: e }));
|
|
2308
2308
|
}
|
|
2309
2309
|
}
|
|
2310
2310
|
setEnabled(e) {
|
|
@@ -2326,26 +2326,26 @@ var $ = new L(), ir = class {
|
|
|
2326
2326
|
...e
|
|
2327
2327
|
}, e.enablePathTracing !== void 0 && this.setEnabled(e.enablePathTracing), this.pathTracer && (e.bounces !== void 0 && (this.pathTracer.bounces = e.bounces), e.transmissiveBounces !== void 0 && (this.pathTracer.transmissiveBounces = e.transmissiveBounces), e.renderScale !== void 0 && (this.pathTracer.renderScale = e.renderScale), e.lowResScale !== void 0 && (this.pathTracer.lowResScale = e.lowResScale), e.dynamicLowRes !== void 0 && (this.pathTracer.dynamicLowRes = e.dynamicLowRes));
|
|
2328
2328
|
}
|
|
2329
|
-
async render(
|
|
2330
|
-
if (this.disposed) return
|
|
2331
|
-
let
|
|
2332
|
-
if (!
|
|
2333
|
-
if (!this.enabled) return this.renderWhileDisabled(
|
|
2329
|
+
async render(e, t) {
|
|
2330
|
+
if (this.disposed) return u.ok(void 0);
|
|
2331
|
+
let n = this.renderer;
|
|
2332
|
+
if (!n) return u.ok(void 0);
|
|
2333
|
+
if (!this.enabled) return this.renderWhileDisabled(e, t);
|
|
2334
2334
|
if (!this.pathTracer) {
|
|
2335
|
-
let
|
|
2336
|
-
if (
|
|
2335
|
+
let r = this.ensurePathTracerCreated(n, e, t);
|
|
2336
|
+
if (r) return r;
|
|
2337
2337
|
}
|
|
2338
2338
|
try {
|
|
2339
|
-
let
|
|
2340
|
-
if (!
|
|
2341
|
-
let { threeScene: o, threeCamera: s } =
|
|
2339
|
+
let r = this.extractThreeObjects(e, t);
|
|
2340
|
+
if (!r) return u.err(new a("Could not extract Three.js scene or camera", i.INVALID_PARAMETER));
|
|
2341
|
+
let { threeScene: o, threeCamera: s } = r;
|
|
2342
2342
|
if (!this.sceneInitialized) {
|
|
2343
|
-
let
|
|
2344
|
-
if (
|
|
2343
|
+
let r = await this.initializeSceneForPathTracing(n, e, t, o, s);
|
|
2344
|
+
if (r) return r;
|
|
2345
2345
|
}
|
|
2346
|
-
return this.sceneInitialized ? this.accumulateSample(
|
|
2347
|
-
} catch (
|
|
2348
|
-
return
|
|
2346
|
+
return this.sceneInitialized ? this.accumulateSample(n, e, t) : n.render(e, t);
|
|
2347
|
+
} catch (e) {
|
|
2348
|
+
return u.err(new a("Failed to render with path tracing", i.RENDER_FAILED, { originalError: e }));
|
|
2349
2349
|
}
|
|
2350
2350
|
}
|
|
2351
2351
|
ensurePathTracerCreated(e, t, n) {
|
|
@@ -2354,7 +2354,7 @@ var $ = new L(), ir = class {
|
|
|
2354
2354
|
return r.ok ? (this.createAttempts = 0, null) : this.createAttempts < this.maxCreateAttempts && r.error?.message === "Renderer not ready, will retry" ? e.render(t, n) : (this.disableAfterSelfPause("gave-up"), this.createAttempts = 0, e.render(t, n));
|
|
2355
2355
|
}
|
|
2356
2356
|
extractThreeObjects(e, t) {
|
|
2357
|
-
let n =
|
|
2357
|
+
let n = f(e), r = d(t);
|
|
2358
2358
|
return !n || !r ? null : {
|
|
2359
2359
|
threeScene: n,
|
|
2360
2360
|
threeCamera: r
|
|
@@ -2372,7 +2372,7 @@ var $ = new L(), ir = class {
|
|
|
2372
2372
|
} finally {
|
|
2373
2373
|
r.environment = e;
|
|
2374
2374
|
}
|
|
2375
|
-
} else if (a && a.mapping ===
|
|
2375
|
+
} else if (a && a.mapping === v.EquirectangularReflectionMapping) {
|
|
2376
2376
|
let e = a;
|
|
2377
2377
|
if (a.image instanceof HTMLImageElement) if (this.convertedEnvTexture && this.convertedEnvSourceUuid === a.uuid) e = this.convertedEnvTexture;
|
|
2378
2378
|
else {
|
|
@@ -2395,27 +2395,27 @@ var $ = new L(), ir = class {
|
|
|
2395
2395
|
} catch (e) {
|
|
2396
2396
|
throw r.environment = t, e;
|
|
2397
2397
|
}
|
|
2398
|
-
} else if (r.environment?.mapping ===
|
|
2398
|
+
} else if (r.environment?.mapping === v.EquirectangularReflectionMapping) this.ingestSceneWithoutShadowHelpers(r, i), this.sceneInitialized = !0;
|
|
2399
2399
|
else return this.disableAfterSelfPause("gave-up"), e.render(t, n);
|
|
2400
2400
|
} catch (r) {
|
|
2401
2401
|
return console.warn("Scene initialization error:", r), e.render(t, n);
|
|
2402
2402
|
}
|
|
2403
2403
|
return null;
|
|
2404
2404
|
}
|
|
2405
|
-
accumulateSample(e, n,
|
|
2405
|
+
accumulateSample(e, n, r) {
|
|
2406
2406
|
if (this.sampleCount === 0) try {
|
|
2407
2407
|
this.pathTracer?.updateLights();
|
|
2408
2408
|
} catch (e) {
|
|
2409
2409
|
console.warn("Failed to update lights for path tracing:", e);
|
|
2410
2410
|
}
|
|
2411
|
-
let
|
|
2412
|
-
if (!
|
|
2413
|
-
if (performance.now() - this.lastCameraMoveTime < t.CAMERA_SETTLE_MS) return
|
|
2414
|
-
if (this.cameraDirty && (this.cameraDirty = !1, this.pathTracer?.updateCamera()), this.fadeSupported && this.sampleCount === 0 && this.runFadeStep(() => this.captureRasterFade(e, n,
|
|
2411
|
+
let i = e.render(n, r);
|
|
2412
|
+
if (!i.ok) return i;
|
|
2413
|
+
if (performance.now() - this.lastCameraMoveTime < t.CAMERA_SETTLE_MS) return u.ok(void 0);
|
|
2414
|
+
if (this.cameraDirty && (this.cameraDirty = !1, this.pathTracer?.updateCamera()), this.fadeSupported && this.sampleCount === 0 && this.runFadeStep(() => this.captureRasterFade(e, n, r)), this.accumulateOneSample(), this.sampleCount++, this.fadeSupported && this.sampleCount < this.fadeWindowSamples()) {
|
|
2415
2415
|
let e = 1 - this.pathTracedLayerOpacity(this.sampleCount);
|
|
2416
2416
|
this.runFadeStep(() => this.renderRasterFade(e));
|
|
2417
2417
|
}
|
|
2418
|
-
return this.sampleCount === this.settings.samples ? this.captureCompletedFrame() :
|
|
2418
|
+
return this.sampleCount === this.settings.samples ? this.captureCompletedFrame() : u.ok(void 0);
|
|
2419
2419
|
}
|
|
2420
2420
|
runFadeStep(e) {
|
|
2421
2421
|
try {
|
|
@@ -2433,21 +2433,20 @@ var $ = new L(), ir = class {
|
|
|
2433
2433
|
return e < a ? i * t.smoothstep(n, a, e) : i + (1 - i) * t.smoothstep(a, r, e);
|
|
2434
2434
|
}
|
|
2435
2435
|
static smoothstep(e, t, n) {
|
|
2436
|
-
|
|
2437
|
-
return r * r * (3 - 2 * r);
|
|
2436
|
+
return p(Math.min(1, Math.max(0, (n - e) / (t - e))));
|
|
2438
2437
|
}
|
|
2439
2438
|
captureRasterFade(e, t, n) {
|
|
2440
2439
|
let r = this.getThreeRenderer();
|
|
2441
2440
|
if (!r) return;
|
|
2442
|
-
let i = r.getDrawingBufferSize(new
|
|
2443
|
-
this.rasterFadeTarget ? (this.rasterFadeTarget.width !== i.x || this.rasterFadeTarget.height !== i.y) && this.rasterFadeTarget.setSize(i.x, i.y) : (this.rasterFadeTarget = new
|
|
2441
|
+
let i = r.getDrawingBufferSize(new v.Vector2());
|
|
2442
|
+
this.rasterFadeTarget ? (this.rasterFadeTarget.width !== i.x || this.rasterFadeTarget.height !== i.y) && this.rasterFadeTarget.setSize(i.x, i.y) : (this.rasterFadeTarget = new v.WebGLRenderTarget(i.x, i.y, { type: v.HalfFloatType }), this.rasterFadeTarget.texture.colorSpace = v.LinearSRGBColorSpace);
|
|
2444
2443
|
let a = r.getRenderTarget();
|
|
2445
2444
|
r.setRenderTarget(this.rasterFadeTarget), e.render(t, n), r.setRenderTarget(a);
|
|
2446
2445
|
}
|
|
2447
2446
|
renderRasterFade(e) {
|
|
2448
2447
|
let t = this.getThreeRenderer();
|
|
2449
2448
|
if (!t || !this.rasterFadeTarget) return;
|
|
2450
|
-
(!this.fadeQuad || this.fadeToneMapping !== t.toneMapping) && ((this.fadeQuad?.material)?.dispose(), this.fadeToneMapping = t.toneMapping, this.fadeQuad = new
|
|
2449
|
+
(!this.fadeQuad || this.fadeToneMapping !== t.toneMapping) && ((this.fadeQuad?.material)?.dispose(), this.fadeToneMapping = t.toneMapping, this.fadeQuad = new _(this.createFadeMaterial(t.toneMapping)));
|
|
2451
2450
|
let n = this.fadeQuad.material;
|
|
2452
2451
|
n.uniforms.tRaster.value = this.rasterFadeTarget.texture, n.uniforms.uOpacity.value = e;
|
|
2453
2452
|
let r = t.autoClear, i = t.getRenderTarget();
|
|
@@ -2460,14 +2459,14 @@ var $ = new L(), ir = class {
|
|
|
2460
2459
|
}
|
|
2461
2460
|
createFadeMaterial(e) {
|
|
2462
2461
|
let t = {
|
|
2463
|
-
[
|
|
2464
|
-
[
|
|
2465
|
-
[
|
|
2466
|
-
[
|
|
2467
|
-
[
|
|
2468
|
-
[
|
|
2462
|
+
[v.LinearToneMapping]: "LINEAR_TONE_MAPPING",
|
|
2463
|
+
[v.ReinhardToneMapping]: "REINHARD_TONE_MAPPING",
|
|
2464
|
+
[v.CineonToneMapping]: "CINEON_TONE_MAPPING",
|
|
2465
|
+
[v.ACESFilmicToneMapping]: "ACES_FILMIC_TONE_MAPPING",
|
|
2466
|
+
[v.AgXToneMapping]: "AGX_TONE_MAPPING",
|
|
2467
|
+
[v.NeutralToneMapping]: "NEUTRAL_TONE_MAPPING"
|
|
2469
2468
|
}, n = {}, r = t[e];
|
|
2470
|
-
return r && (n[r] = ""), new
|
|
2469
|
+
return r && (n[r] = ""), new v.ShaderMaterial({
|
|
2471
2470
|
defines: n,
|
|
2472
2471
|
uniforms: {
|
|
2473
2472
|
tRaster: { value: null },
|
|
@@ -2481,10 +2480,10 @@ var $ = new L(), ir = class {
|
|
|
2481
2480
|
});
|
|
2482
2481
|
}
|
|
2483
2482
|
renderWhileDisabled(e, t) {
|
|
2484
|
-
if (!this.renderer) return
|
|
2483
|
+
if (!this.renderer) return u.ok(void 0);
|
|
2485
2484
|
if (this.sampleCount >= this.settings.samples && this.sampleCount > 0) {
|
|
2486
2485
|
let e = this.getThreeRenderer();
|
|
2487
|
-
return this.pathTracer && e && e.setRenderTarget(null),
|
|
2486
|
+
return this.pathTracer && e && e.setRenderTarget(null), u.ok(void 0);
|
|
2488
2487
|
}
|
|
2489
2488
|
return this.renderer.render(e, t);
|
|
2490
2489
|
}
|
|
@@ -2504,7 +2503,7 @@ var $ = new L(), ir = class {
|
|
|
2504
2503
|
} catch (e) {
|
|
2505
2504
|
console.warn("Failed to present path traced result:", e);
|
|
2506
2505
|
}
|
|
2507
|
-
return this.disableAfterSelfPause("completed"),
|
|
2506
|
+
return this.disableAfterSelfPause("completed"), u.ok(void 0);
|
|
2508
2507
|
}
|
|
2509
2508
|
getSampleCount() {
|
|
2510
2509
|
return this.sampleCount;
|
|
@@ -2543,4 +2542,4 @@ var $ = new L(), ir = class {
|
|
|
2543
2542
|
}
|
|
2544
2543
|
};
|
|
2545
2544
|
//#endregion
|
|
2546
|
-
export {
|
|
2545
|
+
export { or as ThreePathTracingService };
|