softbox 4.18.0 → 4.20.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.
@@ -1,9 +1,9 @@
1
- import { C as e, S as t, _ as n, d as r, f as i, g as a, h as o, m as s, p as c, u as l, v as u, w as d, x as f } from "./ContactShadowBaker-MzqtJ-0h.js";
2
- import { t as p } from "./Pass-CSHIrJrV.js";
3
- import * as m from "three";
4
- import { AdditiveBlending as h, BackSide as g, BufferAttribute as _, BufferGeometry as v, ByteType as y, ClampToEdgeWrapping as b, Clock as ee, Color as x, DataArrayTexture as te, DataTexture as S, DataUtils as C, DoubleSide as w, EquirectangularReflectionMapping as T, FloatType as E, FrontSide as ne, HalfFloatType as D, IntType as re, LinearFilter as O, LinearMipMapLinearFilter as ie, Matrix3 as ae, Matrix4 as k, Mesh as oe, MeshBasicMaterial as se, NearestFilter as A, NoBlending as j, NoToneMapping as ce, NormalBlending as le, PerspectiveCamera as ue, Quaternion as de, RGBAFormat as M, RGBAIntegerFormat as fe, RGFormat as pe, RGIntegerFormat as me, RedFormat as N, RedIntegerFormat as he, RepeatWrapping as P, Scene as ge, ShaderMaterial as F, ShortType as _e, Source as ve, Spherical as ye, UnsignedByteType as be, UnsignedIntType as I, UnsignedShortType as xe, Vector2 as L, Vector3 as R, Vector4 as z, WebGLArrayRenderTarget as Se, WebGLRenderTarget as B } from "three";
1
+ import { A as e, C as t, D as n, O as r, S as i, _ as a, a as o, b as s, g as c, i as l, k as u, t as d, v as f, w as p, x as m, y as h } from "./unwrap-DdgS2iXe.js";
2
+ import { t as g } from "./Pass-CSHIrJrV.js";
3
+ import * as _ from "three";
4
+ import { AdditiveBlending as v, BackSide as y, BufferAttribute as b, BufferGeometry as x, ByteType as S, ClampToEdgeWrapping as C, Clock as ee, Color as w, DataArrayTexture as T, DataTexture as E, DataUtils as D, DoubleSide as te, EquirectangularReflectionMapping as ne, FloatType as O, FrontSide as re, HalfFloatType as k, IntType as ie, LinearFilter as A, LinearMipMapLinearFilter as ae, Matrix3 as oe, Matrix4 as j, Mesh as se, MeshBasicMaterial as ce, NearestFilter as M, NoBlending as N, NoToneMapping as le, NormalBlending as ue, PerspectiveCamera as de, Quaternion as fe, RGBAFormat as P, RGBAIntegerFormat as pe, RGFormat as me, RGIntegerFormat as he, RedFormat as ge, RedIntegerFormat as _e, RepeatWrapping as F, Scene as ve, ShaderMaterial as ye, ShortType as be, Source as xe, Spherical as Se, UnsignedByteType as Ce, UnsignedIntType as I, UnsignedShortType as we, Vector2 as L, Vector3 as R, Vector4 as z, WebGLArrayRenderTarget as Te, WebGLRenderTarget as B } from "three";
5
5
  //#region node_modules/three-mesh-bvh/src/webgl/VertexAttributeTexture.js
6
- function Ce(e) {
6
+ function Ee(e) {
7
7
  switch (e) {
8
8
  case 1: return "R";
9
9
  case 2: return "RG";
@@ -12,25 +12,25 @@ function Ce(e) {
12
12
  }
13
13
  throw Error();
14
14
  }
15
- function we(e) {
15
+ function De(e) {
16
16
  switch (e) {
17
- case 1: return N;
18
- case 2: return pe;
19
- case 3: return M;
20
- case 4: return M;
17
+ case 1: return ge;
18
+ case 2: return me;
19
+ case 3: return P;
20
+ case 4: return P;
21
21
  }
22
22
  }
23
- function Te(e) {
23
+ function Oe(e) {
24
24
  switch (e) {
25
- case 1: return he;
26
- case 2: return me;
27
- case 3: return fe;
28
- case 4: return fe;
25
+ case 1: return _e;
26
+ case 2: return he;
27
+ case 3: return pe;
28
+ case 4: return pe;
29
29
  }
30
30
  }
31
- var Ee = class extends S {
31
+ var ke = class extends E {
32
32
  constructor() {
33
- super(), this.minFilter = A, this.magFilter = A, this.generateMipmaps = !1, this.overrideItemSize = null, this._forcedType = null;
33
+ super(), this.minFilter = M, this.magFilter = M, this.generateMipmaps = !1, this.overrideItemSize = null, this._forcedType = null;
34
34
  }
35
35
  updateFrom(e) {
36
36
  let t = this.overrideItemSize, n = e.itemSize, r = e.count;
@@ -41,7 +41,7 @@ var Ee = class extends S {
41
41
  let i = e.itemSize, a = e.count, o = e.normalized, s = e.array.constructor, c = s.BYTES_PER_ELEMENT, l = this._forcedType, u = i;
42
42
  if (l === null) switch (s) {
43
43
  case Float32Array:
44
- l = E;
44
+ l = O;
45
45
  break;
46
46
  case Uint8Array:
47
47
  case Uint16Array:
@@ -51,52 +51,52 @@ var Ee = class extends S {
51
51
  case Int8Array:
52
52
  case Int16Array:
53
53
  case Int32Array:
54
- l = re;
54
+ l = ie;
55
55
  break;
56
56
  }
57
- let d, f, p, m, h = Ce(i);
57
+ let d, f, p, m, h = Ee(i);
58
58
  switch (l) {
59
- case E:
60
- p = 1, f = we(i), o && c === 1 ? (m = s, h += "8", s === Uint8Array ? d = be : (d = y, h += "_SNORM")) : (m = Float32Array, h += "32F", d = E);
59
+ case O:
60
+ p = 1, f = De(i), o && c === 1 ? (m = s, h += "8", s === Uint8Array ? d = Ce : (d = S, h += "_SNORM")) : (m = Float32Array, h += "32F", d = O);
61
61
  break;
62
- case re:
63
- h += c * 8 + "I", p = o ? 2 ** (s.BYTES_PER_ELEMENT * 8 - 1) : 1, f = Te(i), c === 1 ? (m = Int8Array, d = y) : c === 2 ? (m = Int16Array, d = _e) : (m = Int32Array, d = re);
62
+ case ie:
63
+ h += c * 8 + "I", p = o ? 2 ** (s.BYTES_PER_ELEMENT * 8 - 1) : 1, f = Oe(i), c === 1 ? (m = Int8Array, d = S) : c === 2 ? (m = Int16Array, d = be) : (m = Int32Array, d = ie);
64
64
  break;
65
65
  case I:
66
- h += c * 8 + "UI", p = o ? 2 ** (s.BYTES_PER_ELEMENT * 8 - 1) : 1, f = Te(i), c === 1 ? (m = Uint8Array, d = be) : c === 2 ? (m = Uint16Array, d = xe) : (m = Uint32Array, d = I);
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 = I);
67
67
  break;
68
68
  }
69
- u === 3 && (f === M || f === fe) && (u = 4);
70
- let g = Math.ceil(Math.sqrt(a)) || 1, _ = u * g * g, v = new m(_), b = e.normalized;
69
+ u === 3 && (f === P || f === pe) && (u = 4);
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++) {
73
73
  let n = u * t;
74
74
  v[n] = e.getX(t) / p, i >= 2 && (v[n + 1] = e.getY(t) / p), i >= 3 && (v[n + 2] = e.getZ(t) / p, u === 4 && (v[n + 3] = 1)), i >= 4 && (v[n + 3] = e.getW(t) / p);
75
75
  }
76
- e.normalized = b, this.internalFormat = h, this.format = f, this.type = d, this.image.width = g, this.image.height = g, this.image.data = v, this.needsUpdate = !0, this.dispose(), e.itemSize = n, e.count = r;
76
+ e.normalized = y, this.internalFormat = h, this.format = f, this.type = d, this.image.width = g, this.image.height = g, this.image.data = v, this.needsUpdate = !0, this.dispose(), e.itemSize = n, e.count = r;
77
77
  }
78
- }, De = class extends Ee {
78
+ }, Ae = class extends ke {
79
79
  constructor() {
80
80
  super(), this._forcedType = I;
81
81
  }
82
- }, Oe = class extends Ee {
82
+ }, je = class extends ke {
83
83
  constructor() {
84
- super(), this._forcedType = E;
84
+ super(), this._forcedType = O;
85
85
  }
86
- }, ke = class {
86
+ }, Me = class {
87
87
  constructor() {
88
- this.index = new De(), this.position = new Oe(), this.bvhBounds = new S(), this.bvhContents = new S(), this._cachedIndexAttr = null, this.index.overrideItemSize = 3;
88
+ this.index = new Ae(), this.position = new je(), this.bvhBounds = new E(), this.bvhContents = new E(), this._cachedIndexAttr = null, this.index.overrideItemSize = 3;
89
89
  }
90
90
  updateFrom(e) {
91
91
  let { geometry: t } = e;
92
- if (je(e, this.bvhBounds, this.bvhContents), this.position.updateFrom(t.attributes.position), e.indirect) {
92
+ if (Pe(e, this.bvhBounds, this.bvhContents), this.position.updateFrom(t.attributes.position), e.indirect) {
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 = r(i(t));
97
- this._cachedIndexAttr = new _(e, 1, !1);
96
+ let e = a(f(t));
97
+ this._cachedIndexAttr = new b(e, 1, !1);
98
98
  }
99
- Ae(t, n, this._cachedIndexAttr), this.index.updateFrom(this._cachedIndexAttr);
99
+ Ne(t, n, this._cachedIndexAttr), this.index.updateFrom(this._cachedIndexAttr);
100
100
  } else this.index.updateFrom(t.index);
101
101
  }
102
102
  dispose() {
@@ -104,36 +104,36 @@ var Ee = class extends S {
104
104
  e && e.dispose(), t && t.dispose(), n && n.dispose(), r && r.dispose();
105
105
  }
106
106
  };
107
- function Ae(e, t, n) {
107
+ function Ne(e, t, n) {
108
108
  let r = n.array, i = e.index ? e.index.array : null;
109
109
  for (let e = 0, n = t.length; e < n; e++) {
110
110
  let n = 3 * e, a = 3 * t[e];
111
111
  for (let e = 0; e < 3; e++) r[n + e] = i ? i[a + e] : a + e;
112
112
  }
113
113
  }
114
- function je(e, t, r) {
115
- let i = e._roots;
116
- if (i.length !== 1) throw Error("MeshBVHUniformStruct: Multi-root BVHs not supported.");
117
- let l = i[0], d = new Uint16Array(l), f = new Uint32Array(l), p = new Float32Array(l), m = l.byteLength / 32, h = 2 * Math.ceil(Math.sqrt(m / 2)), g = new Float32Array(4 * h * h), _ = Math.ceil(Math.sqrt(m)), v = new Uint32Array(2 * _ * _);
118
- for (let e = 0; e < m; e++) {
119
- let t = e * 32 / 4, r = t * 2, i = c(t);
120
- for (let t = 0; t < 3; t++) g[8 * e + 0 + t] = p[i + 0 + t], g[8 * e + 4 + t] = p[i + 3 + t];
121
- if (o(r, d)) {
122
- let n = s(r, d), i = a(t, f), o = u | n;
123
- v[e * 2 + 0] = o, v[e * 2 + 1] = i;
114
+ function Pe(e, n, r) {
115
+ let a = e._roots;
116
+ if (a.length !== 1) throw Error("MeshBVHUniformStruct: Multi-root BVHs not supported.");
117
+ let o = a[0], c = new Uint16Array(o), l = new Uint32Array(o), u = new Float32Array(o), d = o.byteLength / 32, f = 2 * Math.ceil(Math.sqrt(d / 2)), g = new Float32Array(4 * f * f), _ = Math.ceil(Math.sqrt(d)), v = new Uint32Array(2 * _ * _);
118
+ for (let e = 0; e < d; e++) {
119
+ let n = e * 32 / 4, r = n * 2, a = h(n);
120
+ for (let t = 0; t < 3; t++) g[8 * e + 0 + t] = u[a + 0 + t], g[8 * e + 4 + t] = u[a + 3 + t];
121
+ if (m(r, c)) {
122
+ let t = s(r, c), a = i(n, l), o = p | t;
123
+ v[e * 2 + 0] = o, v[e * 2 + 1] = a;
124
124
  } else {
125
- let r = f[t + 6], i = n(t, f);
125
+ let r = l[n + 6], i = t(n, l);
126
126
  v[e * 2 + 0] = i, v[e * 2 + 1] = r;
127
127
  }
128
128
  }
129
- t.image.data = g, t.image.width = h, t.image.height = h, t.format = M, t.type = E, t.internalFormat = "RGBA32F", t.minFilter = A, t.magFilter = A, t.generateMipmaps = !1, t.needsUpdate = !0, t.dispose(), r.image.data = v, r.image.width = _, r.image.height = _, r.format = me, r.type = I, r.internalFormat = "RG32UI", r.minFilter = A, r.magFilter = A, r.generateMipmaps = !1, r.needsUpdate = !0, r.dispose();
129
+ n.image.data = g, n.image.width = f, n.image.height = f, n.format = P, n.type = O, n.internalFormat = "RGBA32F", n.minFilter = M, n.magFilter = M, n.generateMipmaps = !1, n.needsUpdate = !0, n.dispose(), r.image.data = v, r.image.width = _, r.image.height = _, r.format = he, r.type = I, r.internalFormat = "RG32UI", r.minFilter = M, r.magFilter = M, r.generateMipmaps = !1, r.needsUpdate = !0, r.dispose();
130
130
  }
131
131
  //#endregion
132
132
  //#region node_modules/three-mesh-bvh/src/webgl/glsl/common_functions.glsl.js
133
- var Me = "\n\n// A stack of uint32 indices can can store the indices for\n// a perfectly balanced tree with a depth up to 31. Lower stack\n// depth gets higher performance.\n//\n// However not all trees are balanced. Best value to set this to\n// is the trees max depth.\n#ifndef BVH_STACK_DEPTH\n#define BVH_STACK_DEPTH 60\n#endif\n\n#ifndef INFINITY\n#define INFINITY 1e20\n#endif\n\n// Utilities\nuvec4 uTexelFetch1D( usampler2D tex, 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, ivec2( uv ), 0 );\n\n}\n\nivec4 iTexelFetch1D( isampler2D tex, 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, ivec2( uv ), 0 );\n\n}\n\nvec4 texelFetch1D( sampler2D tex, 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, ivec2( uv ), 0 );\n\n}\n\nvec4 textureSampleBarycoord( sampler2D tex, vec3 barycoord, uvec3 faceIndices ) {\n\n return\n barycoord.x * texelFetch1D( tex, faceIndices.x ) +\n barycoord.y * texelFetch1D( tex, faceIndices.y ) +\n barycoord.z * texelFetch1D( tex, faceIndices.z );\n\n}\n\nvoid ndcToCameraRay(\n vec2 coord, mat4 cameraWorld, mat4 invProjectionMatrix,\n out vec3 rayOrigin, out vec3 rayDirection\n) {\n\n // get camera look direction and near plane for camera clipping\n vec4 lookDirection = cameraWorld * vec4( 0.0, 0.0, - 1.0, 0.0 );\n vec4 nearVector = invProjectionMatrix * vec4( 0.0, 0.0, - 1.0, 1.0 );\n float near = abs( nearVector.z / nearVector.w );\n\n // get the camera direction and position from camera matrices\n vec4 origin = cameraWorld * vec4( 0.0, 0.0, 0.0, 1.0 );\n vec4 direction = invProjectionMatrix * vec4( coord, 0.5, 1.0 );\n direction /= direction.w;\n direction = cameraWorld * direction - origin;\n\n // slide the origin along the ray until it sits at the near clip plane position\n origin.xyz += direction.xyz * near / dot( direction, lookDirection );\n\n rayOrigin = origin.xyz;\n rayDirection = direction.xyz;\n\n}\n", Ne = "\n\n#ifndef TRI_INTERSECT_EPSILON\n#define TRI_INTERSECT_EPSILON 1e-5\n#endif\n\n// Raycasting\nbool intersectsBounds( vec3 rayOrigin, vec3 rayDirection, vec3 boundsMin, vec3 boundsMax, out float dist ) {\n\n // https://www.reddit.com/r/opengl/comments/8ntzz5/fast_glsl_ray_box_intersection/\n // https://tavianator.com/2011/ray_box.html\n vec3 invDir = 1.0 / rayDirection;\n\n // find intersection distances for each plane\n vec3 tMinPlane = invDir * ( boundsMin - rayOrigin );\n vec3 tMaxPlane = invDir * ( boundsMax - rayOrigin );\n\n // get the min and max distances from each intersection\n vec3 tMinHit = min( tMaxPlane, tMinPlane );\n vec3 tMaxHit = max( tMaxPlane, tMinPlane );\n\n // get the furthest hit distance\n vec2 t = max( tMinHit.xx, tMinHit.yz );\n float t0 = max( t.x, t.y );\n\n // get the minimum hit distance\n t = min( tMaxHit.xx, tMaxHit.yz );\n float t1 = min( t.x, t.y );\n\n // set distance to 0.0 if the ray starts inside the box\n dist = max( t0, 0.0 );\n\n return t1 >= dist;\n\n}\n\nbool intersectsTriangle(\n vec3 rayOrigin, vec3 rayDirection, vec3 a, vec3 b, vec3 c,\n out vec3 barycoord, out vec3 norm, out float dist, out float side\n) {\n\n // https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d\n vec3 edge1 = b - a;\n vec3 edge2 = c - a;\n norm = cross( edge1, edge2 );\n\n float det = - dot( rayDirection, norm );\n float invdet = 1.0 / det;\n\n vec3 AO = rayOrigin - a;\n vec3 DAO = cross( AO, rayDirection );\n\n vec4 uvt;\n uvt.x = dot( edge2, DAO ) * invdet;\n uvt.y = - dot( edge1, DAO ) * invdet;\n uvt.z = dot( AO, norm ) * invdet;\n uvt.w = 1.0 - uvt.x - uvt.y;\n\n // set the hit information\n barycoord = uvt.wxy; // arranged in A, B, C order\n dist = uvt.z;\n side = sign( det );\n norm = side * normalize( norm );\n\n // add an epsilon to avoid misses between triangles\n uvt += vec4( TRI_INTERSECT_EPSILON );\n\n return all( greaterThanEqual( uvt, vec4( 0.0 ) ) );\n\n}\n\nbool intersectTriangles(\n // geometry info and triangle range\n sampler2D positionAttr, usampler2D indexAttr, uint offset, uint count,\n\n // ray\n vec3 rayOrigin, vec3 rayDirection,\n\n // outputs\n inout float minDistance, inout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,\n inout float side, inout float dist\n) {\n\n bool found = false;\n vec3 localBarycoord, localNormal;\n float localDist, localSide;\n for ( uint i = offset, l = offset + count; i < l; i ++ ) {\n\n uvec3 indices = uTexelFetch1D( indexAttr, i ).xyz;\n vec3 a = texelFetch1D( positionAttr, indices.x ).rgb;\n vec3 b = texelFetch1D( positionAttr, indices.y ).rgb;\n vec3 c = texelFetch1D( positionAttr, indices.z ).rgb;\n\n if (\n intersectsTriangle( rayOrigin, rayDirection, a, b, c, localBarycoord, localNormal, localDist, localSide )\n && localDist < minDistance\n ) {\n\n found = true;\n minDistance = localDist;\n\n faceIndices = uvec4( indices.xyz, i );\n faceNormal = localNormal;\n\n side = localSide;\n barycoord = localBarycoord;\n dist = localDist;\n\n }\n\n }\n\n return found;\n\n}\n\nbool intersectsBVHNodeBounds( vec3 rayOrigin, vec3 rayDirection, sampler2D bvhBounds, uint currNodeIndex, out float dist ) {\n\n uint cni2 = currNodeIndex * 2u;\n vec3 boundsMin = texelFetch1D( bvhBounds, cni2 ).xyz;\n vec3 boundsMax = texelFetch1D( bvhBounds, cni2 + 1u ).xyz;\n return intersectsBounds( rayOrigin, rayDirection, boundsMin, boundsMax, dist );\n\n}\n\n// use a macro to hide the fact that we need to expand the struct into separate fields\n#define bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist ) _bvhIntersectFirstHit( bvh.position, bvh.index, bvh.bvhBounds, bvh.bvhContents, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist )\n\nbool _bvhIntersectFirstHit(\n // bvh info\n sampler2D bvh_position, usampler2D bvh_index, sampler2D bvh_bvhBounds, usampler2D bvh_bvhContents,\n\n // ray\n vec3 rayOrigin, vec3 rayDirection,\n\n // output variables split into separate variables due to output precision\n inout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,\n inout float side, inout float dist\n) {\n\n // stack needs to be twice as long as the deepest tree we expect because\n // we push both the left and right child onto the stack every traversal\n int pointer = 0;\n uint stack[ BVH_STACK_DEPTH ];\n stack[ 0 ] = 0u;\n\n float triangleDistance = INFINITY;\n bool found = false;\n while ( pointer > - 1 && pointer < BVH_STACK_DEPTH ) {\n\n uint currNodeIndex = stack[ pointer ];\n pointer --;\n\n // check if we intersect the current bounds\n float boundsHitDistance;\n if (\n ! intersectsBVHNodeBounds( rayOrigin, rayDirection, bvh_bvhBounds, currNodeIndex, boundsHitDistance )\n || boundsHitDistance > triangleDistance\n ) {\n\n continue;\n\n }\n\n uvec2 boundsInfo = uTexelFetch1D( bvh_bvhContents, currNodeIndex ).xy;\n bool isLeaf = bool( boundsInfo.x & 0xffff0000u );\n\n if ( isLeaf ) {\n\n uint count = boundsInfo.x & 0x0000ffffu;\n uint offset = boundsInfo.y;\n\n found = intersectTriangles(\n bvh_position, bvh_index, offset, count,\n rayOrigin, rayDirection, triangleDistance,\n faceIndices, faceNormal, barycoord, side, dist\n ) || found;\n\n } else {\n\n uint leftIndex = currNodeIndex + 1u;\n uint splitAxis = boundsInfo.x & 0x0000ffffu;\n uint rightIndex = currNodeIndex + boundsInfo.y;\n\n bool leftToRight = rayDirection[ splitAxis ] >= 0.0;\n uint c1 = leftToRight ? leftIndex : rightIndex;\n uint c2 = leftToRight ? rightIndex : leftIndex;\n\n // set c2 in the stack so we traverse it later. We need to keep track of a pointer in\n // the stack while we traverse. The second pointer added is the one that will be\n // traversed first\n pointer ++;\n stack[ pointer ] = c2;\n\n pointer ++;\n stack[ pointer ] = c1;\n\n }\n\n }\n\n return found;\n\n}\n", Pe = "\nstruct BVH {\n\n usampler2D index;\n sampler2D position;\n\n sampler2D bvhBounds;\n usampler2D bvhContents;\n\n};\n";
133
+ var Fe = "\n\n// A stack of uint32 indices can can store the indices for\n// a perfectly balanced tree with a depth up to 31. Lower stack\n// depth gets higher performance.\n//\n// However not all trees are balanced. Best value to set this to\n// is the trees max depth.\n#ifndef BVH_STACK_DEPTH\n#define BVH_STACK_DEPTH 60\n#endif\n\n#ifndef INFINITY\n#define INFINITY 1e20\n#endif\n\n// Utilities\nuvec4 uTexelFetch1D( usampler2D tex, 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, ivec2( uv ), 0 );\n\n}\n\nivec4 iTexelFetch1D( isampler2D tex, 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, ivec2( uv ), 0 );\n\n}\n\nvec4 texelFetch1D( sampler2D tex, 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, ivec2( uv ), 0 );\n\n}\n\nvec4 textureSampleBarycoord( sampler2D tex, vec3 barycoord, uvec3 faceIndices ) {\n\n return\n barycoord.x * texelFetch1D( tex, faceIndices.x ) +\n barycoord.y * texelFetch1D( tex, faceIndices.y ) +\n barycoord.z * texelFetch1D( tex, faceIndices.z );\n\n}\n\nvoid ndcToCameraRay(\n vec2 coord, mat4 cameraWorld, mat4 invProjectionMatrix,\n out vec3 rayOrigin, out vec3 rayDirection\n) {\n\n // get camera look direction and near plane for camera clipping\n vec4 lookDirection = cameraWorld * vec4( 0.0, 0.0, - 1.0, 0.0 );\n vec4 nearVector = invProjectionMatrix * vec4( 0.0, 0.0, - 1.0, 1.0 );\n float near = abs( nearVector.z / nearVector.w );\n\n // get the camera direction and position from camera matrices\n vec4 origin = cameraWorld * vec4( 0.0, 0.0, 0.0, 1.0 );\n vec4 direction = invProjectionMatrix * vec4( coord, 0.5, 1.0 );\n direction /= direction.w;\n direction = cameraWorld * direction - origin;\n\n // slide the origin along the ray until it sits at the near clip plane position\n origin.xyz += direction.xyz * near / dot( direction, lookDirection );\n\n rayOrigin = origin.xyz;\n rayDirection = direction.xyz;\n\n}\n", Ie = "\n\n#ifndef TRI_INTERSECT_EPSILON\n#define TRI_INTERSECT_EPSILON 1e-5\n#endif\n\n// Raycasting\nbool intersectsBounds( vec3 rayOrigin, vec3 rayDirection, vec3 boundsMin, vec3 boundsMax, out float dist ) {\n\n // https://www.reddit.com/r/opengl/comments/8ntzz5/fast_glsl_ray_box_intersection/\n // https://tavianator.com/2011/ray_box.html\n vec3 invDir = 1.0 / rayDirection;\n\n // find intersection distances for each plane\n vec3 tMinPlane = invDir * ( boundsMin - rayOrigin );\n vec3 tMaxPlane = invDir * ( boundsMax - rayOrigin );\n\n // get the min and max distances from each intersection\n vec3 tMinHit = min( tMaxPlane, tMinPlane );\n vec3 tMaxHit = max( tMaxPlane, tMinPlane );\n\n // get the furthest hit distance\n vec2 t = max( tMinHit.xx, tMinHit.yz );\n float t0 = max( t.x, t.y );\n\n // get the minimum hit distance\n t = min( tMaxHit.xx, tMaxHit.yz );\n float t1 = min( t.x, t.y );\n\n // set distance to 0.0 if the ray starts inside the box\n dist = max( t0, 0.0 );\n\n return t1 >= dist;\n\n}\n\nbool intersectsTriangle(\n vec3 rayOrigin, vec3 rayDirection, vec3 a, vec3 b, vec3 c,\n out vec3 barycoord, out vec3 norm, out float dist, out float side\n) {\n\n // https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d\n vec3 edge1 = b - a;\n vec3 edge2 = c - a;\n norm = cross( edge1, edge2 );\n\n float det = - dot( rayDirection, norm );\n float invdet = 1.0 / det;\n\n vec3 AO = rayOrigin - a;\n vec3 DAO = cross( AO, rayDirection );\n\n vec4 uvt;\n uvt.x = dot( edge2, DAO ) * invdet;\n uvt.y = - dot( edge1, DAO ) * invdet;\n uvt.z = dot( AO, norm ) * invdet;\n uvt.w = 1.0 - uvt.x - uvt.y;\n\n // set the hit information\n barycoord = uvt.wxy; // arranged in A, B, C order\n dist = uvt.z;\n side = sign( det );\n norm = side * normalize( norm );\n\n // add an epsilon to avoid misses between triangles\n uvt += vec4( TRI_INTERSECT_EPSILON );\n\n return all( greaterThanEqual( uvt, vec4( 0.0 ) ) );\n\n}\n\nbool intersectTriangles(\n // geometry info and triangle range\n sampler2D positionAttr, usampler2D indexAttr, uint offset, uint count,\n\n // ray\n vec3 rayOrigin, vec3 rayDirection,\n\n // outputs\n inout float minDistance, inout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,\n inout float side, inout float dist\n) {\n\n bool found = false;\n vec3 localBarycoord, localNormal;\n float localDist, localSide;\n for ( uint i = offset, l = offset + count; i < l; i ++ ) {\n\n uvec3 indices = uTexelFetch1D( indexAttr, i ).xyz;\n vec3 a = texelFetch1D( positionAttr, indices.x ).rgb;\n vec3 b = texelFetch1D( positionAttr, indices.y ).rgb;\n vec3 c = texelFetch1D( positionAttr, indices.z ).rgb;\n\n if (\n intersectsTriangle( rayOrigin, rayDirection, a, b, c, localBarycoord, localNormal, localDist, localSide )\n && localDist < minDistance\n ) {\n\n found = true;\n minDistance = localDist;\n\n faceIndices = uvec4( indices.xyz, i );\n faceNormal = localNormal;\n\n side = localSide;\n barycoord = localBarycoord;\n dist = localDist;\n\n }\n\n }\n\n return found;\n\n}\n\nbool intersectsBVHNodeBounds( vec3 rayOrigin, vec3 rayDirection, sampler2D bvhBounds, uint currNodeIndex, out float dist ) {\n\n uint cni2 = currNodeIndex * 2u;\n vec3 boundsMin = texelFetch1D( bvhBounds, cni2 ).xyz;\n vec3 boundsMax = texelFetch1D( bvhBounds, cni2 + 1u ).xyz;\n return intersectsBounds( rayOrigin, rayDirection, boundsMin, boundsMax, dist );\n\n}\n\n// use a macro to hide the fact that we need to expand the struct into separate fields\n#define bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist ) _bvhIntersectFirstHit( bvh.position, bvh.index, bvh.bvhBounds, bvh.bvhContents, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist )\n\nbool _bvhIntersectFirstHit(\n // bvh info\n sampler2D bvh_position, usampler2D bvh_index, sampler2D bvh_bvhBounds, usampler2D bvh_bvhContents,\n\n // ray\n vec3 rayOrigin, vec3 rayDirection,\n\n // output variables split into separate variables due to output precision\n inout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,\n inout float side, inout float dist\n) {\n\n // stack needs to be twice as long as the deepest tree we expect because\n // we push both the left and right child onto the stack every traversal\n int pointer = 0;\n uint stack[ BVH_STACK_DEPTH ];\n stack[ 0 ] = 0u;\n\n float triangleDistance = INFINITY;\n bool found = false;\n while ( pointer > - 1 && pointer < BVH_STACK_DEPTH ) {\n\n uint currNodeIndex = stack[ pointer ];\n pointer --;\n\n // check if we intersect the current bounds\n float boundsHitDistance;\n if (\n ! intersectsBVHNodeBounds( rayOrigin, rayDirection, bvh_bvhBounds, currNodeIndex, boundsHitDistance )\n || boundsHitDistance > triangleDistance\n ) {\n\n continue;\n\n }\n\n uvec2 boundsInfo = uTexelFetch1D( bvh_bvhContents, currNodeIndex ).xy;\n bool isLeaf = bool( boundsInfo.x & 0xffff0000u );\n\n if ( isLeaf ) {\n\n uint count = boundsInfo.x & 0x0000ffffu;\n uint offset = boundsInfo.y;\n\n found = intersectTriangles(\n bvh_position, bvh_index, offset, count,\n rayOrigin, rayDirection, triangleDistance,\n faceIndices, faceNormal, barycoord, side, dist\n ) || found;\n\n } else {\n\n uint leftIndex = currNodeIndex + 1u;\n uint splitAxis = boundsInfo.x & 0x0000ffffu;\n uint rightIndex = currNodeIndex + boundsInfo.y;\n\n bool leftToRight = rayDirection[ splitAxis ] >= 0.0;\n uint c1 = leftToRight ? leftIndex : rightIndex;\n uint c2 = leftToRight ? rightIndex : leftIndex;\n\n // set c2 in the stack so we traverse it later. We need to keep track of a pointer in\n // the stack while we traverse. The second pointer added is the one that will be\n // traversed first\n pointer ++;\n stack[ pointer ] = c2;\n\n pointer ++;\n stack[ pointer ] = c1;\n\n }\n\n }\n\n return found;\n\n}\n", Le = "\nstruct BVH {\n\n usampler2D index;\n sampler2D position;\n\n sampler2D bvhBounds;\n usampler2D bvhContents;\n\n};\n";
134
134
  //#endregion
135
135
  //#region node_modules/three-gpu-pathtracer/src/core/utils/BufferAttributeUtils.js
136
- function Fe(e, t, n = 0) {
136
+ function Re(e, t, n = 0) {
137
137
  if (e.isInterleavedBufferAttribute) {
138
138
  let r = e.itemSize;
139
139
  for (let i = 0, a = e.count; i < a; i++) {
@@ -147,7 +147,7 @@ function Fe(e, t, n = 0) {
147
147
  }
148
148
  function V(e, t = null) {
149
149
  let n = e.array.constructor, r = e.normalized, i = e.itemSize;
150
- return new _(new n(i * (t === null ? e.count : t)), i, r);
150
+ return new b(new n(i * (t === null ? e.count : t)), i, r);
151
151
  }
152
152
  function H(e, t) {
153
153
  if (!e && !t) return !0;
@@ -157,7 +157,7 @@ function H(e, t) {
157
157
  }
158
158
  //#endregion
159
159
  //#region node_modules/three-gpu-pathtracer/src/core/utils/mergeGeometries.js
160
- function Ie(e) {
160
+ function ze(e) {
161
161
  let t = e[0].index !== null, n = new Set(Object.keys(e[0].attributes));
162
162
  if (!e[0].getAttribute("position")) throw Error("StaticGeometryGenerator: position attribute is required.");
163
163
  for (let r = 0; r < e.length; ++r) {
@@ -170,26 +170,26 @@ function Ie(e) {
170
170
  if (a !== n.size) throw Error("StaticGeometryGenerator: All geometries must have the same number of attributes.");
171
171
  }
172
172
  }
173
- function Le(e) {
173
+ function Be(e) {
174
174
  let t = 0;
175
175
  for (let n = 0, r = e.length; n < r; n++) t += e[n].getIndex().count;
176
176
  return t;
177
177
  }
178
- function Re(e) {
178
+ function Ve(e) {
179
179
  let t = 0;
180
180
  for (let n = 0, r = e.length; n < r; n++) t += e[n].getAttribute("position").count;
181
181
  return t;
182
182
  }
183
- function ze(e, t, n) {
183
+ function He(e, t, n) {
184
184
  e.index && e.index.count !== t && e.setIndex(null);
185
185
  let r = e.attributes;
186
186
  for (let t in r) r[t].count !== n && e.deleteAttribute(t);
187
187
  }
188
- function Be(e, t = {}, n = new v()) {
188
+ function Ue(e, t = {}, n = new x()) {
189
189
  let { useGroups: r = !1, forceUpdate: i = !1, skipAssigningAttributes: a = [], overwriteIndex: o = !0 } = t;
190
- Ie(e);
191
- let s = e[0].index !== null, c = s ? Le(e) : -1, l = Re(e);
192
- if (ze(n, c, l), r) {
190
+ ze(e);
191
+ let s = e[0].index !== null, c = s ? Be(e) : -1, l = Ve(e);
192
+ if (He(n, c, l), r) {
193
193
  let t = 0;
194
194
  for (let r = 0, i = e.length; r < i; r++) {
195
195
  let i = e[r], a;
@@ -198,7 +198,7 @@ function Be(e, t = {}, n = new v()) {
198
198
  }
199
199
  if (s) {
200
200
  let t = !1;
201
- if (n.index || (n.setIndex(new _(new Uint32Array(c), 1, !1)), t = !0), t || o) {
201
+ if (n.index || (n.setIndex(new b(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();
@@ -217,13 +217,13 @@ function Be(e, t = {}, n = new v()) {
217
217
  let s = 0, c = n.getAttribute(o);
218
218
  for (let t = 0, n = e.length; t < n; t++) {
219
219
  let n = e[t], l = !i && !r && a[t], u = n.getAttribute(o);
220
- l || Fe(u, c, s), s += u.count;
220
+ l || Re(u, c, s), s += u.count;
221
221
  }
222
222
  }
223
223
  }
224
224
  //#endregion
225
225
  //#region node_modules/three-gpu-pathtracer/src/core/utils/GeometryPreparationUtils.js
226
- function Ve(e, t, n) {
226
+ function We(e, t, n) {
227
227
  let r = e.index, i = e.attributes.position.count, a = r ? r.count : i, o = e.groups;
228
228
  o.length === 0 && (o = [{
229
229
  count: a,
@@ -233,7 +233,7 @@ function Ve(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 _(t, 1, !1), e.deleteAttribute("materialIndex"), e.setAttribute("materialIndex", s);
236
+ t = n.length <= 255 ? new Uint8Array(i) : new Uint16Array(i), s = new b(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++) {
@@ -244,7 +244,7 @@ function Ve(e, t, n) {
244
244
  }
245
245
  }
246
246
  }
247
- function He(e, t) {
247
+ function Ge(e, t) {
248
248
  if (!e.index) {
249
249
  let t = e.attributes.position.count, n = Array(t);
250
250
  for (let e = 0; e < t; e++) n[e] = e;
@@ -252,25 +252,25 @@ function He(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 _(new Float32Array(t * 2), 2, !1));
255
+ e.setAttribute("uv", new b(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 _(new Float32Array(t * 2), 2, !1));
259
+ e.setAttribute("uv2", new b(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 _(new Float32Array(t * 4), 4, !1));
264
+ e.setAttribute("tangent", new b(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 _(n, 4));
268
+ n.fill(1), e.setAttribute("color", new b(n, 4));
269
269
  }
270
270
  }
271
271
  //#endregion
272
272
  //#region node_modules/three-gpu-pathtracer/src/utils/bufferToHash.js
273
- function Ue(e) {
273
+ function Ke(e) {
274
274
  let t = 0;
275
275
  if (e.byteLength !== 0) {
276
276
  let n = new Uint8Array(e);
@@ -283,7 +283,7 @@ function Ue(e) {
283
283
  }
284
284
  //#endregion
285
285
  //#region node_modules/three-gpu-pathtracer/src/core/utils/MeshDiff.js
286
- function We(e) {
286
+ function qe(e) {
287
287
  let t = e.uuid, n = Object.values(e.attributes);
288
288
  e.index && (n.push(e.index), t += `index|${e.index.version}`);
289
289
  let r = Object.keys(n).sort();
@@ -293,48 +293,48 @@ function We(e) {
293
293
  }
294
294
  return t;
295
295
  }
296
- function Ge(e) {
296
+ function Je(e) {
297
297
  let t = e.skeleton;
298
- return t ? (t.boneTexture || t.computeBoneTexture(), `${Ue(t.boneTexture.image.data.buffer)}_${t.boneTexture.uuid}`) : null;
298
+ return t ? (t.boneTexture || t.computeBoneTexture(), `${Ke(t.boneTexture.image.data.buffer)}_${t.boneTexture.uuid}`) : null;
299
299
  }
300
- var Ke = class {
300
+ var Ye = class {
301
301
  constructor(e = null) {
302
- this.matrixWorld = new k(), this.geometryHash = null, this.skeletonHash = null, this.primitiveCount = -1, e !== null && this.updateFrom(e);
302
+ this.matrixWorld = new j(), this.geometryHash = null, this.skeletonHash = null, this.primitiveCount = -1, e !== null && this.updateFrom(e);
303
303
  }
304
304
  updateFrom(e) {
305
305
  let t = e.geometry, n = (t.index ? t.index.count : t.attributes.position.count) / 3;
306
- this.matrixWorld.copy(e.matrixWorld), this.geometryHash = We(t), this.primitiveCount = n, this.skeletonHash = Ge(e);
306
+ this.matrixWorld.copy(e.matrixWorld), this.geometryHash = qe(t), this.primitiveCount = n, this.skeletonHash = Je(e);
307
307
  }
308
308
  didChange(e) {
309
309
  let t = e.geometry, n = (t.index ? t.index.count : t.attributes.position.count) / 3;
310
- return !(this.matrixWorld.equals(e.matrixWorld) && this.geometryHash === We(t) && this.skeletonHash === Ge(e) && this.primitiveCount === n);
310
+ return !(this.matrixWorld.equals(e.matrixWorld) && this.geometryHash === qe(t) && this.skeletonHash === Je(e) && this.primitiveCount === n);
311
311
  }
312
- }, U = /*@__PURE__*/ new R(), W = /*@__PURE__*/ new R(), G = /*@__PURE__*/ new R(), qe = /*@__PURE__*/ new z(), K = /*@__PURE__*/ new R(), Je = /*@__PURE__*/ new R(), Ye = /*@__PURE__*/ new z(), Xe = /*@__PURE__*/ new z(), Ze = /*@__PURE__*/ new k(), Qe = /*@__PURE__*/ new k();
313
- function $e(e, t, n) {
312
+ }, U = /*@__PURE__*/ new R(), W = /*@__PURE__*/ new R(), G = /*@__PURE__*/ new R(), Xe = /*@__PURE__*/ new z(), K = /*@__PURE__*/ new R(), Ze = /*@__PURE__*/ new R(), Qe = /*@__PURE__*/ new z(), $e = /*@__PURE__*/ new z(), q = /*@__PURE__*/ new j(), et = /*@__PURE__*/ new j();
313
+ function tt(e, t, n) {
314
314
  let r = e.skeleton, i = e.geometry, a = r.bones, o = r.boneInverses;
315
- Ye.fromBufferAttribute(i.attributes.skinIndex, t), Xe.fromBufferAttribute(i.attributes.skinWeight, t), Ze.elements.fill(0);
315
+ Qe.fromBufferAttribute(i.attributes.skinIndex, t), $e.fromBufferAttribute(i.attributes.skinWeight, t), q.elements.fill(0);
316
316
  for (let e = 0; e < 4; e++) {
317
- let t = Xe.getComponent(e);
317
+ let t = $e.getComponent(e);
318
318
  if (t !== 0) {
319
- let n = Ye.getComponent(e);
320
- Qe.multiplyMatrices(a[n].matrixWorld, o[n]), tt(Ze, Qe, t);
319
+ let n = Qe.getComponent(e);
320
+ et.multiplyMatrices(a[n].matrixWorld, o[n]), rt(q, et, t);
321
321
  }
322
322
  }
323
- return Ze.multiply(e.bindMatrix).premultiply(e.bindMatrixInverse), n.transformDirection(Ze), n;
323
+ return q.multiply(e.bindMatrix).premultiply(e.bindMatrixInverse), n.transformDirection(q), n;
324
324
  }
325
- function et(e, t, n, r, i) {
325
+ function nt(e, t, n, r, i) {
326
326
  K.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 && (Je.fromBufferAttribute(s, r), n ? K.addScaledVector(Je, o) : K.addScaledVector(Je.sub(i), o));
329
+ o !== 0 && (Ze.fromBufferAttribute(s, r), n ? K.addScaledVector(Ze, o) : K.addScaledVector(Ze.sub(i), o));
330
330
  }
331
331
  i.add(K);
332
332
  }
333
- function tt(e, t, n) {
333
+ function rt(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 nt(e) {
337
+ function it(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 nt(e) {
349
349
  }
350
350
  return e;
351
351
  }
352
- function rt(e, t = {}, n = new v()) {
352
+ function at(e, t = {}, n = new x()) {
353
353
  t = {
354
354
  applyWorldTransforms: !0,
355
355
  attributes: [],
@@ -358,20 +358,20 @@ function rt(e, t = {}, n = new v()) {
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
360
  !n.index && r.index && (n.index = r.index.clone()), c.position || n.setAttribute("position", V(s.position)), a && !c.normal && s.normal && n.setAttribute("normal", V(s.normal)), o && !c.tangent && s.tangent && n.setAttribute("tangent", V(s.tangent)), H(r.index, n.index), H(s.position, c.position), a && H(s.normal, c.normal), o && H(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 ae();
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 oe();
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++) U.fromBufferAttribute(l, t), u && W.fromBufferAttribute(u, t), d && (qe.fromBufferAttribute(d, t), G.fromBufferAttribute(d, t)), g && (f && et(f, g, h, t, U), p && et(p, g, h, t, W), m && et(m, g, h, t, G)), e.isSkinnedMesh && (e.applyBoneTransform(t, U), u && $e(e, t, W), d && $e(e, t, G)), i && U.applyMatrix4(e.matrixWorld), c.position.setXYZ(t, U.x, U.y, U.z), u && (i && W.applyNormalMatrix(_), c.normal.setXYZ(t, W.x, W.y, W.z)), d && (i && G.transformDirection(e.matrixWorld), c.tangent.setXYZW(t, G.x, G.y, G.z, qe.w));
363
+ for (let t = 0, n = s.position.count; t < n; t++) U.fromBufferAttribute(l, t), u && W.fromBufferAttribute(u, t), d && (Xe.fromBufferAttribute(d, t), G.fromBufferAttribute(d, t)), g && (f && nt(f, g, h, t, U), p && nt(p, g, h, t, W), m && nt(m, g, h, t, G)), e.isSkinnedMesh && (e.applyBoneTransform(t, U), u && tt(e, t, W), d && tt(e, t, G)), i && U.applyMatrix4(e.matrixWorld), c.position.setXYZ(t, U.x, U.y, U.z), u && (i && W.applyNormalMatrix(_), c.normal.setXYZ(t, W.x, W.y, W.z)), d && (i && G.transformDirection(e.matrixWorld), c.tangent.setXYZW(t, G.x, G.y, G.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, V(s[r])), H(s[r], c[r]), Fe(s[r], c[r]));
366
+ r === "position" || r === "tangent" || r === "normal" || !(r in s) || (c[r] || n.setAttribute(r, V(s[r])), H(s[r], c[r]), Re(s[r], c[r]));
367
367
  }
368
- return e.matrixWorld.determinant() < 0 && nt(n), n;
368
+ return e.matrixWorld.determinant() < 0 && it(n), n;
369
369
  }
370
370
  //#endregion
371
371
  //#region node_modules/three-gpu-pathtracer/src/core/utils/BakedGeometry.js
372
- var it = class extends v {
372
+ var ot = class extends x {
373
373
  constructor() {
374
- super(), this.version = 0, this.hash = null, this._diff = new Ke();
374
+ super(), this.version = 0, this.hash = null, this._diff = new Ye();
375
375
  }
376
376
  isCompatible(e, t) {
377
377
  let n = e.geometry;
@@ -383,15 +383,15 @@ var it = class extends v {
383
383
  }
384
384
  updateFrom(e, t) {
385
385
  let n = this._diff;
386
- return n.didChange(e) ? (rt(e, t, this), n.updateFrom(e), this.version++, this.hash = `${this.uuid}_${this.version}`, !0) : !1;
386
+ return n.didChange(e) ? (at(e, t, this), n.updateFrom(e), this.version++, this.hash = `${this.uuid}_${this.version}`, !0) : !1;
387
387
  }
388
388
  };
389
- function at(e, t) {
389
+ function st(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 ot(e) {
394
+ function ct(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 ot(e) {
399
399
  }
400
400
  return t;
401
401
  }
402
- function st(e, t, n) {
402
+ function lt(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 _(/* @__PURE__ */ new Float32Array(), 4, !1));
408
- } else Be(e, n, t);
407
+ for (let e in n.attributes) t.setAttribute(n.attributes[e], new b(/* @__PURE__ */ new Float32Array(), 4, !1));
408
+ } else Ue(e, n, t);
409
409
  for (let e in t.attributes) t.attributes[e].needsUpdate = !0;
410
410
  }
411
- var ct = class {
411
+ var ut = 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 ct = class {
421
421
  }
422
422
  _getDummyMesh() {
423
423
  if (!this._dummyMesh) {
424
- let e = new se(), t = new v();
425
- t.setAttribute("position", new _(/* @__PURE__ */ new Float32Array(9), 3)), this._dummyMesh = new oe(t, e);
424
+ let e = new ce(), t = new x();
425
+ t.setAttribute("position", new b(/* @__PURE__ */ new Float32Array(9), 3)), this._dummyMesh = new se(t, e);
426
426
  }
427
427
  return this._dummyMesh;
428
428
  }
429
429
  _getMeshes() {
430
430
  let e = [];
431
- return at(this.objects, (t) => {
431
+ return st(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 ct = 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 it(), e.set(o, s)), s.updateFrom(a, r) && this.generateMissingAttributes && He(s, this.attributes);
444
+ (!s || !s.isCompatible(a, this.attributes)) && (s && s.dispose(), s = new ot(), 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 ct = class {
450
450
  setObjects(e) {
451
451
  Array.isArray(e) ? this.objects = [...e] : this.objects = [e];
452
452
  }
453
- generate(e = new v()) {
453
+ generate(e = new x()) {
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 ct = 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
- st(s, e, {
464
+ lt(s, e, {
465
465
  useGroups: t,
466
466
  forceUpdate: l,
467
467
  skipAssigningAttributes: o,
@@ -473,14 +473,14 @@ var ct = class {
473
473
  let u = 0;
474
474
  return l ? u = 2 : o.includes(!1) && (u = 1), {
475
475
  changeType: u,
476
- materials: ot(a),
476
+ materials: ct(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 lt(e) {
483
+ function dt(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 lt(e) {
491
491
  }
492
492
  return Array.from(t);
493
493
  }
494
- function ut(e) {
494
+ function ft(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 ut(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 dt = class {
504
+ var pt = class {
505
505
  get initialized() {
506
506
  return !!this.bvh;
507
507
  }
@@ -513,7 +513,7 @@ var dt = class {
513
513
  "color",
514
514
  "uv",
515
515
  "uv2"
516
- ], this.generateBVH = !0, this.bvh = null, this.geometry = new v(), this.staticGeometryGenerator = new ct(e), this._bvhWorker = null, this._pendingGenerate = null, this._buildAsync = !1;
516
+ ], this.generateBVH = !0, this.bvh = null, this.geometry = new x(), this.staticGeometryGenerator = new ut(e), this._bvhWorker = null, this._pendingGenerate = null, this._buildAsync = !1;
517
517
  }
518
518
  setObjects(e) {
519
519
  this.staticGeometryGenerator.setObjects(e);
@@ -537,8 +537,8 @@ var dt = class {
537
537
  e.isSkinnedMesh && e.skeleton && e.skeleton.update();
538
538
  });
539
539
  });
540
- let a = t.generate(n), o = a.materials, s = lt(o), { lights: c, iesTextures: u } = ut(i);
541
- if (a.changeType !== 0 && Ve(n, o, o), this.generateBVH) {
540
+ let a = t.generate(n), o = a.materials, s = dt(o), { lights: l, iesTextures: u } = ft(i);
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) {
544
544
  let t = {
@@ -548,13 +548,13 @@ var dt = class {
548
548
  onProgress: e,
549
549
  ...this.bvhOptions
550
550
  };
551
- this._buildAsync ? this.bvh = this._bvhWorker.generate(n, t) : this.bvh = new l(n, t);
551
+ this._buildAsync ? this.bvh = this._bvhWorker.generate(n, t) : this.bvh = new c(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: c,
557
+ lights: l,
558
558
  iesTextures: u,
559
559
  geometry: n,
560
560
  materials: o,
@@ -562,7 +562,7 @@ var dt = class {
562
562
  objects: i
563
563
  };
564
564
  }
565
- }, ft = class extends F {
565
+ }, mt = class extends ye {
566
566
  set needsUpdate(e) {
567
567
  super.needsUpdate = !0, this.dispatchEvent({ type: "recompilation" });
568
568
  }
@@ -583,10 +583,10 @@ var dt = 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
- }, pt = class extends ft {
586
+ }, ht = class extends mt {
587
587
  constructor(e) {
588
588
  super({
589
- blending: j,
589
+ blending: N,
590
590
  uniforms: {
591
591
  target1: { value: null },
592
592
  target2: { value: null },
@@ -599,7 +599,7 @@ var dt = class {
599
599
  };
600
600
  //#endregion
601
601
  //#region node_modules/three-gpu-pathtracer/src/shader/rand/sobol.glsl.js
602
- function mt(e = 1) {
602
+ function gt(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 mt(e = 1) {
638
638
  }
639
639
  `;
640
640
  }
641
- function ht(e = 1) {
641
+ function _t(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 ht(e = 1) {
660
660
  }
661
661
  `;
662
662
  }
663
- var gt = `
663
+ var vt = `
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
- ${mt(1)}
670
- ${mt(2)}
671
- ${mt(3)}
672
- ${mt(4)}
669
+ ${gt(1)}
670
+ ${gt(2)}
671
+ ${gt(3)}
672
+ ${gt(4)}
673
673
 
674
674
  uint sobolHash( uint x ) {
675
675
 
@@ -683,7 +683,7 @@ var gt = `
683
683
 
684
684
  }
685
685
 
686
- `, _t = "\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", vt = `
686
+ `, yt = "\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", bt = `
687
687
 
688
688
  // Seeds
689
689
  uniform sampler2D sobolTexture;
@@ -721,21 +721,21 @@ var gt = `
721
721
 
722
722
  }
723
723
 
724
- ${ht(1)}
725
- ${ht(2)}
726
- ${ht(3)}
727
- ${ht(4)}
724
+ ${_t(1)}
725
+ ${_t(2)}
726
+ ${_t(3)}
727
+ ${_t(4)}
728
728
 
729
- `, yt = class extends ft {
729
+ `, xt = class extends mt {
730
730
  constructor() {
731
731
  super({
732
- blending: j,
732
+ blending: N,
733
733
  uniforms: { resolution: { value: new L() } },
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
- ${gt}
738
- ${_t}
737
+ ${vt}
738
+ ${yt}
739
739
 
740
740
  varying vec2 vUv;
741
741
  uniform vec2 resolution;
@@ -748,20 +748,20 @@ var gt = `
748
748
  `
749
749
  });
750
750
  }
751
- }, bt = class {
751
+ }, St = class {
752
752
  generate(e, t = 256) {
753
753
  let n = new B(t, t, {
754
- type: E,
755
- format: M,
756
- minFilter: A,
757
- magFilter: A,
754
+ type: O,
755
+ format: P,
756
+ minFilter: M,
757
+ magFilter: M,
758
758
  generateMipmaps: !1
759
759
  }), r = e.getRenderTarget();
760
760
  e.setRenderTarget(n);
761
- let i = new p(new yt());
761
+ let i = new g(new xt());
762
762
  return i.material.resolution.set(t, t), i.render(e), e.setRenderTarget(r), i.dispose(), n;
763
763
  }
764
- }, xt = class extends ue {
764
+ }, Ct = class extends de {
765
765
  set bokehSize(e) {
766
766
  this.fStop = this.getFocalLength() / e;
767
767
  }
@@ -774,24 +774,24 @@ var gt = `
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
- }, St = class {
777
+ }, wt = 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 xt ? (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);
782
+ e instanceof Ct ? (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 Ct(e) {
787
+ function Tt(e) {
788
788
  let t = new Uint16Array(e.length);
789
- for (let n = 0, r = e.length; n < r; ++n) t[n] = C.toHalfFloat(e[n]);
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 wt(e, t, n = 0, r = e.length) {
794
+ function Et(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,20 +799,20 @@ function wt(e, t, n = 0, r = e.length) {
799
799
  }
800
800
  return i - n;
801
801
  }
802
- function Tt(e, t, n) {
802
+ function Dt(e, t, n) {
803
803
  return .2126 * e + .7152 * t + .0722 * n;
804
804
  }
805
- function Et(e, t = D) {
805
+ function Ot(e, t = k) {
806
806
  let n = e.clone();
807
- n.source = new ve({ ...n.image });
807
+ n.source = new xe({ ...n.image });
808
808
  let { width: r, height: i, data: a } = n.image, o = a;
809
809
  if (n.type !== t) {
810
- o = t === D ? new Uint16Array(a.length) : new Float32Array(a.length);
810
+ o = t === k ? new Uint16Array(a.length) : new Float32Array(a.length);
811
811
  let e;
812
812
  e = a instanceof Int8Array || a instanceof Int16Array || a instanceof Int32Array ? 2 ** (8 * a.BYTES_PER_ELEMENT - 1) - 1 : 2 ** (8 * a.BYTES_PER_ELEMENT) - 1;
813
813
  for (let r = 0, i = a.length; r < i; r++) {
814
814
  let i = a[r];
815
- n.type === D && (i = C.fromHalfFloat(a[r])), n.type !== E && n.type !== D && (i /= e), t === D && (o[r] = C.toHalfFloat(i));
815
+ n.type === k && (i = D.fromHalfFloat(a[r])), n.type !== O && n.type !== k && (i /= e), t === k && (o[r] = D.toHalfFloat(i));
816
816
  }
817
817
  n.image.data = o, n.type = t;
818
818
  }
@@ -827,36 +827,36 @@ function Et(e, t = D) {
827
827
  }
828
828
  return n;
829
829
  }
830
- var Dt = class {
830
+ var kt = class {
831
831
  constructor() {
832
- let e = new S(Ct(new Float32Array([
832
+ let e = new E(Tt(new Float32Array([
833
833
  0,
834
834
  0,
835
835
  0,
836
836
  0
837
837
  ])), 1, 1);
838
- e.type = D, e.format = M, e.minFilter = O, e.magFilter = O, e.wrapS = P, e.wrapT = P, e.generateMipmaps = !1, e.needsUpdate = !0;
839
- let t = new S(Ct(new Float32Array([0, 1])), 1, 2);
840
- t.type = D, t.format = N, t.minFilter = O, t.magFilter = O, t.generateMipmaps = !1, t.needsUpdate = !0;
841
- let n = new S(Ct(new Float32Array([
838
+ e.type = k, e.format = P, e.minFilter = A, e.magFilter = A, e.wrapS = F, e.wrapT = F, e.generateMipmaps = !1, e.needsUpdate = !0;
839
+ let t = new E(Tt(new Float32Array([0, 1])), 1, 2);
840
+ t.type = k, t.format = ge, t.minFilter = A, t.magFilter = A, t.generateMipmaps = !1, t.needsUpdate = !0;
841
+ let n = new E(Tt(new Float32Array([
842
842
  0,
843
843
  0,
844
844
  1,
845
845
  1
846
846
  ])), 2, 2);
847
- n.type = D, n.format = N, n.minFilter = O, n.magFilter = O, n.generateMipmaps = !1, n.needsUpdate = !0, this.map = e, this.marginalWeights = t, this.conditionalWeights = n, this.totalSum = 0;
847
+ n.type = k, n.format = ge, 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 = Et(e);
854
- t.wrapS = P, t.wrapT = b;
853
+ let t = Ot(e);
854
+ t.wrapS = F, t.wrapT = C;
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 = Tt(C.fromHalfFloat(i[4 * s + 0]), C.fromHalfFloat(i[4 * s + 1]), C.fromHalfFloat(i[4 * s + 2]));
859
+ let s = e * n + r, c = Dt(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,12 +865,12 @@ var Dt = 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 = wt(c, (e + 1) / r);
869
- d[e] = C.toHalfFloat((t + .5) / r);
868
+ let t = Et(c, (e + 1) / r);
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 = wt(o, (t + 1) / n, e * n, n);
873
- f[r] = C.toHalfFloat((i + .5) / n);
872
+ let r = e * n + t, i = Et(o, (t + 1) / n, e * n, n);
873
+ f[r] = D.toHalfFloat((i + .5) / n);
874
874
  }
875
875
  this.dispose();
876
876
  let { marginalWeights: p, conditionalWeights: m } = this;
@@ -884,40 +884,40 @@ var Dt = class {
884
884
  data: f
885
885
  }, m.needsUpdate = !0, this.totalSum = l, this.map = t;
886
886
  }
887
- }, Ot = 6, kt = 0, At = 1, jt = 2, Mt = 3, Nt = 4, q = new R(), J = new R(), Pt = new k(), Y = new de(), Ft = new R(), X = new R(), It = new R(0, 1, 0), Lt = class {
887
+ }, At = 6, jt = 0, Mt = 1, Nt = 2, Pt = 3, Ft = 4, J = new R(), Y = new R(), It = new j(), X = new fe(), Lt = new R(), Z = new R(), Rt = new R(0, 1, 0), zt = class {
888
888
  constructor() {
889
- let e = new S(/* @__PURE__ */ new Float32Array(4), 1, 1);
890
- e.format = M, e.type = E, e.wrapS = b, e.wrapT = b, e.generateMipmaps = !1, e.minFilter = A, e.magFilter = A, this.tex = e, this.count = 0;
889
+ let e = new E(/* @__PURE__ */ new Float32Array(4), 1, 1);
890
+ e.format = P, e.type = O, e.wrapS = C, e.wrapT = C, 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 * Ot, 1), i = Math.ceil(Math.sqrt(r));
893
+ let n = this.tex, r = Math.max(e.length * At, 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 * Ot * 4, o = 0;
898
- for (let e = 0; e < Ot * 4; e++) a[i + e] = 0;
899
- r.getWorldPosition(J), a[i + o++] = J.x, a[i + o++] = J.y, a[i + o++] = J.z;
900
- let s = kt;
901
- if (r.isRectAreaLight && r.isCircular ? s = At : r.isSpotLight ? s = jt : r.isDirectionalLight ? s = Mt : r.isPointLight && (s = Nt), 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(Y), r.isRectAreaLight) q.set(r.width, 0, 0).applyQuaternion(Y), a[i + o++] = q.x, a[i + o++] = q.y, a[i + o++] = q.z, o++, J.set(0, r.height, 0).applyQuaternion(Y), a[i + o++] = J.x, a[i + o++] = J.y, a[i + o++] = J.z, a[i + o++] = q.cross(J).length() * (r.isCircular ? Math.PI / 4 : 1);
897
+ let r = e[n], i = n * At * 4, o = 0;
898
+ for (let e = 0; e < At * 4; e++) a[i + e] = 0;
899
+ r.getWorldPosition(Y), a[i + o++] = Y.x, a[i + o++] = Y.y, a[i + o++] = Y.z;
900
+ let s = jt;
901
+ if (r.isRectAreaLight && r.isCircular ? s = Mt : r.isSpotLight ? s = Nt : r.isDirectionalLight ? s = Pt : r.isPointLight && (s = Ft), 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
- Ft.setFromMatrixPosition(r.matrixWorld), X.setFromMatrixPosition(r.target.matrixWorld), Pt.lookAt(Ft, X, It), Y.setFromRotationMatrix(Pt), q.set(1, 0, 0).applyQuaternion(Y), a[i + o++] = q.x, a[i + o++] = q.y, a[i + o++] = q.z, o++, J.set(0, 1, 0).applyQuaternion(Y), a[i + o++] = J.x, a[i + o++] = J.y, a[i + o++] = J.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;
904
+ Lt.setFromMatrixPosition(r.matrixWorld), Z.setFromMatrixPosition(r.target.matrixWorld), It.lookAt(Lt, Z, Rt), X.setFromRotationMatrix(It), 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
- let e = q.setFromMatrixPosition(r.matrixWorld);
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;
908
908
  } else if (r.isDirectionalLight) {
909
- let e = q.setFromMatrixPosition(r.matrixWorld), t = J.setFromMatrixPosition(r.target.matrixWorld);
910
- X.subVectors(e, t).normalize(), a[i + o++] = X.x, a[i + o++] = X.y, a[i + o++] = X.z;
909
+ let e = J.setFromMatrixPosition(r.matrixWorld), t = Y.setFromMatrixPosition(r.target.matrixWorld);
910
+ Z.subVectors(e, t).normalize(), a[i + o++] = Z.x, a[i + o++] = Z.y, a[i + o++] = Z.z;
911
911
  }
912
912
  }
913
913
  this.count = e.length;
914
- let o = Ue(a.buffer);
914
+ let o = Ke(a.buffer);
915
915
  return this.hash === o ? !1 : (this.hash = o, n.needsUpdate = !0, !0);
916
916
  }
917
917
  };
918
918
  //#endregion
919
919
  //#region node_modules/three-gpu-pathtracer/src/uniforms/FloatAttributeTextureArray.js
920
- function Rt(e, t, n, r, i) {
920
+ function Bt(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,9 +937,9 @@ function Rt(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 zt = class extends te {
940
+ var Vt = class extends T {
941
941
  constructor() {
942
- super(), this._textures = [], this.type = E, this.format = M, this.internalFormat = "RGBA32F";
942
+ super(), this._textures = [], this.type = O, this.format = P, this.internalFormat = "RGBA32F";
943
943
  }
944
944
  updateAttribute(e, t) {
945
945
  let n = this._textures[e];
@@ -947,14 +947,14 @@ var zt = class extends te {
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), Rt(n.image.data, l, s, 4, c), this.dispose(), this.needsUpdate = !0;
950
+ l === 3 && (l = 4), Bt(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;
954
954
  for (let r = 0, i = n; r < i; r++) if (e[r].count !== t) throw Error("FloatAttributeTextureArray: All attributes must have the same item count.");
955
955
  let r = this._textures;
956
956
  for (; r.length < n;) {
957
- let e = new Oe();
957
+ let e = new je();
958
958
  r.push(e);
959
959
  }
960
960
  for (; r.length > n;) r.pop();
@@ -964,11 +964,11 @@ var zt = class extends te {
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), Rt(n.image.data, a, o, 4, i);
967
+ a === 3 && (a = 4), Bt(n.image.data, a, o, 4, i);
968
968
  }
969
969
  this.dispose(), this.needsUpdate = !0;
970
970
  }
971
- }, Bt = class extends zt {
971
+ }, Ht = class extends Vt {
972
972
  updateNormalAttribute(e) {
973
973
  this.updateAttribute(0, e);
974
974
  }
@@ -992,25 +992,25 @@ var zt = class extends te {
992
992
  };
993
993
  //#endregion
994
994
  //#region node_modules/three-gpu-pathtracer/src/core/utils/sceneUpdateUtils.js
995
- function Vt(e, t) {
995
+ function Ut(e, t) {
996
996
  return e.uuid < t.uuid ? 1 : e.uuid > t.uuid ? -1 : 0;
997
997
  }
998
- function Ht(e) {
998
+ function Wt(e) {
999
999
  return `${e.source.uuid}:${e.colorSpace}`;
1000
1000
  }
1001
- function Ut(e) {
1001
+ function Gt(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 = Ht(i);
1004
+ let i = e[r], a = Wt(i);
1005
1005
  t.has(a) || (t.add(a), n.push(i));
1006
1006
  }
1007
1007
  return n;
1008
1008
  }
1009
- function Wt(e) {
1009
+ function Kt(e) {
1010
1010
  let t = e.map((e) => e.iesMap || null).filter((e) => e), n = new Set(t);
1011
- return Array.from(n).sort(Vt);
1011
+ return Array.from(n).sort(Ut);
1012
1012
  }
1013
- function Gt(e) {
1013
+ function qt(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 Gt(e) {
1019
1019
  n && n.isTexture && t.add(n);
1020
1020
  }
1021
1021
  }
1022
- return Ut(Array.from(t)).sort(Vt);
1022
+ return Gt(Array.from(t)).sort(Ut);
1023
1023
  }
1024
- function Kt(e) {
1024
+ function Jt(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(Vt);
1028
+ }), t.sort(Ut);
1029
1029
  }
1030
1030
  //#endregion
1031
1031
  //#region node_modules/three-gpu-pathtracer/src/uniforms/MaterialsTexture.js
1032
- var qt = 45, Jt = qt * 4, Yt = class {
1032
+ var Yt = 45, Xt = Yt * 4, Zt = class {
1033
1033
  constructor() {
1034
1034
  this._features = {};
1035
1035
  }
@@ -1042,14 +1042,14 @@ var qt = 45, Jt = qt * 4, Yt = class {
1042
1042
  reset() {
1043
1043
  this._features = {};
1044
1044
  }
1045
- }, Xt = class extends S {
1045
+ }, Qt = class extends E {
1046
1046
  constructor() {
1047
- super(/* @__PURE__ */ new Float32Array(4), 1, 1), this.format = M, this.type = E, this.wrapS = b, this.wrapT = b, this.minFilter = A, this.magFilter = A, this.generateMipmaps = !1, this.features = new Yt();
1047
+ super(/* @__PURE__ */ new Float32Array(4), 1, 1), this.format = P, this.type = O, this.wrapS = C, this.wrapT = C, this.minFilter = M, this.magFilter = M, this.generateMipmaps = !1, this.features = new Zt();
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 = Ht(e[t]);
1052
+ let n = Wt(e[t]);
1053
1053
  return u[n];
1054
1054
  } else return n;
1055
1055
  }
@@ -1065,8 +1065,8 @@ var qt = 45, Jt = qt * 4, Yt = class {
1065
1065
  }
1066
1066
  return 8;
1067
1067
  }
1068
- let a = 0, o = e.length * qt, 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[Ht(t[e])] = e;
1068
+ let a = 0, o = e.length * Yt, 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[Wt(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 qt = 45, Jt = qt * 4, Yt = class {
1074
1074
  let o = e[t];
1075
1075
  if (o.isFogVolumeMaterial) {
1076
1076
  l.setUsed("FOG");
1077
- for (let e = 0; e < Jt; 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 += Jt;
1077
+ for (let e = 0; e < Xt; 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 += Xt;
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,62 +1084,62 @@ var qt = 45, Jt = qt * 4, Yt = 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 ne:
1087
+ case re:
1088
1088
  d[a++] = 1;
1089
1089
  break;
1090
- case g:
1090
+ case y:
1091
1091
  d[a++] = -1;
1092
1092
  break;
1093
- case w:
1093
+ case te:
1094
1094
  d[a++] = 0;
1095
1095
  break;
1096
1096
  }
1097
1097
  d[a++] = Number(r(o, "matte", !1)), d[a++] = Number(r(o, "castShadow", !0)), d[a++] = Number(o.vertexColors) | Number(o.flatShading) << 1, d[a++] = Number(o.transparent), a += i(o, "map", d, a), a += i(o, "metalnessMap", d, a), a += i(o, "roughnessMap", d, a), a += i(o, "transmissionMap", d, a), a += i(o, "emissiveMap", d, a), a += i(o, "normalMap", d, a), a += i(o, "clearcoatMap", d, a), a += i(o, "clearcoatNormalMap", d, a), a += i(o, "clearcoatRoughnessMap", d, a), a += i(o, "sheenColorMap", d, a), a += i(o, "sheenRoughnessMap", d, a), a += i(o, "iridescenceMap", d, a), a += i(o, "iridescenceThicknessMap", d, a), a += i(o, "specularColorMap", d, a), a += i(o, "specularIntensityMap", d, a);
1098
1098
  }
1099
- let f = Ue(d.buffer);
1099
+ let f = Ke(d.buffer);
1100
1100
  return this.hash === f ? !1 : (this.hash = f, this.needsUpdate = !0, !0);
1101
1101
  }
1102
- }, Zt = new x();
1103
- function Qt(e) {
1102
+ }, $t = new w();
1103
+ function en(e) {
1104
1104
  return e ? `${e.uuid}:${e.version}` : null;
1105
1105
  }
1106
- function $t(e, t) {
1106
+ function tn(e, t) {
1107
1107
  for (let n in t) n in e && (e[n] = t[n]);
1108
1108
  }
1109
- var en = class extends Se {
1109
+ var nn = class extends Te {
1110
1110
  constructor(e, t, n) {
1111
1111
  let r = {
1112
- format: M,
1113
- type: be,
1114
- minFilter: O,
1115
- magFilter: O,
1116
- wrapS: P,
1117
- wrapT: P,
1112
+ format: P,
1113
+ type: Ce,
1114
+ minFilter: A,
1115
+ magFilter: A,
1116
+ wrapS: F,
1117
+ wrapT: F,
1118
1118
  generateMipmaps: !1,
1119
1119
  ...n
1120
1120
  };
1121
- super(e, t, 1, r), $t(this.texture, r), this.texture.setTextures = (...e) => {
1121
+ super(e, t, 1, r), tn(this.texture, r), this.texture.setTextures = (...e) => {
1122
1122
  this.setTextures(...e);
1123
1123
  }, this.hashes = [null];
1124
- let i = new p(new tn());
1124
+ let i = new g(new rn());
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(Zt);
1129
+ e.getClearColor($t);
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 = ce;
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 = le;
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 = Qt(r);
1134
+ let r = t[n], i = en(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(Zt, o), e.setRenderTarget(i), e.toneMapping = a, u;
1137
+ return c.material.map = null, e.setClearColor($t, o), e.setRenderTarget(i), e.toneMapping = a, u;
1138
1138
  }
1139
1139
  dispose() {
1140
1140
  super.dispose(), this.fsQuad.dispose();
1141
1141
  }
1142
- }, tn = class extends F {
1142
+ }, rn = class extends ye {
1143
1143
  get map() {
1144
1144
  return this.uniforms.map.value;
1145
1145
  }
@@ -1156,14 +1156,14 @@ var en = class extends Se {
1156
1156
  };
1157
1157
  //#endregion
1158
1158
  //#region node_modules/three-gpu-pathtracer/src/uniforms/stratified/StratifiedSampler.js
1159
- function nn(e, t = Math.random()) {
1159
+ function an(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 rn = class {
1166
+ var on = 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 rn = class {
1174
1174
  a = 0;
1175
1175
  }, this.next = function() {
1176
1176
  let { samples: r } = this;
1177
- a >= i.length && (nn(i, n), this.reshuffle());
1177
+ a >= i.length && (an(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
- }, an = class {
1183
+ }, sn = 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 rn(e, r, n);
1189
+ let t = new on(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 rn = class {
1198
1198
  for (let e of a) e.reset();
1199
1199
  };
1200
1200
  }
1201
- }, on = class {
1201
+ }, cn = 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 rn = class {
1208
1208
  nextFloat() {
1209
1209
  return this.nextInt() / (this.m - 1);
1210
1210
  }
1211
- }, sn = class extends S {
1211
+ }, ln = class extends E {
1212
1212
  constructor(e = 1, t = 1, n = 8) {
1213
- super(/* @__PURE__ */ new Float32Array(1), 1, 1, M, E), this.minFilter = A, this.magFilter = A, this.strata = n, this.sampler = null, this.generator = new on(), this.stableNoise = !1, this.random = () => this.stableNoise ? this.generator.nextFloat() : Math.random(), this.init(e, t, n);
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 cn(), 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 an(n, Array(e * t).fill(4), this.random);
1218
+ let i = new sn(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 rn = class {
1227
1227
  };
1228
1228
  //#endregion
1229
1229
  //#region node_modules/three-gpu-pathtracer/src/textures/blueNoise/utils.js
1230
- function cn(e, t = Math.random) {
1230
+ function un(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 ln(e, t) {
1236
+ function dn(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 un = class {
1242
+ var fn = 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 un = 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
- }, dn = class {
1308
+ }, pn = class {
1309
1309
  constructor() {
1310
- this.random = Math.random, this.sigma = 1.5, this.size = 64, this.majorityPointsRatio = .1, this.samples = new un(1), this.savedSamples = new un(1);
1310
+ this.random = Math.random, this.sigma = 1.5, this.size = 64, this.majorityPointsRatio = .1, this.samples = new fn(1), this.savedSamples = new fn(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
- ln(o, a), cn(o, this.random);
1316
+ dn(o, a), un(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 un = class {
1349
1349
  };
1350
1350
  //#endregion
1351
1351
  //#region node_modules/three-gpu-pathtracer/src/textures/BlueNoiseTexture.js
1352
- function fn(e) {
1352
+ function mn(e) {
1353
1353
  return e >= 3 ? 4 : e;
1354
1354
  }
1355
- function pn(e) {
1355
+ function hn(e) {
1356
1356
  switch (e) {
1357
- case 1: return N;
1358
- case 2: return pe;
1359
- default: return M;
1357
+ case 1: return ge;
1358
+ case 2: return me;
1359
+ default: return P;
1360
1360
  }
1361
1361
  }
1362
- var mn = class extends S {
1362
+ var gn = class extends E {
1363
1363
  constructor(e = 64, t = 1) {
1364
- super(/* @__PURE__ */ new Float32Array(4), 1, 1, M, E), this.minFilter = A, this.magFilter = A, this.size = e, this.channels = t, this.update();
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 dn();
1367
+ let e = this.channels, t = this.size, n = new pn();
1368
1368
  n.channels = e, n.size = t;
1369
- let r = fn(e), i = pn(r);
1369
+ let r = mn(e), i = hn(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 mn = class extends S {
1378
1378
  }
1379
1379
  this.needsUpdate = !0;
1380
1380
  }
1381
- }, hn = "\n\n struct PhysicalCamera {\n\n float focusDistance;\n float anamorphicRatio;\n float bokehSize;\n int apertureBlades;\n float apertureRotation;\n\n };\n\n", gn = "\n\n struct EquirectHdrInfo {\n\n sampler2D marginalWeights;\n sampler2D conditionalWeights;\n sampler2D map;\n\n float totalSum;\n\n };\n\n", _n = "\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", vn = "\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", yn = "\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", bn = "\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", xn = "\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", Sn = "\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", Cn = "\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", wn = "\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", Tn = "\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", En = "\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", Dn = "\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", On = "\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", kn = "\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", An = "\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", jn = "\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", Mn = "\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", Nn = "\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", Pn = "\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", Fn = "\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", In = "\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", Ln = "\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", Rn = "\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", zn = "\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", Bn = "\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", Vn = "\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", Hn = class extends ft {
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 {
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
  }
@@ -1406,32 +1406,32 @@ var mn = class extends S {
1406
1406
  bounces: { value: 10 },
1407
1407
  transmissiveBounces: { value: 10 },
1408
1408
  filterGlossyFactor: { value: 0 },
1409
- physicalCamera: { value: new St() },
1410
- cameraWorldMatrix: { value: new k() },
1411
- invProjectionMatrix: { value: new k() },
1412
- bvh: { value: new ke() },
1413
- attributesArray: { value: new Bt() },
1414
- materialIndexAttribute: { value: new De() },
1415
- materials: { value: new Xt() },
1416
- textures: { value: new en().texture },
1417
- lights: { value: new Lt() },
1418
- iesProfiles: { value: new en(360, 180, {
1419
- type: D,
1420
- wrapS: b,
1421
- wrapT: b
1409
+ physicalCamera: { value: new wt() },
1410
+ cameraWorldMatrix: { value: new j() },
1411
+ invProjectionMatrix: { value: new j() },
1412
+ bvh: { value: new Me() },
1413
+ attributesArray: { value: new Ht() },
1414
+ materialIndexAttribute: { value: new Ae() },
1415
+ materials: { value: new Qt() },
1416
+ textures: { value: new nn().texture },
1417
+ lights: { value: new zt() },
1418
+ iesProfiles: { value: new nn(360, 180, {
1419
+ type: k,
1420
+ wrapS: C,
1421
+ wrapT: C
1422
1422
  }).texture },
1423
1423
  environmentIntensity: { value: 1 },
1424
- environmentRotation: { value: new k() },
1425
- envMapInfo: { value: new Dt() },
1424
+ environmentRotation: { value: new j() },
1425
+ envMapInfo: { value: new kt() },
1426
1426
  backgroundBlur: { value: 0 },
1427
1427
  backgroundMap: { value: null },
1428
1428
  backgroundAlpha: { value: 1 },
1429
1429
  backgroundIntensity: { value: 1 },
1430
- backgroundRotation: { value: new k() },
1430
+ backgroundRotation: { value: new j() },
1431
1431
  seed: { value: 0 },
1432
1432
  sobolTexture: { value: null },
1433
- stratifiedTexture: { value: new sn() },
1434
- stratifiedOffsetTexture: { value: new mn(64, 1) }
1433
+ stratifiedTexture: { value: new ln() },
1434
+ stratifiedOffsetTexture: { value: new gn(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: `
@@ -1445,27 +1445,27 @@ var mn = class extends S {
1445
1445
  #include <common>
1446
1446
 
1447
1447
  // bvh intersection
1448
- ${Me}
1449
- ${Pe}
1450
- ${Ne}
1448
+ ${Fe}
1449
+ ${Le}
1450
+ ${Ie}
1451
1451
 
1452
1452
  // uniform structs
1453
- ${hn}
1454
1453
  ${_n}
1455
- ${gn}
1456
- ${vn}
1457
1454
  ${yn}
1455
+ ${vn}
1456
+ ${bn}
1457
+ ${xn}
1458
1458
 
1459
1459
  // random
1460
1460
  #if RANDOM_TYPE == 2 // Stratified List
1461
1461
 
1462
- ${kn}
1462
+ ${jn}
1463
1463
 
1464
1464
  #elif RANDOM_TYPE == 1 // Sobol
1465
1465
 
1466
- ${On}
1467
- ${gt}
1466
+ ${An}
1468
1467
  ${vt}
1468
+ ${bt}
1469
1469
 
1470
1470
  #define rand(v) sobol(v)
1471
1471
  #define rand2(v) sobol2(v)
@@ -1474,7 +1474,7 @@ var mn = class extends S {
1474
1474
 
1475
1475
  #else // PCG
1476
1476
 
1477
- ${On}
1477
+ ${An}
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 mn = class extends S {
1490
1490
  #endif
1491
1491
 
1492
1492
  // common
1493
+ ${On}
1494
+ ${Tn}
1495
+ ${kn}
1493
1496
  ${En}
1494
- ${Cn}
1495
1497
  ${Dn}
1496
- ${wn}
1497
- ${Tn}
1498
1498
 
1499
1499
  // environment
1500
1500
  uniform EquirectHdrInfo envMapInfo;
@@ -1550,16 +1550,16 @@ var mn = class extends S {
1550
1550
  float lightsDenom;
1551
1551
 
1552
1552
  // sampling
1553
+ ${wn}
1553
1554
  ${Sn}
1554
- ${bn}
1555
- ${xn}
1555
+ ${Cn}
1556
1556
 
1557
- ${Fn}
1558
- ${Mn}
1557
+ ${Ln}
1559
1558
  ${Pn}
1559
+ ${In}
1560
+ ${Fn}
1560
1561
  ${Nn}
1561
- ${jn}
1562
- ${An}
1562
+ ${Mn}
1563
1563
 
1564
1564
  float applyFilteredGlossy( float roughness, float accumulatedRoughness ) {
1565
1565
 
@@ -1591,12 +1591,12 @@ var mn = class extends S {
1591
1591
 
1592
1592
  }
1593
1593
 
1594
+ ${Hn}
1595
+ ${zn}
1596
+ ${Un}
1597
+ ${Rn}
1594
1598
  ${Bn}
1595
- ${Ln}
1596
1599
  ${Vn}
1597
- ${In}
1598
- ${Rn}
1599
- ${zn}
1600
1600
 
1601
1601
  void main() {
1602
1602
 
@@ -1894,13 +1894,13 @@ var mn = class extends S {
1894
1894
  };
1895
1895
  //#endregion
1896
1896
  //#region node_modules/three-gpu-pathtracer/src/core/PathTracingRenderer.js
1897
- function* Un() {
1897
+ function* Gn() {
1898
1898
  let { _renderer: e, _fsQuad: t, _blendQuad: n, _primaryTarget: r, _blendTargets: i, _sobolTarget: a, _subframe: o, alpha: s, material: c } = this, l = new z(), u = new z(), d = n.material, [f, p] = i;
1899
1899
  for (;;) {
1900
- s ? (d.opacity = this._opacityFactor / (this.samples + 1), c.blending = j, c.opacity = 1) : (c.opacity = this._opacityFactor / (this.samples + 1), c.blending = le);
1900
+ s ? (d.opacity = this._opacityFactor / (this.samples + 1), c.blending = N, c.opacity = 1) : (c.opacity = this._opacityFactor / (this.samples + 1), c.blending = ue);
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, ee = y * b, x = Math.ceil(_ * h), te = Math.ceil(v * g), S = Math.floor(i * _), C = Math.floor(m * v), w = Math.ceil(x / y), T = Math.ceil(te / b);
1903
+ let y = this.tiles.x || 1, b = this.tiles.y || 1, x = y * b, S = Math.ceil(_ * h), C = Math.ceil(v * g), ee = Math.floor(i * _), w = Math.floor(m * v), T = Math.ceil(S / y), E = 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* Un() {
1910
1910
  h = e % y, g = ~~(e / y), this._currentTile = e + 1;
1911
1911
  }
1912
1912
  let _ = b - g - 1;
1913
- r.scissor.set(S + h * w, C + _ * T, Math.min(w, x - h * w), Math.min(T, te - _ * T)), r.viewport.set(S, C, x, te), 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 / ee, a === y - 1 && i === b - 1 && (this.samples = Math.round(this.samples)), yield;
1913
+ r.scissor.set(ee + h * T, w + _ * E, Math.min(T, S - h * T), Math.min(E, C - _ * E)), r.viewport.set(ee, w, 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 Wn = new x(), Gn = class {
1918
+ var Kn = new w(), qn = class {
1919
1919
  get material() {
1920
1920
  return this._fsQuad.material;
1921
1921
  }
@@ -1935,21 +1935,21 @@ var Wn = new x(), Gn = class {
1935
1935
  return !!this._compilePromise;
1936
1936
  }
1937
1937
  constructor(e) {
1938
- this.camera = null, this.tiles = new L(3, 3), this.stableNoise = !1, this.stableTiles = !0, this.samples = 0, this._subframe = new z(0, 0, 1, 1), this._opacityFactor = 1, this._renderer = e, this._alpha = !1, this._fsQuad = new p(new Hn()), this._blendQuad = new p(new pt()), this._task = null, this._currentTile = 0, this._compilePromise = null, this._sobolTarget = new bt().generate(e), this._primaryTarget = new B(1, 1, {
1939
- format: M,
1940
- type: E,
1941
- magFilter: A,
1942
- minFilter: A
1938
+ this.camera = null, this.tiles = new L(3, 3), this.stableNoise = !1, this.stableTiles = !0, this.samples = 0, this._subframe = new z(0, 0, 1, 1), this._opacityFactor = 1, this._renderer = e, this._alpha = !1, this._fsQuad = new g(new Wn()), this._blendQuad = new g(new ht()), this._task = null, this._currentTile = 0, this._compilePromise = null, this._sobolTarget = new St().generate(e), this._primaryTarget = new B(1, 1, {
1939
+ format: P,
1940
+ type: O,
1941
+ magFilter: M,
1942
+ minFilter: M
1943
1943
  }), this._blendTargets = [new B(1, 1, {
1944
- format: M,
1945
- type: E,
1946
- magFilter: A,
1947
- minFilter: A
1944
+ format: P,
1945
+ type: O,
1946
+ magFilter: M,
1947
+ minFilter: M
1948
1948
  }), new B(1, 1, {
1949
- format: M,
1950
- type: E,
1951
- magFilter: A,
1952
- minFilter: A
1949
+ format: P,
1950
+ type: O,
1951
+ magFilter: M,
1952
+ minFilter: M
1953
1953
  })], this._compileFunction = () => {
1954
1954
  let e = this.compileMaterial(this._fsQuad._mesh);
1955
1955
  e.then(() => {
@@ -1977,39 +1977,39 @@ var Wn = new x(), Gn = 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(Wn), 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(Wn, 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());
1980
+ e.getClearColor(Kn), 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(Kn, 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 ||= Un.call(this), this._task.next());
1983
+ this.material.onBeforeRender(), !this.isCompiling && (this._task ||= Gn.call(this), this._task.next());
1984
1984
  }
1985
- }, Z = new L(), Kn = new L(), qn = new ye(), Jn = new x(), Yn = class extends S {
1985
+ }, Q = new L(), Jn = new L(), Yn = new Se(), Xn = new w(), Zn = class extends E {
1986
1986
  constructor(e = 512, t = 512) {
1987
- super(new Float32Array(e * t * 4), e, t, M, E, T, P, b, O, O), this.generationCallback = null;
1987
+ super(new Float32Array(e * t * 4), e, t, P, O, ne, F, C, 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
- Kn.set(t, n), Z.set(r / t, i / n), Z.x -= .5, Z.y = 1 - Z.y, qn.theta = Z.x * 2 * Math.PI, qn.phi = Z.y * Math.PI, qn.radius = 1, this.generationCallback(qn, Z, Kn, Jn);
1993
+ Jn.set(t, n), Q.set(r / t, i / n), Q.x -= .5, Q.y = 1 - Q.y, Yn.theta = Q.x * 2 * Math.PI, Yn.phi = Q.y * Math.PI, Yn.radius = 1, this.generationCallback(Yn, Q, Jn, Xn);
1994
1994
  let a = 4 * (i * t + r);
1995
- e[a + 0] = Jn.r, e[a + 1] = Jn.g, e[a + 2] = Jn.b, e[a + 3] = 1;
1995
+ e[a + 0] = Xn.r, e[a + 1] = Xn.g, e[a + 2] = Xn.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
- }, Xn = new R(), Zn = class extends Yn {
2001
+ }, Qn = new R(), $n = class extends Zn {
2002
2002
  constructor(e = 512) {
2003
- super(e, e), this.topColor = new x().set(16777215), this.bottomColor = new x().set(0), this.exponent = 2, this.generationCallback = (e, t, n, r) => {
2004
- Xn.setFromSpherical(e);
2005
- let i = Xn.y * .5 + .5;
2003
+ super(e, e), this.topColor = new w().set(16777215), this.bottomColor = new w().set(0), this.exponent = 2, this.generationCallback = (e, t, n, r) => {
2004
+ Qn.setFromSpherical(e);
2005
+ let i = Qn.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
- }, Qn = class extends F {
2012
+ }, er = class extends ye {
2013
2013
  get map() {
2014
2014
  return this.uniforms.map.value;
2015
2015
  }
@@ -2032,7 +2032,7 @@ var Wn = new x(), Gn = 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
- }, $n = class extends F {
2035
+ }, tr = class extends ye {
2036
2036
  constructor() {
2037
2037
  super({
2038
2038
  uniforms: {
@@ -2050,7 +2050,7 @@ var Wn = new x(), Gn = class {
2050
2050
  #include <common>
2051
2051
  #include <cube_uv_reflection_fragment>
2052
2052
 
2053
- ${Dn}
2053
+ ${kn}
2054
2054
 
2055
2055
  void main() {
2056
2056
 
@@ -2061,16 +2061,16 @@ var Wn = new x(), Gn = class {
2061
2061
  }`
2062
2062
  }), this.depthWrite = !1, this.depthTest = !1;
2063
2063
  }
2064
- }, er = class {
2064
+ }, nr = class {
2065
2065
  constructor(e) {
2066
- this._renderer = e, this._quad = new p(new $n());
2066
+ this._renderer = e, this._quad = new g(new tr());
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
2072
  let o = new B(t, n, {
2073
- type: E,
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));
2076
2076
  a.material.defines.CUBEUV_MAX_MIP = `${c}.0`, a.material.defines.CUBEUV_TEXEL_WIDTH = u, a.material.defines.CUBEUV_TEXEL_HEIGHT = l, a.material.uniforms.envMap.value = e, a.material.uniforms.flipEnvMap.value = e.isRenderTargetTexture ? 1 : -1, a.material.needsUpdate = !0;
@@ -2078,9 +2078,9 @@ var Wn = new x(), Gn = class {
2078
2078
  i.autoClear = !0, i.setRenderTarget(o), a.render(i), i.setRenderTarget(d), i.autoClear = f;
2079
2079
  let p = new Uint16Array(t * n * 4), m = new Float32Array(t * n * 4);
2080
2080
  i.readRenderTargetPixels(o, 0, 0, t, n, m), o.dispose();
2081
- for (let e = 0, t = m.length; e < t; e++) p[e] = C.toHalfFloat(m[e]);
2082
- let h = new S(p, t, n, M, D);
2083
- return h.minFilter = ie, h.magFilter = O, h.wrapS = P, h.wrapT = P, h.mapping = T, h.needsUpdate = !0, h;
2081
+ for (let e = 0, t = m.length; e < t; e++) p[e] = D.toHalfFloat(m[e]);
2082
+ let h = new E(p, t, n, P, k);
2083
+ return h.minFilter = ae, h.magFilter = A, h.wrapS = F, h.wrapT = F, h.mapping = ne, h.needsUpdate = !0, h;
2084
2084
  }
2085
2085
  dispose() {
2086
2086
  this._quad.dispose();
@@ -2088,10 +2088,10 @@ var Wn = new x(), Gn = class {
2088
2088
  };
2089
2089
  //#endregion
2090
2090
  //#region node_modules/three-gpu-pathtracer/src/core/WebGLPathTracer.js
2091
- function tr(e) {
2091
+ function rr(e) {
2092
2092
  return e.extensions.get("EXT_float_blend");
2093
2093
  }
2094
- var Q = new L(), nr = class {
2094
+ var $ = new L(), ir = class {
2095
2095
  get multipleImportanceSampling() {
2096
2096
  return !!this._pathTracer.material.defines.FEATURE_MIS;
2097
2097
  }
@@ -2135,17 +2135,17 @@ var Q = new L(), nr = class {
2135
2135
  return !!this._pathTracer.isCompiling;
2136
2136
  }
2137
2137
  constructor(e) {
2138
- this._renderer = e, this._generator = new dt(), this._pathTracer = new Gn(e), this._queueReset = !1, this._clock = new ee(), this._compilePromise = null, this._lowResPathTracer = new Gn(e), this._lowResPathTracer.tiles.set(1, 1), this._quad = new p(new Qn({
2138
+ this._renderer = e, this._generator = new pt(), this._pathTracer = new qn(e), this._queueReset = !1, this._clock = new ee(), this._compilePromise = null, this._lowResPathTracer = new qn(e), this._lowResPathTracer.tiles.set(1, 1), this._quad = new g(new er({
2139
2139
  map: null,
2140
2140
  transparent: !0,
2141
- blending: j,
2141
+ blending: N,
2142
2142
  premultipliedAlpha: e.getContextAttributes().premultipliedAlpha
2143
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 L(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 ge(), new ue());
2148
+ }, this.setScene(new ve(), new de());
2149
2149
  }
2150
2150
  setBVHWorker(e) {
2151
2151
  this._generator.setBVHWorker(e);
@@ -2172,28 +2172,28 @@ var Q = new L(), nr = 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 = Gt(n);
2175
+ let e = this._pathTracer.material, t = this._renderer, n = this._materials, r = this.textureSize, i = qt(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 = Kt(e), i = Wt(r);
2179
+ let e = this.scene, t = this._renderer, n = this._pathTracer.material, r = Jt(e), i = Kt(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 Zn(16);
2186
+ this._colorBackground = this._colorBackground || new $n(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 er(this._renderer).generate(e.background);
2191
+ let n = new nr(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 er(this._renderer).generate(e.environment);
2196
+ let n = new nr(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 Q = new L(), nr = 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 || !tr(n), e.alpha = t.alpha, this.renderToCanvas) {
2212
+ if (!this.pausePathTracing && this.enablePathTracing && this.renderDelay <= o && !this.isCompiling && t.update(), t.alpha = t.material.backgroundAlpha !== 1 || !rr(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 Q = new L(), nr = 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 ? h : le), i.material.map = t.target.texture, this.renderToCanvasCallback(t.target, n, i), i.material.blending = j);
2222
+ this.enablePathTracing && i.material.opacity > 0 && (i.material.opacity < 1 && (i.material.blending = this.dynamicLowRes ? v : ue), i.material.map = t.target.texture, this.renderToCanvasCallback(t.target, n, i), i.material.blending = N);
2223
2223
  }
2224
2224
  }
2225
2225
  reset() {
@@ -2230,28 +2230,15 @@ var Q = new L(), nr = class {
2230
2230
  }
2231
2231
  _updateScale() {
2232
2232
  if (this.synchronizeRenderSize) {
2233
- this._renderer.getDrawingBufferSize(Q);
2234
- let e = Math.floor(this.renderScale * Q.x), t = Math.floor(this.renderScale * Q.y);
2235
- if (this._pathTracer.getSize(Q), Q.x !== e || Q.y !== t) {
2233
+ this._renderer.getDrawingBufferSize($);
2234
+ let e = Math.floor(this.renderScale * $.x), t = Math.floor(this.renderScale * $.y);
2235
+ if (this._pathTracer.getSize($), $.x !== e || $.y !== t) {
2236
2236
  let n = this.lowResScale;
2237
2237
  this._pathTracer.setSize(e, t), this._lowResPathTracer.setSize(Math.floor(e * n), Math.floor(t * n));
2238
2238
  }
2239
2239
  }
2240
2240
  }
2241
- };
2242
- //#endregion
2243
- //#region src/core/interfaces/IRendererExtension.ts
2244
- function rr(e) {
2245
- return typeof e == "object" && !!e && "getInternalRenderer" in e && typeof e.getInternalRenderer == "function";
2246
- }
2247
- //#endregion
2248
- //#region src/infrastructure/three/types/PathTracerTypes.ts
2249
- function $(e) {
2250
- return typeof e == "object" && !!e && "getInternalRenderer" in e && typeof e.getInternalRenderer == "function";
2251
- }
2252
- //#endregion
2253
- //#region src/infrastructure/three/ThreePathTracingService.ts
2254
- var ir = class n {
2241
+ }, ar = class t {
2255
2242
  ingestSceneWithoutShadowHelpers(e, t) {
2256
2243
  let n = [], r = [];
2257
2244
  e.traverse((e) => {
@@ -2272,9 +2259,12 @@ var ir = class n {
2272
2259
  r.drawImage(t, 0, 0);
2273
2260
  let i = r.getImageData(0, 0, n.width, n.height), a = new Float32Array(i.data.length);
2274
2261
  for (let e = 0; e < i.data.length; e++) a[e] = i.data[e] / 255;
2275
- let o = new m.DataTexture(a, n.width, n.height, m.RGBAFormat, m.FloatType);
2262
+ let o = new _.DataTexture(a, n.width, n.height, _.RGBAFormat, _.FloatType);
2276
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;
2277
2264
  }
2265
+ getThreeRenderer() {
2266
+ return l(this.renderer);
2267
+ }
2278
2268
  static {
2279
2269
  this.CAMERA_SETTLE_MS = 200;
2280
2270
  }
@@ -2291,7 +2281,7 @@ var ir = class n {
2291
2281
  this.FADE_RELEASE_FRACTION = .5;
2292
2282
  }
2293
2283
  constructor() {
2294
- 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.resumable = !1, this.lastCameraMoveTime = -Infinity, this.cameraDirty = !1, this.events = new f(), this.rasterFadeTarget = null, this.fadeQuad = null, this.fadeToneMapping = null, this.fadeSupported = !0, this.settings = {
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 n(), this.rasterFadeTarget = null, this.fadeQuad = null, this.fadeToneMapping = null, this.fadeSupported = !0, this.settings = {
2295
2285
  samples: 300,
2296
2286
  bounces: 4,
2297
2287
  transmissiveBounces: 2,
@@ -2301,26 +2291,26 @@ var ir = class n {
2301
2291
  enablePathTracing: !0
2302
2292
  };
2303
2293
  }
2304
- async initialize(n) {
2294
+ async initialize(t) {
2305
2295
  try {
2306
- return this.renderer = n.renderer, this.enabled = n.enabled, this.isSupported() ? t.ok(void 0) : t.err(new d("Path tracing is not supported in this environment", e.PATH_TRACING_INIT_FAILED, { reason: "WebGL2 or required extensions not available" }));
2307
- } catch (n) {
2308
- return t.err(new d("Failed to initialize path tracing", e.PATH_TRACING_INIT_FAILED, { originalError: n }));
2296
+ return this.renderer = t.renderer, this.enabled = t.enabled, this.isSupported() ? r.ok(void 0) : r.err(new e("Path tracing is not supported in this environment", u.PATH_TRACING_INIT_FAILED, { reason: "WebGL2 or required extensions not available" }));
2297
+ } catch (t) {
2298
+ return r.err(new e("Failed to initialize path tracing", u.PATH_TRACING_INIT_FAILED, { originalError: t }));
2309
2299
  }
2310
2300
  }
2311
2301
  createPathTracer() {
2312
- if (this.disposed) return t.err(new d("Instance is disposed", e.INVALID_STATE));
2302
+ if (this.disposed) return r.err(new e("Instance is disposed", u.INVALID_STATE));
2313
2303
  try {
2314
- let n = $(this.renderer) ? this.renderer.getInternalRenderer() : null;
2315
- return n ? (this.pathTracer = new nr(n), 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, n.setRenderTarget(null), t.ok(void 0)) : t.err(new d("Renderer not ready, will retry", e.RENDERER_NOT_INITIALIZED));
2316
- } catch (n) {
2317
- return t.err(new d("Failed to create path tracer", e.PATH_TRACING_INIT_FAILED, { originalError: n }));
2304
+ let t = this.getThreeRenderer();
2305
+ return t ? (this.pathTracer = new ir(t), 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, t.setRenderTarget(null), r.ok(void 0)) : r.err(new e("Renderer not ready, will retry", u.RENDERER_NOT_INITIALIZED));
2306
+ } catch (t) {
2307
+ return r.err(new e("Failed to create path tracer", u.PATH_TRACING_INIT_FAILED, { originalError: t }));
2318
2308
  }
2319
2309
  }
2320
2310
  setEnabled(e) {
2321
2311
  if (this.enabled !== e && (this.enabled = e, !e)) {
2322
2312
  this.resumable = !1, this.reset(), this.sceneInitialized = !1;
2323
- let e = $(this.renderer) ? this.renderer.getInternalRenderer() : null;
2313
+ let e = this.getThreeRenderer();
2324
2314
  e && (e.autoClear = !0);
2325
2315
  }
2326
2316
  }
@@ -2336,26 +2326,26 @@ var ir = class n {
2336
2326
  ...e
2337
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));
2338
2328
  }
2339
- async render(n, r) {
2340
- if (this.disposed) return t.ok(void 0);
2329
+ async render(t, n) {
2330
+ if (this.disposed) return r.ok(void 0);
2341
2331
  let i = this.renderer;
2342
- if (!i) return t.ok(void 0);
2343
- if (!this.enabled) return this.renderWhileDisabled(n, r);
2332
+ if (!i) return r.ok(void 0);
2333
+ if (!this.enabled) return this.renderWhileDisabled(t, n);
2344
2334
  if (!this.pathTracer) {
2345
- let e = this.ensurePathTracerCreated(i, n, r);
2335
+ let e = this.ensurePathTracerCreated(i, t, n);
2346
2336
  if (e) return e;
2347
2337
  }
2348
2338
  try {
2349
- let a = this.extractThreeObjects(n, r);
2350
- if (!a) return t.err(new d("Could not extract Three.js scene or camera", e.INVALID_PARAMETER));
2339
+ let a = this.extractThreeObjects(t, n);
2340
+ if (!a) return r.err(new e("Could not extract Three.js scene or camera", u.INVALID_PARAMETER));
2351
2341
  let { threeScene: o, threeCamera: s } = a;
2352
2342
  if (!this.sceneInitialized) {
2353
- let e = await this.initializeSceneForPathTracing(i, n, r, o, s);
2343
+ let e = await this.initializeSceneForPathTracing(i, t, n, o, s);
2354
2344
  if (e) return e;
2355
2345
  }
2356
- return this.sceneInitialized ? this.accumulateSample(i, n, r) : i.render(n, r);
2357
- } catch (n) {
2358
- return t.err(new d("Failed to render with path tracing", e.RENDER_FAILED, { originalError: n }));
2346
+ return this.sceneInitialized ? this.accumulateSample(i, t, n) : i.render(t, n);
2347
+ } catch (t) {
2348
+ return r.err(new e("Failed to render with path tracing", u.RENDER_FAILED, { originalError: t }));
2359
2349
  }
2360
2350
  }
2361
2351
  ensurePathTracerCreated(e, t, n) {
@@ -2364,8 +2354,8 @@ var ir = class n {
2364
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));
2365
2355
  }
2366
2356
  extractThreeObjects(e, t) {
2367
- let n = null, r = null;
2368
- return rr(e) && (n = e.getInternalRenderer()), rr(t) && (r = t.getInternalRenderer()), !n || !r ? null : {
2357
+ let n = o(e), r = d(t);
2358
+ return !n || !r ? null : {
2369
2359
  threeScene: n,
2370
2360
  threeCamera: r
2371
2361
  };
@@ -2382,13 +2372,14 @@ var ir = class n {
2382
2372
  } finally {
2383
2373
  r.environment = e;
2384
2374
  }
2385
- } else if (a && a.mapping === m.EquirectangularReflectionMapping) {
2375
+ } else if (a && a.mapping === _.EquirectangularReflectionMapping) {
2386
2376
  let e = a;
2387
- if (a.image instanceof HTMLImageElement) if (this.convertedEnvTexture) e = this.convertedEnvTexture;
2377
+ if (a.image instanceof HTMLImageElement) if (this.convertedEnvTexture && this.convertedEnvSourceUuid === a.uuid) e = this.convertedEnvTexture;
2388
2378
  else {
2379
+ this.convertedEnvTexture?.dispose(), this.convertedEnvTexture = null, this.convertedEnvSourceUuid = null;
2389
2380
  let t = this.convertToDataTexture(a);
2390
2381
  if (!t) throw Error("Failed to convert environment texture to DataTexture");
2391
- this.convertedEnvTexture = t, e = t;
2382
+ this.convertedEnvTexture = t, this.convertedEnvSourceUuid = a.uuid, e = t;
2392
2383
  }
2393
2384
  let t = r.environment;
2394
2385
  r.environment = e;
@@ -2404,27 +2395,27 @@ var ir = class n {
2404
2395
  } catch (e) {
2405
2396
  throw r.environment = t, e;
2406
2397
  }
2407
- } else if (r.environment?.mapping === m.EquirectangularReflectionMapping) this.ingestSceneWithoutShadowHelpers(r, i), this.sceneInitialized = !0;
2398
+ } else if (r.environment?.mapping === _.EquirectangularReflectionMapping) this.ingestSceneWithoutShadowHelpers(r, i), this.sceneInitialized = !0;
2408
2399
  else return this.disableAfterSelfPause("gave-up"), e.render(t, n);
2409
2400
  } catch (r) {
2410
2401
  return console.warn("Scene initialization error:", r), e.render(t, n);
2411
2402
  }
2412
2403
  return null;
2413
2404
  }
2414
- accumulateSample(e, r, i) {
2405
+ accumulateSample(e, n, i) {
2415
2406
  if (this.sampleCount === 0) try {
2416
2407
  this.pathTracer?.updateLights();
2417
2408
  } catch (e) {
2418
2409
  console.warn("Failed to update lights for path tracing:", e);
2419
2410
  }
2420
- let a = e.render(r, i);
2411
+ let a = e.render(n, i);
2421
2412
  if (!a.ok) return a;
2422
- if (performance.now() - this.lastCameraMoveTime < n.CAMERA_SETTLE_MS) return t.ok(void 0);
2423
- if (this.cameraDirty && (this.cameraDirty = !1, this.pathTracer?.updateCamera()), this.fadeSupported && this.sampleCount === 0 && this.runFadeStep(() => this.captureRasterFade(e, r, i)), this.accumulateOneSample(), this.sampleCount++, this.fadeSupported && this.sampleCount < n.FADE_SAMPLES) {
2413
+ if (performance.now() - this.lastCameraMoveTime < t.CAMERA_SETTLE_MS) return r.ok(void 0);
2414
+ if (this.cameraDirty && (this.cameraDirty = !1, this.pathTracer?.updateCamera()), this.fadeSupported && this.sampleCount === 0 && this.runFadeStep(() => this.captureRasterFade(e, n, i)), this.accumulateOneSample(), this.sampleCount++, this.fadeSupported && this.sampleCount < this.fadeWindowSamples()) {
2424
2415
  let e = 1 - this.pathTracedLayerOpacity(this.sampleCount);
2425
2416
  this.runFadeStep(() => this.renderRasterFade(e));
2426
2417
  }
2427
- return this.sampleCount === this.settings.samples ? this.captureCompletedFrame() : t.ok(void 0);
2418
+ return this.sampleCount === this.settings.samples ? this.captureCompletedFrame() : r.ok(void 0);
2428
2419
  }
2429
2420
  runFadeStep(e) {
2430
2421
  try {
@@ -2433,26 +2424,30 @@ var ir = class n {
2433
2424
  console.warn("Path-tracing startup dissolve unavailable; showing samples directly:", e), this.fadeSupported = !1;
2434
2425
  }
2435
2426
  }
2427
+ fadeWindowSamples() {
2428
+ let e = t.FADE_HOLD_SAMPLES + 2;
2429
+ return Math.max(e, Math.min(t.FADE_SAMPLES, this.settings.samples));
2430
+ }
2436
2431
  pathTracedLayerOpacity(e) {
2437
- let t = n.FADE_HOLD_SAMPLES, r = n.FADE_SAMPLES, i = n.FADE_PREVIEW_OPACITY, a = t + (r - t) * n.FADE_RELEASE_FRACTION;
2438
- return e < a ? i * n.smoothstep(t, a, e) : i + (1 - i) * n.smoothstep(a, r, e);
2432
+ let n = t.FADE_HOLD_SAMPLES, r = this.fadeWindowSamples(), i = t.FADE_PREVIEW_OPACITY, a = n + (r - n) * t.FADE_RELEASE_FRACTION;
2433
+ return e < a ? i * t.smoothstep(n, a, e) : i + (1 - i) * t.smoothstep(a, r, e);
2439
2434
  }
2440
2435
  static smoothstep(e, t, n) {
2441
2436
  let r = Math.min(1, Math.max(0, (n - e) / (t - e)));
2442
2437
  return r * r * (3 - 2 * r);
2443
2438
  }
2444
2439
  captureRasterFade(e, t, n) {
2445
- let r = $(this.renderer) ? this.renderer.getInternalRenderer() : null;
2440
+ let r = this.getThreeRenderer();
2446
2441
  if (!r) return;
2447
- let i = r.getDrawingBufferSize(new m.Vector2());
2448
- this.rasterFadeTarget ? (this.rasterFadeTarget.width !== i.x || this.rasterFadeTarget.height !== i.y) && this.rasterFadeTarget.setSize(i.x, i.y) : (this.rasterFadeTarget = new m.WebGLRenderTarget(i.x, i.y, { type: m.HalfFloatType }), this.rasterFadeTarget.texture.colorSpace = m.LinearSRGBColorSpace);
2442
+ let i = r.getDrawingBufferSize(new _.Vector2());
2443
+ this.rasterFadeTarget ? (this.rasterFadeTarget.width !== i.x || this.rasterFadeTarget.height !== i.y) && this.rasterFadeTarget.setSize(i.x, i.y) : (this.rasterFadeTarget = new _.WebGLRenderTarget(i.x, i.y, { type: _.HalfFloatType }), this.rasterFadeTarget.texture.colorSpace = _.LinearSRGBColorSpace);
2449
2444
  let a = r.getRenderTarget();
2450
2445
  r.setRenderTarget(this.rasterFadeTarget), e.render(t, n), r.setRenderTarget(a);
2451
2446
  }
2452
2447
  renderRasterFade(e) {
2453
- let t = $(this.renderer) ? this.renderer.getInternalRenderer() : null;
2448
+ let t = this.getThreeRenderer();
2454
2449
  if (!t || !this.rasterFadeTarget) return;
2455
- (!this.fadeQuad || this.fadeToneMapping !== t.toneMapping) && ((this.fadeQuad?.material)?.dispose(), this.fadeToneMapping = t.toneMapping, this.fadeQuad = new p(this.createFadeMaterial(t.toneMapping)));
2450
+ (!this.fadeQuad || this.fadeToneMapping !== t.toneMapping) && ((this.fadeQuad?.material)?.dispose(), this.fadeToneMapping = t.toneMapping, this.fadeQuad = new g(this.createFadeMaterial(t.toneMapping)));
2456
2451
  let n = this.fadeQuad.material;
2457
2452
  n.uniforms.tRaster.value = this.rasterFadeTarget.texture, n.uniforms.uOpacity.value = e;
2458
2453
  let r = t.autoClear, i = t.getRenderTarget();
@@ -2465,14 +2460,14 @@ var ir = class n {
2465
2460
  }
2466
2461
  createFadeMaterial(e) {
2467
2462
  let t = {
2468
- [m.LinearToneMapping]: "LINEAR_TONE_MAPPING",
2469
- [m.ReinhardToneMapping]: "REINHARD_TONE_MAPPING",
2470
- [m.CineonToneMapping]: "CINEON_TONE_MAPPING",
2471
- [m.ACESFilmicToneMapping]: "ACES_FILMIC_TONE_MAPPING",
2472
- [m.AgXToneMapping]: "AGX_TONE_MAPPING",
2473
- [m.NeutralToneMapping]: "NEUTRAL_TONE_MAPPING"
2463
+ [_.LinearToneMapping]: "LINEAR_TONE_MAPPING",
2464
+ [_.ReinhardToneMapping]: "REINHARD_TONE_MAPPING",
2465
+ [_.CineonToneMapping]: "CINEON_TONE_MAPPING",
2466
+ [_.ACESFilmicToneMapping]: "ACES_FILMIC_TONE_MAPPING",
2467
+ [_.AgXToneMapping]: "AGX_TONE_MAPPING",
2468
+ [_.NeutralToneMapping]: "NEUTRAL_TONE_MAPPING"
2474
2469
  }, n = {}, r = t[e];
2475
- return r && (n[r] = ""), new m.ShaderMaterial({
2470
+ return r && (n[r] = ""), new _.ShaderMaterial({
2476
2471
  defines: n,
2477
2472
  uniforms: {
2478
2473
  tRaster: { value: null },
@@ -2485,17 +2480,22 @@ var ir = class n {
2485
2480
  depthWrite: !1
2486
2481
  });
2487
2482
  }
2488
- renderWhileDisabled(e, n) {
2489
- return this.renderer ? this.sampleCount >= this.settings.samples && this.sampleCount > 0 ? (this.pathTracer && $(this.renderer) && this.renderer.getInternalRenderer().setRenderTarget(null), t.ok(void 0)) : this.renderer.render(e, n) : t.ok(void 0);
2483
+ renderWhileDisabled(e, t) {
2484
+ if (!this.renderer) return r.ok(void 0);
2485
+ if (this.sampleCount >= this.settings.samples && this.sampleCount > 0) {
2486
+ let e = this.getThreeRenderer();
2487
+ return this.pathTracer && e && e.setRenderTarget(null), r.ok(void 0);
2488
+ }
2489
+ return this.renderer.render(e, t);
2490
2490
  }
2491
2491
  accumulateOneSample() {
2492
- let e = $(this.renderer) ? this.renderer.getInternalRenderer() : null;
2492
+ let e = this.getThreeRenderer();
2493
2493
  if (!e) throw Error("Three.js renderer not available");
2494
2494
  let t = e.autoClear, n = e.getRenderTarget();
2495
2495
  e.autoClear = !1, this.pathTracer && this.pathTracer.renderSample(), e.autoClear = t, e.setRenderTarget(n);
2496
2496
  }
2497
2497
  captureCompletedFrame() {
2498
- let e = $(this.renderer) ? this.renderer.getInternalRenderer() : null;
2498
+ let e = this.getThreeRenderer();
2499
2499
  if (e && this.pathTracer) try {
2500
2500
  let t = e.autoClear;
2501
2501
  e.autoClear = !0, e.setRenderTarget(null), e.clear(!0, !0, !0);
@@ -2504,7 +2504,7 @@ var ir = class n {
2504
2504
  } catch (e) {
2505
2505
  console.warn("Failed to present path traced result:", e);
2506
2506
  }
2507
- return this.disableAfterSelfPause("completed"), t.ok(void 0);
2507
+ return this.disableAfterSelfPause("completed"), r.ok(void 0);
2508
2508
  }
2509
2509
  getSampleCount() {
2510
2510
  return this.sampleCount;
@@ -2536,11 +2536,11 @@ var ir = class n {
2536
2536
  }
2537
2537
  this.pathTracer = null;
2538
2538
  }
2539
- this.convertedEnvTexture &&= (this.convertedEnvTexture.dispose(), null), this.fadeQuad &&= (this.fadeQuad.material.dispose(), null), this.fadeToneMapping = null, this.rasterFadeTarget &&= (this.rasterFadeTarget.dispose(), null), this.sampleCount = 0, this.sceneInitialized = !1, this.createAttempts = 0, this.renderer = null;
2539
+ this.convertedEnvTexture && (this.convertedEnvTexture.dispose(), this.convertedEnvTexture = null, this.convertedEnvSourceUuid = null), this.fadeQuad &&= (this.fadeQuad.material.dispose(), null), this.fadeToneMapping = null, this.rasterFadeTarget &&= (this.rasterFadeTarget.dispose(), null), this.sampleCount = 0, this.sceneInitialized = !1, this.createAttempts = 0, this.renderer = null;
2540
2540
  }
2541
2541
  isSupported() {
2542
2542
  return document.createElement("canvas").getContext("webgl2") !== null;
2543
2543
  }
2544
2544
  };
2545
2545
  //#endregion
2546
- export { ir as ThreePathTracingService };
2546
+ export { ar as ThreePathTracingService };