@react-three/drei 11.0.0-alpha.6 → 11.0.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/native/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as THREE from 'three/webgpu';
2
- import { MeshBasicNodeMaterial, RenderTarget, MeshPhongNodeMaterial, MeshNormalNodeMaterial, MeshPhysicalNodeMaterial, Frustum, Matrix4, QuadMesh, CubeRenderTarget, Line2NodeMaterial, Vector3, Vector4, Vector2, Color, InstancedInterleavedBuffer, InterleavedBufferAttribute, Object3D, HalfFloatType, CubeCamera as CubeCamera$1, EventDispatcher, Euler, Quaternion, MathUtils, TextureLoader, Texture as Texture$1, MeshLambertMaterial, DynamicDrawUsage, CatmullRomCurve3, CubicBezierCurve3, QuadraticBezierCurve3, Shape as Shape$1, CanvasTexture, PerspectiveCamera as PerspectiveCamera$1, OrthographicCamera as OrthographicCamera$1, REVISION, AudioListener, AudioLoader, AnimationMixer, BufferAttribute, Box3, Sphere as Sphere$1, InstancedBufferAttribute, DoubleSide, DepthTexture, DepthFormat, UnsignedShortType, CubeTextureLoader, DefaultLoadingManager, Ray, Raycaster, Camera, CubeReflectionMapping, EquirectangularReflectionMapping, Scene, RepeatWrapping, SpriteNodeMaterial, AdditiveBlending, ShadowNode, CylinderGeometry } from 'three/webgpu';
3
- import { uniform, Fn, float, vec4, uniformTexture, uv, vec2 as vec2$2, texture, Discard, max, sub, mix, output, mul, negate, add, dot, refract, div, length, cross, select, vec3, normalize, normalWorld, positionWorld, cameraPosition, screenCoordinate, mx_fractal_noise_vec3, int, thickness, pow, roughness, Loop, ior, screenUV, screenSize, cameraProjectionMatrix, cameraViewMatrix, attenuationColor, attenuationDistance, diffuseColor, transmission, fract, sin, modelWorldMatrix, log, exp, DFGLUT, reflector, clamp, equirectUV, reflect, smoothstep, round, distance, positionLocal, mx_noise_vec3, cos, mat3, normalLocal, attribute, modelViewMatrix, varying, min, frontFacing, fwidth, abs, saturate, positionView, positionGeometry, reference, renderGroup, interleavedGradientNoise, vogelDiskSample, step } from 'three/tsl';
2
+ import { MeshBasicNodeMaterial, RenderTarget, MeshPhongNodeMaterial, MeshNormalNodeMaterial, MeshPhysicalNodeMaterial, Frustum, Matrix4, QuadMesh, CubeRenderTarget, Line2NodeMaterial, Vector3, Vector4, Vector2, Color, InstancedInterleavedBuffer, InterleavedBufferAttribute, Object3D, HalfFloatType, CubeCamera as CubeCamera$1, EventDispatcher, Euler, Quaternion, MathUtils, TextureLoader, Texture as Texture$1, MeshLambertMaterial, DynamicDrawUsage, CatmullRomCurve3, CubicBezierCurve3, QuadraticBezierCurve3, Shape as Shape$1, CanvasTexture, PerspectiveCamera as PerspectiveCamera$1, OrthographicCamera as OrthographicCamera$1, REVISION, AudioListener, AudioLoader, AnimationMixer, BufferAttribute, Box3, Sphere as Sphere$1, InstancedBufferAttribute, DoubleSide, DepthTexture, DepthFormat, UnsignedShortType, CubeTextureLoader, DefaultLoadingManager, Ray, Raycaster, Camera, CubeReflectionMapping, EquirectangularReflectionMapping, Scene, RepeatWrapping, AdditiveBlending, SpriteNodeMaterial, ShadowNode, CylinderGeometry } from 'three/webgpu';
3
+ import { Fn, float, vec4, uv, vec2 as vec2$2, uniform, uniformTexture, Discard, materialReference, context as context$a, max, materialAlphaTest, sub, mix, output, mul, negate, add, dot, refract, div, length, cross, select, vec3, normalize, normalWorld, positionWorld, materialColor, cameraPosition, screenCoordinate, mx_fractal_noise_vec3, int, thickness, pow, roughness, Loop, ior, screenUV, screenSize, cameraProjectionMatrix, cameraViewMatrix, attenuationColor, attenuationDistance, diffuseColor, transmission, fract, sin, modelWorldMatrix, log, exp, DFGLUT, reflector, clamp, materialIOR, equirectUV, materialOpacity, reflect, smoothstep, round, distance, positionLocal, mx_noise_vec3, cos, mat3, normalLocal, attribute, modelViewMatrix, varying, min, frontFacing, fwidth, texture, abs, saturate, positionView, positionGeometry, reference, renderGroup, interleavedGradientNoise, vogelDiskSample, step } from 'three/tsl';
4
4
  import * as React from 'react';
5
5
  import { forwardRef, useImperativeHandle, useRef, useMemo, useEffect, useCallback, useLayoutEffect, useState, Fragment, createContext, useContext } from 'react';
6
- import { useThree, useFrame, extend, createPortal, applyProps, useInstanceHandle, context as context$a, useLoader, addEffect, addAfterEffect } from '@react-three/fiber';
6
+ import { useThree, useFrame, extend, createPortal, applyProps, useInstanceHandle, context as context$b, useLoader, addEffect, addAfterEffect } from '@react-three/fiber';
7
7
  import { SimplexNoise } from 'three/examples/jsm/math/SimplexNoise.js';
8
8
  import { Line2 } from 'three/examples/jsm/lines/webgpu/Line2.js';
9
9
  import { LineSegments2 } from 'three/examples/jsm/lines/webgpu/LineSegments2.js';
@@ -44,43 +44,150 @@ import { TransformControls as TransformControls$1 } from 'three/examples/jsm/con
44
44
  import tunnel from 'tunnel-rat';
45
45
  import 'zustand/middleware';
46
46
 
47
- class DepthNodeMaterial extends MeshBasicNodeMaterial {
48
- _opacity;
47
+ function assignUniform(node, factory, v) {
48
+ const current = node.value;
49
+ if (v === null || v === void 0) {
50
+ if (current && current.isTexture) node.value = factory().value;
51
+ else node.value = v;
52
+ return;
53
+ }
54
+ if (typeof current === "number") {
55
+ node.value = typeof v === "boolean" ? v ? 1 : 0 : v;
56
+ return;
57
+ }
58
+ if (typeof current === "boolean") {
59
+ node.value = !!v;
60
+ return;
61
+ }
62
+ if (current && typeof current === "object") {
63
+ if (typeof v === "object" && !Array.isArray(v)) {
64
+ node.value = v;
65
+ return;
66
+ }
67
+ if (Array.isArray(v) && typeof current.fromArray === "function") {
68
+ current.fromArray(v);
69
+ return;
70
+ }
71
+ if (current.isColor) {
72
+ current.set(v);
73
+ return;
74
+ }
75
+ if (typeof v === "number" && typeof current.setScalar === "function") {
76
+ current.setScalar(v);
77
+ return;
78
+ }
79
+ }
80
+ node.value = v;
81
+ }
82
+ function withUniforms(Base, table) {
83
+ const keys = Object.keys(table);
84
+ const factories = table;
85
+ let installed = false;
86
+ const install = (instance) => {
87
+ for (const key of keys) {
88
+ if (key.startsWith("_") || key in instance) {
89
+ throw new Error(
90
+ `withUniforms: "${key}" is reserved on ${Base.name}. Read three's own node for it (materialOpacity, materialColor, materialReference(...)) instead of declaring a uniform named "${key}".`
91
+ );
92
+ }
93
+ }
94
+ for (const key of keys) {
95
+ Object.defineProperty(Wrapped.prototype, key, {
96
+ get() {
97
+ return this._uniforms?.[key]?.value;
98
+ },
99
+ set(v) {
100
+ const node = this._uniforms?.[key];
101
+ if (node) assignUniform(node, factories[key], v);
102
+ },
103
+ enumerable: false,
104
+ configurable: true
105
+ });
106
+ }
107
+ installed = true;
108
+ };
109
+ const splitParameters = (args) => {
110
+ const params = args[0];
111
+ if (!params || typeof params !== "object" || Array.isArray(params)) return { args, own: null };
112
+ const own = {};
113
+ const rest = {};
114
+ let hasOwn = false;
115
+ for (const k in params) {
116
+ if (Object.prototype.hasOwnProperty.call(factories, k)) {
117
+ own[k] = params[k];
118
+ hasOwn = true;
119
+ } else rest[k] = params[k];
120
+ }
121
+ return hasOwn ? { args: [rest, ...args.slice(1)], own } : { args, own: null };
122
+ };
123
+ class Wrapped extends Base {
124
+ constructor(...args) {
125
+ const { args: baseArgs, own } = splitParameters(args);
126
+ super(...baseArgs);
127
+ if (!installed) install(this);
128
+ const nodes = {};
129
+ for (const key of keys) nodes[key] = factories[key]();
130
+ Object.defineProperty(this, "_uniforms", { value: nodes, enumerable: false, writable: false });
131
+ if (own) for (const key in own) this[key] = own[key];
132
+ }
133
+ get uniforms() {
134
+ return this._uniforms;
135
+ }
136
+ /** Copies values for inherited accessors that NodeMaterial.copy does not visit. */
137
+ copy(source) {
138
+ super.copy(source);
139
+ const from = source._uniforms;
140
+ if (!from) return this;
141
+ for (const key of keys) {
142
+ const value = from[key]?.value;
143
+ const node = this._uniforms[key];
144
+ const own = node.value;
145
+ if (value && value.isTexture) node.value = value;
146
+ else if (own && typeof own.copy === "function") own.copy(value);
147
+ else node.value = value;
148
+ }
149
+ return this;
150
+ }
151
+ }
152
+ return Wrapped;
153
+ }
154
+
155
+ class DepthNodeMaterial extends withUniforms(MeshBasicNodeMaterial, {
156
+ /** Shadow strength, 1 = full darkening, 0 = none */
157
+ shadowOpacity: () => uniform(1)
158
+ }) {
49
159
  constructor(opacity = 1) {
50
160
  super();
51
- this._opacity = uniform(opacity);
161
+ this.shadowOpacity = opacity;
52
162
  this.depthTest = false;
53
163
  this.depthWrite = false;
54
164
  this._buildShader();
55
165
  }
56
166
  _buildShader() {
57
- const opacityUniform = this._opacity;
167
+ const { shadowOpacity } = this.uniforms;
58
168
  this.colorNode = Fn(() => {
59
- const shadowStrength = opacityUniform.mul(0.7);
169
+ const shadowStrength = shadowOpacity.mul(0.7);
60
170
  const gray = float(1).sub(shadowStrength);
61
171
  return vec4(gray, gray, gray, 1);
62
172
  })();
63
173
  }
64
- set shadowOpacity(value) {
65
- this._opacity.value = value;
66
- }
67
174
  }
68
- class BlurNodeMaterial extends MeshBasicNodeMaterial {
69
- _inputTexture;
70
- _blurAmount;
175
+ class BlurNodeMaterial extends withUniforms(MeshBasicNodeMaterial, {
176
+ /** Texture to blur */
177
+ inputTexture: () => uniformTexture(new THREE.Texture()),
178
+ /** Per-tap UV offset */
179
+ blurAmount: () => uniform(0)
180
+ }) {
71
181
  _direction;
72
182
  constructor(direction = "horizontal") {
73
183
  super();
74
- this._inputTexture = uniformTexture(new THREE.Texture());
75
- this._blurAmount = uniform(0);
76
184
  this._direction = direction;
77
185
  this.depthTest = false;
78
186
  this.depthWrite = false;
79
187
  this._buildShader();
80
188
  }
81
189
  _buildShader() {
82
- const inputTex = this._inputTexture;
83
- const blurAmountUniform = this._blurAmount;
190
+ const { inputTexture: inputTex, blurAmount: blurAmountUniform } = this.uniforms;
84
191
  const isHorizontal = this._direction === "horizontal";
85
192
  const weights = [0.051, 0.0918, 0.12245, 0.1531, 0.1633, 0.1531, 0.12245, 0.0918, 0.051];
86
193
  this.colorNode = Fn(() => {
@@ -89,18 +196,12 @@ class BlurNodeMaterial extends MeshBasicNodeMaterial {
89
196
  for (let i = 0; i < 9; i++) {
90
197
  const offset = float(i - 4).mul(blurAmountUniform);
91
198
  const sampleUV = isHorizontal ? texCoord.add(vec2$2(offset, 0)) : texCoord.add(vec2$2(0, offset));
92
- const sampledColor = texture(inputTex, sampleUV);
199
+ const sampledColor = inputTex.sample(sampleUV);
93
200
  result.addAssign(sampledColor.mul(weights[i]));
94
201
  }
95
202
  return result;
96
203
  })();
97
204
  }
98
- set inputTexture(value) {
99
- this._inputTexture.value = value;
100
- }
101
- set blurAmount(value) {
102
- this._blurAmount.value = value;
103
- }
104
205
  }
105
206
  const ContactShadows = /* @__PURE__ */ React.forwardRef(
106
207
  ({
@@ -235,9 +336,13 @@ const discardFragment = /* @__PURE__ */ Fn(() => {
235
336
  Discard();
236
337
  return vec4(0, 0, 0, 0);
237
338
  });
238
- const DiscardMaterial = /* @__PURE__ */ new MeshBasicNodeMaterial({
239
- fragmentNode: discardFragment()
240
- });
339
+ class DiscardNodeMaterial extends MeshBasicNodeMaterial {
340
+ constructor() {
341
+ super();
342
+ this.fragmentNode = discardFragment();
343
+ }
344
+ }
345
+ const DiscardMaterial = /* @__PURE__ */ new DiscardNodeMaterial();
241
346
 
242
347
  function isLight(object) {
243
348
  return object.isLight;
@@ -248,105 +353,51 @@ function isGeometry$1(object) {
248
353
  const accumulativeContext = /* @__PURE__ */ React.createContext(
249
354
  null
250
355
  );
251
- class SoftShadowMaterialImpl extends MeshBasicNodeMaterial {
252
- _color;
253
- _blend;
254
- _alphaTest;
255
- _opacity;
256
- _map;
356
+ class SoftShadowMaterialImpl extends withUniforms(MeshBasicNodeMaterial, {
357
+ /** Shadow color, black */
358
+ shadowColor: () => uniform(new THREE.Color()),
359
+ /** Colorblend, how much colors turn to black, 0 is black */
360
+ blend: () => uniform(2)
361
+ }) {
257
362
  constructor() {
258
363
  super();
259
- this._color = uniform(new THREE.Color());
260
- this._blend = uniform(2);
261
- this._alphaTest = uniform(0.75);
262
- this._opacity = uniform(0);
263
- this._map = uniformTexture(new THREE.Texture());
264
364
  this.transparent = true;
265
365
  this.depthWrite = false;
366
+ this.opacity = 0;
367
+ this.alphaTest = 0.75;
368
+ this.map = new THREE.Texture();
369
+ this.alphaTestNode = float(0);
266
370
  this._buildShader();
267
371
  }
268
372
  _buildShader() {
269
- const colorUniform = this._color;
270
- const blendUniform = this._blend;
271
- const alphaTestUniform = this._alphaTest;
272
- const opacityUniform = this._opacity;
273
- const mapTex = this._map;
373
+ const { shadowColor, blend } = this.uniforms;
374
+ const map = materialReference("map", "texture", this);
274
375
  this.colorNode = Fn(() => {
275
- const texCoord = uv();
276
- const sampled = texture(mapTex, texCoord);
277
- const rgb = colorUniform.mul(sampled.r).mul(blendUniform);
376
+ const sampled = context$a(map, { getUV: () => uv() });
377
+ const rgb = shadowColor.mul(sampled.r).mul(blend);
278
378
  const sum = sampled.r.add(sampled.g).add(sampled.b);
279
- const alpha = max(float(0), float(1).sub(sum.div(alphaTestUniform))).mul(opacityUniform);
379
+ const alpha = max(float(0), float(1).sub(sum.div(materialAlphaTest)));
280
380
  return vec4(rgb, alpha);
281
381
  })();
282
382
  }
283
- get shadowColor() {
284
- return this._color.value;
285
- }
286
- set shadowColor(v) {
287
- if (v instanceof THREE.Color) {
288
- this._color.value.copy(v);
289
- } else {
290
- this._color.value.set(v);
291
- }
292
- }
293
- get blend() {
294
- return this._blend.value;
295
- }
296
- set blend(v) {
297
- this._blend.value = v;
298
- }
299
- get alphaTest() {
300
- return this._alphaTest.value;
301
- }
302
- set alphaTest(v) {
303
- this._alphaTest.value = v;
304
- }
305
- get opacity() {
306
- return this._opacity.value;
307
- }
308
- set opacity(v) {
309
- if (!this._opacity) this._opacity = uniform(v);
310
- else this._opacity.value = v;
311
- }
312
- get map() {
313
- if (!this._map) {
314
- this._map = uniformTexture(new THREE.Texture());
315
- }
316
- return this._map.value;
317
- }
318
- set map(v) {
319
- this._map.value = v;
320
- }
321
383
  }
322
- class ProgressiveShadowMaterial extends MeshPhongNodeMaterial {
323
- _previousShadowMap;
324
- _averagingWindow;
384
+ class ProgressiveShadowMaterial extends withUniforms(MeshPhongNodeMaterial, {
385
+ /** Accumulation buffer from the previous frame, blended with the current shading */
386
+ previousShadowMap: () => uniformTexture(new THREE.Texture()),
387
+ /** Mix 1/averagingWindow of the new shading into the accumulated frames */
388
+ averagingWindow: () => uniform(100)
389
+ }) {
325
390
  constructor(initialTexture) {
326
391
  super();
327
- this._previousShadowMap = texture(initialTexture);
328
- this._averagingWindow = uniform(100);
392
+ this.previousShadowMap = initialTexture;
329
393
  this.fog = false;
330
394
  this._buildShader();
331
395
  }
332
396
  _buildShader() {
333
- const previousMapTex = this._previousShadowMap;
334
- const averagingWindowUniform = this._averagingWindow;
397
+ const { previousShadowMap, averagingWindow } = this.uniforms;
335
398
  const uvNode = uv();
336
399
  this.vertexNode = vec4(sub(uvNode, vec2$2(0.5)).mul(2), 1, 1);
337
- this.outputNode = vec4(mix(previousMapTex.sample(uv()), output, float(1).div(averagingWindowUniform)));
338
- }
339
- get previousShadowMap() {
340
- return this._previousShadowMap.value;
341
- }
342
- set previousShadowMap(v) {
343
- this._previousShadowMap.value = v;
344
- }
345
- get averagingWindow() {
346
- return this._averagingWindow.value;
347
- }
348
- set averagingWindow(v) {
349
- this._averagingWindow.value = v;
400
+ this.outputNode = vec4(mix(previousShadowMap.sample(uv()), output, float(1).div(averagingWindow)));
350
401
  }
351
402
  }
352
403
  class ProgressiveLightMap {
@@ -463,7 +514,7 @@ const AccumulativeShadows = /* @__PURE__ */ React.forwardRef(
463
514
  plm.configure(gPlane.current);
464
515
  }, [plm]);
465
516
  React.useEffect(() => {
466
- softShadowMat.shadowColor = color;
517
+ softShadowMat.shadowColor.set(color);
467
518
  softShadowMat.blend = colorBlend;
468
519
  softShadowMat.map = plm.progressiveLightMap2.texture;
469
520
  softShadowMat.toneMapped = toneMapped;
@@ -676,19 +727,18 @@ const Edges = /* @__PURE__ */ React.forwardRef(
676
727
  }
677
728
  );
678
729
 
679
- class CausticsProjectionMaterial extends MeshBasicNodeMaterial {
680
- _causticsTexture;
681
- _causticsTextureB;
682
- _color;
683
- _lightProjMatrix;
684
- _lightViewMatrix;
730
+ class CausticsProjectionMaterial extends withUniforms(MeshBasicNodeMaterial, {
731
+ /** Front-face caustics, rendered by CausticsMaterial */
732
+ causticsTexture: () => uniformTexture(new THREE.Texture()),
733
+ /** Back-face caustics, rendered by CausticsMaterial when `backside` is enabled */
734
+ causticsTextureB: () => uniformTexture(new THREE.Texture()),
735
+ /** Projection matrix of the light camera */
736
+ lightProjMatrix: () => uniform(new THREE.Matrix4()),
737
+ /** View matrix (matrixWorldInverse) of the light camera */
738
+ lightViewMatrix: () => uniform(new THREE.Matrix4())
739
+ }) {
685
740
  constructor() {
686
741
  super();
687
- this._causticsTexture = uniformTexture(new THREE.Texture());
688
- this._causticsTextureB = uniformTexture(new THREE.Texture());
689
- this._color = uniform(new THREE.Color(1, 1, 1));
690
- this._lightProjMatrix = uniform(new THREE.Matrix4());
691
- this._lightViewMatrix = uniform(new THREE.Matrix4());
692
742
  this.transparent = true;
693
743
  this.blending = THREE.CustomBlending;
694
744
  this.blendSrc = THREE.OneFactor;
@@ -697,100 +747,68 @@ class CausticsProjectionMaterial extends MeshBasicNodeMaterial {
697
747
  this._buildShader();
698
748
  }
699
749
  _buildShader() {
700
- const causticsTexture = this._causticsTexture;
701
- const causticsTextureB = this._causticsTextureB;
702
- const colorUniform = this._color;
703
- const lightProjMatrix = this._lightProjMatrix;
704
- const lightViewMatrix = this._lightViewMatrix;
750
+ const { causticsTexture, causticsTextureB, lightProjMatrix, lightViewMatrix } = this.uniforms;
705
751
  this.colorNode = Fn(() => {
706
752
  const worldPos = positionWorld;
707
753
  const worldPos4 = vec4(worldPos, 1);
708
754
  const lightSpacePos = mul(lightProjMatrix, mul(lightViewMatrix, worldPos4)).toVar();
709
755
  const xyz = lightSpacePos.xyz.div(lightSpacePos.w);
710
756
  const lightUv = xyz.mul(0.5).add(0.5).xy;
711
- const front = texture(causticsTexture, lightUv).rgb;
712
- const back = texture(causticsTextureB, lightUv).rgb;
713
- return vec4(add(front, back).mul(colorUniform), 1);
757
+ const front = causticsTexture.sample(lightUv).rgb;
758
+ const back = causticsTextureB.sample(lightUv).rgb;
759
+ return vec4(add(front, back).mul(materialColor), 1);
714
760
  })();
715
761
  }
716
- //* Uniform Accessors ==============================
717
- get causticsTexture() {
718
- return this._causticsTexture.value;
719
- }
720
- set causticsTexture(v) {
721
- this._causticsTexture.value = v;
722
- }
723
- get causticsTextureB() {
724
- return this._causticsTextureB.value;
725
- }
726
- set causticsTextureB(v) {
727
- this._causticsTextureB.value = v;
728
- }
729
- get color() {
730
- return this._color?.value;
731
- }
732
- set color(v) {
733
- if (this._color) this._color.value = v;
734
- }
735
- get lightProjMatrix() {
736
- return this._lightProjMatrix.value;
737
- }
738
- set lightProjMatrix(v) {
739
- this._lightProjMatrix.value = v;
740
- }
741
- get lightViewMatrix() {
742
- return this._lightViewMatrix.value;
743
- }
744
- set lightViewMatrix(v) {
745
- this._lightViewMatrix.value = v;
746
- }
747
762
  }
748
- class CausticsMaterial extends MeshBasicNodeMaterial {
749
- _cameraMatrixWorld;
750
- _cameraProjectionMatrixInv;
751
- _normalTexture;
752
- _depthTexture;
753
- _lightDir;
754
- _lightPlaneNormal;
755
- _lightPlaneConstant;
756
- _near;
757
- _far;
758
- _worldRadius;
759
- _ior;
760
- _resolution;
761
- _size;
762
- _intensity;
763
+ class CausticsMaterial extends withUniforms(MeshBasicNodeMaterial, {
764
+ /** World matrix of the light camera */
765
+ cameraMatrixWorld: () => uniform(new THREE.Matrix4()),
766
+ /** Inverse projection matrix of the light camera, for depth reconstruction */
767
+ cameraProjectionMatrixInv: () => uniform(new THREE.Matrix4()),
768
+ /** World-space normals of the refractive geometry, rendered by CausticsNormalMaterial */
769
+ normalTexture: () => uniformTexture(new THREE.Texture()),
770
+ /** Depth of the refractive geometry, from the same render target as `normalTexture` */
771
+ depthTexture: () => uniformTexture(new THREE.Texture()),
772
+ /** Direction light travels in (inverse of the light position direction) */
773
+ lightDir: () => uniform(new THREE.Vector3(0, 1, 0)),
774
+ /** Normal of the receiving plane in light space */
775
+ lightPlaneNormal: () => uniform(new THREE.Vector3(0, 1, 0)),
776
+ /** Plane constant of the receiving plane */
777
+ lightPlaneConstant: () => uniform(0),
778
+ /** Light camera near plane */
779
+ near: () => uniform(0.1),
780
+ /** Light camera far plane */
781
+ far: () => uniform(100),
782
+ /** The texel size in world units */
783
+ worldRadius: () => uniform(1 / 40),
784
+ /** Refraction index of the surface */
785
+ ior: () => uniform(1.1),
786
+ /** Buffer resolution in pixels */
787
+ resolution: () => uniform(1024),
788
+ /** Half-extent of the light camera frustum */
789
+ size: () => uniform(10),
790
+ /** Intensity of the projected caustics */
791
+ intensity: () => uniform(0.5)
792
+ }) {
763
793
  constructor() {
764
794
  super();
765
- this._cameraMatrixWorld = uniform(new THREE.Matrix4());
766
- this._cameraProjectionMatrixInv = uniform(new THREE.Matrix4());
767
- this._normalTexture = uniformTexture(new THREE.Texture());
768
- this._depthTexture = uniformTexture(new THREE.Texture());
769
- this._lightDir = uniform(new THREE.Vector3(0, 1, 0));
770
- this._lightPlaneNormal = uniform(new THREE.Vector3(0, 1, 0));
771
- this._lightPlaneConstant = uniform(0);
772
- this._near = uniform(0.1);
773
- this._far = uniform(100);
774
- this._worldRadius = uniform(1 / 40);
775
- this._ior = uniform(1.1);
776
- this._resolution = uniform(1024);
777
- this._size = uniform(10);
778
- this._intensity = uniform(0.5);
779
795
  this._buildShader();
780
796
  }
781
797
  _buildShader() {
782
- const cameraMatrixWorld = this._cameraMatrixWorld;
783
- const cameraProjectionMatrixInv = this._cameraProjectionMatrixInv;
784
- const normalTexture = this._normalTexture;
785
- const depthTexture = this._depthTexture;
786
- const lightDir = this._lightDir;
787
- const lightPlaneNormal = this._lightPlaneNormal;
788
- const lightPlaneConstant = this._lightPlaneConstant;
789
- const worldRadius = this._worldRadius;
790
- const ior = this._ior;
791
- const resolution = this._resolution;
792
- const size = this._size;
793
- const intensity = this._intensity;
798
+ const {
799
+ cameraMatrixWorld,
800
+ cameraProjectionMatrixInv,
801
+ normalTexture,
802
+ depthTexture,
803
+ lightDir,
804
+ lightPlaneNormal,
805
+ lightPlaneConstant,
806
+ worldRadius,
807
+ ior,
808
+ resolution,
809
+ size,
810
+ intensity
811
+ } = this.uniforms;
794
812
  const worldPosFromDepth = Fn(({ depth, coord }) => {
795
813
  const z = depth.mul(2).sub(1);
796
814
  const clipSpacePos = vec4(coord.mul(2).sub(1), z, 1);
@@ -817,7 +835,7 @@ class CausticsMaterial extends MeshBasicNodeMaterial {
817
835
  );
818
836
  this.colorNode = Fn(() => {
819
837
  const baseUv = uv();
820
- const centerDepth = texture(depthTexture, baseUv).x;
838
+ const centerDepth = depthTexture.sample(baseUv).x;
821
839
  const causticTexelSize = div(float(1), resolution).mul(size).mul(2);
822
840
  const texelsNeeded = div(worldRadius, causticTexelSize);
823
841
  const sampleRadius = div(texelsNeeded, resolution);
@@ -829,14 +847,14 @@ class CausticsMaterial extends MeshBasicNodeMaterial {
829
847
  const uv2 = add(baseUv, mul(offset2, sampleRadius));
830
848
  const uv3 = add(baseUv, mul(offset3, sampleRadius));
831
849
  const uv4 = add(baseUv, mul(offset4, sampleRadius));
832
- const normal1 = sub(mul(texture(normalTexture, uv1).rgb, 2), 1);
833
- const normal2 = sub(mul(texture(normalTexture, uv2).rgb, 2), 1);
834
- const normal3 = sub(mul(texture(normalTexture, uv3).rgb, 2), 1);
835
- const normal4 = sub(mul(texture(normalTexture, uv4).rgb, 2), 1);
836
- const depth1 = texture(depthTexture, uv1).x;
837
- const depth2 = texture(depthTexture, uv2).x;
838
- const depth3 = texture(depthTexture, uv3).x;
839
- const depth4 = texture(depthTexture, uv4).x;
850
+ const normal1 = sub(mul(normalTexture.sample(uv1).rgb, 2), 1);
851
+ const normal2 = sub(mul(normalTexture.sample(uv2).rgb, 2), 1);
852
+ const normal3 = sub(mul(normalTexture.sample(uv3).rgb, 2), 1);
853
+ const normal4 = sub(mul(normalTexture.sample(uv4).rgb, 2), 1);
854
+ const depth1 = depthTexture.sample(uv1).x;
855
+ const depth2 = depthTexture.sample(uv2).x;
856
+ const depth3 = depthTexture.sample(uv3).x;
857
+ const depth4 = depthTexture.sample(uv4).x;
840
858
  const pos1 = worldPosFromDepth({ depth: depth1, coord: uv1 });
841
859
  const pos2 = worldPosFromDepth({ depth: depth2, coord: uv2 });
842
860
  const pos3 = worldPosFromDepth({ depth: depth3, coord: uv3 });
@@ -875,91 +893,6 @@ class CausticsMaterial extends MeshBasicNodeMaterial {
875
893
  return vec4(vec3(finalCaustic), 1);
876
894
  })();
877
895
  }
878
- //* Uniform Accessors ==============================
879
- get cameraMatrixWorld() {
880
- return this._cameraMatrixWorld.value;
881
- }
882
- set cameraMatrixWorld(v) {
883
- this._cameraMatrixWorld.value = v;
884
- }
885
- get cameraProjectionMatrixInv() {
886
- return this._cameraProjectionMatrixInv.value;
887
- }
888
- set cameraProjectionMatrixInv(v) {
889
- this._cameraProjectionMatrixInv.value = v;
890
- }
891
- get normalTexture() {
892
- return this._normalTexture.value;
893
- }
894
- set normalTexture(v) {
895
- this._normalTexture.value = v ?? new THREE.Texture();
896
- }
897
- get depthTexture() {
898
- return this._depthTexture.value;
899
- }
900
- set depthTexture(v) {
901
- this._depthTexture.value = v ?? new THREE.Texture();
902
- }
903
- get lightDir() {
904
- return this._lightDir.value;
905
- }
906
- set lightDir(v) {
907
- this._lightDir.value = v;
908
- }
909
- get lightPlaneNormal() {
910
- return this._lightPlaneNormal.value;
911
- }
912
- set lightPlaneNormal(v) {
913
- this._lightPlaneNormal.value = v;
914
- }
915
- get lightPlaneConstant() {
916
- return this._lightPlaneConstant.value;
917
- }
918
- set lightPlaneConstant(v) {
919
- this._lightPlaneConstant.value = v;
920
- }
921
- get near() {
922
- return this._near.value;
923
- }
924
- set near(v) {
925
- this._near.value = v;
926
- }
927
- get far() {
928
- return this._far.value;
929
- }
930
- set far(v) {
931
- this._far.value = v;
932
- }
933
- get worldRadius() {
934
- return this._worldRadius.value;
935
- }
936
- set worldRadius(v) {
937
- this._worldRadius.value = v;
938
- }
939
- get ior() {
940
- return this._ior.value;
941
- }
942
- set ior(v) {
943
- this._ior.value = v;
944
- }
945
- get resolution() {
946
- return this._resolution.value;
947
- }
948
- set resolution(v) {
949
- this._resolution.value = v;
950
- }
951
- get size() {
952
- return this._size.value;
953
- }
954
- set size(v) {
955
- this._size.value = v;
956
- }
957
- get intensity() {
958
- return this._intensity.value;
959
- }
960
- set intensity(v) {
961
- this._intensity.value = v;
962
- }
963
896
  }
964
897
  class CausticsNormalMaterial extends MeshNormalNodeMaterial {
965
898
  constructor(side = THREE.FrontSide) {
@@ -1108,9 +1041,9 @@ class TransmissionLightingModel extends PhysicalLightingModel {
1108
1041
  const uvR = getRefractionUV(sampleNorm, v, iorR, sampleThickness, position);
1109
1042
  const uvG = getRefractionUV(sampleNorm, v, iorG, sampleThickness, position);
1110
1043
  const uvB = getRefractionUV(sampleNorm, v, iorB, sampleThickness, position);
1111
- const sampleR = texture(bufferTex, uvR);
1112
- const sampleG = texture(bufferTex, uvG);
1113
- const sampleB = texture(bufferTex, uvB);
1044
+ const sampleR = bufferTex.sample(uvR);
1045
+ const sampleG = bufferTex.sample(uvG);
1046
+ const sampleB = bufferTex.sample(uvB);
1114
1047
  transmissionAccum.x.addAssign(sampleR.r);
1115
1048
  transmissionAccum.y.addAssign(sampleG.g);
1116
1049
  transmissionAccum.z.addAssign(sampleB.b);
@@ -1120,7 +1053,7 @@ class TransmissionLightingModel extends PhysicalLightingModel {
1120
1053
  const debugNdotV = n.dot(v);
1121
1054
  const isNeg = debugNdotV.lessThan(0);
1122
1055
  const sampleUVFlipped = vec2$2(screenUV.x, screenUV.y.oneMinus()).clamp(1e-3, 0.999);
1123
- const directSampleFlipped = texture(bufferTex, sampleUVFlipped);
1056
+ const directSampleFlipped = bufferTex.sample(sampleUVFlipped);
1124
1057
  const testRay = getVolumeTransmissionRay(n, v, thickness, ior);
1125
1058
  const rayLen = length(testRay);
1126
1059
  const manualUV = screenCoordinate.xy.div(screenSize);
@@ -1128,9 +1061,9 @@ class TransmissionLightingModel extends PhysicalLightingModel {
1128
1061
  const flippedUV = vec2$2(screenUV.x, screenUV.y.oneMinus()).clamp(1e-3, 0.999);
1129
1062
  const useFlipped = screenUV.x.greaterThan(0.5);
1130
1063
  const splitSampleUV = select(useFlipped, flippedUV, noFlipUV);
1131
- const splitSample = texture(bufferTex, splitSampleUV);
1132
- const directSampleNoFlip = texture(bufferTex, screenUV.clamp(1e-3, 0.999));
1133
- const centerSample = texture(bufferTex, vec2$2(0.5, 0.5));
1064
+ const splitSample = bufferTex.sample(splitSampleUV);
1065
+ const directSampleNoFlip = bufferTex.sample(screenUV.clamp(1e-3, 0.999));
1066
+ const centerSample = bufferTex.sample(vec2$2(0.5, 0.5));
1134
1067
  const transmissionRayDbg = getVolumeTransmissionRay(n, v, thickness, ior);
1135
1068
  const refractedRayExitDbg = position.add(transmissionRayDbg);
1136
1069
  const ndcPosDbg = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(refractedRayExitDbg, 1)));
@@ -1147,7 +1080,7 @@ class TransmissionLightingModel extends PhysicalLightingModel {
1147
1080
  projUVDbg.divAssign(2);
1148
1081
  projUVDbg.assign(vec2$2(projUVDbg.x, projUVDbg.y.oneMinus()));
1149
1082
  projUVDbg.assign(projUVDbg.clamp(1e-3, 0.999));
1150
- const projectedSample = texture(bufferTex, projUVDbg);
1083
+ const projectedSample = bufferTex.sample(projUVDbg);
1151
1084
  const wNorm = clipPosDbg.w.div(10).add(0.5).clamp(0, 1);
1152
1085
  const isBehind = clipPosDbg.w.lessThan(0);
1153
1086
  const rawNdcX = clipPosDbg.x.div(safeWDbg2);
@@ -1270,18 +1203,29 @@ class TransmissionLightingModel extends PhysicalLightingModel {
1270
1203
  }
1271
1204
  }
1272
1205
  }
1273
- class MeshTransmissionMaterialImpl extends MeshPhysicalNodeMaterial {
1274
- // Custom uniforms
1275
- _chromaticAberration;
1276
- _anisotropicBlur;
1277
- _time;
1278
- _distortion;
1279
- _distortionScale;
1280
- _temporalDistortion;
1281
- _buffer;
1282
- // Texture node
1283
- _transmissionValue;
1284
- _debugMode;
1206
+ function createPlaceholderTexture() {
1207
+ const placeholder = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);
1208
+ placeholder.needsUpdate = true;
1209
+ return placeholder;
1210
+ }
1211
+ class MeshTransmissionMaterialImpl extends withUniforms(MeshPhysicalNodeMaterial, {
1212
+ /** Chromatic aberration, default: 0.05 */
1213
+ chromaticAberration: () => uniform(0.05),
1214
+ /** Anisotropic blur, default: 0.1 */
1215
+ anisotropicBlur: () => uniform(0.1),
1216
+ /** Elapsed time, drives the temporal distortion */
1217
+ time: () => uniform(0),
1218
+ /** Distortion, default: 0 */
1219
+ distortion: () => uniform(0),
1220
+ /** Distortion scale, default: 0.5 */
1221
+ distortionScale: () => uniform(0.5),
1222
+ /** Temporal distortion (speed of movement), default: 0 */
1223
+ temporalDistortion: () => uniform(0),
1224
+ /** The scene rendered into a texture (use it to share a texture between materials) */
1225
+ buffer: () => uniformTexture(createPlaceholderTexture()),
1226
+ /** Debug mode for development (0 = normal, 1-19 = various debug outputs), default: 0 */
1227
+ debugMode: () => uniform(0)
1228
+ }) {
1285
1229
  /** Type flag for identification */
1286
1230
  isMeshTransmissionMaterial = true;
1287
1231
  _samples;
@@ -1290,27 +1234,26 @@ class MeshTransmissionMaterialImpl extends MeshPhysicalNodeMaterial {
1290
1234
  super();
1291
1235
  this._samples = samples;
1292
1236
  this._transmissionSampler = transmissionSampler;
1293
- this._chromaticAberration = uniform(0.05);
1294
- this._anisotropicBlur = uniform(0.1);
1295
- this._time = uniform(0);
1296
- this._distortion = uniform(0);
1297
- this._distortionScale = uniform(0.5);
1298
- this._temporalDistortion = uniform(0);
1299
- this._debugMode = uniform(0);
1300
- const placeholderTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);
1301
- placeholderTexture.needsUpdate = true;
1302
- this._buffer = uniformTexture(placeholderTexture);
1303
- this._transmissionValue = uniform(1);
1304
- this.transmission = transmissionSampler ? 1 : 1e-3;
1237
+ this.transmission = 1;
1305
1238
  this.roughness = 0;
1306
1239
  this.thickness = 0;
1307
1240
  this.ior = 1.5;
1308
1241
  this.transparent = true;
1309
1242
  }
1310
1243
  setupLightingModel() {
1311
- if (this._transmissionSampler) {
1244
+ if (this._transmissionSampler || !this.useTransmission) {
1312
1245
  return super.setupLightingModel();
1313
1246
  }
1247
+ const {
1248
+ buffer,
1249
+ chromaticAberration,
1250
+ anisotropicBlur,
1251
+ time,
1252
+ distortion,
1253
+ distortionScale,
1254
+ temporalDistortion,
1255
+ debugMode
1256
+ } = this.uniforms;
1314
1257
  return new TransmissionLightingModel(
1315
1258
  {
1316
1259
  clearcoat: this.useClearcoat,
@@ -1320,82 +1263,18 @@ class MeshTransmissionMaterialImpl extends MeshPhysicalNodeMaterial {
1320
1263
  dispersion: this.useDispersion
1321
1264
  },
1322
1265
  {
1323
- bufferTex: this._buffer,
1324
- chromaticAberration: this._chromaticAberration,
1325
- anisotropicBlur: this._anisotropicBlur,
1326
- timeUniform: this._time,
1327
- distortion: this._distortion,
1328
- distortionScale: this._distortionScale,
1329
- temporalDistortion: this._temporalDistortion,
1266
+ bufferTex: buffer,
1267
+ chromaticAberration,
1268
+ anisotropicBlur,
1269
+ timeUniform: time,
1270
+ distortion,
1271
+ distortionScale,
1272
+ temporalDistortion,
1330
1273
  samples: this._samples,
1331
- debugMode: this._debugMode
1274
+ debugMode
1332
1275
  }
1333
1276
  );
1334
1277
  }
1335
- //* Property Accessors ==============================
1336
- get time() {
1337
- return this._time.value;
1338
- }
1339
- set time(v) {
1340
- this._time.value = v;
1341
- }
1342
- get buffer() {
1343
- return this._buffer.value;
1344
- }
1345
- set buffer(v) {
1346
- this._buffer.value = v;
1347
- }
1348
- get chromaticAberration() {
1349
- return this._chromaticAberration.value;
1350
- }
1351
- set chromaticAberration(v) {
1352
- this._chromaticAberration.value = v;
1353
- }
1354
- get anisotropicBlur() {
1355
- return this._anisotropicBlur.value;
1356
- }
1357
- set anisotropicBlur(v) {
1358
- this._anisotropicBlur.value = v;
1359
- }
1360
- get distortion() {
1361
- return this._distortion.value;
1362
- }
1363
- set distortion(v) {
1364
- this._distortion.value = v;
1365
- }
1366
- get distortionScale() {
1367
- return this._distortionScale.value;
1368
- }
1369
- set distortionScale(v) {
1370
- this._distortionScale.value = v;
1371
- }
1372
- get temporalDistortion() {
1373
- return this._temporalDistortion.value;
1374
- }
1375
- set temporalDistortion(v) {
1376
- this._temporalDistortion.value = v;
1377
- }
1378
- get debugMode() {
1379
- return this._debugMode.value;
1380
- }
1381
- set debugMode(v) {
1382
- this._debugMode.value = v;
1383
- }
1384
- // Expose _transmission for legacy compatibility
1385
- // This stores the user's intended transmission value, separate from the base class's transmission
1386
- // which is kept at 0.001 to enable the transmission code path without triggering Three's internal rendering
1387
- get _transmission() {
1388
- if (!this._transmissionValue) {
1389
- this._transmissionValue = uniform(1);
1390
- }
1391
- return this._transmissionValue.value;
1392
- }
1393
- set _transmission(v) {
1394
- if (!this._transmissionValue) {
1395
- this._transmissionValue = uniform(1);
1396
- }
1397
- this._transmissionValue.value = v;
1398
- }
1399
1278
  }
1400
1279
  const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
1401
1280
  ({
@@ -1528,7 +1407,7 @@ const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
1528
1407
  ref,
1529
1408
  ...props,
1530
1409
  buffer: buffer || fboMain.texture,
1531
- _transmission: transmission2,
1410
+ transmission: transmission2,
1532
1411
  anisotropicBlur: anisotropicBlur ?? anisotropy,
1533
1412
  thickness: thickness2,
1534
1413
  side,
@@ -1538,23 +1417,36 @@ const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
1538
1417
  }
1539
1418
  );
1540
1419
 
1541
- let MeshReflectorMaterial$1 = class MeshReflectorMaterial extends THREE.MeshStandardNodeMaterial {
1420
+ let MeshReflectorMaterial$1 = class MeshReflectorMaterial extends withUniforms(THREE.MeshStandardNodeMaterial, {
1421
+ /** Mirror strength, 0 = base material only, 1 = pure reflection */
1422
+ mirror: () => uniform(0),
1423
+ /** Positive values enable the blurred reflection sample */
1424
+ mixBlur: () => uniform(0),
1425
+ /** Strength of the reflection added on top of the base colour */
1426
+ mixStrength: () => uniform(1),
1427
+ /** Lower depth threshold for depth-based blur */
1428
+ minDepthThreshold: () => uniform(0.9),
1429
+ /** Upper depth threshold for depth-based blur */
1430
+ maxDepthThreshold: () => uniform(1),
1431
+ /** Depth scale for depth-based blur, 0 = disabled */
1432
+ depthScale: () => uniform(0),
1433
+ /** Bias added to the depth-to-blur ratio */
1434
+ depthToBlurRatioBias: () => uniform(0.25),
1435
+ /** Distortion strength */
1436
+ distortion: () => uniform(1),
1437
+ /** Contrast applied to the (clamped) reflection colour */
1438
+ mixContrast: () => uniform(1),
1439
+ /** Blur radius in the 0-1 range, scaled to 0.01-0.15 in the shader */
1440
+ blurRadius: () => uniform(0.1)
1441
+ }) {
1542
1442
  //* Reflector Node ----------------------------------------
1543
1443
  reflection;
1544
- //* Uniforms ----------------------------------------
1545
- mirrorUniform;
1546
- mixBlurUniform;
1547
- mixStrengthUniform;
1548
- minDepthThresholdUniform;
1549
- maxDepthThresholdUniform;
1550
- depthScaleUniform;
1551
- depthToBlurRatioBiasUniform;
1552
- distortionUniform;
1553
- mixContrastUniform;
1554
- blurRadiusUniform;
1555
- // Feature flags
1556
- hasBlurUniform;
1557
- hasDepthUniform;
1444
+ /**
1445
+ * Add this target to the scene and align it with the reflective surface.
1446
+ */
1447
+ get reflectorTarget() {
1448
+ return this.reflection?.target;
1449
+ }
1558
1450
  constructor(options = {}, parameters = {}) {
1559
1451
  super();
1560
1452
  const { distortionMap, ...validParams } = parameters;
@@ -1578,109 +1470,37 @@ let MeshReflectorMaterial$1 = class MeshReflectorMaterial extends THREE.MeshStan
1578
1470
  resolutionScale,
1579
1471
  generateMipmaps: true
1580
1472
  });
1581
- this.mirrorUniform = uniform(mirror);
1582
- this.mixBlurUniform = uniform(mixBlur);
1583
- this.mixStrengthUniform = uniform(mixStrength);
1584
- this.minDepthThresholdUniform = uniform(minDepthThreshold);
1585
- this.maxDepthThresholdUniform = uniform(maxDepthThreshold);
1586
- this.depthScaleUniform = uniform(depthScale);
1587
- this.depthToBlurRatioBiasUniform = uniform(depthToBlurRatioBias);
1588
- this.distortionUniform = uniform(distortion);
1589
- this.mixContrastUniform = uniform(mixContrast);
1590
- this.blurRadiusUniform = uniform(0.1);
1591
- this.hasBlurUniform = uniform(mixBlur > 0 ? 1 : 0);
1592
- this.hasDepthUniform = uniform(depthScale > 0 ? 1 : 0);
1473
+ this.mirror = mirror;
1474
+ this.mixBlur = mixBlur;
1475
+ this.mixStrength = mixStrength;
1476
+ this.minDepthThreshold = minDepthThreshold;
1477
+ this.maxDepthThreshold = maxDepthThreshold;
1478
+ this.depthScale = depthScale;
1479
+ this.depthToBlurRatioBias = depthToBlurRatioBias;
1480
+ this.distortion = distortion;
1481
+ this.mixContrast = mixContrast;
1593
1482
  this.setupNodes();
1594
1483
  }
1595
1484
  setupNodes() {
1485
+ const { mirror, mixBlur, mixStrength, mixContrast, blurRadius } = this.uniforms;
1596
1486
  this.colorNode = Fn(() => {
1597
1487
  const reflectionSample = this.reflection.sample(this.reflection.uvNode);
1598
- const blurRadius = mix(float(0.01), float(0.15), this.blurRadiusUniform);
1599
- const reflectionBlurred = hashBlur(this.reflection, blurRadius, {
1488
+ const radius = mix(float(0.01), float(0.15), blurRadius);
1489
+ const reflectionBlurred = hashBlur(this.reflection, radius, {
1600
1490
  repeats: float(20),
1601
1491
  premultipliedAlpha: false
1602
1492
  });
1603
- const reflectionColor = mix(reflectionSample.rgb, reflectionBlurred.rgb, clamp(this.hasBlurUniform, 0, 1));
1493
+ const reflectionColor = select(mixBlur.greaterThan(0), reflectionBlurred.rgb, reflectionSample.rgb);
1604
1494
  const reflectionClamped = clamp(reflectionColor, 0, 1);
1605
1495
  const contrastAdjusted = vec3(
1606
- reflectionClamped.x.sub(0.5).mul(this.mixContrastUniform).add(0.5),
1607
- reflectionClamped.y.sub(0.5).mul(this.mixContrastUniform).add(0.5),
1608
- reflectionClamped.z.sub(0.5).mul(this.mixContrastUniform).add(0.5)
1496
+ reflectionClamped.x.sub(0.5).mul(mixContrast).add(0.5),
1497
+ reflectionClamped.y.sub(0.5).mul(mixContrast).add(0.5),
1498
+ reflectionClamped.z.sub(0.5).mul(mixContrast).add(0.5)
1609
1499
  );
1610
- const mirrorClamped = clamp(this.mirrorUniform, 0, 1);
1611
- return vec4(vec3(1).sub(vec3(mirrorClamped)).add(contrastAdjusted.mul(this.mixStrengthUniform)), 1);
1500
+ const mirrorClamped = clamp(mirror, 0, 1);
1501
+ return vec4(vec3(1).sub(vec3(mirrorClamped)).add(contrastAdjusted.mul(mixStrength)), 1);
1612
1502
  })();
1613
1503
  }
1614
- //* Getters and Setters ----------------------------------------
1615
- get mirror() {
1616
- return this.mirrorUniform.value;
1617
- }
1618
- set mirror(v) {
1619
- this.mirrorUniform.value = v;
1620
- }
1621
- get mixBlur() {
1622
- return this.mixBlurUniform.value;
1623
- }
1624
- set mixBlur(v) {
1625
- this.mixBlurUniform.value = v;
1626
- this.hasBlurUniform.value = v > 0 ? 1 : 0;
1627
- }
1628
- get mixStrength() {
1629
- return this.mixStrengthUniform.value;
1630
- }
1631
- set mixStrength(v) {
1632
- this.mixStrengthUniform.value = v;
1633
- }
1634
- get minDepthThreshold() {
1635
- return this.minDepthThresholdUniform.value;
1636
- }
1637
- set minDepthThreshold(v) {
1638
- this.minDepthThresholdUniform.value = v;
1639
- }
1640
- get maxDepthThreshold() {
1641
- return this.maxDepthThresholdUniform.value;
1642
- }
1643
- set maxDepthThreshold(v) {
1644
- this.maxDepthThresholdUniform.value = v;
1645
- }
1646
- get depthScale() {
1647
- return this.depthScaleUniform.value;
1648
- }
1649
- set depthScale(v) {
1650
- this.depthScaleUniform.value = v;
1651
- this.hasDepthUniform.value = v > 0 ? 1 : 0;
1652
- }
1653
- get depthToBlurRatioBias() {
1654
- return this.depthToBlurRatioBiasUniform.value;
1655
- }
1656
- set depthToBlurRatioBias(v) {
1657
- this.depthToBlurRatioBiasUniform.value = v;
1658
- }
1659
- get distortion() {
1660
- return this.distortionUniform.value;
1661
- }
1662
- set distortion(v) {
1663
- this.distortionUniform.value = v;
1664
- }
1665
- get mixContrast() {
1666
- return this.mixContrastUniform.value;
1667
- }
1668
- set mixContrast(v) {
1669
- this.mixContrastUniform.value = v;
1670
- }
1671
- get blurRadius() {
1672
- return this.blurRadiusUniform.value;
1673
- }
1674
- set blurRadius(v) {
1675
- this.blurRadiusUniform.value = v;
1676
- }
1677
- /**
1678
- * Get the reflector target mesh that needs to be added to the scene.
1679
- * The target should be positioned and rotated to match the reflective surface.
1680
- */
1681
- get reflectorTarget() {
1682
- return this.reflection.target;
1683
- }
1684
1504
  };
1685
1505
 
1686
1506
  const MeshReflectorMaterial = /* @__PURE__ */ React.forwardRef(
@@ -1802,138 +1622,64 @@ const approximateRefraction = /* @__PURE__ */ Fn(([rayDir, normal, iorValue, bou
1802
1622
  });
1803
1623
  return select(entryValid, currentDir, reflect(rayDir, normal));
1804
1624
  });
1805
- class MeshRefractionMaterialImpl extends MeshPhysicalNodeMaterial {
1806
- //* Private Uniform Nodes --
1807
- _envMap;
1808
- _bounces;
1809
- _ior;
1810
- _fresnel;
1811
- _aberrationStrength;
1812
- _color;
1813
- _opacityValue;
1625
+ class MeshRefractionMaterialImpl extends withUniforms(MeshPhysicalNodeMaterial, {
1626
+ /** Number of internal bounces, default: 3 */
1627
+ bounces: () => uniform(3),
1628
+ /** Fresnel intensity, default: 0 */
1629
+ fresnel: () => uniform(0),
1630
+ /** Chromatic aberration strength, default: 0.01 */
1631
+ aberrationStrength: () => uniform(0.01),
1632
+ /** Tint applied to the refracted environment, default: white */
1633
+ tintColor: () => uniform(new THREE.Color("white"))
1634
+ }) {
1814
1635
  _fastChroma;
1815
1636
  /** Type flag for identification */
1816
1637
  isMeshRefractionMaterial = true;
1817
1638
  constructor(fastChroma = true) {
1818
1639
  super();
1819
1640
  this._fastChroma = fastChroma;
1820
- this._envMap = uniformTexture(new THREE.Texture());
1821
- this._bounces = uniform(3);
1822
- this._ior = uniform(2.4);
1823
- this._fresnel = uniform(0);
1824
- this._aberrationStrength = uniform(0.01);
1825
- this._color = uniform(new THREE.Color("white"));
1826
- this._opacityValue = uniform(1);
1641
+ this.ior = 2.4;
1642
+ this.envMap = new THREE.Texture();
1643
+ this.lights = false;
1827
1644
  this.transparent = true;
1828
1645
  this.side = THREE.FrontSide;
1829
1646
  this._buildRefractionShader();
1830
1647
  }
1831
1648
  _buildRefractionShader() {
1832
- const envMapTex = this._envMap;
1833
- const bouncesUniform = this._bounces;
1834
- const iorUniform = this._ior;
1835
- const fresnelUniform = this._fresnel;
1836
- const aberrationUniform = this._aberrationStrength;
1837
- const colorUniform = this._color;
1838
- const opacityUniform = this._opacityValue;
1649
+ const { bounces, fresnel, aberrationStrength, tintColor } = this.uniforms;
1839
1650
  const fastChroma = this._fastChroma;
1651
+ const envSample = (uvNode) => context$a(materialReference("envMap", "texture", this), { getUV: () => uvNode });
1840
1652
  this.outputNode = Fn(() => {
1841
1653
  const worldPos = positionWorld;
1842
1654
  const worldNormal = normalize(normalWorld);
1843
1655
  const viewDir = normalize(worldPos.sub(cameraPosition));
1844
- const baseColor = colorUniform.toVar();
1845
- const refractedDirG = approximateRefraction(viewDir, worldNormal, max(iorUniform, 1), bouncesUniform);
1846
- const aberration = aberrationUniform;
1656
+ const baseColor = tintColor.toVar();
1657
+ const iorValue = max(materialIOR, 1);
1658
+ const refractedDirG = approximateRefraction(viewDir, worldNormal, iorValue, bounces);
1659
+ const aberration = aberrationStrength;
1847
1660
  const refractedDirR = vec3(0, 0, 0).toVar();
1848
1661
  const refractedDirB = vec3(0, 0, 0).toVar();
1849
- const useFastChroma = fastChroma;
1850
- if (useFastChroma) {
1662
+ if (fastChroma) {
1851
1663
  refractedDirR.assign(normalize(refractedDirG.add(vec3(aberration.mul(0.5)))));
1852
1664
  refractedDirB.assign(normalize(refractedDirG.sub(vec3(aberration.mul(0.5)))));
1853
1665
  } else {
1854
1666
  refractedDirR.assign(
1855
- approximateRefraction(
1856
- viewDir,
1857
- worldNormal,
1858
- max(iorUniform.mul(float(1).sub(aberration)), 1),
1859
- bouncesUniform
1860
- )
1667
+ approximateRefraction(viewDir, worldNormal, max(materialIOR.mul(float(1).sub(aberration)), 1), bounces)
1861
1668
  );
1862
1669
  refractedDirB.assign(
1863
- approximateRefraction(
1864
- viewDir,
1865
- worldNormal,
1866
- max(iorUniform.mul(float(1).add(aberration)), 1),
1867
- bouncesUniform
1868
- )
1670
+ approximateRefraction(viewDir, worldNormal, max(materialIOR.mul(float(1).add(aberration)), 1), bounces)
1869
1671
  );
1870
1672
  }
1871
- const uvR = equirectUV(refractedDirR);
1872
- const uvG = equirectUV(refractedDirG);
1873
- const uvB = equirectUV(refractedDirB);
1874
- const envColorR = texture(envMapTex, uvR).r;
1875
- const envColorG = texture(envMapTex, uvG).g;
1876
- const envColorB = texture(envMapTex, uvB).b;
1673
+ const envColorR = envSample(equirectUV(refractedDirR)).r;
1674
+ const envColorG = envSample(equirectUV(refractedDirG)).g;
1675
+ const envColorB = envSample(equirectUV(refractedDirB)).b;
1877
1676
  const envColor = vec3(envColorR, envColorG, envColorB);
1878
1677
  const tintedColor = envColor.mul(baseColor);
1879
- const fresnelValue = fresnelEffect(viewDir, worldNormal, float(10)).mul(fresnelUniform);
1678
+ const fresnelValue = fresnelEffect(viewDir, worldNormal, float(10)).mul(fresnel);
1880
1679
  const finalColor = mix(tintedColor, vec3(1), fresnelValue);
1881
- return vec4(finalColor, opacityUniform);
1680
+ return vec4(finalColor, materialOpacity);
1882
1681
  })();
1883
1682
  }
1884
- //* Uniform Accessors ==============================
1885
- /** Environment map texture */
1886
- get envMap() {
1887
- return this._envMap.value;
1888
- }
1889
- set envMap(v) {
1890
- if (v) {
1891
- this._envMap.value = v;
1892
- }
1893
- }
1894
- /** Number of internal bounces, default: 3 */
1895
- get bounces() {
1896
- return this._bounces.value;
1897
- }
1898
- set bounces(v) {
1899
- this._bounces.value = v;
1900
- }
1901
- /** Index of refraction, default: 2.4 (diamond) */
1902
- get ior() {
1903
- return this._ior.value;
1904
- }
1905
- set ior(v) {
1906
- this._ior.value = v;
1907
- }
1908
- /** Fresnel intensity, default: 0 */
1909
- get fresnel() {
1910
- return this._fresnel.value;
1911
- }
1912
- set fresnel(v) {
1913
- this._fresnel.value = v;
1914
- }
1915
- /** Chromatic aberration strength, default: 0.01 */
1916
- get aberrationStrength() {
1917
- return this._aberrationStrength.value;
1918
- }
1919
- set aberrationStrength(v) {
1920
- this._aberrationStrength.value = v;
1921
- }
1922
- /** Tint color - use tintColor to avoid base class conflict */
1923
- get tintColor() {
1924
- return this._color.value;
1925
- }
1926
- set tintColor(v) {
1927
- if (v instanceof THREE.Color) this._color.value = v;
1928
- else this._color.value = new THREE.Color(v);
1929
- }
1930
- /** Opacity, default: 1 */
1931
- get opacity() {
1932
- return this._opacityValue.value;
1933
- }
1934
- set opacity(v) {
1935
- this._opacityValue.value = v;
1936
- }
1937
1683
  }
1938
1684
  const MeshRefractionMaterial = /* @__PURE__ */ React.forwardRef(
1939
1685
  ({
@@ -2156,175 +1902,88 @@ function Container$2({
2156
1902
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
2157
1903
  }
2158
1904
 
2159
- class PortalMaterialImpl extends MeshBasicNodeMaterial {
2160
- _blur;
2161
- _map;
2162
- _sdf;
2163
- _blend;
2164
- _size;
2165
- _resolution;
1905
+ class PortalMaterialImpl extends withUniforms(MeshBasicNodeMaterial, {
1906
+ /** Edge fade blur, 0 = no blur */
1907
+ blur: () => uniform(0),
1908
+ /** Signed distance field of the parent geometry, generated on demand */
1909
+ sdf: () => uniformTexture(new THREE.Texture()),
1910
+ /** 0 = world scene, 0.5 = both, 1 = portal scene */
1911
+ blend: () => uniform(0),
1912
+ /** Largest SDF distance, used to normalise the field */
1913
+ size: () => uniform(0),
1914
+ /** Drawing-buffer size in pixels */
1915
+ resolution: () => uniform(new THREE.Vector2())
1916
+ }) {
2166
1917
  constructor() {
2167
1918
  super();
2168
- this._blur = uniform(0);
2169
- this._map = uniformTexture(new THREE.Texture());
2170
- this._sdf = uniformTexture(new THREE.Texture());
2171
- this._blend = uniform(0);
2172
- this._size = uniform(0);
2173
- this._resolution = uniform(new THREE.Vector2());
1919
+ this.map = new THREE.Texture();
2174
1920
  this._buildShader();
2175
1921
  }
2176
1922
  _buildShader() {
2177
- const blurUniform = this._blur;
2178
- const mapTex = this._map;
2179
- const sdfTex = this._sdf;
2180
- const sizeUniform = this._size;
2181
- const resolutionUniform = this._resolution;
1923
+ const { blur, sdf, size, resolution } = this.uniforms;
1924
+ const map = materialReference("map", "texture", this);
2182
1925
  this.colorNode = Fn(() => {
2183
- const screenUv = screenCoordinate.xy.div(resolutionUniform);
2184
- const t = texture(mapTex, screenUv);
2185
- const meshUv = uv();
2186
- const d = texture(sdfTex, meshUv).r.div(sizeUniform);
2187
- const k = blurUniform;
2188
- const edgeFactor = clamp(d.div(k).add(1), 0, 1);
1926
+ const screenUv = screenCoordinate.xy.div(resolution);
1927
+ const t = context$a(map, { getUV: () => screenUv });
1928
+ const d = sdf.sample(uv()).r.div(size);
1929
+ const edgeFactor = clamp(d.div(blur).add(1), 0, 1);
2189
1930
  const alpha = float(1).sub(smoothstep(float(0), float(1), edgeFactor));
2190
- const isBlurZero = k.equal(0);
2191
- const finalAlpha = select(isBlurZero, t.a, t.a.mul(alpha));
1931
+ const finalAlpha = select(blur.equal(0), t.a, t.a.mul(alpha));
2192
1932
  return vec4(t.rgb, finalAlpha);
2193
1933
  })();
2194
1934
  }
2195
- //* Uniform Accessors --
2196
- get blur() {
2197
- return this._blur.value;
2198
- }
2199
- set blur(v) {
2200
- this._blur.value = v;
2201
- }
2202
- get map() {
2203
- return this._map?.value;
2204
- }
2205
- set map(v) {
2206
- if (this._map) this._map.value = v ?? new THREE.Texture();
2207
- }
2208
- get sdf() {
2209
- return this._sdf.value;
2210
- }
2211
- set sdf(v) {
2212
- if (v) this._sdf.value = v;
2213
- }
2214
- get blend() {
2215
- return this._blend.value;
2216
- }
2217
- set blend(v) {
2218
- this._blend.value = v;
2219
- }
2220
- get size() {
2221
- return this._size.value;
2222
- }
2223
- set size(v) {
2224
- this._size.value = v;
2225
- }
2226
- get resolution() {
2227
- return this._resolution.value;
2228
- }
2229
- set resolution(v) {
2230
- if (Array.isArray(v)) this._resolution.value.set(v[0], v[1]);
2231
- else this._resolution.value.copy(v);
2232
- }
2233
1935
  }
2234
- class BlendMaterial extends MeshBasicNodeMaterial {
2235
- _textureA;
2236
- _textureB;
2237
- _blend;
1936
+ class BlendMaterial extends withUniforms(MeshBasicNodeMaterial, {
1937
+ textureA: () => uniformTexture(new THREE.Texture()),
1938
+ textureB: () => uniformTexture(new THREE.Texture()),
1939
+ blend: () => uniform(0)
1940
+ }) {
2238
1941
  constructor() {
2239
1942
  super();
2240
- this._textureA = uniformTexture(new THREE.Texture());
2241
- this._textureB = uniformTexture(new THREE.Texture());
2242
- this._blend = uniform(0);
2243
- this._buildShader();
2244
- }
2245
- _buildShader() {
2246
- const texA = this._textureA;
2247
- const texB = this._textureB;
2248
- const blendUniform = this._blend;
1943
+ const { textureA, textureB, blend } = this.uniforms;
2249
1944
  this.colorNode = Fn(() => {
2250
1945
  const uvCoord = uv();
2251
- const ta = texture(texA, uvCoord);
2252
- const tb = texture(texB, uvCoord);
2253
- return mix(tb, ta, blendUniform);
1946
+ return mix(textureB.sample(uvCoord), textureA.sample(uvCoord), blend);
2254
1947
  })();
2255
1948
  }
2256
- get textureA() {
2257
- return this._textureA.value;
2258
- }
2259
- set textureA(v) {
2260
- this._textureA.value = v;
2261
- }
2262
- get textureB() {
2263
- return this._textureB.value;
2264
- }
2265
- set textureB(v) {
2266
- this._textureB.value = v;
2267
- }
2268
- get blend() {
2269
- return this._blend.value;
2270
- }
2271
- set blend(v) {
2272
- this._blend.value = v;
2273
- }
2274
1949
  }
2275
- class UVRenderMaterial extends MeshBasicNodeMaterial {
2276
- _tex;
2277
- _inside;
1950
+ class UVRenderMaterial extends withUniforms(MeshBasicNodeMaterial, {
1951
+ tex: () => uniformTexture(new THREE.Texture()),
1952
+ /** 1 = pack the inside of the mask, 0 = the outside */
1953
+ inside: () => uniform(0)
1954
+ }) {
2278
1955
  constructor(inside = false) {
2279
- super();
2280
- this._tex = uniformTexture(new THREE.Texture());
2281
- this._inside = uniform(inside ? 1 : 0);
2282
- this._buildShader();
2283
- }
2284
- _buildShader() {
2285
- const tex = this._tex;
2286
- const insideUniform = this._inside;
2287
- this.colorNode = Fn(() => {
1956
+ super({ toneMapped: false });
1957
+ this.inside = inside ? 1 : 0;
1958
+ const { tex, inside: insideUniform } = this.uniforms;
1959
+ this.fragmentNode = Fn(() => {
2288
1960
  const uvCoord = uv();
2289
- const mask = texture(tex, uvCoord).x;
2290
- const roundedMask = round(mask);
1961
+ const roundedMask = round(tex.sample(uvCoord).x);
2291
1962
  const isInside = insideUniform.greaterThan(0.5);
2292
1963
  const factor = select(isInside, float(1).sub(roundedMask), roundedMask);
2293
1964
  const packedUv = uvCoord.mul(factor);
2294
1965
  return vec4(packedUv.x, packedUv.y, 0, 1);
2295
1966
  })();
2296
1967
  }
2297
- get tex() {
2298
- return this._tex.value;
2299
- }
2300
- set tex(v) {
2301
- this._tex.value = v;
2302
- }
2303
1968
  }
2304
- class JumpFloodMaterial extends MeshBasicNodeMaterial {
2305
- _tex;
2306
- _offset;
2307
- _texelSize;
1969
+ class JumpFloodMaterial extends withUniforms(MeshBasicNodeMaterial, {
1970
+ tex: () => uniformTexture(new THREE.Texture()),
1971
+ offset: () => uniform(0),
1972
+ texelSize: () => uniform(new THREE.Vector2(1, 1))
1973
+ }) {
2308
1974
  constructor(clientWidth, clientHeight) {
2309
- super();
2310
- this._tex = uniformTexture(new THREE.Texture());
2311
- this._offset = uniform(0);
2312
- this._texelSize = uniform(new THREE.Vector2(1 / clientWidth, 1 / clientHeight));
2313
- this._buildShader();
2314
- }
2315
- _buildShader() {
2316
- const tex = this._tex;
2317
- const offsetUniform = this._offset;
2318
- const texelSizeUniform = this._texelSize;
2319
- this.colorNode = Fn(() => {
1975
+ super({ toneMapped: false });
1976
+ this.uniforms.texelSize.value.set(1 / clientWidth, 1 / clientHeight);
1977
+ const { tex, offset, texelSize } = this.uniforms;
1978
+ this.fragmentNode = Fn(() => {
2320
1979
  const uvCoord = uv();
2321
1980
  const closestDist = float(99999999e-1).toVar();
2322
1981
  const closestPos = vec2$2(0, 0).toVar();
2323
1982
  Loop({ start: int(-1), end: int(2), type: "int", condition: "<" }, ({ i: x }) => {
2324
1983
  Loop({ start: int(-1), end: int(2), type: "int", condition: "<" }, ({ i: y }) => {
2325
- const sampleOffset = vec2$2(float(x), float(y)).mul(texelSizeUniform).mul(offsetUniform);
1984
+ const sampleOffset = vec2$2(float(x), float(y)).mul(texelSize).mul(offset);
2326
1985
  const sampleUv = uvCoord.add(sampleOffset);
2327
- const pos = texture(tex, sampleUv).xy;
1986
+ const pos = tex.sample(sampleUv).xy;
2328
1987
  const dist = distance(pos, uvCoord);
2329
1988
  const isValid = pos.x.notEqual(0).and(pos.y.notEqual(0));
2330
1989
  const isCloser = dist.lessThan(closestDist);
@@ -2336,88 +1995,40 @@ class JumpFloodMaterial extends MeshBasicNodeMaterial {
2336
1995
  return vec4(closestPos, 0, 1);
2337
1996
  })();
2338
1997
  }
2339
- get tex() {
2340
- return this._tex.value;
2341
- }
2342
- set tex(v) {
2343
- this._tex.value = v;
2344
- }
2345
- get offset() {
2346
- return this._offset.value;
2347
- }
2348
- set offset(v) {
2349
- this._offset.value = v;
2350
- }
2351
1998
  }
2352
- class DistanceFieldMaterial extends MeshBasicNodeMaterial {
2353
- _tex;
2354
- _size;
1999
+ class DistanceFieldMaterial extends withUniforms(MeshBasicNodeMaterial, {
2000
+ tex: () => uniformTexture(new THREE.Texture()),
2001
+ size: () => uniform(new THREE.Vector2(1, 1))
2002
+ }) {
2355
2003
  constructor(clientWidth, clientHeight) {
2356
- super();
2357
- this._tex = uniformTexture(new THREE.Texture());
2358
- this._size = uniform(new THREE.Vector2(clientWidth, clientHeight));
2359
- this._buildShader();
2360
- }
2361
- _buildShader() {
2362
- const tex = this._tex;
2363
- const sizeUniform = this._size;
2364
- this.colorNode = Fn(() => {
2004
+ super({ toneMapped: false });
2005
+ this.uniforms.size.value.set(clientWidth, clientHeight);
2006
+ const { tex, size } = this.uniforms;
2007
+ this.fragmentNode = Fn(() => {
2365
2008
  const uvCoord = uv();
2366
- const pos = texture(tex, uvCoord).xy;
2367
- const dist = distance(sizeUniform.mul(pos), sizeUniform.mul(uvCoord));
2009
+ const pos = tex.sample(uvCoord).xy;
2010
+ const dist = distance(size.mul(pos), size.mul(uvCoord));
2368
2011
  return vec4(dist, 0, 0, 1);
2369
2012
  })();
2370
2013
  }
2371
- get tex() {
2372
- return this._tex.value;
2373
- }
2374
- set tex(v) {
2375
- this._tex.value = v;
2376
- }
2377
2014
  }
2378
- class CompositeMaterial extends MeshBasicNodeMaterial {
2379
- _inside;
2380
- _outside;
2381
- _mask;
2015
+ class CompositeMaterial extends withUniforms(MeshBasicNodeMaterial, {
2016
+ inside: () => uniformTexture(new THREE.Texture()),
2017
+ outside: () => uniformTexture(new THREE.Texture()),
2018
+ mask: () => uniformTexture(new THREE.Texture())
2019
+ }) {
2382
2020
  constructor() {
2383
- super();
2384
- this._inside = uniformTexture(new THREE.Texture());
2385
- this._outside = uniformTexture(new THREE.Texture());
2386
- this._mask = uniformTexture(new THREE.Texture());
2387
- this._buildShader();
2388
- }
2389
- _buildShader() {
2390
- const insideTex = this._inside;
2391
- const outsideTex = this._outside;
2392
- const maskTex = this._mask;
2393
- this.colorNode = Fn(() => {
2021
+ super({ toneMapped: false });
2022
+ const { inside, outside, mask } = this.uniforms;
2023
+ this.fragmentNode = Fn(() => {
2394
2024
  const uvCoord = uv();
2395
- const i = texture(insideTex, uvCoord).x;
2396
- const o = texture(outsideTex, uvCoord).x;
2397
- const maskVal = texture(maskTex, uvCoord).x;
2398
- const isOutside = maskVal.equal(0);
2399
- const result = select(isOutside, o, i.negate());
2025
+ const i = inside.sample(uvCoord).x;
2026
+ const o = outside.sample(uvCoord).x;
2027
+ const maskVal = mask.sample(uvCoord).x;
2028
+ const result = select(maskVal.equal(0), o, i.negate());
2400
2029
  return vec4(result, 0, 0, 1);
2401
2030
  })();
2402
2031
  }
2403
- get inside() {
2404
- return this._inside.value;
2405
- }
2406
- set inside(v) {
2407
- this._inside.value = v;
2408
- }
2409
- get outside() {
2410
- return this._outside.value;
2411
- }
2412
- set outside(v) {
2413
- this._outside.value = v;
2414
- }
2415
- get mask() {
2416
- return this._mask.value;
2417
- }
2418
- set mask(v) {
2419
- this._mask.value = v;
2420
- }
2421
2032
  }
2422
2033
  const makeSDFGenerator = (clientWidth, clientHeight, renderer) => {
2423
2034
  const finalTarget = new RenderTarget(clientWidth, clientHeight, {
@@ -2465,7 +2076,7 @@ const makeSDFGenerator = (clientWidth, clientHeight, renderer) => {
2465
2076
  const jumpFloodQuad = new QuadMesh(jumpFloodMat);
2466
2077
  const distanceFieldQuad = new QuadMesh(distanceFieldMat);
2467
2078
  const compositeQuad = new QuadMesh(compositeMat);
2468
- return (image) => {
2079
+ const generate = (image) => {
2469
2080
  image.minFilter = THREE.NearestFilter;
2470
2081
  image.magFilter = THREE.NearestFilter;
2471
2082
  uvRenderMat.tex = image;
@@ -2507,9 +2118,28 @@ const makeSDFGenerator = (clientWidth, clientHeight, renderer) => {
2507
2118
  compositeMat.outside = outsideRenderTargetFinal.texture;
2508
2119
  compositeMat.mask = image;
2509
2120
  compositeQuad.render(renderer);
2510
- renderer.setRenderTarget(null);
2511
2121
  return finalTarget;
2512
2122
  };
2123
+ return {
2124
+ generate,
2125
+ dispose() {
2126
+ for (const resource of [
2127
+ finalTarget,
2128
+ outsideRenderTarget,
2129
+ insideRenderTarget,
2130
+ outsideRenderTarget2,
2131
+ insideRenderTarget2,
2132
+ outsideRenderTargetFinal,
2133
+ insideRenderTargetFinal,
2134
+ uvRenderMat,
2135
+ uvRenderInsideMat,
2136
+ jumpFloodMat,
2137
+ distanceFieldMat,
2138
+ compositeMat
2139
+ ])
2140
+ resource.dispose();
2141
+ }
2142
+ };
2513
2143
  };
2514
2144
  const MeshPortalMaterial = /* @__PURE__ */ React.forwardRef(
2515
2145
  ({
@@ -2524,7 +2154,7 @@ const MeshPortalMaterial = /* @__PURE__ */ React.forwardRef(
2524
2154
  }, fref) => {
2525
2155
  extend({ PortalMaterialImpl });
2526
2156
  const ref = React.useRef(null);
2527
- const { scene, gl, size, viewport, setEvents } = useThree();
2157
+ const { scene, renderer, size, viewport, setEvents, invalidate } = useThree();
2528
2158
  const maskRenderTarget = useFBO(resolution, resolution);
2529
2159
  const [priority, setPriority] = React.useState(0);
2530
2160
  useFrame(() => {
@@ -2535,43 +2165,69 @@ const MeshPortalMaterial = /* @__PURE__ */ React.forwardRef(
2535
2165
  if (events !== void 0) setEvents({ enabled: !events });
2536
2166
  }, [events]);
2537
2167
  const [visible, setVisible] = React.useState(true);
2168
+ const needsSdf = blur !== 0;
2538
2169
  const parent = useIntersect(setVisible);
2539
2170
  React.useLayoutEffect(() => {
2540
2171
  parent.current = ref.current?.__r3f?.parent?.object;
2541
2172
  }, []);
2542
2173
  React.useLayoutEffect(() => {
2543
- if (!parent.current) return;
2544
- if (blur && ref.current.sdf === null) {
2545
- const tempMesh = new THREE.Mesh(parent.current.geometry, new THREE.MeshBasicMaterial());
2546
- const boundingBox = new THREE.Box3().setFromBufferAttribute(
2547
- tempMesh.geometry.attributes.position
2548
- );
2549
- const orthoCam = new THREE.OrthographicCamera(
2550
- boundingBox.min.x * (1 + 2 / resolution),
2551
- boundingBox.max.x * (1 + 2 / resolution),
2552
- boundingBox.max.y * (1 + 2 / resolution),
2553
- boundingBox.min.y * (1 + 2 / resolution),
2554
- 0.1,
2555
- 1e3
2556
- );
2557
- orthoCam.position.set(0, 0, 1);
2558
- orthoCam.lookAt(0, 0, 0);
2559
- gl.setRenderTarget(maskRenderTarget);
2560
- gl.render(tempMesh, orthoCam);
2561
- const sg = makeSDFGenerator(resolution, resolution, gl);
2562
- const sdf = sg(maskRenderTarget.texture);
2563
- const readSdf = new Float32Array(resolution * resolution);
2564
- gl.readRenderTargetPixels(sdf, 0, 0, resolution, resolution, readSdf);
2174
+ if (!parent.current || !needsSdf) return;
2175
+ const material = ref.current;
2176
+ const previousSdf = material.sdf;
2177
+ const previousSize = material.size;
2178
+ const gpuRenderer = renderer;
2179
+ const tempMesh = new THREE.Mesh(parent.current.geometry, new THREE.MeshBasicMaterial());
2180
+ const boundingBox = new THREE.Box3().setFromBufferAttribute(
2181
+ tempMesh.geometry.attributes.position
2182
+ );
2183
+ const orthoCam = new THREE.OrthographicCamera(
2184
+ boundingBox.min.x * (1 + 2 / resolution),
2185
+ boundingBox.max.x * (1 + 2 / resolution),
2186
+ boundingBox.max.y * (1 + 2 / resolution),
2187
+ boundingBox.min.y * (1 + 2 / resolution),
2188
+ 0.1,
2189
+ 1e3
2190
+ );
2191
+ orthoCam.position.set(0, 0, 1);
2192
+ orthoCam.lookAt(0, 0, 0);
2193
+ const sg = makeSDFGenerator(resolution, resolution, gpuRenderer);
2194
+ const previousTarget = gpuRenderer.getRenderTarget();
2195
+ const previousClearColor = gpuRenderer.getClearColor(new THREE.Color());
2196
+ const previousClearAlpha = gpuRenderer.getClearAlpha();
2197
+ let sdf;
2198
+ try {
2199
+ gpuRenderer.setClearColor(0, 0);
2200
+ gpuRenderer.setRenderTarget(maskRenderTarget);
2201
+ gpuRenderer.render(tempMesh, orthoCam);
2202
+ sdf = sg.generate(maskRenderTarget.texture);
2203
+ } catch (error) {
2204
+ sg.dispose();
2205
+ throw error;
2206
+ } finally {
2207
+ gpuRenderer.setRenderTarget(previousTarget);
2208
+ gpuRenderer.setClearColor(previousClearColor, previousClearAlpha);
2209
+ tempMesh.material.dispose();
2210
+ }
2211
+ let cancelled = false;
2212
+ gpuRenderer.readRenderTargetPixelsAsync(sdf, 0, 0, resolution, resolution).then((readSdf) => {
2213
+ if (cancelled) return;
2565
2214
  let min = Infinity;
2566
2215
  for (let i = 0; i < readSdf.length; i++) {
2567
2216
  if (readSdf[i] < min) min = readSdf[i];
2568
2217
  }
2569
- min = -min;
2570
- ref.current.size = min;
2571
- ref.current.sdf = sdf.texture;
2572
- gl.setRenderTarget(null);
2573
- }
2574
- }, [resolution, blur]);
2218
+ material.size = -min;
2219
+ material.sdf = sdf.texture;
2220
+ invalidate();
2221
+ }).catch((error) => {
2222
+ if (!cancelled) console.error("MeshPortalMaterial: SDF readback failed.", error);
2223
+ });
2224
+ return () => {
2225
+ cancelled = true;
2226
+ material.sdf = previousSdf;
2227
+ material.size = previousSize;
2228
+ sg.dispose();
2229
+ };
2230
+ }, [resolution, needsSdf, renderer, maskRenderTarget, invalidate]);
2575
2231
  React.useImperativeHandle(fref, () => ref.current);
2576
2232
  const compute = React.useCallback(
2577
2233
  (event, state, _previous) => {
@@ -2676,44 +2332,27 @@ function ManagePortalScene({
2676
2332
  return /* @__PURE__ */ React.createElement(React.Fragment, null);
2677
2333
  }
2678
2334
 
2679
- class DistortMaterialImplWebGPU extends THREE.MeshPhysicalNodeMaterial {
2680
- timeUniform;
2681
- distortUniform;
2682
- radiusUniform;
2335
+ class DistortMaterialImplWebGPU extends withUniforms(THREE.MeshPhysicalNodeMaterial, {
2336
+ /** Animation time, advanced by the component each frame */
2337
+ time: () => uniform(0),
2338
+ /** Distortion intensity */
2339
+ distort: () => uniform(0.4),
2340
+ /** Base scale the distortion is added to */
2341
+ radius: () => uniform(1)
2342
+ }) {
2683
2343
  constructor(parameters = {}) {
2684
2344
  super(parameters);
2685
- this.setValues(parameters);
2686
- this.timeUniform = uniform(0);
2687
- this.distortUniform = uniform(0.4);
2688
- this.radiusUniform = uniform(1);
2345
+ const { time, distort, radius } = this.uniforms;
2689
2346
  this.positionNode = Fn(() => {
2690
2347
  const pos = positionLocal.toVar();
2691
- const updateTime = this.timeUniform.div(50);
2348
+ const updateTime = time.div(50);
2692
2349
  const noiseInput = pos.div(2).add(updateTime.mul(5));
2693
2350
  const noiseVec = mx_noise_vec3(noiseInput);
2694
2351
  const noise = noiseVec.x;
2695
- const distortFactor = noise.mul(pow(this.distortUniform, float(2))).add(this.radiusUniform);
2352
+ const distortFactor = noise.mul(pow(distort, float(2))).add(radius);
2696
2353
  return pos.mul(distortFactor);
2697
2354
  })();
2698
2355
  }
2699
- get time() {
2700
- return this.timeUniform.value;
2701
- }
2702
- set time(v) {
2703
- this.timeUniform.value = v;
2704
- }
2705
- get distort() {
2706
- return this.distortUniform.value;
2707
- }
2708
- set distort(v) {
2709
- this.distortUniform.value = v;
2710
- }
2711
- get radius() {
2712
- return this.radiusUniform.value;
2713
- }
2714
- set radius(v) {
2715
- this.radiusUniform.value = v;
2716
- }
2717
2356
  }
2718
2357
  const MeshDistortMaterial = /* @__PURE__ */ React.forwardRef(({ speed = 1, ...props }, ref) => {
2719
2358
  const [material] = React.useState(() => new DistortMaterialImplWebGPU());
@@ -2721,17 +2360,18 @@ const MeshDistortMaterial = /* @__PURE__ */ React.forwardRef(({ speed = 1, ...pr
2721
2360
  return /* @__PURE__ */ React.createElement("primitive", { object: material, ref, attach: "material", ...props });
2722
2361
  });
2723
2362
 
2724
- class WobbleMaterialImpl extends THREE.MeshStandardNodeMaterial {
2725
- timeUniform;
2726
- factorUniform;
2363
+ class WobbleMaterialImpl extends withUniforms(THREE.MeshStandardNodeMaterial, {
2364
+ /** Animation time, advanced by the component each frame */
2365
+ time: () => uniform(0),
2366
+ /** Wobble strength */
2367
+ factor: () => uniform(1)
2368
+ }) {
2727
2369
  constructor(parameters = {}) {
2728
2370
  super(parameters);
2729
- this.setValues(parameters);
2730
- this.timeUniform = uniform(0);
2731
- this.factorUniform = uniform(1);
2371
+ const { time, factor } = this.uniforms;
2732
2372
  this.positionNode = Fn(() => {
2733
2373
  const pos = positionLocal.toVar();
2734
- const theta = sin(this.timeUniform.add(pos.y)).div(2).mul(this.factorUniform);
2374
+ const theta = sin(time.add(pos.y)).div(2).mul(factor);
2735
2375
  const c = cos(theta);
2736
2376
  const s = sin(theta);
2737
2377
  const rotMatrix = mat3(c, float(0), s, float(0), float(1), float(0), s.negate(), float(0), c);
@@ -2740,25 +2380,13 @@ class WobbleMaterialImpl extends THREE.MeshStandardNodeMaterial {
2740
2380
  this.normalNode = Fn(() => {
2741
2381
  const pos = positionLocal.toVar();
2742
2382
  const norm = normalLocal.toVar();
2743
- const theta = sin(this.timeUniform.add(pos.y)).div(2).mul(this.factorUniform);
2383
+ const theta = sin(time.add(pos.y)).div(2).mul(factor);
2744
2384
  const c = cos(theta);
2745
2385
  const s = sin(theta);
2746
2386
  const rotMatrix = mat3(c, float(0), s, float(0), float(1), float(0), s.negate(), float(0), c);
2747
2387
  return norm.mul(rotMatrix);
2748
2388
  })();
2749
2389
  }
2750
- get time() {
2751
- return this.timeUniform.value;
2752
- }
2753
- set time(v) {
2754
- this.timeUniform.value = v;
2755
- }
2756
- get factor() {
2757
- return this.factorUniform.value;
2758
- }
2759
- set factor(v) {
2760
- this.factorUniform.value = v;
2761
- }
2762
2390
  }
2763
2391
  const MeshWobbleMaterial = /* @__PURE__ */ React.forwardRef(({ speed = 1, ...props }, ref) => {
2764
2392
  const [material] = React.useState(() => new WobbleMaterialImpl());
@@ -2777,84 +2405,36 @@ function FakeCloudMaterial(BaseMaterial) {
2777
2405
  return mat;
2778
2406
  }
2779
2407
 
2780
- class OutlinesMaterial extends MeshBasicNodeMaterial {
2781
- //* Private Uniform Nodes --
2782
- _screenspace;
2783
- // Using number as bool (0/1)
2784
- _color;
2785
- _opacityValue;
2786
- _thickness;
2787
- _size;
2408
+ class OutlinesMaterial extends withUniforms(MeshBasicNodeMaterial, {
2409
+ /** Whether thickness is constant in screen pixels */
2410
+ screenspace: () => uniform(false),
2411
+ /** Outline thickness */
2412
+ thickness: () => uniform(0.05),
2413
+ /** Drawing-buffer size, for screenspace thickness */
2414
+ size: () => uniform(new THREE.Vector2(1, 1))
2415
+ }) {
2788
2416
  /** Type flag for identification */
2789
2417
  isOutlinesMaterial = true;
2790
2418
  constructor() {
2791
2419
  super();
2792
- this._screenspace = uniform(0);
2793
- this._color = uniform(new THREE.Color("black"));
2794
- this._opacityValue = uniform(1);
2795
- this._thickness = uniform(0.05);
2796
- this._size = uniform(new THREE.Vector2(1, 1));
2420
+ this.color.set("black");
2797
2421
  this.side = THREE.BackSide;
2798
2422
  this.transparent = false;
2799
2423
  this._buildOutlineShader();
2800
2424
  }
2801
2425
  _buildOutlineShader() {
2802
- const screenspaceUniform = this._screenspace;
2803
- const colorUniform = this._color;
2804
- const opacityUniform = this._opacityValue;
2805
- const thicknessUniform = this._thickness;
2806
- const sizeUniform = this._size;
2426
+ const { screenspace, thickness, size } = this.uniforms;
2807
2427
  this.positionNode = Fn(() => {
2808
2428
  const position = positionLocal.toVar();
2809
2429
  const normal = normalLocal.toVar();
2810
- const isScreenspace = screenspaceUniform.greaterThan(0.5);
2811
- const screenspacePos = position.add(normal.mul(thicknessUniform));
2430
+ const screenspacePos = position.add(normal.mul(thickness));
2812
2431
  const clipPos = cameraProjectionMatrix.mul(modelViewMatrix.mul(vec4(position, 1)));
2813
2432
  const clipNormal = cameraProjectionMatrix.mul(modelViewMatrix.mul(vec4(normal, 0)));
2814
- normalize(clipNormal.xy).mul(thicknessUniform).div(sizeUniform).mul(clipPos.w).mul(2);
2815
- const worldOffset = normal.mul(thicknessUniform);
2816
- return select(isScreenspace, screenspacePos, position.add(worldOffset));
2433
+ normalize(clipNormal.xy).mul(thickness).div(size).mul(clipPos.w).mul(2);
2434
+ const worldOffset = normal.mul(thickness);
2435
+ return select(screenspace, screenspacePos, position.add(worldOffset));
2817
2436
  })();
2818
- this.outputNode = Fn(() => {
2819
- return vec4(colorUniform, opacityUniform);
2820
- })();
2821
- }
2822
- //* Uniform Accessors ==============================
2823
- /** Whether to use screenspace thickness */
2824
- get screenspace() {
2825
- return this._screenspace.value > 0.5;
2826
- }
2827
- set screenspace(v) {
2828
- this._screenspace.value = v ? 1 : 0;
2829
- }
2830
- /** Outline color */
2831
- get color() {
2832
- return this._color.value;
2833
- }
2834
- set color(v) {
2835
- if (v instanceof THREE.Color) this._color.value = v;
2836
- else this._color.value = new THREE.Color(v);
2837
- }
2838
- /** Outline opacity */
2839
- get opacity() {
2840
- return this._opacityValue.value;
2841
- }
2842
- set opacity(v) {
2843
- this._opacityValue.value = v;
2844
- }
2845
- /** Outline thickness */
2846
- get thickness() {
2847
- return this._thickness.value;
2848
- }
2849
- set thickness(v) {
2850
- this._thickness.value = v;
2851
- }
2852
- /** Screen size for screenspace calculations */
2853
- get size() {
2854
- return this._size.value;
2855
- }
2856
- set size(v) {
2857
- this._size.value = v;
2437
+ this.outputNode = Fn(() => vec4(materialColor, materialOpacity))();
2858
2438
  }
2859
2439
  }
2860
2440
  function Outlines({
@@ -3911,7 +3491,7 @@ const ScrollHtml = React.forwardRef(
3911
3491
  const group = React.useRef(null);
3912
3492
  React.useImperativeHandle(ref, () => group.current, []);
3913
3493
  const { width, height } = useThree((state2) => state2.size);
3914
- const fiberState = React.useContext(context$a);
3494
+ const fiberState = React.useContext(context$b);
3915
3495
  const root = React.useMemo(() => {
3916
3496
  let root2 = rootCache.get(state.fixed);
3917
3497
  if (!root2) {
@@ -3939,7 +3519,7 @@ const ScrollHtml = React.forwardRef(
3939
3519
  style: { ...style, position: "absolute", top: 0, left: 0, willChange: "transform" },
3940
3520
  ...props
3941
3521
  },
3942
- /* @__PURE__ */ React.createElement(context$7.Provider, { value: state }, /* @__PURE__ */ React.createElement(context$a.Provider, { value: fiberState }, children))
3522
+ /* @__PURE__ */ React.createElement(context$7.Provider, { value: state }, /* @__PURE__ */ React.createElement(context$b.Provider, { value: fiberState }, children))
3943
3523
  )
3944
3524
  );
3945
3525
  return null;
@@ -9233,7 +8813,7 @@ const HtmlView = /* @__PURE__ */ React.forwardRef(
9233
8813
  );
9234
8814
  const View = /* @__PURE__ */ (() => {
9235
8815
  const _View = React.forwardRef((props, fref) => {
9236
- const store = React.useContext(context$a);
8816
+ const store = React.useContext(context$b);
9237
8817
  if (!store) return /* @__PURE__ */ React.createElement(HtmlView, { ref: fref, ...props });
9238
8818
  else return /* @__PURE__ */ React.createElement(CanvasView, { ref: fref, ...props });
9239
8819
  });
@@ -10395,62 +9975,63 @@ const remap = /* @__PURE__ */ Fn((inputs) => {
10395
9975
  const [value, min1, max1, min2, max2] = inputs;
10396
9976
  return min2.add(value.sub(min1).mul(max2.sub(min2)).div(max1.sub(min1)));
10397
9977
  });
10398
- class WireframeMaterialImpl extends MeshBasicNodeMaterial {
10399
- //* Private Uniform Nodes --
10400
- _strokeOpacity;
10401
- _fillOpacity;
10402
- _fillMix;
10403
- _thickness;
10404
- _colorBackfaces;
10405
- // Using number as bool (0/1)
10406
- _dashInvert;
10407
- _dash;
10408
- _dashRepeats;
10409
- _dashLength;
10410
- _squeeze;
10411
- _squeezeMin;
10412
- _squeezeMax;
10413
- _stroke;
10414
- _backfaceStroke;
10415
- _fill;
9978
+ class WireframeMaterialImpl extends withUniforms(MeshBasicNodeMaterial, {
9979
+ /** Stroke (edge) opacity, default: 1 */
9980
+ strokeOpacity: () => uniform(1),
9981
+ /** Fill opacity (background), default: 0.25 */
9982
+ fillOpacity: () => uniform(0.25),
9983
+ /** Mix factor between material color and fill color, default: 0 */
9984
+ fillMix: () => uniform(0),
9985
+ /** Edge thickness 0-1, default: 0.05 */
9986
+ thickness: () => uniform(0.05),
9987
+ /** Use different color for backfaces, default: false */
9988
+ colorBackfaces: () => uniform(false),
9989
+ /** Invert dash pattern, default: true */
9990
+ dashInvert: () => uniform(true),
9991
+ /** Enable dashed lines, default: false */
9992
+ dash: () => uniform(false),
9993
+ /** Number of dash repeats, default: 4 */
9994
+ dashRepeats: () => uniform(4),
9995
+ /** Dash length 0-1, default: 0.5 */
9996
+ dashLength: () => uniform(0.5),
9997
+ /** Squeeze thickness toward line center, default: false */
9998
+ squeeze: () => uniform(false),
9999
+ /** Minimum squeeze factor, default: 0.2 */
10000
+ squeezeMin: () => uniform(0.2),
10001
+ /** Maximum squeeze factor, default: 1 */
10002
+ squeezeMax: () => uniform(1),
10003
+ /** Stroke (edge) color */
10004
+ stroke: () => uniform(new THREE.Color("#ff0000")),
10005
+ /** Backface stroke color */
10006
+ backfaceStroke: () => uniform(new THREE.Color("#0000ff")),
10007
+ /** Fill (background) color */
10008
+ fill: () => uniform(new THREE.Color("#00ff00"))
10009
+ }) {
10416
10010
  /** Type flag for identification */
10417
10011
  isWireframeMaterial = true;
10418
10012
  constructor() {
10419
10013
  super();
10420
- this._strokeOpacity = uniform(1);
10421
- this._fillOpacity = uniform(0.25);
10422
- this._fillMix = uniform(0);
10423
- this._thickness = uniform(0.05);
10424
- this._colorBackfaces = uniform(0);
10425
- this._dashInvert = uniform(1);
10426
- this._dash = uniform(0);
10427
- this._dashRepeats = uniform(4);
10428
- this._dashLength = uniform(0.5);
10429
- this._squeeze = uniform(0);
10430
- this._squeezeMin = uniform(0.2);
10431
- this._squeezeMax = uniform(1);
10432
- this._stroke = uniform(new THREE.Color("#ff0000"));
10433
- this._backfaceStroke = uniform(new THREE.Color("#0000ff"));
10434
- this._fill = uniform(new THREE.Color("#00ff00"));
10435
10014
  this.transparent = true;
10436
10015
  this.side = THREE.DoubleSide;
10437
10016
  this._buildWireframeShader();
10438
10017
  }
10439
10018
  _buildWireframeShader() {
10440
- const strokeOpacityUniform = this._strokeOpacity;
10441
- const fillOpacityUniform = this._fillOpacity;
10442
- const thicknessUniform = this._thickness;
10443
- const colorBackfacesUniform = this._colorBackfaces;
10444
- const dashInvertUniform = this._dashInvert;
10445
- const dashUniform = this._dash;
10446
- const dashRepeatsUniform = this._dashRepeats;
10447
- const dashLengthUniform = this._dashLength;
10448
- const squeezeUniform = this._squeeze;
10449
- const squeezeMinUniform = this._squeezeMin;
10450
- const squeezeMaxUniform = this._squeezeMax;
10451
- const strokeUniform = this._stroke;
10452
- const backfaceStrokeUniform = this._backfaceStroke;
10453
- const fillUniform = this._fill;
10019
+ const {
10020
+ strokeOpacity: strokeOpacityUniform,
10021
+ fillOpacity: fillOpacityUniform,
10022
+ thickness: thicknessUniform,
10023
+ colorBackfaces: colorBackfacesUniform,
10024
+ dashInvert: dashInvertUniform,
10025
+ dash: dashUniform,
10026
+ dashRepeats: dashRepeatsUniform,
10027
+ dashLength: dashLengthUniform,
10028
+ squeeze: squeezeUniform,
10029
+ squeezeMin: squeezeMinUniform,
10030
+ squeezeMax: squeezeMaxUniform,
10031
+ stroke: strokeUniform,
10032
+ backfaceStroke: backfaceStrokeUniform,
10033
+ fill: fillUniform
10034
+ } = this.uniforms;
10454
10035
  const barycentricAttr = attribute("barycentric", "vec3");
10455
10036
  const vBarycentric = varying(barycentricAttr, "v_barycentric");
10456
10037
  this.outputNode = Fn(() => {
@@ -10461,136 +10042,23 @@ class WireframeMaterialImpl extends MeshBasicNodeMaterial {
10461
10042
  const isYSmallest = barycentric.y.lessThan(barycentric.x).and(barycentric.y.lessThan(barycentric.z));
10462
10043
  positionAlong.assign(select(isYSmallest, float(1).sub(maxXY), maxXY));
10463
10044
  const computedThickness = remap(thicknessUniform, float(0), float(1), float(0), float(0.34)).toVar();
10464
- const squeezeEnabled = squeezeUniform.greaterThan(0.5);
10465
10045
  const squeezeFactor = mix(squeezeMinUniform, squeezeMaxUniform, float(1).sub(sin(positionAlong.mul(Math.PI))));
10466
- computedThickness.assign(select(squeezeEnabled, computedThickness.mul(squeezeFactor), computedThickness));
10467
- const dashEnabled = dashUniform.greaterThan(0.5);
10468
- const dashInverted = dashInvertUniform.greaterThan(0.5);
10046
+ computedThickness.assign(select(squeezeUniform, computedThickness.mul(squeezeFactor), computedThickness));
10469
10047
  const baseOffset = float(1).div(dashRepeatsUniform).mul(dashLengthUniform).mul(0.5);
10470
10048
  const additionalOffset = float(1).div(dashRepeatsUniform).mul(0.5);
10471
- const dashOffset = select(dashInverted, baseOffset, baseOffset.add(additionalOffset));
10049
+ const dashOffset = select(dashInvertUniform, baseOffset, baseOffset.add(additionalOffset));
10472
10050
  const pattern = fract(positionAlong.add(dashOffset).mul(dashRepeatsUniform));
10473
10051
  const dashMask = float(1).sub(aastep(dashLengthUniform, pattern));
10474
- computedThickness.assign(select(dashEnabled, computedThickness.mul(dashMask), computedThickness));
10052
+ computedThickness.assign(select(dashUniform, computedThickness.mul(dashMask), computedThickness));
10475
10053
  const edge = float(1).sub(aastep(computedThickness, d));
10476
- const useBackfaceColor = colorBackfacesUniform.greaterThan(0.5);
10477
10054
  const isFrontFace = frontFacing;
10478
- const currentStroke = select(useBackfaceColor.and(isFrontFace.not()), backfaceStrokeUniform, strokeUniform);
10055
+ const currentStroke = select(colorBackfacesUniform.and(isFrontFace.not()), backfaceStrokeUniform, strokeUniform);
10479
10056
  const colorStroke = vec4(currentStroke, edge);
10480
10057
  const colorFill = vec4(fillUniform, fillOpacityUniform);
10481
10058
  const outColor = mix(colorFill, colorStroke, edge.mul(strokeOpacityUniform));
10482
10059
  return outColor;
10483
10060
  })();
10484
10061
  }
10485
- //* Uniform Accessors ==============================
10486
- /** Stroke (edge) opacity, default: 1 */
10487
- get strokeOpacity() {
10488
- return this._strokeOpacity.value;
10489
- }
10490
- set strokeOpacity(v) {
10491
- this._strokeOpacity.value = v;
10492
- }
10493
- /** Fill opacity (background), default: 0.25 */
10494
- get fillOpacity() {
10495
- return this._fillOpacity.value;
10496
- }
10497
- set fillOpacity(v) {
10498
- this._fillOpacity.value = v;
10499
- }
10500
- /** Mix factor between material color and fill color, default: 0 */
10501
- get fillMix() {
10502
- return this._fillMix.value;
10503
- }
10504
- set fillMix(v) {
10505
- this._fillMix.value = v;
10506
- }
10507
- /** Edge thickness 0-1, default: 0.05 */
10508
- get thickness() {
10509
- return this._thickness.value;
10510
- }
10511
- set thickness(v) {
10512
- this._thickness.value = v;
10513
- }
10514
- /** Use different color for backfaces */
10515
- get colorBackfaces() {
10516
- return this._colorBackfaces.value > 0.5;
10517
- }
10518
- set colorBackfaces(v) {
10519
- this._colorBackfaces.value = v ? 1 : 0;
10520
- }
10521
- /** Invert dash pattern */
10522
- get dashInvert() {
10523
- return this._dashInvert.value > 0.5;
10524
- }
10525
- set dashInvert(v) {
10526
- this._dashInvert.value = v ? 1 : 0;
10527
- }
10528
- /** Enable dashed lines */
10529
- get dash() {
10530
- return this._dash.value > 0.5;
10531
- }
10532
- set dash(v) {
10533
- this._dash.value = v ? 1 : 0;
10534
- }
10535
- /** Number of dash repeats, default: 4 */
10536
- get dashRepeats() {
10537
- return this._dashRepeats.value;
10538
- }
10539
- set dashRepeats(v) {
10540
- this._dashRepeats.value = v;
10541
- }
10542
- /** Dash length 0-1, default: 0.5 */
10543
- get dashLength() {
10544
- return this._dashLength.value;
10545
- }
10546
- set dashLength(v) {
10547
- this._dashLength.value = v;
10548
- }
10549
- /** Squeeze thickness toward line center */
10550
- get squeeze() {
10551
- return this._squeeze.value > 0.5;
10552
- }
10553
- set squeeze(v) {
10554
- this._squeeze.value = v ? 1 : 0;
10555
- }
10556
- /** Minimum squeeze factor, default: 0.2 */
10557
- get squeezeMin() {
10558
- return this._squeezeMin.value;
10559
- }
10560
- set squeezeMin(v) {
10561
- this._squeezeMin.value = v;
10562
- }
10563
- /** Maximum squeeze factor, default: 1 */
10564
- get squeezeMax() {
10565
- return this._squeezeMax.value;
10566
- }
10567
- set squeezeMax(v) {
10568
- this._squeezeMax.value = v;
10569
- }
10570
- /** Stroke (edge) color */
10571
- get stroke() {
10572
- return this._stroke.value;
10573
- }
10574
- set stroke(v) {
10575
- if (v instanceof THREE.Color) this._stroke.value = v;
10576
- else this._stroke.value = new THREE.Color(v);
10577
- }
10578
- /** Backface stroke color */
10579
- get backfaceStroke() {
10580
- return this._backfaceStroke.value;
10581
- }
10582
- set backfaceStroke(v) {
10583
- if (v instanceof THREE.Color) this._backfaceStroke.value = v;
10584
- else this._backfaceStroke.value = new THREE.Color(v);
10585
- }
10586
- /** Fill (background) color */
10587
- get fill() {
10588
- return this._fill.value;
10589
- }
10590
- set fill(v) {
10591
- if (v instanceof THREE.Color) this._fill.value = v;
10592
- else this._fill.value = new THREE.Color(v);
10593
- }
10594
10062
  }
10595
10063
  function setBarycentricCoordinates(geometry) {
10596
10064
  const position = geometry.getAttribute("position");
@@ -10652,9 +10120,9 @@ const WireframeMaterial = /* @__PURE__ */ React.forwardRef(
10652
10120
  squeeze,
10653
10121
  squeezeMin,
10654
10122
  squeezeMax,
10655
- stroke: stroke instanceof THREE.Color ? stroke : new THREE.Color(stroke),
10656
- backfaceStroke: backfaceStroke instanceof THREE.Color ? backfaceStroke : new THREE.Color(backfaceStroke),
10657
- fill: fill instanceof THREE.Color ? fill : new THREE.Color(fill)
10123
+ stroke,
10124
+ backfaceStroke,
10125
+ fill
10658
10126
  }
10659
10127
  );
10660
10128
  }
@@ -10770,52 +10238,74 @@ function Wireframe({ geometry: customGeometry, ...props }) {
10770
10238
  return /* @__PURE__ */ React.createElement(WireframeWithoutCustomGeo, { ...props });
10771
10239
  }
10772
10240
 
10241
+ function isShadowCastingLight(object) {
10242
+ const light = object;
10243
+ return light.isLight === true && light.castShadow === true && light.shadow != null;
10244
+ }
10773
10245
  function BakeShadows() {
10774
- const gl = useThree((state) => state.gl);
10775
- useEffect(() => {
10776
- gl.shadowMap.autoUpdate = false;
10777
- gl.shadowMap.needsUpdate = true;
10246
+ const scene = useThree((state) => state.scene);
10247
+ const priorRef = React.useRef(/* @__PURE__ */ new WeakMap());
10248
+ useFrame(() => {
10249
+ const prior = priorRef.current;
10250
+ scene.traverse((object) => {
10251
+ if (!isShadowCastingLight(object)) return;
10252
+ const shadow = object.shadow;
10253
+ if (prior.has(shadow)) return;
10254
+ prior.set(shadow, { autoUpdate: shadow.autoUpdate, needsUpdate: shadow.needsUpdate });
10255
+ shadow.autoUpdate = false;
10256
+ shadow.needsUpdate = true;
10257
+ });
10258
+ });
10259
+ React.useEffect(() => {
10260
+ const prior = priorRef.current;
10778
10261
  return () => {
10779
- gl.shadowMap.autoUpdate = gl.shadowMap.needsUpdate = true;
10262
+ scene.traverse((object) => {
10263
+ if (!isShadowCastingLight(object)) return;
10264
+ const previous = prior.get(object.shadow);
10265
+ if (previous === void 0) return;
10266
+ object.shadow.autoUpdate = previous.autoUpdate;
10267
+ object.shadow.needsUpdate = previous.needsUpdate;
10268
+ prior.delete(object.shadow);
10269
+ });
10780
10270
  };
10781
- }, [gl.shadowMap]);
10271
+ }, [scene]);
10782
10272
  return null;
10783
10273
  }
10784
10274
 
10785
- class ConvolutionMaterial extends MeshBasicNodeMaterial {
10786
- //* Private Uniform Nodes --
10787
- _inputBuffer;
10788
- _depthBuffer;
10789
- _resolution;
10790
- _texelSize;
10791
- _halfTexelSize;
10792
- _kernel;
10793
- _scale;
10794
- _cameraNear;
10795
- _cameraFar;
10796
- _minDepthThreshold;
10797
- _maxDepthThreshold;
10798
- _depthScale;
10799
- _depthToBlurRatioBias;
10800
- _useDepth;
10275
+ class ConvolutionMaterial extends withUniforms(MeshBasicNodeMaterial, {
10276
+ /** Input color buffer to blur */
10277
+ inputBuffer: () => uniformTexture(new THREE.Texture()),
10278
+ /** Depth buffer for depth-aware blur */
10279
+ depthBuffer: () => uniformTexture(new THREE.Texture()),
10280
+ /** Render resolution */
10281
+ resolution: () => uniform(new THREE.Vector2()),
10282
+ /** Texel size (1/resolution) */
10283
+ texelSize: () => uniform(new THREE.Vector2()),
10284
+ /** Half texel size for offset calculations */
10285
+ halfTexelSize: () => uniform(new THREE.Vector2()),
10286
+ /** Kernel offset multiplier (changes per blur pass) */
10287
+ kernelValue: () => uniform(0),
10288
+ /** Scale factor for blur spread */
10289
+ scale: () => uniform(1),
10290
+ /** Camera near plane for depth calculations */
10291
+ cameraNear: () => uniform(0),
10292
+ /** Camera far plane for depth calculations */
10293
+ cameraFar: () => uniform(1),
10294
+ /** Minimum depth threshold for blur (objects closer than this get less blur) */
10295
+ minDepthThreshold: () => uniform(0),
10296
+ /** Maximum depth threshold for blur (objects farther than this get full blur) */
10297
+ maxDepthThreshold: () => uniform(1),
10298
+ /** Scale factor for depth-based blur adjustment */
10299
+ depthScale: () => uniform(0),
10300
+ /** Bias added to depth-to-blur ratio */
10301
+ depthToBlurRatioBias: () => uniform(0.25),
10302
+ /** Enable depth-based blur */
10303
+ useDepth: () => uniform(false)
10304
+ }) {
10801
10305
  /** Kernel weights for multi-pass blur */
10802
10306
  kernel;
10803
10307
  constructor(texelSize = new THREE.Vector2()) {
10804
10308
  super();
10805
- this._inputBuffer = uniformTexture(new THREE.Texture());
10806
- this._depthBuffer = uniformTexture(new THREE.Texture());
10807
- this._resolution = uniform(new THREE.Vector2());
10808
- this._texelSize = uniform(new THREE.Vector2());
10809
- this._halfTexelSize = uniform(new THREE.Vector2());
10810
- this._kernel = uniform(0);
10811
- this._scale = uniform(1);
10812
- this._cameraNear = uniform(0);
10813
- this._cameraFar = uniform(1);
10814
- this._minDepthThreshold = uniform(0);
10815
- this._maxDepthThreshold = uniform(1);
10816
- this._depthScale = uniform(0);
10817
- this._depthToBlurRatioBias = uniform(0.25);
10818
- this._useDepth = uniform(0);
10819
10309
  this.blending = THREE.NoBlending;
10820
10310
  this.depthWrite = false;
10821
10311
  this.depthTest = false;
@@ -10825,16 +10315,19 @@ class ConvolutionMaterial extends MeshBasicNodeMaterial {
10825
10315
  this._buildShader();
10826
10316
  }
10827
10317
  _buildShader() {
10828
- const inputBufferTex = this._inputBuffer;
10829
- const depthBufferTex = this._depthBuffer;
10830
- const texelSizeUniform = this._texelSize;
10831
- const halfTexelSizeUniform = this._halfTexelSize;
10832
- const kernelUniform = this._kernel;
10833
- const scaleUniform = this._scale;
10834
- const minDepthThresholdUniform = this._minDepthThreshold;
10835
- const maxDepthThresholdUniform = this._maxDepthThreshold;
10836
- const depthScaleUniform = this._depthScale;
10837
- const useDepthUniform = this._useDepth;
10318
+ const {
10319
+ inputBuffer: inputBufferTex,
10320
+ depthBuffer: depthBufferTex,
10321
+ texelSize: texelSizeUniform,
10322
+ halfTexelSize: halfTexelSizeUniform,
10323
+ kernelValue: kernelUniform,
10324
+ scale: scaleUniform,
10325
+ minDepthThreshold: minDepthThresholdUniform,
10326
+ maxDepthThreshold: maxDepthThresholdUniform,
10327
+ depthScale: depthScaleUniform,
10328
+ depthToBlurRatioBias: depthToBlurRatioBiasUniform,
10329
+ useDepth: useDepthUniform
10330
+ } = this.uniforms;
10838
10331
  const baseUv = varying(uv(), "vUv");
10839
10332
  const dUv = varying(
10840
10333
  Fn(() => {
@@ -10848,17 +10341,16 @@ class ConvolutionMaterial extends MeshBasicNodeMaterial {
10848
10341
  const vUv3 = varying(Fn(() => vec2$2(baseUv.x.sub(dUv.x), baseUv.y.sub(dUv.y)))(), "vUv3");
10849
10342
  this.colorNode = Fn(() => {
10850
10343
  const depthFactor = float(0).toVar();
10851
- const isUsingDepth = useDepthUniform.greaterThan(0.5);
10852
- const depthSample = texture(depthBufferTex, baseUv);
10344
+ const depthSample = depthBufferTex.sample(baseUv);
10853
10345
  const rawDepth = float(1).sub(depthSample.r.mul(depthSample.a));
10854
10346
  const smoothedDepth = smoothstep(minDepthThresholdUniform, maxDepthThresholdUniform, rawDepth);
10855
10347
  const scaledDepth = smoothedDepth.mul(depthScaleUniform);
10856
- const clampedDepth = max(float(0), min(float(1), scaledDepth.add(0.25)));
10857
- depthFactor.assign(select(isUsingDepth, clampedDepth, float(0)));
10858
- const sample0 = texture(inputBufferTex, mix(vUv0, baseUv, depthFactor));
10859
- const sample1 = texture(inputBufferTex, mix(vUv1, baseUv, depthFactor));
10860
- const sample2 = texture(inputBufferTex, mix(vUv2, baseUv, depthFactor));
10861
- const sample3 = texture(inputBufferTex, mix(vUv3, baseUv, depthFactor));
10348
+ const clampedDepth = max(float(0), min(float(1), scaledDepth.add(depthToBlurRatioBiasUniform)));
10349
+ depthFactor.assign(select(useDepthUniform, clampedDepth, float(0)));
10350
+ const sample0 = inputBufferTex.sample(mix(vUv0, baseUv, depthFactor));
10351
+ const sample1 = inputBufferTex.sample(mix(vUv1, baseUv, depthFactor));
10352
+ const sample2 = inputBufferTex.sample(mix(vUv2, baseUv, depthFactor));
10353
+ const sample3 = inputBufferTex.sample(mix(vUv3, baseUv, depthFactor));
10862
10354
  const sum = sample0.add(sample1).add(sample2).add(sample3);
10863
10355
  return sum.mul(0.25);
10864
10356
  })();
@@ -10866,111 +10358,12 @@ class ConvolutionMaterial extends MeshBasicNodeMaterial {
10866
10358
  //* Utility Methods ==============================
10867
10359
  /** Set texel size for blur calculations */
10868
10360
  setTexelSize(x, y) {
10869
- this._texelSize.value.set(x, y);
10870
- this._halfTexelSize.value.set(x * 0.5, y * 0.5);
10361
+ this.uniforms.texelSize.value.set(x, y);
10362
+ this.uniforms.halfTexelSize.value.set(x * 0.5, y * 0.5);
10871
10363
  }
10872
10364
  /** Set render resolution */
10873
10365
  setResolution(resolution) {
10874
- this._resolution.value.copy(resolution);
10875
- }
10876
- //* Uniform Accessors ==============================
10877
- /** Input color buffer to blur */
10878
- get inputBuffer() {
10879
- return this._inputBuffer.value;
10880
- }
10881
- set inputBuffer(v) {
10882
- this._inputBuffer.value = v ?? new THREE.Texture();
10883
- }
10884
- /** Depth buffer for depth-aware blur */
10885
- get depthBuffer() {
10886
- return this._depthBuffer.value;
10887
- }
10888
- set depthBuffer(v) {
10889
- this._depthBuffer.value = v ?? new THREE.Texture();
10890
- }
10891
- /** Render resolution */
10892
- get resolution() {
10893
- return this._resolution.value;
10894
- }
10895
- set resolution(v) {
10896
- this._resolution.value = v;
10897
- }
10898
- /** Texel size (1/resolution) */
10899
- get texelSize() {
10900
- return this._texelSize.value;
10901
- }
10902
- set texelSize(v) {
10903
- this._texelSize.value = v;
10904
- }
10905
- /** Half texel size for offset calculations */
10906
- get halfTexelSize() {
10907
- return this._halfTexelSize.value;
10908
- }
10909
- set halfTexelSize(v) {
10910
- this._halfTexelSize.value = v;
10911
- }
10912
- /** Kernel offset multiplier (changes per blur pass) */
10913
- get kernelValue() {
10914
- return this._kernel.value;
10915
- }
10916
- set kernelValue(v) {
10917
- this._kernel.value = v;
10918
- }
10919
- /** Scale factor for blur spread */
10920
- get scale() {
10921
- return this._scale.value;
10922
- }
10923
- set scale(v) {
10924
- this._scale.value = v;
10925
- }
10926
- /** Camera near plane for depth calculations */
10927
- get cameraNear() {
10928
- return this._cameraNear.value;
10929
- }
10930
- set cameraNear(v) {
10931
- this._cameraNear.value = v;
10932
- }
10933
- /** Camera far plane for depth calculations */
10934
- get cameraFar() {
10935
- return this._cameraFar.value;
10936
- }
10937
- set cameraFar(v) {
10938
- this._cameraFar.value = v;
10939
- }
10940
- /** Minimum depth threshold for blur (objects closer than this get less blur) */
10941
- get minDepthThreshold() {
10942
- return this._minDepthThreshold.value;
10943
- }
10944
- set minDepthThreshold(v) {
10945
- this._minDepthThreshold.value = v;
10946
- }
10947
- /** Maximum depth threshold for blur (objects farther than this get full blur) */
10948
- get maxDepthThreshold() {
10949
- return this._maxDepthThreshold.value;
10950
- }
10951
- set maxDepthThreshold(v) {
10952
- this._maxDepthThreshold.value = v;
10953
- }
10954
- /** Scale factor for depth-based blur adjustment */
10955
- get depthScale() {
10956
- return this._depthScale.value;
10957
- }
10958
- set depthScale(v) {
10959
- this._depthScale.value = v;
10960
- }
10961
- /** Bias added to depth-to-blur ratio */
10962
- get depthToBlurRatioBias() {
10963
- return this._depthToBlurRatioBias.value;
10964
- }
10965
- set depthToBlurRatioBias(v) {
10966
- this._depthToBlurRatioBias.value = v;
10967
- }
10968
- /** Enable/disable depth-based blur (0 = off, 1 = on) */
10969
- get useDepth() {
10970
- return this._useDepth.value > 0.5;
10971
- }
10972
- set useDepth(v) {
10973
- this._useDepth.value = v ? 1 : 0;
10366
+ this.uniforms.resolution.value.copy(resolution);
10974
10367
  }
10975
10368
  }
10976
10369
 
@@ -11168,28 +10561,26 @@ const Image = /* @__PURE__ */ React.forwardRef((props, ref) => {
11168
10561
  else throw new Error("<Image /> requires a url or texture");
11169
10562
  });
11170
10563
 
11171
- class SpotLightMaterial extends MeshBasicNodeMaterial {
11172
- //* Private Uniform Nodes --
11173
- _depth;
11174
- _opacity;
11175
- _attenuation;
11176
- _anglePower;
11177
- _spotPosition;
11178
- _lightColor;
11179
- _cameraNear;
11180
- _cameraFar;
11181
- _resolution;
10564
+ class SpotLightMaterial extends withUniforms(MeshBasicNodeMaterial, {
10565
+ /** Scene depth (in the R channel) for soft intersection with scene geometry */
10566
+ depth: () => uniformTexture(new THREE.Texture()),
10567
+ /** Distance attenuation factor, default: 5 */
10568
+ attenuation: () => uniform(5),
10569
+ /** Angle falloff power - higher = sharper edges, default: 5 */
10570
+ anglePower: () => uniform(5),
10571
+ /** World position of the cone tip */
10572
+ spotPosition: () => uniform(new THREE.Vector3(0, 0, 0)),
10573
+ /** Light color, default: white */
10574
+ lightColor: () => uniform(new THREE.Color("white")),
10575
+ /** Camera near plane, for depth reconstruction */
10576
+ cameraNear: () => uniform(0.1),
10577
+ /** Camera far plane, for depth reconstruction */
10578
+ cameraFar: () => uniform(100),
10579
+ /** Drawing-buffer size in pixels. Zero disables depth-based soft edges. */
10580
+ resolution: () => uniform(new THREE.Vector2(0, 0))
10581
+ }) {
11182
10582
  constructor() {
11183
10583
  super();
11184
- this._depth = uniformTexture(new THREE.Texture());
11185
- this._opacity = uniform(1);
11186
- this._attenuation = uniform(5);
11187
- this._anglePower = uniform(5);
11188
- this._spotPosition = uniform(new THREE.Vector3(0, 0, 0));
11189
- this._lightColor = uniform(new THREE.Color("white"));
11190
- this._cameraNear = uniform(0.1);
11191
- this._cameraFar = uniform(100);
11192
- this._resolution = uniform(new THREE.Vector2(0, 0));
11193
10584
  this.transparent = true;
11194
10585
  this.depthWrite = false;
11195
10586
  this.side = THREE.DoubleSide;
@@ -11197,15 +10588,16 @@ class SpotLightMaterial extends MeshBasicNodeMaterial {
11197
10588
  }
11198
10589
  //* Build TSL Shader ==============================
11199
10590
  _buildShader() {
11200
- const depthTex = this._depth;
11201
- const opacityUniform = this._opacity;
11202
- const attenuationUniform = this._attenuation;
11203
- const anglePowerUniform = this._anglePower;
11204
- const spotPositionUniform = this._spotPosition;
11205
- const lightColorUniform = this._lightColor;
11206
- const cameraNearUniform = this._cameraNear;
11207
- const cameraFarUniform = this._cameraFar;
11208
- const resolutionUniform = this._resolution;
10591
+ const {
10592
+ depth: depthTex,
10593
+ attenuation: attenuationUniform,
10594
+ anglePower: anglePowerUniform,
10595
+ spotPosition: spotPositionUniform,
10596
+ lightColor: lightColorUniform,
10597
+ cameraNear: cameraNearUniform,
10598
+ cameraFar: cameraFarUniform,
10599
+ resolution: resolutionUniform
10600
+ } = this.uniforms;
11209
10601
  const vNormal = varying(normalize(modelViewMatrix.transformDirection(normalLocal)), "vNormal");
11210
10602
  const vIntensity = varying(
11211
10603
  saturate(float(1).sub(distance(positionWorld, spotPositionUniform).div(attenuationUniform))),
@@ -11220,79 +10612,27 @@ class SpotLightMaterial extends MeshBasicNodeMaterial {
11220
10612
  screenCoordinate.x.div(resolutionUniform.x),
11221
10613
  float(1).sub(screenCoordinate.y.div(resolutionUniform.y))
11222
10614
  );
11223
- const sampledDepth = texture(depthTex, screenUV).r;
10615
+ const sampledDepth = depthTex.sample(screenUV).r;
11224
10616
  const near = cameraNearUniform;
11225
10617
  const far = cameraFarUniform;
11226
10618
  const sceneViewZ = near.mul(far).div(far.sub(near).mul(sampledDepth).sub(far));
11227
10619
  const depthDiff = vViewZ.sub(sceneViewZ);
11228
10620
  const softFactor = smoothstep(float(0), float(1), depthDiff);
11229
10621
  intensity.assign(select(hasDepth, intensity.mul(softFactor), intensity));
11230
- return vec4(lightColorUniform, intensity.mul(opacityUniform));
10622
+ return vec4(lightColorUniform, intensity.mul(materialOpacity));
11231
10623
  })();
11232
10624
  }
11233
- //* Uniform Accessors ==============================
11234
- get depth() {
11235
- return this._depth?.value;
11236
- }
11237
- set depth(v) {
11238
- if (this._depth) this._depth.value = v ?? new THREE.Texture();
11239
- }
11240
- get opacity() {
11241
- return this._opacity?.value;
11242
- }
11243
- set opacity(v) {
11244
- if (this._opacity) this._opacity.value = v;
11245
- }
11246
- get attenuation() {
11247
- return this._attenuation?.value;
11248
- }
11249
- set attenuation(v) {
11250
- if (this._attenuation) this._attenuation.value = v;
11251
- }
11252
- get anglePower() {
11253
- return this._anglePower?.value;
11254
- }
11255
- set anglePower(v) {
11256
- if (this._anglePower) this._anglePower.value = v;
11257
- }
11258
- get spotPosition() {
11259
- return this._spotPosition?.value;
11260
- }
11261
- set spotPosition(v) {
11262
- if (this._spotPosition) this._spotPosition.value = v;
11263
- }
11264
- get lightColor() {
11265
- return this._lightColor?.value;
11266
- }
11267
- set lightColor(v) {
11268
- if (this._lightColor) this._lightColor.value = v;
11269
- }
11270
- get cameraNear() {
11271
- return this._cameraNear?.value;
11272
- }
11273
- set cameraNear(v) {
11274
- if (this._cameraNear) this._cameraNear.value = v;
11275
- }
11276
- get cameraFar() {
11277
- return this._cameraFar?.value;
11278
- }
11279
- set cameraFar(v) {
11280
- if (this._cameraFar) this._cameraFar.value = v;
11281
- }
11282
- get resolution() {
11283
- return this._resolution?.value;
11284
- }
11285
- set resolution(v) {
11286
- if (this._resolution) this._resolution.value = v;
11287
- }
11288
10625
  }
11289
10626
 
11290
- class StarfieldMaterial extends SpriteNodeMaterial {
11291
- //* Uniforms ==============================
11292
- _time = uniform(0);
11293
- _fade = uniform(1);
10627
+ class StarfieldMaterial extends withUniforms(SpriteNodeMaterial, {
10628
+ /** Animation time, advanced by the component each frame */
10629
+ time: () => uniform(0),
10630
+ /** 1 = soft circular fade, 0 = hard-edged circle */
10631
+ fade: () => uniform(1)
10632
+ }) {
11294
10633
  constructor() {
11295
10634
  super();
10635
+ const { time, fade } = this.uniforms;
11296
10636
  this.transparent = true;
11297
10637
  this.depthWrite = false;
11298
10638
  this.blending = AdditiveBlending;
@@ -11306,7 +10646,7 @@ class StarfieldMaterial extends SpriteNodeMaterial {
11306
10646
  const worldPos = modelWorldMatrix.mul(vec4(this.positionNode, 1));
11307
10647
  const viewPos = cameraViewMatrix.mul(worldPos);
11308
10648
  const distanceAttenuation = float(30).div(viewPos.z.negate());
11309
- const timeScale = float(3.5).add(sin(this._time.add(100)).mul(0.3));
10649
+ const timeScale = float(3.5).add(sin(time.add(100)).mul(0.3));
11310
10650
  const size = particleSize.mul(distanceAttenuation).mul(timeScale).mul(0.04);
11311
10651
  return vec2$2(size);
11312
10652
  })();
@@ -11315,38 +10655,28 @@ class StarfieldMaterial extends SpriteNodeMaterial {
11315
10655
  const d = length(quadUV.sub(vec2$2(0.5)));
11316
10656
  const softFade = float(1).div(float(1).add(exp(float(16).mul(d.sub(0.25)))));
11317
10657
  const hardMask = float(1).sub(d.smoothstep(0.3, 0.5));
11318
- const circularOpacity = select(this._fade.equal(1), softFade, hardMask);
10658
+ const circularOpacity = select(fade.equal(1), softFade, hardMask);
11319
10659
  const opacity = circularOpacity.mul(0.7);
11320
10660
  return vec4(particleColor, opacity);
11321
10661
  })();
11322
10662
  }
11323
- //* Uniform Accessors ==============================
11324
10663
  setTime(time) {
11325
- this._time.value = time;
10664
+ this.time = time;
11326
10665
  }
11327
10666
  setFade(fade) {
11328
- this._fade.value = fade;
11329
- }
11330
- get time() {
11331
- return this._time.value;
11332
- }
11333
- set time(value) {
11334
- this._time.value = value;
11335
- }
11336
- get fade() {
11337
- return this._fade.value;
11338
- }
11339
- set fade(value) {
11340
- this._fade.value = value;
10667
+ this.fade = fade;
11341
10668
  }
11342
10669
  }
11343
10670
 
11344
- class SparklesMaterial extends SpriteNodeMaterial {
11345
- // Uniforms exposed for external updates
11346
- _time = uniform(0);
11347
- _pixelRatio = uniform(1);
10671
+ class SparklesMaterial extends withUniforms(SpriteNodeMaterial, {
10672
+ /** Animation time, advanced by the component each frame */
10673
+ time: () => uniform(0),
10674
+ /** Device pixel ratio, scales the point size */
10675
+ pixelRatio: () => uniform(1)
10676
+ }) {
11348
10677
  constructor() {
11349
10678
  super();
10679
+ const { time, pixelRatio } = this.uniforms;
11350
10680
  this.transparent = true;
11351
10681
  this.depthWrite = false;
11352
10682
  const particlePosition = attribute("particlePosition", "vec3");
@@ -11357,13 +10687,13 @@ class SparklesMaterial extends SpriteNodeMaterial {
11357
10687
  const particleColor = attribute("color", "vec3");
11358
10688
  this.positionNode = Fn(() => {
11359
10689
  const pos = particlePosition.toVar();
11360
- pos.y.addAssign(sin(this._time.mul(particleSpeed).add(pos.x.mul(particleNoise.x).mul(100))).mul(0.2));
11361
- pos.z.addAssign(cos(this._time.mul(particleSpeed).add(pos.x.mul(particleNoise.y).mul(100))).mul(0.2));
11362
- pos.x.addAssign(cos(this._time.mul(particleSpeed).add(pos.x.mul(particleNoise.z).mul(100))).mul(0.2));
10690
+ pos.y.addAssign(sin(time.mul(particleSpeed).add(pos.x.mul(particleNoise.x).mul(100))).mul(0.2));
10691
+ pos.z.addAssign(cos(time.mul(particleSpeed).add(pos.x.mul(particleNoise.y).mul(100))).mul(0.2));
10692
+ pos.x.addAssign(cos(time.mul(particleSpeed).add(pos.x.mul(particleNoise.z).mul(100))).mul(0.2));
11363
10693
  return pos;
11364
10694
  })();
11365
10695
  this.scaleNode = Fn(() => {
11366
- const pixelSize = particleSize.mul(25).mul(this._pixelRatio);
10696
+ const pixelSize = particleSize.mul(25).mul(pixelRatio);
11367
10697
  const projY = cameraProjectionMatrix.element(1).y;
11368
10698
  const viewportH = screenSize.y;
11369
10699
  const size = pixelSize.mul(2).div(projY.mul(viewportH));
@@ -11376,82 +10706,67 @@ class SparklesMaterial extends SpriteNodeMaterial {
11376
10706
  return vec4(particleColor, strength.mul(particleOpacity));
11377
10707
  })();
11378
10708
  }
11379
- //* Uniform Accessors --------------------------------
11380
- get time() {
11381
- return this._time.value;
11382
- }
11383
- set time(value) {
11384
- this._time.value = value;
11385
- }
11386
- get pixelRatio() {
11387
- return this._pixelRatio.value;
11388
- }
11389
- set pixelRatio(value) {
11390
- this._pixelRatio.value = value;
11391
- }
11392
- }
11393
-
11394
- class GridMaterialImpl extends MeshBasicNodeMaterial {
11395
- //* Private Uniform Nodes --
11396
- _cellSize;
11397
- _sectionSize;
11398
- _fadeDistance;
11399
- _fadeStrength;
11400
- _fadeFrom;
11401
- _cellThickness;
11402
- _sectionThickness;
11403
- _cellColor;
11404
- _sectionColor;
11405
- _infiniteGrid;
11406
- // bool as 0/1
11407
- _followCamera;
11408
- // bool as 0/1
11409
- _worldCamProjPosition;
11410
- _worldPlanePosition;
10709
+ }
10710
+
10711
+ class GridMaterialImpl extends withUniforms(MeshBasicNodeMaterial, {
10712
+ /** Cell size, default: 0.5 */
10713
+ cellSize: () => uniform(0.5),
10714
+ /** Section size, default: 1 */
10715
+ sectionSize: () => uniform(1),
10716
+ /** Fade distance, default: 100 */
10717
+ fadeDistance: () => uniform(100),
10718
+ /** Fade strength, default: 1 */
10719
+ fadeStrength: () => uniform(1),
10720
+ /** Fade from camera (1) or origin (0), default: 1 */
10721
+ fadeFrom: () => uniform(1),
10722
+ /** Cell thickness, default: 0.5 */
10723
+ cellThickness: () => uniform(0.5),
10724
+ /** Section thickness, default: 1 */
10725
+ sectionThickness: () => uniform(1),
10726
+ /** Cell color, default: black */
10727
+ cellColor: () => uniform(new THREE.Color("#000000")),
10728
+ /** Section color, default: #2080ff */
10729
+ sectionColor: () => uniform(new THREE.Color("#2080ff")),
10730
+ /** Display the grid infinitely */
10731
+ infiniteGrid: () => uniform(false),
10732
+ /** Follow camera position */
10733
+ followCamera: () => uniform(false),
10734
+ /** Camera projection position on plane (set by component) */
10735
+ worldCamProjPosition: () => uniform(new THREE.Vector3()),
10736
+ /** Plane world position (set by component) */
10737
+ worldPlanePosition: () => uniform(new THREE.Vector3())
10738
+ }) {
11411
10739
  /** Type flag for identification */
11412
10740
  isGridMaterial = true;
11413
10741
  constructor() {
11414
10742
  super();
11415
- this._cellSize = uniform(0.5);
11416
- this._sectionSize = uniform(1);
11417
- this._fadeDistance = uniform(100);
11418
- this._fadeStrength = uniform(1);
11419
- this._fadeFrom = uniform(1);
11420
- this._cellThickness = uniform(0.5);
11421
- this._sectionThickness = uniform(1);
11422
- this._cellColor = uniform(new THREE.Color("#000000"));
11423
- this._sectionColor = uniform(new THREE.Color("#2080ff"));
11424
- this._infiniteGrid = uniform(0);
11425
- this._followCamera = uniform(0);
11426
- this._worldCamProjPosition = uniform(new THREE.Vector3());
11427
- this._worldPlanePosition = uniform(new THREE.Vector3());
11428
10743
  this.transparent = true;
11429
10744
  this.side = THREE.BackSide;
11430
10745
  this._buildGridShader();
11431
10746
  }
11432
10747
  _buildGridShader() {
11433
- const cellSizeUniform = this._cellSize;
11434
- const sectionSizeUniform = this._sectionSize;
11435
- const fadeDistanceUniform = this._fadeDistance;
11436
- const fadeStrengthUniform = this._fadeStrength;
11437
- const fadeFromUniform = this._fadeFrom;
11438
- const cellThicknessUniform = this._cellThickness;
11439
- const sectionThicknessUniform = this._sectionThickness;
11440
- const cellColorUniform = this._cellColor;
11441
- const sectionColorUniform = this._sectionColor;
11442
- const infiniteGridUniform = this._infiniteGrid;
11443
- const followCameraUniform = this._followCamera;
11444
- const worldCamProjPositionUniform = this._worldCamProjPosition;
11445
- const worldPlanePositionUniform = this._worldPlanePosition;
10748
+ const {
10749
+ cellSize: cellSizeUniform,
10750
+ sectionSize: sectionSizeUniform,
10751
+ fadeDistance: fadeDistanceUniform,
10752
+ fadeStrength: fadeStrengthUniform,
10753
+ fadeFrom: fadeFromUniform,
10754
+ cellThickness: cellThicknessUniform,
10755
+ sectionThickness: sectionThicknessUniform,
10756
+ cellColor: cellColorUniform,
10757
+ sectionColor: sectionColorUniform,
10758
+ infiniteGrid: infiniteGridUniform,
10759
+ followCamera: followCameraUniform,
10760
+ worldCamProjPosition: worldCamProjPositionUniform,
10761
+ worldPlanePosition: worldPlanePositionUniform
10762
+ } = this.uniforms;
11446
10763
  const computeLocalPosition = Fn(() => {
11447
10764
  const pos = positionGeometry;
11448
10765
  let localPos = vec3(pos.x, pos.z, pos.y).toVar();
11449
- const isInfinite = infiniteGridUniform.greaterThan(0.5);
11450
10766
  const scaleFactor = float(1).add(fadeDistanceUniform);
11451
- localPos.assign(select(isInfinite, localPos.mul(scaleFactor), localPos));
11452
- const isFollowCamera = followCameraUniform.greaterThan(0.5);
10767
+ localPos.assign(select(infiniteGridUniform, localPos.mul(scaleFactor), localPos));
11453
10768
  const cameraOffset = worldCamProjPositionUniform.sub(worldPlanePositionUniform);
11454
- localPos.assign(select(isFollowCamera, localPos.add(cameraOffset), localPos));
10769
+ localPos.assign(select(followCameraUniform, localPos.add(cameraOffset), localPos));
11455
10770
  return localPos;
11456
10771
  });
11457
10772
  const vLocalPosition = varying(computeLocalPosition(), "vLocalPosition");
@@ -11463,12 +10778,10 @@ class GridMaterialImpl extends MeshBasicNodeMaterial {
11463
10778
  this.positionNode = Fn(() => {
11464
10779
  const pos = positionGeometry;
11465
10780
  let localPos = vec3(pos.x, pos.z, pos.y).toVar();
11466
- const isInfinite = infiniteGridUniform.greaterThan(0.5);
11467
10781
  const scaleFactor = float(1).add(fadeDistanceUniform);
11468
- localPos.assign(select(isInfinite, localPos.mul(scaleFactor), localPos));
11469
- const isFollowCamera = followCameraUniform.greaterThan(0.5);
10782
+ localPos.assign(select(infiniteGridUniform, localPos.mul(scaleFactor), localPos));
11470
10783
  const cameraOffset = worldCamProjPositionUniform.sub(worldPlanePositionUniform);
11471
- localPos.assign(select(isFollowCamera, localPos.add(cameraOffset), localPos));
10784
+ localPos.assign(select(followCameraUniform, localPos.add(cameraOffset), localPos));
11472
10785
  return localPos;
11473
10786
  })();
11474
10787
  const getGrid = Fn((inputs) => {
@@ -11494,100 +10807,6 @@ class GridMaterialImpl extends MeshBasicNodeMaterial {
11494
10807
  return vec4(gridColor, finalAlpha);
11495
10808
  })();
11496
10809
  }
11497
- //* Uniform Accessors ==============================
11498
- /** Cell size, default: 0.5 */
11499
- get cellSize() {
11500
- return this._cellSize.value;
11501
- }
11502
- set cellSize(v) {
11503
- this._cellSize.value = v;
11504
- }
11505
- /** Section size, default: 1 */
11506
- get sectionSize() {
11507
- return this._sectionSize.value;
11508
- }
11509
- set sectionSize(v) {
11510
- this._sectionSize.value = v;
11511
- }
11512
- /** Fade distance, default: 100 */
11513
- get fadeDistance() {
11514
- return this._fadeDistance.value;
11515
- }
11516
- set fadeDistance(v) {
11517
- this._fadeDistance.value = v;
11518
- }
11519
- /** Fade strength, default: 1 */
11520
- get fadeStrength() {
11521
- return this._fadeStrength.value;
11522
- }
11523
- set fadeStrength(v) {
11524
- this._fadeStrength.value = v;
11525
- }
11526
- /** Fade from camera (1) or origin (0), default: 1 */
11527
- get fadeFrom() {
11528
- return this._fadeFrom.value;
11529
- }
11530
- set fadeFrom(v) {
11531
- this._fadeFrom.value = v;
11532
- }
11533
- /** Cell thickness, default: 0.5 */
11534
- get cellThickness() {
11535
- return this._cellThickness.value;
11536
- }
11537
- set cellThickness(v) {
11538
- this._cellThickness.value = v;
11539
- }
11540
- /** Section thickness, default: 1 */
11541
- get sectionThickness() {
11542
- return this._sectionThickness.value;
11543
- }
11544
- set sectionThickness(v) {
11545
- this._sectionThickness.value = v;
11546
- }
11547
- /** Cell color */
11548
- get cellColor() {
11549
- return this._cellColor.value;
11550
- }
11551
- set cellColor(v) {
11552
- if (v instanceof THREE.Color) this._cellColor.value = v;
11553
- else this._cellColor.value = new THREE.Color(v);
11554
- }
11555
- /** Section color */
11556
- get sectionColor() {
11557
- return this._sectionColor.value;
11558
- }
11559
- set sectionColor(v) {
11560
- if (v instanceof THREE.Color) this._sectionColor.value = v;
11561
- else this._sectionColor.value = new THREE.Color(v);
11562
- }
11563
- /** Display the grid infinitely */
11564
- get infiniteGrid() {
11565
- return this._infiniteGrid.value > 0.5;
11566
- }
11567
- set infiniteGrid(v) {
11568
- this._infiniteGrid.value = v ? 1 : 0;
11569
- }
11570
- /** Follow camera position */
11571
- get followCamera() {
11572
- return this._followCamera.value > 0.5;
11573
- }
11574
- set followCamera(v) {
11575
- this._followCamera.value = v ? 1 : 0;
11576
- }
11577
- /** Camera projection position on plane (set by component) */
11578
- get worldCamProjPosition() {
11579
- return this._worldCamProjPosition.value;
11580
- }
11581
- set worldCamProjPosition(v) {
11582
- this._worldCamProjPosition.value = v;
11583
- }
11584
- /** Plane world position (set by component) */
11585
- get worldPlanePosition() {
11586
- return this._worldPlanePosition.value;
11587
- }
11588
- set worldPlanePosition(v) {
11589
- this._worldPlanePosition.value = v;
11590
- }
11591
10810
  }
11592
10811
  const Grid = /* @__PURE__ */ React.forwardRef(
11593
10812
  ({