@react-three/drei 11.0.0-alpha.4 → 11.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/native/index.mjs CHANGED
@@ -1,56 +1,48 @@
1
1
  import * as React from 'react';
2
- import { forwardRef, useImperativeHandle, useMemo, useEffect, useCallback, useRef, useLayoutEffect, useState, Fragment, createContext, useContext } from 'react';
2
+ import { forwardRef, useImperativeHandle, useRef, useMemo, useEffect, useCallback, useLayoutEffect, useState, Fragment, createContext, useContext } from 'react';
3
3
  import { useThree, useFrame, extend, createPortal, applyProps, useInstanceHandle, context as context$a, useLoader, addEffect, addAfterEffect } from '@react-three/fiber';
4
4
  import * as THREE from 'three/webgpu';
5
- import { MeshBasicNodeMaterial, REVISION, RenderTarget, MeshNormalNodeMaterial, MeshPhysicalNodeMaterial, Frustum, Matrix4, QuadMesh, Line2NodeMaterial, Vector3, Vector4, Vector2, Color, InstancedInterleavedBuffer, InterleavedBufferAttribute, Object3D, WebGLCubeRenderTarget, HalfFloatType, CubeCamera as CubeCamera$1, MathUtils, TextureLoader, Texture as Texture$1, MeshLambertMaterial, Quaternion, DynamicDrawUsage, CatmullRomCurve3, CubicBezierCurve3, QuadraticBezierCurve3, Shape as Shape$1, CanvasTexture, DoubleSide, PerspectiveCamera as PerspectiveCamera$1, OrthographicCamera as OrthographicCamera$1, AudioListener, AudioLoader, AnimationMixer, BufferAttribute, Box3, Sphere as Sphere$1, InstancedBufferAttribute, DepthTexture, DepthFormat, UnsignedShortType, CubeTextureLoader, DefaultLoadingManager, Ray, Raycaster, Camera, CubeReflectionMapping, EquirectangularReflectionMapping, Scene, RepeatWrapping, WebGLRenderTarget, LinearFilter, BufferGeometry, Mesh, SpriteNodeMaterial, AdditiveBlending, CylinderGeometry } from 'three/webgpu';
6
- import { ArcballControls as ArcballControls$1 } from 'three/examples/jsm/controls/ArcballControls.js';
7
- import { DeviceOrientationControls as DeviceOrientationControls$1 } from 'three-stdlib';
8
- import { useGesture } from '@use-gesture/react';
9
- import { FirstPersonControls as FirstPersonControls$1 } from 'three/examples/jsm/controls/FirstPersonControls.js';
10
- import { FlyControls as FlyControls$1 } from 'three/examples/jsm/controls/FlyControls.js';
11
- import { create as create$1 } from 'zustand';
12
- import { subscribeWithSelector } from 'zustand/middleware';
13
- import { MapControls as MapControls$1 } from 'three/examples/jsm/controls/MapControls.js';
14
- import { misc, easing } from 'maath';
15
- import { OrbitControls as OrbitControls$1 } from 'three/addons/controls/OrbitControls.js';
16
- import { PointerLockControls as PointerLockControls$1 } from 'three/examples/jsm/controls/PointerLockControls.js';
17
- import * as ReactDOM from 'react-dom/client';
18
- import { TrackballControls as TrackballControls$1 } from 'three/examples/jsm/controls/TrackballControls.js';
5
+ import { MeshBasicNodeMaterial, RenderTarget, MeshNormalNodeMaterial, MeshPhysicalNodeMaterial, Frustum, Matrix4, QuadMesh, Line2NodeMaterial, Vector3, Vector4, Vector2, Color, InstancedInterleavedBuffer, InterleavedBufferAttribute, Object3D, WebGLCubeRenderTarget, HalfFloatType, CubeCamera as CubeCamera$1, EventDispatcher, Euler, Quaternion, MathUtils, TextureLoader, Texture as Texture$1, MeshLambertMaterial, DynamicDrawUsage, CatmullRomCurve3, CubicBezierCurve3, QuadraticBezierCurve3, Shape as Shape$1, CanvasTexture, DoubleSide, PerspectiveCamera as PerspectiveCamera$1, OrthographicCamera as OrthographicCamera$1, REVISION, AudioListener, AudioLoader, AnimationMixer, BufferAttribute, Box3, Sphere as Sphere$1, InstancedBufferAttribute, DepthTexture, DepthFormat, UnsignedShortType, CubeTextureLoader, DefaultLoadingManager, Ray, Raycaster, Camera, CubeReflectionMapping, EquirectangularReflectionMapping, Scene, RepeatWrapping, SpriteNodeMaterial, AdditiveBlending, CylinderGeometry } from 'three/webgpu';
19
6
  import { SimplexNoise } from 'three/examples/jsm/math/SimplexNoise.js';
20
- import { uniform, Fn, float, vec4, uniformTexture, uv, vec2 as vec2$2, texture, positionWorld, mul, add, negate, dot, refract, div, sub, length, cross, select, max, vec3, normalize, normalWorld, Discard, screenCoordinate, cameraPosition, pow, mx_fractal_noise_vec3, int, Loop, cameraProjectionMatrix, cameraViewMatrix, diffuseColor, mix, fract, sin, log, exp, reflector, clamp, reflect, smoothstep, round, distance, positionLocal, mx_noise_vec3, cos, mat3, normalLocal, attribute, modelViewMatrix, varying, min, abs, saturate, positionView, frontFacing, fwidth, modelWorldMatrix, positionGeometry } from 'three/tsl';
21
7
  import { Line2 } from 'three/examples/jsm/lines/webgpu/Line2.js';
22
8
  import { LineSegments2 } from 'three/examples/jsm/lines/webgpu/LineSegments2.js';
23
9
  import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
24
10
  import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry.js';
11
+ import { uniform, Fn, float, vec4, uniformTexture, uv, vec2 as vec2$2, texture, mul, negate, add, dot, refract, div, sub, length, cross, select, max, vec3, normalize, normalWorld, positionWorld, Discard, screenCoordinate, cameraPosition, pow, mx_fractal_noise_vec3, int, Loop, cameraProjectionMatrix, cameraViewMatrix, diffuseColor, mix, fract, sin, log, exp, reflector, clamp, reflect, smoothstep, round, distance, positionLocal, mx_noise_vec3, cos, mat3, normalLocal, attribute, modelViewMatrix, varying, min, frontFacing, fwidth, abs, saturate, positionView, modelWorldMatrix, positionGeometry } from 'three/tsl';
12
+ import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils.js';
25
13
  import { Flow } from 'three/examples/jsm/modifiers/CurveModifier.js';
26
14
  import { DecalGeometry } from 'three/examples/jsm/geometries/DecalGeometry.js';
15
+ import { getGPUTier } from 'detect-gpu';
16
+ import { suspend, preload, clear as clear$1 } from 'suspend-react';
17
+ import { GroundedSkybox } from 'three/examples/jsm/objects/GroundedSkybox.js';
18
+ import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
19
+ import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';
20
+ import { HDRJPGLoader, GainMapLoader } from '@monogrid/gainmap-js';
27
21
  import { toCreasedNormals, mergeVertices } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
28
22
  import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js';
29
23
  import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js';
30
- import { suspend, preload, clear as clear$1 } from 'suspend-react';
31
- import { TransformControls as TransformControls$1 } from 'three/examples/jsm/controls/TransformControls.js';
32
- import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils.js';
33
- import { MeshSurfaceSampler } from 'three/examples/jsm/math/MeshSurfaceSampler.js';
34
- import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader.js';
35
- import { Events } from 'hls.js';
36
24
  import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
37
25
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
38
26
  import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
39
27
  import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
40
28
  import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
41
- import { getGPUTier } from 'detect-gpu';
29
+ import { create as create$1 } from 'zustand';
30
+ import { hashBlur } from 'three/examples/jsm/tsl/display/hashBlur.js';
31
+ import { misc, easing } from 'maath';
32
+ import * as ReactDOM from 'react-dom/client';
33
+ import { useGesture } from '@use-gesture/react';
34
+ import { MeshSurfaceSampler } from 'three/examples/jsm/math/MeshSurfaceSampler.js';
35
+ import { Events } from 'hls.js';
36
+ import { SelectionBox } from 'three/examples/jsm/interactive/SelectionBox.js';
37
+ import { shallow } from 'zustand/shallow';
38
+ import { Sky as Sky$1 } from 'three/examples/jsm/objects/Sky.js';
39
+ import { SkyMesh } from 'three/examples/jsm/objects/SkyMesh.js';
42
40
  import StatsImpl from 'stats.js';
43
41
  import Stats$1 from 'stats-gl';
42
+ import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader.js';
43
+ import { TransformControls as TransformControls$1 } from 'three/examples/jsm/controls/TransformControls.js';
44
44
  import tunnel from 'tunnel-rat';
45
- import { GroundedSkybox } from 'three/examples/jsm/objects/GroundedSkybox.js';
46
- import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
47
- import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';
48
- import { HDRJPGLoader, GainMapLoader } from '@monogrid/gainmap-js';
49
- import { Sky as Sky$1 } from 'three/examples/jsm/objects/Sky.js';
50
- import { SkyMesh } from 'three/examples/jsm/objects/SkyMesh.js';
51
- import { SelectionBox } from 'three/examples/jsm/interactive/SelectionBox.js';
52
- import { shallow } from 'zustand/shallow';
53
- import { hashBlur } from 'three/examples/jsm/tsl/display/hashBlur.js';
45
+ import 'zustand/middleware';
54
46
 
55
47
  class DepthNodeMaterial extends MeshBasicNodeMaterial {
56
48
  _opacity;
@@ -239,318 +231,28 @@ const ContactShadows = /* @__PURE__ */ React.forwardRef(
239
231
  }
240
232
  );
241
233
 
242
- function shaderMaterial(uniforms, vertexShader, fragmentShader, onInit) {
243
- return class extends THREE.ShaderMaterial {
244
- static key = THREE.MathUtils.generateUUID();
245
- constructor(parameters) {
246
- super({ vertexShader, fragmentShader, ...parameters });
247
- for (const key in uniforms) {
248
- this.uniforms[key] = new THREE.Uniform(uniforms[key]);
249
- Object.defineProperty(this, key, {
250
- get() {
251
- return this.uniforms[key].value;
252
- },
253
- set(value) {
254
- this.uniforms[key].value = value;
255
- }
256
- });
257
- }
258
- this.uniforms = THREE.UniformsUtils.clone(this.uniforms);
259
- }
260
- };
261
- }
262
-
263
- const DiscardMaterial$1 = /* @__PURE__ */ shaderMaterial(
264
- {},
265
- "void main() { }",
266
- "void main() { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); discard; }"
267
- );
268
-
269
- const getVersion = () => parseInt(REVISION.replace(/\D+/g, ""));
270
- const version = /* @__PURE__ */ getVersion();
271
-
272
- function isLight(object) {
273
- return object.isLight;
274
- }
275
- function isGeometry$1(object) {
276
- return !!object.geometry;
277
- }
278
234
  const accumulativeContext = /* @__PURE__ */ React.createContext(
279
235
  null
280
236
  );
281
- const SoftShadowMaterial = /* @__PURE__ */ shaderMaterial(
282
- {
283
- color: /* @__PURE__ */ new THREE.Color(),
284
- blend: 2,
285
- alphaTest: 0.75,
286
- opacity: 0,
287
- map: null
288
- },
289
- `varying vec2 vUv;
290
- void main() {
291
- gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);
292
- vUv = uv;
293
- }`,
294
- `varying vec2 vUv;
295
- uniform sampler2D map;
296
- uniform vec3 color;
297
- uniform float opacity;
298
- uniform float alphaTest;
299
- uniform float blend;
300
- void main() {
301
- vec4 sampledDiffuseColor = texture2D(map, vUv);
302
- gl_FragColor = vec4(color * sampledDiffuseColor.r * blend, max(0.0, (1.0 - (sampledDiffuseColor.r + sampledDiffuseColor.g + sampledDiffuseColor.b) / alphaTest)) * opacity);
303
- #include <tonemapping_fragment>
304
- #include <${version >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
305
- }`
306
- );
307
- const AccumulativeShadows = /* @__PURE__ */ React.forwardRef(
308
- ({
309
- children,
310
- temporal,
311
- frames = 40,
312
- limit = Infinity,
313
- blend = 20,
314
- scale = 10,
315
- opacity = 1,
316
- alphaTest = 0.75,
317
- color = "black",
318
- colorBlend = 2,
319
- resolution = 1024,
320
- toneMapped = true,
321
- ...props
322
- }, forwardRef) => {
323
- extend({ SoftShadowMaterial });
324
- const gl = useThree((state) => state.gl);
325
- const scene = useThree((state) => state.scene);
326
- const camera = useThree((state) => state.camera);
327
- const invalidate = useThree((state) => state.invalidate);
328
- const gPlane = React.useRef(
329
- null
330
- );
331
- const gLights = React.useRef(null);
332
- const [plm] = React.useState(() => new ProgressiveLightMap(gl, scene, resolution));
333
- React.useLayoutEffect(() => {
334
- plm.configure(gPlane.current);
335
- }, []);
336
- const api = React.useMemo(
337
- () => ({
338
- lights: /* @__PURE__ */ new Map(),
339
- temporal: !!temporal,
340
- frames: Math.max(2, frames),
341
- blend: Math.max(2, frames === Infinity ? blend : frames),
342
- count: 0,
343
- getMesh: () => gPlane.current,
344
- reset: () => {
345
- plm.clear();
346
- const material = gPlane.current.material;
347
- material.opacity = 0;
348
- material.alphaTest = 0;
349
- api.count = 0;
350
- },
351
- update: (frames2 = 1) => {
352
- const material = gPlane.current.material;
353
- if (!api.temporal) {
354
- material.opacity = opacity;
355
- material.alphaTest = alphaTest;
356
- } else {
357
- material.opacity = Math.min(opacity, material.opacity + opacity / api.blend);
358
- material.alphaTest = Math.min(alphaTest, material.alphaTest + alphaTest / api.blend);
359
- }
360
- gLights.current.visible = true;
361
- plm.prepare();
362
- for (let i = 0; i < frames2; i++) {
363
- api.lights.forEach((light) => light.update());
364
- plm.update(camera, api.blend);
365
- }
366
- gLights.current.visible = false;
367
- plm.finish();
368
- }
369
- }),
370
- [plm, camera, scene, temporal, frames, blend, opacity, alphaTest]
371
- );
372
- React.useLayoutEffect(() => {
373
- api.reset();
374
- if (!api.temporal && api.frames !== Infinity) api.update(api.blend);
375
- });
376
- React.useImperativeHandle(forwardRef, () => api, [api]);
377
- useFrame(() => {
378
- if ((api.temporal || api.frames === Infinity) && api.count < api.frames && api.count < limit) {
379
- invalidate();
380
- api.update();
381
- api.count++;
382
- }
383
- });
384
- return /* @__PURE__ */ React.createElement("group", { ...props }, /* @__PURE__ */ React.createElement("group", { traverse: () => null, ref: gLights }, /* @__PURE__ */ React.createElement(accumulativeContext.Provider, { value: api }, children)), /* @__PURE__ */ React.createElement("mesh", { receiveShadow: true, ref: gPlane, scale, rotation: [-Math.PI / 2, 0, 0] }, /* @__PURE__ */ React.createElement("planeGeometry", null), /* @__PURE__ */ React.createElement(
385
- "softShadowMaterial",
386
- {
387
- transparent: true,
388
- depthWrite: false,
389
- toneMapped,
390
- color,
391
- blend: colorBlend,
392
- map: plm.progressiveLightMap2.texture
393
- }
394
- )));
395
- }
396
- );
397
- const RandomizedLight = /* @__PURE__ */ React.forwardRef(
398
- ({
399
- castShadow = true,
400
- bias = 1e-3,
401
- mapSize = 512,
402
- size = 5,
403
- near = 0.5,
404
- far = 500,
405
- frames = 1,
406
- position = [0, 0, 0],
407
- radius = 1,
408
- amount = 8,
409
- intensity = version >= 155 ? Math.PI : 1,
410
- ambient = 0.5,
411
- ...props
412
- }, forwardRef) => {
413
- const gLights = React.useRef(null);
414
- const length = new THREE.Vector3(...position).length();
415
- const parent = React.useContext(accumulativeContext);
416
- const update = React.useCallback(() => {
417
- let light;
418
- if (gLights.current) {
419
- for (let l = 0; l < gLights.current.children.length; l++) {
420
- light = gLights.current.children[l];
421
- if (Math.random() > ambient) {
422
- light.position.set(
423
- position[0] + THREE.MathUtils.randFloatSpread(radius),
424
- position[1] + THREE.MathUtils.randFloatSpread(radius),
425
- position[2] + THREE.MathUtils.randFloatSpread(radius)
426
- );
427
- } else {
428
- let lambda = Math.acos(2 * Math.random() - 1) - Math.PI / 2;
429
- let phi = 2 * Math.PI * Math.random();
430
- light.position.set(
431
- Math.cos(lambda) * Math.cos(phi) * length,
432
- Math.abs(Math.cos(lambda) * Math.sin(phi) * length),
433
- Math.sin(lambda) * length
434
- );
435
- }
436
- }
437
- }
438
- }, [radius, ambient, length, ...position]);
439
- const api = React.useMemo(() => ({ update }), [update]);
440
- React.useImperativeHandle(forwardRef, () => api, [api]);
441
- React.useLayoutEffect(() => {
442
- const group = gLights.current;
443
- if (parent) parent.lights?.set(group.uuid, api);
444
- return () => void parent?.lights?.delete(group.uuid);
445
- }, [parent, api]);
446
- return /* @__PURE__ */ React.createElement("group", { ref: gLights, ...props }, Array.from({ length: amount }, (_, index) => /* @__PURE__ */ React.createElement(
447
- "directionalLight",
448
- {
449
- key: index,
450
- castShadow,
451
- "shadow-bias": bias,
452
- "shadow-mapSize": [mapSize, mapSize],
453
- intensity: intensity / amount
454
- },
455
- /* @__PURE__ */ React.createElement("orthographicCamera", { attach: "shadow-camera", args: [-size, size, size, -size, near, far] })
456
- )));
457
- }
458
- );
459
- class ProgressiveLightMap {
460
- renderer;
461
- res;
462
- scene;
463
- object;
464
- buffer1Active;
465
- progressiveLightMap1;
466
- progressiveLightMap2;
467
- discardMat;
468
- targetMat;
469
- previousShadowMap;
470
- averagingWindow;
471
- clearColor;
472
- clearAlpha;
473
- lights;
474
- meshes;
475
- constructor(renderer, scene, res = 1024) {
476
- this.renderer = renderer;
477
- this.res = res;
478
- this.scene = scene;
479
- this.buffer1Active = false;
480
- this.lights = [];
481
- this.meshes = [];
482
- this.object = null;
483
- this.clearColor = new THREE.Color();
484
- this.clearAlpha = 0;
485
- const textureParams = {
486
- type: THREE.HalfFloatType,
487
- magFilter: THREE.NearestFilter,
488
- minFilter: THREE.NearestFilter
489
- };
490
- this.progressiveLightMap1 = new THREE.WebGLRenderTarget(this.res, this.res, textureParams);
491
- this.progressiveLightMap2 = new THREE.WebGLRenderTarget(this.res, this.res, textureParams);
492
- this.discardMat = new DiscardMaterial$1();
493
- this.targetMat = new THREE.MeshLambertMaterial({ fog: false });
494
- this.previousShadowMap = { value: this.progressiveLightMap1.texture };
495
- this.averagingWindow = { value: 100 };
496
- this.targetMat.onBeforeCompile = (shader) => {
497
- shader.vertexShader = "varying vec2 vUv;\n" + shader.vertexShader.slice(0, -1) + "vUv = uv; gl_Position = vec4((uv - 0.5) * 2.0, 1.0, 1.0); }";
498
- const bodyStart = shader.fragmentShader.indexOf("void main() {");
499
- shader.fragmentShader = "varying vec2 vUv;\n" + shader.fragmentShader.slice(0, bodyStart) + "uniform sampler2D previousShadowMap;\n uniform float averagingWindow;\n" + shader.fragmentShader.slice(bodyStart - 1, -1) + `
500
- vec3 texelOld = texture2D(previousShadowMap, vUv).rgb;
501
- gl_FragColor.rgb = mix(texelOld, gl_FragColor.rgb, 1.0/ averagingWindow);
502
- }`;
503
- shader.uniforms.previousShadowMap = this.previousShadowMap;
504
- shader.uniforms.averagingWindow = this.averagingWindow;
505
- };
506
- }
507
- clear() {
508
- this.renderer.getClearColor(this.clearColor);
509
- this.clearAlpha = this.renderer.getClearAlpha();
510
- this.renderer.setClearColor("black", 1);
511
- this.renderer.setRenderTarget(this.progressiveLightMap1);
512
- this.renderer.clear();
513
- this.renderer.setRenderTarget(this.progressiveLightMap2);
514
- this.renderer.clear();
515
- this.renderer.setRenderTarget(null);
516
- this.renderer.setClearColor(this.clearColor, this.clearAlpha);
517
- this.lights = [];
518
- this.meshes = [];
519
- this.scene.traverse((object) => {
520
- if (isGeometry$1(object)) {
521
- this.meshes.push({ object, material: object.material });
522
- } else if (isLight(object)) {
523
- this.lights.push({ object, intensity: object.intensity });
524
- }
525
- });
526
- }
527
- prepare() {
528
- this.lights.forEach((light) => light.object.intensity = 0);
529
- this.meshes.forEach((mesh) => mesh.object.material = this.discardMat);
530
- }
531
- finish() {
532
- this.lights.forEach((light) => light.object.intensity = light.intensity);
533
- this.meshes.forEach((mesh) => mesh.object.material = mesh.material);
534
- }
535
- configure(object) {
536
- this.object = object;
537
- }
538
- update(camera, blendWindow = 100) {
539
- if (!this.object) return;
540
- this.averagingWindow.value = blendWindow;
541
- this.object.material = this.targetMat;
542
- const activeMap = this.buffer1Active ? this.progressiveLightMap1 : this.progressiveLightMap2;
543
- const inactiveMap = this.buffer1Active ? this.progressiveLightMap2 : this.progressiveLightMap1;
544
- const oldBg = this.scene.background;
545
- this.scene.background = null;
546
- this.renderer.setRenderTarget(activeMap);
547
- this.previousShadowMap.value = inactiveMap.texture;
548
- this.buffer1Active = !this.buffer1Active;
549
- this.renderer.render(this.scene, camera);
550
- this.renderer.setRenderTarget(null);
551
- this.scene.background = oldBg;
237
+ let hasWarned$1 = false;
238
+ function warnOnce$1(message) {
239
+ if (!hasWarned$1) {
240
+ console.warn(message);
241
+ hasWarned$1 = true;
552
242
  }
553
243
  }
244
+ const AccumulativeShadows = /* @__PURE__ */ React.forwardRef((props, ref) => {
245
+ warnOnce$1(
246
+ "drei: AccumulativeShadows is not yet supported in WebGPU. It uses GLSL shaders that need to be converted to TSL. Consider using ContactShadows instead, or import from @react-three/drei/legacy for WebGL."
247
+ );
248
+ return null;
249
+ });
250
+ const RandomizedLight = /* @__PURE__ */ React.forwardRef((props, ref) => {
251
+ warnOnce$1(
252
+ "drei: RandomizedLight is not yet supported in WebGPU. It requires AccumulativeShadows which uses GLSL shaders. Import from @react-three/drei/legacy for WebGL."
253
+ );
254
+ return null;
255
+ });
554
256
 
555
257
  function useFBO(width, height, settings) {
556
258
  const size = useThree((state) => state.size);
@@ -1305,10 +1007,11 @@ let MeshReflectorMaterial$1 = class MeshReflectorMaterial extends THREE.MeshStan
1305
1007
  premultipliedAlpha: false
1306
1008
  });
1307
1009
  const reflectionColor = mix(reflectionSample.rgb, reflectionBlurred.rgb, clamp(this.hasBlurUniform, 0, 1));
1010
+ const reflectionClamped = clamp(reflectionColor, 0, 1);
1308
1011
  const contrastAdjusted = vec3(
1309
- reflectionColor.x.sub(0.5).mul(this.mixContrastUniform).add(0.5),
1310
- reflectionColor.y.sub(0.5).mul(this.mixContrastUniform).add(0.5),
1311
- reflectionColor.z.sub(0.5).mul(this.mixContrastUniform).add(0.5)
1012
+ reflectionClamped.x.sub(0.5).mul(this.mixContrastUniform).add(0.5),
1013
+ reflectionClamped.y.sub(0.5).mul(this.mixContrastUniform).add(0.5),
1014
+ reflectionClamped.z.sub(0.5).mul(this.mixContrastUniform).add(0.5)
1312
1015
  );
1313
1016
  const mirrorClamped = clamp(this.mirrorUniform, 0, 1);
1314
1017
  return vec4(vec3(1).sub(vec3(mirrorClamped)).add(contrastAdjusted.mul(this.mixStrengthUniform)), 1);
@@ -3004,12 +2707,12 @@ const Segments = /* @__PURE__ */ React.forwardRef((props, forwardedRef) => {
3004
2707
  for (let i = 0; i < limit; i++) {
3005
2708
  const segment = segments[i]?.current;
3006
2709
  if (segment) {
3007
- positions[i * 6 + 0] = segment.start.x;
3008
- positions[i * 6 + 1] = segment.start.y;
3009
- positions[i * 6 + 2] = segment.start.z;
3010
- positions[i * 6 + 3] = segment.end.x;
3011
- positions[i * 6 + 4] = segment.end.y;
3012
- positions[i * 6 + 5] = segment.end.z;
2710
+ positions[i * 6 + 0] = segment.start?.x || 0;
2711
+ positions[i * 6 + 1] = segment.start?.y || 0;
2712
+ positions[i * 6 + 2] = segment.start?.z || 0;
2713
+ positions[i * 6 + 3] = segment.end?.x || 0;
2714
+ positions[i * 6 + 4] = segment.end?.y || 0;
2715
+ positions[i * 6 + 5] = segment.end?.z || 0;
3013
2716
  colors[i * 6 + 0] = segment.color.r;
3014
2717
  colors[i * 6 + 1] = segment.color.g;
3015
2718
  colors[i * 6 + 2] = segment.color.b;
@@ -3044,7 +2747,10 @@ class SegmentObject {
3044
2747
  this.end = new THREE.Vector3(0, 0, 0);
3045
2748
  }
3046
2749
  }
3047
- const normPos = (pos) => pos instanceof THREE.Vector3 ? pos : new THREE.Vector3(...typeof pos === "number" ? [pos, pos, pos] : pos);
2750
+ const normPos = (pos) => {
2751
+ if (!pos) return new THREE.Vector3(0, 0, 0);
2752
+ return pos instanceof THREE.Vector3 ? pos : new THREE.Vector3(...typeof pos === "number" ? [pos, pos, pos] : pos);
2753
+ };
3048
2754
  const Segment = /* @__PURE__ */ React.forwardRef(({ color, start, end }, forwardedRef) => {
3049
2755
  const api = React.useContext(context$9);
3050
2756
  if (!api) throw "Segment must used inside Segments component.";
@@ -3323,50 +3029,80 @@ const PerspectiveCamera = /* @__PURE__ */ React.forwardRef(
3323
3029
  }
3324
3030
  );
3325
3031
 
3326
- const ArcballControls = /* @__PURE__ */ forwardRef(
3327
- ({ camera, makeDefault, regress, domElement, onChange, onStart, onEnd, ...restProps }, ref) => {
3328
- const invalidate = useThree((state) => state.invalidate);
3329
- const defaultCamera = useThree((state) => state.camera);
3330
- const gl = useThree((state) => state.gl);
3331
- const events = useThree((state) => state.events);
3332
- const set = useThree((state) => state.set);
3333
- const get = useThree((state) => state.get);
3334
- const performance = useThree((state) => state.performance);
3335
- const explCamera = camera || defaultCamera;
3336
- const explDomElement = domElement || events.connected || gl.domElement;
3337
- const controls = useMemo(() => new ArcballControls$1(explCamera), [explCamera]);
3338
- useFrame(() => {
3339
- if (controls.enabled) controls.update();
3340
- }, -1);
3341
- useEffect(() => {
3342
- controls.connect(explDomElement);
3343
- return () => void controls.dispose();
3344
- }, [explDomElement, regress, controls, invalidate]);
3345
- useEffect(() => {
3346
- const callback = (e) => {
3347
- invalidate();
3348
- if (regress) performance.regress();
3349
- if (onChange) onChange(e);
3350
- };
3351
- controls.addEventListener("change", callback);
3352
- if (onStart) controls.addEventListener("start", onStart);
3353
- if (onEnd) controls.addEventListener("end", onEnd);
3354
- return () => {
3355
- controls.removeEventListener("change", callback);
3356
- if (onStart) controls.removeEventListener("start", onStart);
3357
- if (onEnd) controls.removeEventListener("end", onEnd);
3358
- };
3359
- }, [onChange, onStart, onEnd]);
3360
- useEffect(() => {
3361
- if (makeDefault) {
3362
- const old = get().controls;
3363
- set({ controls });
3364
- return () => set({ controls: old });
3365
- }
3366
- }, [makeDefault, controls]);
3367
- return /* @__PURE__ */ React.createElement("primitive", { ref, object: controls, ...restProps });
3032
+ let DeviceOrientationControls$1 = class DeviceOrientationControls extends EventDispatcher {
3033
+ object;
3034
+ changeEvent = { type: "change" };
3035
+ EPS = 1e-6;
3036
+ enabled = true;
3037
+ deviceOrientation = { alpha: 0, beta: 0, gamma: 0 };
3038
+ screenOrientation = 0;
3039
+ alphaOffset = 0;
3040
+ // radians
3041
+ constructor(object) {
3042
+ super();
3043
+ this.object = object;
3044
+ this.object.rotation.reorder("YXZ");
3045
+ this.connect();
3368
3046
  }
3369
- );
3047
+ onDeviceOrientationChangeEvent = (event) => {
3048
+ this.deviceOrientation = event;
3049
+ };
3050
+ onScreenOrientationChangeEvent = () => {
3051
+ this.screenOrientation = window.orientation || 0;
3052
+ };
3053
+ // The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
3054
+ zee = new Vector3(0, 0, 1);
3055
+ euler = new Euler();
3056
+ q0 = new Quaternion();
3057
+ q1 = new Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5));
3058
+ // - PI/2 around the x-axis
3059
+ setObjectQuaternion = (quaternion, alpha, beta, gamma, orient) => {
3060
+ this.euler.set(beta, alpha, -gamma, "YXZ");
3061
+ quaternion.setFromEuler(this.euler);
3062
+ quaternion.multiply(this.q1);
3063
+ quaternion.multiply(this.q0.setFromAxisAngle(this.zee, -orient));
3064
+ };
3065
+ connect = () => {
3066
+ this.onScreenOrientationChangeEvent();
3067
+ if (window.DeviceOrientationEvent !== void 0 && // @ts-ignore
3068
+ typeof window.DeviceOrientationEvent.requestPermission === "function") {
3069
+ window.DeviceOrientationEvent.requestPermission().then((response) => {
3070
+ if (response == "granted") {
3071
+ window.addEventListener("orientationchange", this.onScreenOrientationChangeEvent);
3072
+ window.addEventListener("deviceorientation", this.onDeviceOrientationChangeEvent);
3073
+ }
3074
+ }).catch((error) => {
3075
+ console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:", error);
3076
+ });
3077
+ } else {
3078
+ window.addEventListener("orientationchange", this.onScreenOrientationChangeEvent);
3079
+ window.addEventListener("deviceorientation", this.onDeviceOrientationChangeEvent);
3080
+ }
3081
+ this.enabled = true;
3082
+ };
3083
+ disconnect = () => {
3084
+ window.removeEventListener("orientationchange", this.onScreenOrientationChangeEvent);
3085
+ window.removeEventListener("deviceorientation", this.onDeviceOrientationChangeEvent);
3086
+ this.enabled = false;
3087
+ };
3088
+ lastQuaternion = new Quaternion();
3089
+ update = () => {
3090
+ if (this.enabled === false) return;
3091
+ const device = this.deviceOrientation;
3092
+ if (device) {
3093
+ const alpha = device.alpha ? MathUtils.degToRad(device.alpha) + this.alphaOffset : 0;
3094
+ const beta = device.beta ? MathUtils.degToRad(device.beta) : 0;
3095
+ const gamma = device.gamma ? MathUtils.degToRad(device.gamma) : 0;
3096
+ const orient = this.screenOrientation ? MathUtils.degToRad(this.screenOrientation) : 0;
3097
+ this.setObjectQuaternion(this.object.quaternion, alpha, beta, gamma, orient);
3098
+ if (8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > this.EPS) {
3099
+ this.lastQuaternion.copy(this.object.quaternion);
3100
+ this.dispatchEvent(this.changeEvent);
3101
+ }
3102
+ }
3103
+ };
3104
+ dispose = () => this.disconnect();
3105
+ };
3370
3106
 
3371
3107
  const DeviceOrientationControls = /* @__PURE__ */ React.forwardRef(
3372
3108
  (props, ref) => {
@@ -3402,265 +3138,13 @@ const DeviceOrientationControls = /* @__PURE__ */ React.forwardRef(
3402
3138
  }
3403
3139
  );
3404
3140
 
3405
- const initialModelPosition = /* @__PURE__ */ new THREE.Vector3();
3406
- const mousePosition2D = /* @__PURE__ */ new THREE.Vector2();
3407
- const mousePosition3D = /* @__PURE__ */ new THREE.Vector3();
3408
- const dragOffset = /* @__PURE__ */ new THREE.Vector3();
3409
- const dragPlaneNormal = /* @__PURE__ */ new THREE.Vector3();
3410
- const dragPlane = /* @__PURE__ */ new THREE.Plane();
3411
- const DragControls = React.forwardRef(
3412
- ({
3413
- autoTransform = true,
3414
- matrix,
3415
- axisLock,
3416
- dragLimits,
3417
- onHover,
3418
- onDragStart,
3419
- onDrag,
3420
- onDragEnd,
3421
- children,
3422
- dragConfig,
3423
- ...props
3424
- }, fRef) => {
3425
- const defaultControls = useThree((state) => state.controls);
3426
- const { camera, size, raycaster, invalidate } = useThree();
3427
- const ref = React.useRef(null);
3428
- const bind = useGesture(
3429
- {
3430
- onHover: ({ hovering }) => onHover && onHover(hovering ?? false),
3431
- onDragStart: ({ event }) => {
3432
- if (defaultControls) defaultControls.enabled = false;
3433
- const { point } = event;
3434
- ref.current.matrix.decompose(initialModelPosition, new THREE.Quaternion(), new THREE.Vector3());
3435
- mousePosition3D.copy(point);
3436
- dragOffset.copy(mousePosition3D).sub(initialModelPosition);
3437
- onDragStart && onDragStart(initialModelPosition);
3438
- invalidate();
3439
- },
3440
- onDrag: ({ xy: [dragX, dragY], intentional }) => {
3441
- if (!intentional) return;
3442
- const normalizedMouseX = (dragX - size.left) / size.width * 2 - 1;
3443
- const normalizedMouseY = -((dragY - size.top) / size.height) * 2 + 1;
3444
- mousePosition2D.set(normalizedMouseX, normalizedMouseY);
3445
- raycaster.setFromCamera(mousePosition2D, camera);
3446
- if (!axisLock) {
3447
- camera.getWorldDirection(dragPlaneNormal).negate();
3448
- } else {
3449
- switch (axisLock) {
3450
- case "x":
3451
- dragPlaneNormal.set(1, 0, 0);
3452
- break;
3453
- case "y":
3454
- dragPlaneNormal.set(0, 1, 0);
3455
- break;
3456
- case "z":
3457
- dragPlaneNormal.set(0, 0, 1);
3458
- break;
3459
- }
3460
- }
3461
- dragPlane.setFromNormalAndCoplanarPoint(dragPlaneNormal, mousePosition3D);
3462
- raycaster.ray.intersectPlane(dragPlane, mousePosition3D);
3463
- const previousLocalMatrix = ref.current.matrix.clone();
3464
- const previousWorldMatrix = ref.current.matrixWorld.clone();
3465
- const intendedNewPosition = new THREE.Vector3(
3466
- mousePosition3D.x - dragOffset.x,
3467
- mousePosition3D.y - dragOffset.y,
3468
- mousePosition3D.z - dragOffset.z
3469
- );
3470
- if (dragLimits) {
3471
- intendedNewPosition.x = dragLimits[0] ? Math.max(Math.min(intendedNewPosition.x, dragLimits[0][1]), dragLimits[0][0]) : intendedNewPosition.x;
3472
- intendedNewPosition.y = dragLimits[1] ? Math.max(Math.min(intendedNewPosition.y, dragLimits[1][1]), dragLimits[1][0]) : intendedNewPosition.y;
3473
- intendedNewPosition.z = dragLimits[2] ? Math.max(Math.min(intendedNewPosition.z, dragLimits[2][1]), dragLimits[2][0]) : intendedNewPosition.z;
3474
- }
3475
- if (autoTransform) {
3476
- ref.current.matrix.setPosition(intendedNewPosition);
3477
- const deltaLocalMatrix = ref.current.matrix.clone().multiply(previousLocalMatrix.invert());
3478
- const deltaWorldMatrix = ref.current.matrix.clone().multiply(previousWorldMatrix.invert());
3479
- onDrag && onDrag(ref.current.matrix, deltaLocalMatrix, ref.current.matrixWorld, deltaWorldMatrix);
3480
- } else {
3481
- const tempMatrix = new THREE.Matrix4().copy(ref.current.matrix);
3482
- tempMatrix.setPosition(intendedNewPosition);
3483
- const deltaLocalMatrix = tempMatrix.clone().multiply(previousLocalMatrix.invert());
3484
- const deltaWorldMatrix = tempMatrix.clone().multiply(previousWorldMatrix.invert());
3485
- onDrag && onDrag(tempMatrix, deltaLocalMatrix, ref.current.matrixWorld, deltaWorldMatrix);
3486
- }
3487
- invalidate();
3488
- },
3489
- onDragEnd: () => {
3490
- if (defaultControls) defaultControls.enabled = true;
3491
- onDragEnd && onDragEnd();
3492
- invalidate();
3493
- }
3494
- },
3495
- {
3496
- drag: {
3497
- filterTaps: true,
3498
- threshold: 1,
3499
- ...typeof dragConfig === "object" ? dragConfig : {}
3500
- }
3501
- }
3502
- );
3503
- React.useImperativeHandle(fRef, () => ref.current, []);
3504
- React.useLayoutEffect(() => {
3505
- if (!matrix) return;
3506
- ref.current.matrix = matrix;
3507
- }, [matrix]);
3508
- return /* @__PURE__ */ React.createElement("group", { ref, ...bind(), matrix, matrixAutoUpdate: false, ...props }, children);
3509
- }
3510
- );
3511
-
3512
- const FirstPersonControls = /* @__PURE__ */ React.forwardRef(
3513
- ({ domElement, makeDefault, ...props }, ref) => {
3514
- const camera = useThree((state) => state.camera);
3515
- const gl = useThree((state) => state.gl);
3516
- const events = useThree((state) => state.events);
3517
- const get = useThree((state) => state.get);
3518
- const set = useThree((state) => state.set);
3519
- const explDomElement = domElement || events.connected || gl.domElement;
3520
- const [controls] = React.useState(() => new FirstPersonControls$1(camera, explDomElement));
3521
- React.useEffect(() => {
3522
- if (makeDefault) {
3523
- const old = get().controls;
3524
- set({ controls });
3525
- return () => set({ controls: old });
3526
- }
3527
- }, [makeDefault, controls]);
3528
- useFrame((_, delta) => {
3529
- controls.update(delta);
3530
- }, -1);
3531
- return controls ? /* @__PURE__ */ React.createElement("primitive", { ref, object: controls, ...props }) : null;
3532
- }
3533
- );
3534
-
3535
- const FlyControls = /* @__PURE__ */ React.forwardRef(({ domElement, ...props }, fref) => {
3536
- const { onChange, makeDefault, ...rest } = props;
3537
- const invalidate = useThree((state) => state.invalidate);
3538
- const camera = useThree((state) => state.camera);
3539
- const gl = useThree((state) => state.gl);
3540
- const events = useThree((state) => state.events);
3541
- const get = useThree((state) => state.get);
3542
- const set = useThree((state) => state.set);
3543
- const explDomElement = domElement || events.connected || gl.domElement;
3544
- const controls = React.useMemo(() => new FlyControls$1(camera), [camera]);
3545
- React.useEffect(() => {
3546
- controls.connect(explDomElement);
3547
- return () => void controls.dispose();
3548
- }, [explDomElement, controls, invalidate]);
3549
- React.useEffect(() => {
3550
- const callback = (e) => {
3551
- invalidate();
3552
- if (onChange) onChange(e);
3553
- };
3554
- controls.addEventListener?.("change", callback);
3555
- return () => controls.removeEventListener?.("change", callback);
3556
- }, [onChange, invalidate]);
3557
- React.useEffect(() => {
3558
- if (makeDefault) {
3559
- const old = get().controls;
3560
- set({ controls });
3561
- return () => set({ controls: old });
3562
- }
3563
- }, [makeDefault, controls]);
3564
- useFrame((_, delta) => controls.update(delta));
3565
- return /* @__PURE__ */ React.createElement("primitive", { ref: fref, object: controls, args: [camera, explDomElement], ...rest });
3566
- });
3567
-
3568
3141
  const context$8 = /* @__PURE__ */ React.createContext(null);
3569
- function KeyboardControls({ map, children, onChange, domElement }) {
3570
- const key = map.map((item) => item.name + item.keys).join("-");
3571
- const useControls = React.useMemo(() => {
3572
- return create$1(
3573
- subscribeWithSelector(
3574
- () => map.reduce((prev, cur) => ({ ...prev, [cur.name]: false }), {})
3575
- )
3576
- );
3577
- }, [key]);
3578
- const api = React.useMemo(
3579
- () => [useControls.subscribe, useControls.getState, useControls],
3580
- [key]
3581
- );
3582
- const set = useControls.setState;
3583
- React.useEffect(() => {
3584
- const config = map.map(({ name, keys, up }) => ({
3585
- keys,
3586
- up,
3587
- fn: (value) => {
3588
- set({ [name]: value });
3589
- if (onChange) onChange(name, value, api[1]());
3590
- }
3591
- }));
3592
- const keyMap = config.reduce((out, { keys, fn, up = true }) => {
3593
- keys.forEach((key2) => out[key2] = { fn, pressed: false, up });
3594
- return out;
3595
- }, {});
3596
- const downHandler = ({ key: key2, code }) => {
3597
- const obj = keyMap[key2] || keyMap[code];
3598
- if (!obj) return;
3599
- const { fn, pressed, up } = obj;
3600
- obj.pressed = true;
3601
- if (up || !pressed) fn(true);
3602
- };
3603
- const upHandler = ({ key: key2, code }) => {
3604
- const obj = keyMap[key2] || keyMap[code];
3605
- if (!obj) return;
3606
- const { fn, up } = obj;
3607
- obj.pressed = false;
3608
- if (up) fn(false);
3609
- };
3610
- const source = domElement || window;
3611
- source.addEventListener("keydown", downHandler, { passive: true });
3612
- source.addEventListener("keyup", upHandler, { passive: true });
3613
- return () => {
3614
- source.removeEventListener("keydown", downHandler);
3615
- source.removeEventListener("keyup", upHandler);
3616
- };
3617
- }, [domElement, key]);
3618
- return /* @__PURE__ */ React.createElement(context$8.Provider, { value: api, children });
3619
- }
3620
3142
  function useKeyboardControls(sel) {
3621
3143
  const [sub, get, store] = React.useContext(context$8);
3622
3144
  if (sel) return store(sel);
3623
3145
  else return [sub, get];
3624
3146
  }
3625
3147
 
3626
- const MapControls = /* @__PURE__ */ React.forwardRef((props = { enableDamping: true }, ref) => {
3627
- const { domElement, camera, makeDefault, onChange, onStart, onEnd, ...rest } = props;
3628
- const invalidate = useThree((state) => state.invalidate);
3629
- const defaultCamera = useThree((state) => state.camera);
3630
- const gl = useThree((state) => state.gl);
3631
- const events = useThree((state) => state.events);
3632
- const set = useThree((state) => state.set);
3633
- const get = useThree((state) => state.get);
3634
- const explDomElement = domElement || events.connected || gl.domElement;
3635
- const explCamera = camera || defaultCamera;
3636
- const controls = React.useMemo(() => new MapControls$1(explCamera), [explCamera]);
3637
- React.useEffect(() => {
3638
- controls.connect(explDomElement);
3639
- const callback = (e) => {
3640
- invalidate();
3641
- if (onChange) onChange(e);
3642
- };
3643
- controls.addEventListener("change", callback);
3644
- if (onStart) controls.addEventListener("start", onStart);
3645
- if (onEnd) controls.addEventListener("end", onEnd);
3646
- return () => {
3647
- controls.dispose();
3648
- controls.removeEventListener("change", callback);
3649
- if (onStart) controls.removeEventListener("start", onStart);
3650
- if (onEnd) controls.removeEventListener("end", onEnd);
3651
- };
3652
- }, [onChange, onStart, onEnd, controls, invalidate, explDomElement]);
3653
- React.useEffect(() => {
3654
- if (makeDefault) {
3655
- const old = get().controls;
3656
- set({ controls });
3657
- return () => set({ controls: old });
3658
- }
3659
- }, [makeDefault, controls]);
3660
- useFrame(() => controls.update(), -1);
3661
- return /* @__PURE__ */ React.createElement("primitive", { ref, object: controls, enableDamping: true, ...rest });
3662
- });
3663
-
3664
3148
  const isObject3DRef = (ref) => ref?.current instanceof THREE.Object3D;
3665
3149
  const MotionContext = /* @__PURE__ */ React.createContext(null);
3666
3150
  function useMotion() {
@@ -3770,132 +3254,6 @@ const MotionPathControls = /* @__PURE__ */ React.forwardRef(
3770
3254
  }
3771
3255
  );
3772
3256
 
3773
- const OrbitControls = /* @__PURE__ */ React.forwardRef(
3774
- ({
3775
- makeDefault,
3776
- camera,
3777
- regress,
3778
- domElement,
3779
- enableDamping = true,
3780
- keyEvents = false,
3781
- onChange,
3782
- onStart,
3783
- onEnd,
3784
- ...restProps
3785
- }, ref) => {
3786
- const invalidate = useThree((state) => state.invalidate);
3787
- const defaultCamera = useThree((state) => state.camera);
3788
- const gl = useThree((state) => state.gl);
3789
- const events = useThree((state) => state.events);
3790
- const setEvents = useThree((state) => state.setEvents);
3791
- const set = useThree((state) => state.set);
3792
- const get = useThree((state) => state.get);
3793
- const performance = useThree((state) => state.performance);
3794
- const explCamera = camera || defaultCamera;
3795
- const explDomElement = domElement || events.connected || gl.domElement;
3796
- const controls = React.useMemo(() => new OrbitControls$1(explCamera), [explCamera]);
3797
- useFrame(() => {
3798
- if (controls.enabled) controls.update();
3799
- }, -1);
3800
- React.useEffect(() => {
3801
- if (keyEvents) {
3802
- controls.connect(keyEvents === true ? explDomElement : keyEvents);
3803
- }
3804
- controls.connect(explDomElement);
3805
- return () => void controls.dispose();
3806
- }, [keyEvents, explDomElement, regress, controls, invalidate]);
3807
- React.useEffect(() => {
3808
- const callback = (e) => {
3809
- invalidate();
3810
- if (regress) performance.regress();
3811
- if (onChange) onChange(e);
3812
- };
3813
- const onStartCb = (e) => {
3814
- if (onStart) onStart(e);
3815
- };
3816
- const onEndCb = (e) => {
3817
- if (onEnd) onEnd(e);
3818
- };
3819
- controls.addEventListener("change", callback);
3820
- controls.addEventListener("start", onStartCb);
3821
- controls.addEventListener("end", onEndCb);
3822
- return () => {
3823
- controls.removeEventListener("start", onStartCb);
3824
- controls.removeEventListener("end", onEndCb);
3825
- controls.removeEventListener("change", callback);
3826
- };
3827
- }, [onChange, onStart, onEnd, controls, invalidate, setEvents]);
3828
- React.useEffect(() => {
3829
- if (makeDefault) {
3830
- const old = get().controls;
3831
- set({ controls });
3832
- return () => set({ controls: old });
3833
- }
3834
- }, [makeDefault, controls]);
3835
- return /* @__PURE__ */ React.createElement("primitive", { ref, object: controls, enableDamping, ...restProps });
3836
- }
3837
- );
3838
-
3839
- const PointerLockControls = /* @__PURE__ */ React.forwardRef(
3840
- ({ domElement, selector, onChange, onLock, onUnlock, enabled = true, makeDefault, ...props }, ref) => {
3841
- const { camera, ...rest } = props;
3842
- const setEvents = useThree((state) => state.setEvents);
3843
- const gl = useThree((state) => state.gl);
3844
- const defaultCamera = useThree((state) => state.camera);
3845
- const invalidate = useThree((state) => state.invalidate);
3846
- const events = useThree((state) => state.events);
3847
- const get = useThree((state) => state.get);
3848
- const set = useThree((state) => state.set);
3849
- const explCamera = camera || defaultCamera;
3850
- const explDomElement = domElement || events.connected || gl.domElement;
3851
- const controls = React.useMemo(() => new PointerLockControls$1(explCamera), [explCamera]);
3852
- React.useEffect(() => {
3853
- if (enabled) {
3854
- controls.connect(explDomElement);
3855
- const oldComputeOffsets = get().events.compute;
3856
- setEvents({
3857
- compute(event, state) {
3858
- const offsetX = state.size.width / 2;
3859
- const offsetY = state.size.height / 2;
3860
- state.pointer.set(offsetX / state.size.width * 2 - 1, -(offsetY / state.size.height) * 2 + 1);
3861
- state.raycaster.setFromCamera(state.pointer, state.camera);
3862
- }
3863
- });
3864
- return () => {
3865
- controls.disconnect();
3866
- setEvents({ compute: oldComputeOffsets });
3867
- };
3868
- }
3869
- }, [enabled, controls]);
3870
- React.useEffect(() => {
3871
- const callback = (e) => {
3872
- invalidate();
3873
- if (onChange) onChange(e);
3874
- };
3875
- controls.addEventListener("change", callback);
3876
- if (onLock) controls.addEventListener("lock", onLock);
3877
- if (onUnlock) controls.addEventListener("unlock", onUnlock);
3878
- const handler = () => controls.lock();
3879
- const elements = selector ? Array.from(document.querySelectorAll(selector)) : [document];
3880
- elements.forEach((element) => element && element.addEventListener("click", handler));
3881
- return () => {
3882
- controls.removeEventListener("change", callback);
3883
- if (onLock) controls.removeEventListener("lock", onLock);
3884
- if (onUnlock) controls.removeEventListener("unlock", onUnlock);
3885
- elements.forEach((element) => element ? element.removeEventListener("click", handler) : void 0);
3886
- };
3887
- }, [onChange, onLock, onUnlock, selector, controls, invalidate]);
3888
- React.useEffect(() => {
3889
- if (makeDefault) {
3890
- const old = get().controls;
3891
- set({ controls });
3892
- return () => set({ controls: old });
3893
- }
3894
- }, [makeDefault, controls]);
3895
- return /* @__PURE__ */ React.createElement("primitive", { ref, object: controls, ...rest });
3896
- }
3897
- );
3898
-
3899
3257
  function PresentationControls({
3900
3258
  enabled = true,
3901
3259
  snap,
@@ -3963,152 +3321,16 @@ function PresentationControls({
3963
3321
  return /* @__PURE__ */ React.createElement("group", { ref, ...bind?.() }, children);
3964
3322
  }
3965
3323
 
3324
+ function roundToPixelRatio(value) {
3325
+ const ratio = window.devicePixelRatio || 1;
3326
+ return Math.round(value * ratio) / ratio;
3327
+ }
3328
+
3966
3329
  const context$7 = /* @__PURE__ */ React.createContext(null);
3330
+ const rootCache = /* @__PURE__ */ new WeakMap();
3967
3331
  function useScroll() {
3968
3332
  return React.useContext(context$7);
3969
3333
  }
3970
- function ScrollControls({
3971
- eps = 1e-5,
3972
- enabled = true,
3973
- infinite,
3974
- horizontal,
3975
- pages = 1,
3976
- distance = 1,
3977
- damping = 0.25,
3978
- maxSpeed = Infinity,
3979
- prepend = false,
3980
- style = {},
3981
- children
3982
- }) {
3983
- const { get, setEvents, gl, size, invalidate, events } = useThree();
3984
- const [el] = React.useState(() => document.createElement("div"));
3985
- const [fill] = React.useState(() => document.createElement("div"));
3986
- const [fixed] = React.useState(() => document.createElement("div"));
3987
- const target = gl.domElement.parentNode;
3988
- const scroll = React.useRef(0);
3989
- const state = React.useMemo(() => {
3990
- const state2 = {
3991
- el,
3992
- eps,
3993
- fill,
3994
- fixed,
3995
- horizontal,
3996
- damping,
3997
- offset: 0,
3998
- delta: 0,
3999
- scroll,
4000
- pages,
4001
- // 0-1 for a range between from -> from + distance
4002
- range(from, distance2, margin = 0) {
4003
- const start = from - margin;
4004
- const end = start + distance2 + margin * 2;
4005
- return this.offset < start ? 0 : this.offset > end ? 1 : (this.offset - start) / (end - start);
4006
- },
4007
- // 0-1-0 for a range between from -> from + distance
4008
- curve(from, distance2, margin = 0) {
4009
- return Math.sin(this.range(from, distance2, margin) * Math.PI);
4010
- },
4011
- // true/false for a range between from -> from + distance
4012
- visible(from, distance2, margin = 0) {
4013
- const start = from - margin;
4014
- const end = start + distance2 + margin * 2;
4015
- return this.offset >= start && this.offset <= end;
4016
- }
4017
- };
4018
- return state2;
4019
- }, [eps, damping, horizontal, pages]);
4020
- React.useEffect(() => {
4021
- el.style.position = "absolute";
4022
- el.style.width = "100%";
4023
- el.style.height = "100%";
4024
- el.style[horizontal ? "overflowX" : "overflowY"] = "auto";
4025
- el.style[horizontal ? "overflowY" : "overflowX"] = "hidden";
4026
- el.style.top = "0px";
4027
- el.style.left = "0px";
4028
- for (const key in style) {
4029
- el.style[key] = style[key];
4030
- }
4031
- fixed.style.position = "sticky";
4032
- fixed.style.top = "0px";
4033
- fixed.style.left = "0px";
4034
- fixed.style.width = "100%";
4035
- fixed.style.height = "100%";
4036
- fixed.style.overflow = "hidden";
4037
- el.appendChild(fixed);
4038
- fill.style.height = horizontal ? "100%" : `${pages * distance * 100}%`;
4039
- fill.style.width = horizontal ? `${pages * distance * 100}%` : "100%";
4040
- fill.style.pointerEvents = "none";
4041
- el.appendChild(fill);
4042
- if (prepend) target.prepend(el);
4043
- else target.appendChild(el);
4044
- el[horizontal ? "scrollLeft" : "scrollTop"] = 1;
4045
- const oldTarget = events.connected || gl.domElement;
4046
- requestAnimationFrame(() => events.connect?.(el));
4047
- const oldCompute = get().events.compute;
4048
- setEvents({
4049
- compute(event, state2) {
4050
- const { left, top } = target.getBoundingClientRect();
4051
- const offsetX = event.clientX - left;
4052
- const offsetY = event.clientY - top;
4053
- state2.pointer.set(offsetX / state2.size.width * 2 - 1, -(offsetY / state2.size.height) * 2 + 1);
4054
- state2.raycaster.setFromCamera(state2.pointer, state2.camera);
4055
- }
4056
- });
4057
- return () => {
4058
- target.removeChild(el);
4059
- setEvents({ compute: oldCompute });
4060
- events.connect?.(oldTarget);
4061
- };
4062
- }, [pages, distance, horizontal, el, fill, fixed, target]);
4063
- React.useEffect(() => {
4064
- if (events.connected === el) {
4065
- const containerLength = size[horizontal ? "width" : "height"];
4066
- const scrollLength = el[horizontal ? "scrollWidth" : "scrollHeight"];
4067
- const scrollThreshold = scrollLength - containerLength;
4068
- let current = 0;
4069
- let disableScroll = true;
4070
- let firstRun = true;
4071
- const onScroll = () => {
4072
- if (!enabled || firstRun) return;
4073
- invalidate();
4074
- current = el[horizontal ? "scrollLeft" : "scrollTop"];
4075
- scroll.current = current / scrollThreshold;
4076
- if (infinite) {
4077
- if (!disableScroll) {
4078
- if (current >= scrollThreshold) {
4079
- const damp = 1 - state.offset;
4080
- el[horizontal ? "scrollLeft" : "scrollTop"] = 1;
4081
- scroll.current = state.offset = -damp;
4082
- disableScroll = true;
4083
- } else if (current <= 0) {
4084
- const damp = 1 + state.offset;
4085
- el[horizontal ? "scrollLeft" : "scrollTop"] = scrollLength;
4086
- scroll.current = state.offset = damp;
4087
- disableScroll = true;
4088
- }
4089
- }
4090
- if (disableScroll) setTimeout(() => disableScroll = false, 40);
4091
- }
4092
- };
4093
- el.addEventListener("scroll", onScroll, { passive: true });
4094
- requestAnimationFrame(() => firstRun = false);
4095
- const onWheel = (e) => el.scrollLeft += e.deltaY / 2;
4096
- if (horizontal) el.addEventListener("wheel", onWheel, { passive: true });
4097
- return () => {
4098
- el.removeEventListener("scroll", onScroll);
4099
- if (horizontal) el.removeEventListener("wheel", onWheel);
4100
- };
4101
- }
4102
- }, [el, events, size, infinite, state, invalidate, horizontal, enabled]);
4103
- let last = 0;
4104
- useFrame((_, delta) => {
4105
- last = state.offset;
4106
- easing.damp(state, "offset", scroll.current, damping, delta, maxSpeed, void 0, eps);
4107
- easing.damp(state, "delta", Math.abs(last - state.offset), damping, delta, maxSpeed, void 0, eps);
4108
- if (state.delta > eps) invalidate();
4109
- });
4110
- return /* @__PURE__ */ React.createElement(context$7.Provider, { value: state }, children);
4111
- }
4112
3334
  const ScrollCanvas = /* @__PURE__ */ React.forwardRef(
4113
3335
  ({ children }, ref) => {
4114
3336
  const group = React.useRef(null);
@@ -4129,10 +3351,23 @@ const ScrollHtml = React.forwardRef(
4129
3351
  React.useImperativeHandle(ref, () => group.current, []);
4130
3352
  const { width, height } = useThree((state2) => state2.size);
4131
3353
  const fiberState = React.useContext(context$a);
4132
- const root = React.useMemo(() => ReactDOM.createRoot(state.fixed), [state.fixed]);
3354
+ const root = React.useMemo(() => {
3355
+ let root2 = rootCache.get(state.fixed);
3356
+ if (!root2) {
3357
+ root2 = ReactDOM.createRoot(state.fixed);
3358
+ rootCache.set(state.fixed, root2);
3359
+ }
3360
+ return root2;
3361
+ }, [state.fixed]);
4133
3362
  useFrame(() => {
4134
3363
  if (state.delta > state.eps) {
4135
- group.current.style.transform = `translate3d(${state.horizontal ? -width * (state.pages - 1) * state.offset : 0}px,${state.horizontal ? 0 : height * (state.pages - 1) * -state.offset}px,0)`;
3364
+ let x = state.horizontal ? -width * (state.pages - 1) * state.offset : 0;
3365
+ let y = state.horizontal ? 0 : height * (state.pages - 1) * -state.offset;
3366
+ if (state.pixelPerfect) {
3367
+ x = roundToPixelRatio(x);
3368
+ y = roundToPixelRatio(y);
3369
+ }
3370
+ group.current.style.transform = `translate3d(${x}px,${y}px,0)`;
4136
3371
  }
4137
3372
  });
4138
3373
  root.render(
@@ -4156,51 +3391,6 @@ const Scroll = /* @__PURE__ */ React.forwardRef(
4156
3391
  }
4157
3392
  );
4158
3393
 
4159
- const TrackballControls = /* @__PURE__ */ React.forwardRef(
4160
- ({ makeDefault, camera, domElement, regress, onChange, onStart, onEnd, ...restProps }, ref) => {
4161
- const { invalidate, camera: defaultCamera, gl, events, set, get, performance, viewport } = useThree();
4162
- const explCamera = camera || defaultCamera;
4163
- const explDomElement = domElement || events.connected || gl.domElement;
4164
- const controls = React.useMemo(
4165
- () => new TrackballControls$1(explCamera),
4166
- [explCamera]
4167
- );
4168
- useFrame(() => {
4169
- if (controls.enabled) controls.update();
4170
- }, -1);
4171
- React.useEffect(() => {
4172
- controls.connect(explDomElement);
4173
- return () => void controls.dispose();
4174
- }, [explDomElement, regress, controls, invalidate]);
4175
- React.useEffect(() => {
4176
- const callback = (e) => {
4177
- invalidate();
4178
- if (regress) performance.regress();
4179
- if (onChange) onChange(e);
4180
- };
4181
- controls.addEventListener("change", callback);
4182
- if (onStart) controls.addEventListener("start", onStart);
4183
- if (onEnd) controls.addEventListener("end", onEnd);
4184
- return () => {
4185
- if (onStart) controls.removeEventListener("start", onStart);
4186
- if (onEnd) controls.removeEventListener("end", onEnd);
4187
- controls.removeEventListener("change", callback);
4188
- };
4189
- }, [onChange, onStart, onEnd, controls, invalidate]);
4190
- React.useEffect(() => {
4191
- controls.handleResize();
4192
- }, [viewport]);
4193
- React.useEffect(() => {
4194
- if (makeDefault) {
4195
- const old = get().controls;
4196
- set({ controls });
4197
- return () => set({ controls: old });
4198
- }
4199
- }, [makeDefault, controls]);
4200
- return /* @__PURE__ */ React.createElement("primitive", { ref, object: controls, ...restProps });
4201
- }
4202
- );
4203
-
4204
3394
  const CameraShake = /* @__PURE__ */ React.forwardRef(
4205
3395
  ({
4206
3396
  intensity = 1,
@@ -5061,377 +4251,6 @@ const Text3D = /* @__PURE__ */ React.forwardRef(
5061
4251
  }
5062
4252
  );
5063
4253
 
5064
- const WireframeMaterialShaders$1 = {
5065
- uniforms: {
5066
- strokeOpacity: 1,
5067
- fillOpacity: 0.25,
5068
- fillMix: 0,
5069
- thickness: 0.05,
5070
- colorBackfaces: false,
5071
- dashInvert: true,
5072
- dash: false,
5073
- dashRepeats: 4,
5074
- dashLength: 0.5,
5075
- squeeze: false,
5076
- squeezeMin: 0.2,
5077
- squeezeMax: 1,
5078
- stroke: /* @__PURE__ */ new THREE.Color("#ff0000"),
5079
- backfaceStroke: /* @__PURE__ */ new THREE.Color("#0000ff"),
5080
- fill: /* @__PURE__ */ new THREE.Color("#00ff00")
5081
- },
5082
- vertex: (
5083
- /* glsl */
5084
- `
5085
- attribute vec3 barycentric;
5086
-
5087
- varying vec3 v_edges_Barycentric;
5088
- varying vec3 v_edges_Position;
5089
-
5090
- void initWireframe() {
5091
- v_edges_Barycentric = barycentric;
5092
- v_edges_Position = position.xyz;
5093
- }
5094
- `
5095
- ),
5096
- fragment: (
5097
- /* glsl */
5098
- `
5099
- #ifndef PI
5100
- #define PI 3.1415926535897932384626433832795
5101
- #endif
5102
-
5103
- varying vec3 v_edges_Barycentric;
5104
- varying vec3 v_edges_Position;
5105
-
5106
- uniform float strokeOpacity;
5107
- uniform float fillOpacity;
5108
- uniform float fillMix;
5109
- uniform float thickness;
5110
- uniform bool colorBackfaces;
5111
-
5112
- // Dash
5113
- uniform bool dashInvert;
5114
- uniform bool dash;
5115
- uniform bool dashOnly;
5116
- uniform float dashRepeats;
5117
- uniform float dashLength;
5118
-
5119
- // Squeeze
5120
- uniform bool squeeze;
5121
- uniform float squeezeMin;
5122
- uniform float squeezeMax;
5123
-
5124
- // Colors
5125
- uniform vec3 stroke;
5126
- uniform vec3 backfaceStroke;
5127
- uniform vec3 fill;
5128
-
5129
- // This is like
5130
- float wireframe_aastep(float threshold, float dist) {
5131
- float afwidth = fwidth(dist) * 0.5;
5132
- return smoothstep(threshold - afwidth, threshold + afwidth, dist);
5133
- }
5134
-
5135
- float wireframe_map(float value, float min1, float max1, float min2, float max2) {
5136
- return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
5137
- }
5138
-
5139
- float getWireframe() {
5140
- vec3 barycentric = v_edges_Barycentric;
5141
-
5142
- // Distance from center of each triangle to its edges.
5143
- float d = min(min(barycentric.x, barycentric.y), barycentric.z);
5144
-
5145
- // for dashed rendering, we can use this to get the 0 .. 1 value of the line length
5146
- float positionAlong = max(barycentric.x, barycentric.y);
5147
- if (barycentric.y < barycentric.x && barycentric.y < barycentric.z) {
5148
- positionAlong = 1.0 - positionAlong;
5149
- }
5150
-
5151
- // the thickness of the stroke
5152
- float computedThickness = wireframe_map(thickness, 0.0, 1.0, 0.0, 0.34);
5153
-
5154
- // if we want to shrink the thickness toward the center of the line segment
5155
- if (squeeze) {
5156
- computedThickness *= mix(squeezeMin, squeezeMax, (1.0 - sin(positionAlong * PI)));
5157
- }
5158
-
5159
- // Create dash pattern
5160
- if (dash) {
5161
- // here we offset the stroke position depending on whether it
5162
- // should overlap or not
5163
- float offset = 1.0 / dashRepeats * dashLength / 2.0;
5164
- if (!dashInvert) {
5165
- offset += 1.0 / dashRepeats / 2.0;
5166
- }
5167
-
5168
- // if we should animate the dash or not
5169
- // if (dashAnimate) {
5170
- // offset += time * 0.22;
5171
- // }
5172
-
5173
- // create the repeating dash pattern
5174
- float pattern = fract((positionAlong + offset) * dashRepeats);
5175
- computedThickness *= 1.0 - wireframe_aastep(dashLength, pattern);
5176
- }
5177
-
5178
- // compute the anti-aliased stroke edge
5179
- float edge = 1.0 - wireframe_aastep(computedThickness, d);
5180
-
5181
- return edge;
5182
- }
5183
- `
5184
- )
5185
- };
5186
- const WireframeMaterial$1 = /* @__PURE__ */ shaderMaterial(
5187
- WireframeMaterialShaders$1.uniforms,
5188
- WireframeMaterialShaders$1.vertex + /* glsl */
5189
- `
5190
- void main() {
5191
- initWireframe();
5192
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
5193
- }
5194
- `,
5195
- WireframeMaterialShaders$1.fragment + /* glsl */
5196
- `
5197
- void main () {
5198
- // Compute color
5199
-
5200
- float edge = getWireframe();
5201
- vec4 colorStroke = vec4(stroke, edge);
5202
-
5203
- #ifdef FLIP_SIDED
5204
- colorStroke.rgb = backfaceStroke;
5205
- #endif
5206
-
5207
- vec4 colorFill = vec4(fill, fillOpacity);
5208
- vec4 outColor = mix(colorFill, colorStroke, edge * strokeOpacity);
5209
-
5210
- gl_FragColor = outColor;
5211
- }
5212
- `
5213
- );
5214
- function setWireframeOverride$1(material, uniforms) {
5215
- material.onBeforeCompile = (shader) => {
5216
- shader.uniforms = {
5217
- ...shader.uniforms,
5218
- ...uniforms
5219
- };
5220
- shader.vertexShader = shader.vertexShader.replace(
5221
- "void main() {",
5222
- `
5223
- ${WireframeMaterialShaders$1.vertex}
5224
- void main() {
5225
- initWireframe();
5226
- `
5227
- );
5228
- shader.fragmentShader = shader.fragmentShader.replace(
5229
- "void main() {",
5230
- `
5231
- ${WireframeMaterialShaders$1.fragment}
5232
- void main() {
5233
- `
5234
- );
5235
- shader.fragmentShader = shader.fragmentShader.replace(
5236
- "#include <color_fragment>",
5237
- /* glsl */
5238
- `
5239
- #include <color_fragment>
5240
- float edge = getWireframe();
5241
- vec4 colorStroke = vec4(stroke, edge);
5242
- #ifdef FLIP_SIDED
5243
- colorStroke.rgb = backfaceStroke;
5244
- #endif
5245
- vec4 colorFill = vec4(mix(diffuseColor.rgb, fill, fillMix), mix(diffuseColor.a, fillOpacity, fillMix));
5246
- vec4 outColor = mix(colorFill, colorStroke, edge * strokeOpacity);
5247
-
5248
- diffuseColor.rgb = outColor.rgb;
5249
- diffuseColor.a *= outColor.a;
5250
- `
5251
- );
5252
- };
5253
- material.side = THREE.DoubleSide;
5254
- material.transparent = true;
5255
- }
5256
- function useWireframeUniforms$1(uniforms, props) {
5257
- React.useEffect(
5258
- () => void (uniforms.fillOpacity.value = props.fillOpacity ?? uniforms.fillOpacity.value),
5259
- [props.fillOpacity]
5260
- );
5261
- React.useEffect(() => void (uniforms.fillMix.value = props.fillMix ?? uniforms.fillMix.value), [props.fillMix]);
5262
- React.useEffect(
5263
- () => void (uniforms.strokeOpacity.value = props.strokeOpacity ?? uniforms.strokeOpacity.value),
5264
- [props.strokeOpacity]
5265
- );
5266
- React.useEffect(
5267
- () => void (uniforms.thickness.value = props.thickness ?? uniforms.thickness.value),
5268
- [props.thickness]
5269
- );
5270
- React.useEffect(() => void (uniforms.colorBackfaces.value = !!props.colorBackfaces), [props.colorBackfaces]);
5271
- React.useEffect(() => void (uniforms.dash.value = !!props.dash), [props.dash]);
5272
- React.useEffect(() => void (uniforms.dashInvert.value = !!props.dashInvert), [props.dashInvert]);
5273
- React.useEffect(
5274
- () => void (uniforms.dashRepeats.value = props.dashRepeats ?? uniforms.dashRepeats.value),
5275
- [props.dashRepeats]
5276
- );
5277
- React.useEffect(
5278
- () => void (uniforms.dashLength.value = props.dashLength ?? uniforms.dashLength.value),
5279
- [props.dashLength]
5280
- );
5281
- React.useEffect(() => void (uniforms.squeeze.value = !!props.squeeze), [props.squeeze]);
5282
- React.useEffect(
5283
- () => void (uniforms.squeezeMin.value = props.squeezeMin ?? uniforms.squeezeMin.value),
5284
- [props.squeezeMin]
5285
- );
5286
- React.useEffect(
5287
- () => void (uniforms.squeezeMax.value = props.squeezeMax ?? uniforms.squeezeMax.value),
5288
- [props.squeezeMax]
5289
- );
5290
- React.useEffect(
5291
- () => void (uniforms.stroke.value = props.stroke ? new THREE.Color(props.stroke) : uniforms.stroke.value),
5292
- [props.stroke]
5293
- );
5294
- React.useEffect(
5295
- () => void (uniforms.fill.value = props.fill ? new THREE.Color(props.fill) : uniforms.fill.value),
5296
- [props.fill]
5297
- );
5298
- React.useEffect(
5299
- () => void (uniforms.backfaceStroke.value = props.backfaceStroke ? new THREE.Color(props.backfaceStroke) : uniforms.backfaceStroke.value),
5300
- [props.backfaceStroke]
5301
- );
5302
- }
5303
-
5304
- function isWithGeometry(object) {
5305
- return !!object?.geometry;
5306
- }
5307
- function isGeometry(object) {
5308
- return !!object?.isBufferGeometry;
5309
- }
5310
- function isRefObject$1(object) {
5311
- return !!object?.current;
5312
- }
5313
- function isRef$1(object) {
5314
- return object?.current !== void 0;
5315
- }
5316
- function isWireframeGeometry(geometry) {
5317
- return geometry.type === "WireframeGeometry";
5318
- }
5319
- function getUniforms() {
5320
- const u = {};
5321
- for (const key in WireframeMaterialShaders$1.uniforms) {
5322
- u[key] = { value: WireframeMaterialShaders$1.uniforms[key] };
5323
- }
5324
- return u;
5325
- }
5326
- function getBarycentricCoordinates(geometry, removeEdge) {
5327
- const position = geometry.getAttribute("position");
5328
- const count = position.count;
5329
- const barycentric = [];
5330
- for (let i = 0; i < count; i++) {
5331
- const even = i % 2 === 0;
5332
- const Q = removeEdge ? 1 : 0;
5333
- if (even) {
5334
- barycentric.push(0, 0, 1, 0, 1, 0, 1, 0, Q);
5335
- } else {
5336
- barycentric.push(0, 1, 0, 0, 0, 1, 1, 0, Q);
5337
- }
5338
- }
5339
- return new THREE.BufferAttribute(Float32Array.from(barycentric), 3);
5340
- }
5341
- function getInputGeometry(inputGeometry) {
5342
- const geo = isRefObject$1(inputGeometry) ? inputGeometry.current : inputGeometry;
5343
- if (!isGeometry(geo)) {
5344
- if (isWireframeGeometry(geo)) {
5345
- throw new Error("Wireframe: WireframeGeometry is not supported.");
5346
- }
5347
- const parent = geo.parent;
5348
- if (isWithGeometry(parent)) {
5349
- if (isWireframeGeometry(parent.geometry)) {
5350
- throw new Error("Wireframe: WireframeGeometry is not supported.");
5351
- }
5352
- return parent.geometry;
5353
- }
5354
- } else {
5355
- return geo;
5356
- }
5357
- }
5358
- function setBarycentricCoordinates$1(geometry, simplify) {
5359
- if (geometry.index) {
5360
- console.warn("Wireframe: Requires non-indexed geometry, converting to non-indexed geometry.");
5361
- const nonIndexedGeo = geometry.toNonIndexed();
5362
- geometry.copy(nonIndexedGeo);
5363
- geometry.setIndex(null);
5364
- }
5365
- const newBarycentric = getBarycentricCoordinates(geometry, simplify);
5366
- geometry.setAttribute("barycentric", newBarycentric);
5367
- }
5368
- function WireframeWithCustomGeo({
5369
- geometry: customGeometry,
5370
- simplify = false,
5371
- ...props
5372
- }) {
5373
- extend({ MeshWireframeMaterial: WireframeMaterial$1 });
5374
- const [geometry, setGeometry] = React.useState(null);
5375
- React.useLayoutEffect(() => {
5376
- const geom = getInputGeometry(customGeometry);
5377
- if (!geom) {
5378
- throw new Error("Wireframe: geometry prop must be a BufferGeometry or a ref to a BufferGeometry.");
5379
- }
5380
- setBarycentricCoordinates$1(geom, simplify);
5381
- if (isRef$1(customGeometry)) {
5382
- setGeometry(geom);
5383
- }
5384
- }, [simplify, customGeometry]);
5385
- const drawnGeo = isRef$1(customGeometry) ? geometry : customGeometry;
5386
- return /* @__PURE__ */ React.createElement(React.Fragment, null, drawnGeo && /* @__PURE__ */ React.createElement("mesh", { geometry: drawnGeo }, /* @__PURE__ */ React.createElement(
5387
- "meshWireframeMaterial",
5388
- {
5389
- attach: "material",
5390
- transparent: true,
5391
- side: THREE.DoubleSide,
5392
- polygonOffset: true,
5393
- polygonOffsetFactor: -4,
5394
- ...props
5395
- }
5396
- )));
5397
- }
5398
- function WireframeWithoutCustomGeo({
5399
- simplify = false,
5400
- ...props
5401
- }) {
5402
- const objectRef = React.useRef(null);
5403
- const uniforms = React.useMemo(() => getUniforms(), [WireframeMaterialShaders$1.uniforms]);
5404
- useWireframeUniforms$1(uniforms, props);
5405
- React.useLayoutEffect(() => {
5406
- const geom = getInputGeometry(objectRef);
5407
- if (!geom) {
5408
- throw new Error("Wireframe: Must be a child of a Mesh, Line or Points object or specify a geometry prop.");
5409
- }
5410
- const og = geom.clone();
5411
- setBarycentricCoordinates$1(geom, simplify);
5412
- return () => {
5413
- geom.copy(og);
5414
- og.dispose();
5415
- };
5416
- }, [simplify]);
5417
- React.useLayoutEffect(() => {
5418
- const parentMesh = objectRef.current.parent;
5419
- const og = parentMesh.material.clone();
5420
- setWireframeOverride$1(parentMesh.material, uniforms);
5421
- return () => {
5422
- parentMesh.material.dispose();
5423
- parentMesh.material = og;
5424
- };
5425
- }, []);
5426
- return /* @__PURE__ */ React.createElement("object3D", { ref: objectRef });
5427
- }
5428
- function Wireframe({ geometry: customGeometry, ...props }) {
5429
- if (customGeometry) {
5430
- return /* @__PURE__ */ React.createElement(WireframeWithCustomGeo, { geometry: customGeometry, ...props });
5431
- }
5432
- return /* @__PURE__ */ React.createElement(WireframeWithoutCustomGeo, { ...props });
5433
- }
5434
-
5435
4254
  const Context = /* @__PURE__ */ React.createContext({});
5436
4255
  const useGizmoContext = () => {
5437
4256
  return React.useContext(Context);
@@ -5727,6 +4546,11 @@ const GizmoViewport = ({
5727
4546
  return /* @__PURE__ */ React.createElement("group", { scale: 40, ...props }, /* @__PURE__ */ React.createElement(Axis, { color: colorX, rotation: [0, 0, 0], scale: axisScale }), /* @__PURE__ */ React.createElement(Axis, { color: colorY, rotation: [0, 0, Math.PI / 2], scale: axisScale }), /* @__PURE__ */ React.createElement(Axis, { color: colorZ, rotation: [0, -Math.PI / 2, 0], scale: axisScale }), !hideAxisHeads && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(AxisHead, { arcStyle: colorX, position: [1, 0, 0], label: labels[0], ...axisHeadProps }), /* @__PURE__ */ React.createElement(AxisHead, { arcStyle: colorY, position: [0, 1, 0], label: labels[1], ...axisHeadProps }), /* @__PURE__ */ React.createElement(AxisHead, { arcStyle: colorZ, position: [0, 0, 1], label: labels[2], ...axisHeadProps }), !hideNegativeAxes && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(AxisHead, { arcStyle: colorX, position: [-1, 0, 0], ...axisHeadProps }), /* @__PURE__ */ React.createElement(AxisHead, { arcStyle: colorY, position: [0, -1, 0], ...axisHeadProps }), /* @__PURE__ */ React.createElement(AxisHead, { arcStyle: colorZ, position: [0, 0, -1], ...axisHeadProps }))));
5728
4547
  };
5729
4548
 
4549
+ const roundEven = (n) => {
4550
+ const rounded = Math.ceil(n);
4551
+ return rounded % 2 === 0 ? rounded : rounded + 1;
4552
+ };
4553
+
5730
4554
  const v1 = /* @__PURE__ */ new Vector3();
5731
4555
  const v2 = /* @__PURE__ */ new Vector3();
5732
4556
  const v3 = /* @__PURE__ */ new Vector3();
@@ -5798,10 +4622,10 @@ const getCameraCSSMatrix = /* @__PURE__ */ ((multipliers) => {
5798
4622
  const getObjectCSSMatrix = /* @__PURE__ */ ((scaleMultipliers) => {
5799
4623
  return (matrix, factor) => getCSSMatrix(matrix, scaleMultipliers(factor), "translate(-50%,-50%)");
5800
4624
  })((f) => [1 / f, 1 / f, 1 / f, 1, -1 / f, -1 / f, -1 / f, -1, 1 / f, 1 / f, 1 / f, 1, 1, 1, 1, 1]);
5801
- function isRefObject(ref) {
4625
+ function isRefObject$1(ref) {
5802
4626
  return ref && typeof ref === "object" && "current" in ref;
5803
4627
  }
5804
- const Html$1 = /* @__PURE__ */ React.forwardRef(
4628
+ const Html = /* @__PURE__ */ React.forwardRef(
5805
4629
  ({
5806
4630
  children,
5807
4631
  eps = 1e-3,
@@ -5825,9 +4649,11 @@ const Html$1 = /* @__PURE__ */ React.forwardRef(
5825
4649
  as = "div",
5826
4650
  wrapperClass,
5827
4651
  pointerEvents = "auto",
4652
+ pixelPerfect = true,
5828
4653
  ...props
5829
4654
  }, ref) => {
5830
4655
  const { gl, camera, scene, size, raycaster, events, viewport } = useThree();
4656
+ const forceEven = useThree((state) => state.internal.forceEven);
5831
4657
  const [el] = React.useState(() => document.createElement(as));
5832
4658
  const root = React.useRef(null);
5833
4659
  const group = React.useRef(null);
@@ -5839,7 +4665,7 @@ const Html$1 = /* @__PURE__ */ React.forwardRef(
5839
4665
  const occlusionMeshRef = React.useRef(null);
5840
4666
  const isMeshSizeSet = React.useRef(false);
5841
4667
  const isRayCastOcclusion = React.useMemo(() => {
5842
- return occlude && occlude !== "blending" || Array.isArray(occlude) && occlude.length && isRefObject(occlude[0]);
4668
+ return occlude && occlude !== "blending" || Array.isArray(occlude) && occlude.length && isRefObject$1(occlude[0]);
5843
4669
  }, [occlude]);
5844
4670
  React.useLayoutEffect(() => {
5845
4671
  const el2 = gl.domElement;
@@ -5852,38 +4678,54 @@ const Html$1 = /* @__PURE__ */ React.forwardRef(
5852
4678
  el2.style.position = null;
5853
4679
  el2.style.pointerEvents = null;
5854
4680
  }
5855
- }, [occlude]);
4681
+ }, [occlude, zIndexRange, gl.domElement]);
5856
4682
  React.useLayoutEffect(() => {
5857
4683
  if (group.current) {
5858
- const currentRoot = root.current = ReactDOM.createRoot(el);
4684
+ if (!root.current) {
4685
+ root.current = ReactDOM.createRoot(el);
4686
+ }
5859
4687
  scene.updateMatrixWorld();
5860
4688
  if (transform) {
5861
4689
  el.style.cssText = `position:absolute;top:0;left:0;pointer-events:none;overflow:hidden;`;
5862
4690
  } else {
5863
- const vec = calculatePosition(group.current, camera, size);
5864
- el.style.cssText = `position:absolute;top:0;left:0;transform:translate3d(${vec[0]}px,${vec[1]}px,0);transform-origin:0 0;`;
4691
+ el.style.cssText = `position:absolute;top:0;left:0;transform:translate3d(0,-9999px,0);transform-origin:0 0;`;
5865
4692
  }
5866
4693
  if (target) {
5867
4694
  if (prepend) target.prepend(el);
5868
4695
  else target.appendChild(el);
5869
4696
  }
5870
4697
  return () => {
5871
- if (target) target.removeChild(el);
5872
- currentRoot.unmount();
4698
+ if (root.current) {
4699
+ root.current.unmount();
4700
+ root.current = null;
4701
+ }
4702
+ if (target && target.contains(el)) {
4703
+ target.removeChild(el);
4704
+ }
5873
4705
  };
5874
4706
  }
5875
- }, [target, transform]);
4707
+ }, [target, transform, el, prepend, scene]);
5876
4708
  React.useLayoutEffect(() => {
5877
4709
  if (wrapperClass) el.className = wrapperClass;
5878
- }, [wrapperClass]);
4710
+ }, [wrapperClass, el]);
4711
+ React.useLayoutEffect(() => {
4712
+ return () => {
4713
+ if (root.current) {
4714
+ root.current.unmount();
4715
+ root.current = null;
4716
+ }
4717
+ };
4718
+ }, []);
5879
4719
  const styles = React.useMemo(() => {
4720
+ const width = forceEven ? roundEven(size.width) : size.width;
4721
+ const height = forceEven ? roundEven(size.height) : size.height;
5880
4722
  if (transform) {
5881
4723
  return {
5882
4724
  position: "absolute",
5883
4725
  top: 0,
5884
4726
  left: 0,
5885
- width: size.width,
5886
- height: size.height,
4727
+ width,
4728
+ height,
5887
4729
  transformStyle: "preserve-3d",
5888
4730
  pointerEvents: "none"
5889
4731
  };
@@ -5892,15 +4734,15 @@ const Html$1 = /* @__PURE__ */ React.forwardRef(
5892
4734
  position: "absolute",
5893
4735
  transform: center ? "translate3d(-50%,-50%,0)" : "none",
5894
4736
  ...fullscreen && {
5895
- top: -size.height / 2,
5896
- left: -size.width / 2,
5897
- width: size.width,
5898
- height: size.height
4737
+ top: forceEven ? roundEven(-size.height / 2) : -size.height / 2,
4738
+ left: forceEven ? roundEven(-size.width / 2) : -size.width / 2,
4739
+ width,
4740
+ height
5899
4741
  },
5900
4742
  ...style
5901
4743
  };
5902
4744
  }
5903
- }, [style, center, fullscreen, size, transform]);
4745
+ }, [style, center, fullscreen, size, transform, forceEven]);
5904
4746
  const transformInnerStyles = React.useMemo(
5905
4747
  () => ({ position: "absolute", pointerEvents }),
5906
4748
  [pointerEvents]
@@ -5914,7 +4756,7 @@ const Html$1 = /* @__PURE__ */ React.forwardRef(
5914
4756
  } else {
5915
4757
  root.current?.render(/* @__PURE__ */ React.createElement("div", { ref, style: styles, className, children }));
5916
4758
  }
5917
- });
4759
+ }, [transform, styles, transformInnerStyles, ref, className, style, children]);
5918
4760
  const visible = React.useRef(true);
5919
4761
  useFrame((gl2) => {
5920
4762
  if (group.current) {
@@ -5946,7 +4788,12 @@ const Html$1 = /* @__PURE__ */ React.forwardRef(
5946
4788
  const zRange = occlude ? isRayCastOcclusion ? [zIndexRange[0], halfRange] : [halfRange - 1, 0] : zIndexRange;
5947
4789
  el.style.zIndex = `${objectZIndex(group.current, camera, zRange)}`;
5948
4790
  if (transform) {
5949
- const [widthHalf, heightHalf] = [size.width / 2, size.height / 2];
4791
+ let widthHalf = forceEven ? roundEven(size.width / 2) : size.width / 2;
4792
+ let heightHalf = forceEven ? roundEven(size.height / 2) : size.height / 2;
4793
+ if (pixelPerfect) {
4794
+ widthHalf = roundToPixelRatio(widthHalf);
4795
+ heightHalf = roundToPixelRatio(heightHalf);
4796
+ }
5950
4797
  const fov = camera.projectionMatrix.elements[5] * heightHalf;
5951
4798
  const { isOrthographicCamera, top, left, bottom, right } = camera;
5952
4799
  const cameraMatrix = getCameraCSSMatrix(camera.matrixWorldInverse);
@@ -5957,8 +4804,10 @@ const Html$1 = /* @__PURE__ */ React.forwardRef(
5957
4804
  matrix.elements[3] = matrix.elements[7] = matrix.elements[11] = 0;
5958
4805
  matrix.elements[15] = 1;
5959
4806
  }
5960
- el.style.width = size.width + "px";
5961
- el.style.height = size.height + "px";
4807
+ const elWidth = forceEven ? roundEven(size.width) : size.width;
4808
+ const elHeight = forceEven ? roundEven(size.height) : size.height;
4809
+ el.style.width = elWidth + "px";
4810
+ el.style.height = elHeight + "px";
5962
4811
  el.style.perspective = isOrthographicCamera ? "" : `${fov}px`;
5963
4812
  if (transformOuterRef.current && transformInnerRef.current) {
5964
4813
  transformOuterRef.current.style.transform = `${cameraTransform}${cameraMatrix}translate(${widthHalf}px,${heightHalf}px)`;
@@ -5966,7 +4815,13 @@ const Html$1 = /* @__PURE__ */ React.forwardRef(
5966
4815
  }
5967
4816
  } else {
5968
4817
  const scale = distanceFactor === void 0 ? 1 : objectScale(group.current, camera) * distanceFactor;
5969
- el.style.transform = `translate3d(${vec[0]}px,${vec[1]}px,0) scale(${scale})`;
4818
+ let x = forceEven ? roundEven(vec[0]) : vec[0];
4819
+ let y = forceEven ? roundEven(vec[1]) : vec[1];
4820
+ if (pixelPerfect) {
4821
+ x = roundToPixelRatio(x);
4822
+ y = roundToPixelRatio(y);
4823
+ }
4824
+ el.style.transform = `translate3d(${x}px,${y}px,0) scale(${scale})`;
5970
4825
  }
5971
4826
  oldPosition.current = vec;
5972
4827
  oldZoom.current = camera.zoom;
@@ -6072,6 +4927,11 @@ const Html$1 = /* @__PURE__ */ React.forwardRef(
6072
4927
  );
6073
4928
 
6074
4929
  const context$4 = /* @__PURE__ */ React.createContext(null);
4930
+ const resolveObject = (object, fallback) => {
4931
+ if (!object) return fallback;
4932
+ if ("current" in object) return object.current;
4933
+ return object;
4934
+ };
6075
4935
 
6076
4936
  const vec1$1 = /* @__PURE__ */ new THREE.Vector3();
6077
4937
  const vec2$1 = /* @__PURE__ */ new THREE.Vector3();
@@ -6106,6 +4966,8 @@ const AxisArrow = ({ direction, axis }) => {
6106
4966
  onDragStart,
6107
4967
  onDrag,
6108
4968
  onDragEnd,
4969
+ onHover,
4970
+ dragState,
6109
4971
  userData,
6110
4972
  LineComponent: Line
6111
4973
  } = React.useContext(context$4);
@@ -6137,7 +4999,13 @@ const AxisArrow = ({ direction, axis }) => {
6137
4999
  const onPointerMove = React.useCallback(
6138
5000
  (e) => {
6139
5001
  e.stopPropagation();
6140
- if (!isHovered) setIsHovered(true);
5002
+ if (!isHovered) {
5003
+ const drag = dragState.current;
5004
+ if (drag === null || drag.component === "Arrow" && drag.axis === axis) {
5005
+ setIsHovered(true);
5006
+ onHover({ component: "Arrow", axis, hovering: true });
5007
+ }
5008
+ }
6141
5009
  if (clickInfo.current) {
6142
5010
  const { clickPoint, dir } = clickInfo.current;
6143
5011
  const [min, max] = translationLimits?.[axis] || [void 0, void 0];
@@ -6156,7 +5024,7 @@ const AxisArrow = ({ direction, axis }) => {
6156
5024
  onDrag(offsetMatrix$1);
6157
5025
  }
6158
5026
  },
6159
- [annotations, onDrag, isHovered, translation, translationLimits, axis]
5027
+ [annotations, onDrag, onHover, dragState, isHovered, translation, translationLimits, axis]
6160
5028
  );
6161
5029
  const onPointerUp = React.useCallback(
6162
5030
  (e) => {
@@ -6171,10 +5039,16 @@ const AxisArrow = ({ direction, axis }) => {
6171
5039
  },
6172
5040
  [annotations, camControls, onDragEnd]
6173
5041
  );
6174
- const onPointerOut = React.useCallback((e) => {
6175
- e.stopPropagation();
6176
- setIsHovered(false);
6177
- }, []);
5042
+ const onPointerOut = React.useCallback(
5043
+ (e) => {
5044
+ e.stopPropagation();
5045
+ if (isHovered) {
5046
+ setIsHovered(false);
5047
+ onHover({ component: "Arrow", axis, hovering: false });
5048
+ }
5049
+ },
5050
+ [onHover, axis, isHovered]
5051
+ );
6178
5052
  const { cylinderLength, coneWidth, coneLength, matrixL } = React.useMemo(() => {
6179
5053
  const coneWidth2 = fixed ? lineWidth / scale * 1.6 : scale / 20;
6180
5054
  const coneLength2 = fixed ? 0.2 : scale / 5;
@@ -6194,7 +5068,7 @@ const AxisArrow = ({ direction, axis }) => {
6194
5068
  onPointerUp,
6195
5069
  onPointerOut
6196
5070
  },
6197
- annotations && /* @__PURE__ */ React.createElement(Html$1, { position: [0, -coneLength, 0] }, /* @__PURE__ */ React.createElement(
5071
+ annotations && /* @__PURE__ */ React.createElement(Html, { position: [0, -coneLength, 0] }, /* @__PURE__ */ React.createElement(
6198
5072
  "div",
6199
5073
  {
6200
5074
  style: {
@@ -6278,6 +5152,8 @@ const rotMatrix = /* @__PURE__ */ new THREE.Matrix4();
6278
5152
  const posNew = /* @__PURE__ */ new THREE.Vector3();
6279
5153
  const ray$1 = /* @__PURE__ */ new THREE.Ray();
6280
5154
  const intersection$1 = /* @__PURE__ */ new THREE.Vector3();
5155
+ const viewPlane = /* @__PURE__ */ new THREE.Plane();
5156
+ const viewIntersection = /* @__PURE__ */ new THREE.Vector3();
6281
5157
  const AxisRotator = ({
6282
5158
  dir1,
6283
5159
  dir2,
@@ -6298,6 +5174,8 @@ const AxisRotator = ({
6298
5174
  onDragStart,
6299
5175
  onDrag,
6300
5176
  onDragEnd,
5177
+ onHover,
5178
+ dragState,
6301
5179
  userData,
6302
5180
  LineComponent: Line
6303
5181
  } = React.useContext(context$4);
@@ -6331,14 +5209,29 @@ const AxisRotator = ({
6331
5209
  const onPointerMove = React.useCallback(
6332
5210
  (e) => {
6333
5211
  e.stopPropagation();
6334
- if (!isHovered) setIsHovered(true);
5212
+ if (!isHovered) {
5213
+ const drag = dragState.current;
5214
+ if (drag === null || drag.component === "Rotator" && drag.axis === axis) {
5215
+ setIsHovered(true);
5216
+ onHover({ component: "Rotator", axis, hovering: true });
5217
+ }
5218
+ }
6335
5219
  if (clickInfo.current) {
6336
5220
  const { clickPoint, origin, e1, e2, normal, plane } = clickInfo.current;
6337
5221
  const [min, max] = rotationLimits?.[axis] || [void 0, void 0];
6338
5222
  ray$1.copy(e.ray);
6339
- ray$1.intersectPlane(plane, intersection$1);
6340
- ray$1.direction.negate();
6341
- ray$1.intersectPlane(plane, intersection$1);
5223
+ const dotProduct = Math.abs(ray$1.direction.dot(normal));
5224
+ if (dotProduct < 0.1) {
5225
+ viewPlane.setFromNormalAndCoplanarPoint(ray$1.direction.clone().negate(), origin);
5226
+ ray$1.intersectPlane(viewPlane, viewIntersection);
5227
+ const toIntersection = viewIntersection.clone().sub(origin);
5228
+ const projectedDist = toIntersection.dot(normal);
5229
+ intersection$1.copy(viewIntersection).sub(normal.clone().multiplyScalar(projectedDist));
5230
+ } else {
5231
+ ray$1.intersectPlane(plane, intersection$1);
5232
+ ray$1.direction.negate();
5233
+ ray$1.intersectPlane(plane, intersection$1);
5234
+ }
6342
5235
  let deltaAngle = calculateAngle(clickPoint, intersection$1, origin, e1, e2);
6343
5236
  let degrees = toDegrees(deltaAngle);
6344
5237
  if (e.shiftKey) {
@@ -6364,7 +5257,7 @@ const AxisRotator = ({
6364
5257
  onDrag(rotMatrix);
6365
5258
  }
6366
5259
  },
6367
- [annotations, onDrag, isHovered, rotationLimits, axis]
5260
+ [annotations, onDrag, onHover, dragState, isHovered, rotationLimits, axis]
6368
5261
  );
6369
5262
  const onPointerUp = React.useCallback(
6370
5263
  (e) => {
@@ -6380,10 +5273,16 @@ const AxisRotator = ({
6380
5273
  },
6381
5274
  [annotations, camControls, onDragEnd]
6382
5275
  );
6383
- const onPointerOut = React.useCallback((e) => {
6384
- e.stopPropagation();
6385
- setIsHovered(false);
6386
- }, []);
5276
+ const onPointerOut = React.useCallback(
5277
+ (e) => {
5278
+ e.stopPropagation();
5279
+ if (isHovered) {
5280
+ setIsHovered(false);
5281
+ onHover({ component: "Rotator", axis, hovering: false });
5282
+ }
5283
+ },
5284
+ [onHover, axis, isHovered]
5285
+ );
6387
5286
  const matrixL = React.useMemo(() => {
6388
5287
  const dir1N = dir1.clone().normalize();
6389
5288
  const dir2N = dir2.clone().normalize();
@@ -6410,7 +5309,7 @@ const AxisRotator = ({
6410
5309
  matrix: matrixL,
6411
5310
  matrixAutoUpdate: false
6412
5311
  },
6413
- annotations && /* @__PURE__ */ React.createElement(Html$1, { position: [r, r, 0] }, /* @__PURE__ */ React.createElement(
5312
+ annotations && /* @__PURE__ */ React.createElement(Html, { position: [r, r, 0] }, /* @__PURE__ */ React.createElement(
6414
5313
  "div",
6415
5314
  {
6416
5315
  style: {
@@ -6484,6 +5383,8 @@ const PlaneSlider = ({
6484
5383
  onDragStart,
6485
5384
  onDrag,
6486
5385
  onDragEnd,
5386
+ onHover,
5387
+ dragState,
6487
5388
  userData,
6488
5389
  LineComponent: Line
6489
5390
  } = React.useContext(context$4);
@@ -6519,7 +5420,13 @@ const PlaneSlider = ({
6519
5420
  const onPointerMove = React.useCallback(
6520
5421
  (e) => {
6521
5422
  e.stopPropagation();
6522
- if (!isHovered) setIsHovered(true);
5423
+ if (!isHovered) {
5424
+ const drag = dragState.current;
5425
+ if (drag === null || drag.component === "Slider" && drag.axis === axis) {
5426
+ setIsHovered(true);
5427
+ onHover({ component: "Slider", axis, hovering: true });
5428
+ }
5429
+ }
6523
5430
  if (clickInfo.current) {
6524
5431
  const { clickPoint, e1, e2, plane } = clickInfo.current;
6525
5432
  const [minX, maxX] = translationLimits?.[(axis + 1) % 3] || [void 0, void 0];
@@ -6555,7 +5462,7 @@ const PlaneSlider = ({
6555
5462
  onDrag(offsetMatrix);
6556
5463
  }
6557
5464
  },
6558
- [annotations, onDrag, isHovered, translation, translationLimits, axis]
5465
+ [annotations, onDrag, onHover, dragState, isHovered, translation, translationLimits, axis]
6559
5466
  );
6560
5467
  const onPointerUp = React.useCallback(
6561
5468
  (e) => {
@@ -6570,10 +5477,16 @@ const PlaneSlider = ({
6570
5477
  },
6571
5478
  [annotations, camControls, onDragEnd]
6572
5479
  );
6573
- const onPointerOut = React.useCallback((e) => {
6574
- e.stopPropagation();
6575
- setIsHovered(false);
6576
- }, []);
5480
+ const onPointerOut = React.useCallback(
5481
+ (e) => {
5482
+ e.stopPropagation();
5483
+ if (isHovered) {
5484
+ setIsHovered(false);
5485
+ onHover({ component: "Slider", axis, hovering: false });
5486
+ }
5487
+ },
5488
+ [onHover, axis, isHovered]
5489
+ );
6577
5490
  const matrixL = React.useMemo(() => {
6578
5491
  const dir1N = dir1.clone().normalize();
6579
5492
  const dir2N = dir2.clone().normalize();
@@ -6592,7 +5505,7 @@ const PlaneSlider = ({
6592
5505
  ],
6593
5506
  [length]
6594
5507
  );
6595
- return /* @__PURE__ */ React.createElement("group", { ref: objRef, matrix: matrixL, matrixAutoUpdate: false }, annotations && /* @__PURE__ */ React.createElement(Html$1, { position: [0, 0, 0] }, /* @__PURE__ */ React.createElement(
5508
+ return /* @__PURE__ */ React.createElement("group", { ref: objRef, matrix: matrixL, matrixAutoUpdate: false }, annotations && /* @__PURE__ */ React.createElement(Html, { position: [0, 0, 0] }, /* @__PURE__ */ React.createElement(
6596
5509
  "div",
6597
5510
  {
6598
5511
  style: {
@@ -6711,6 +5624,8 @@ const ScalingSphere = ({ direction, axis }) => {
6711
5624
  onDragStart,
6712
5625
  onDrag,
6713
5626
  onDragEnd,
5627
+ onHover,
5628
+ dragState,
6714
5629
  userData
6715
5630
  } = React.useContext(context$4);
6716
5631
  const size = useThree((state) => state.size);
@@ -6747,7 +5662,13 @@ const ScalingSphere = ({ direction, axis }) => {
6747
5662
  const onPointerMove = React.useCallback(
6748
5663
  (e) => {
6749
5664
  e.stopPropagation();
6750
- if (!isHovered) setIsHovered(true);
5665
+ if (!isHovered) {
5666
+ const drag = dragState.current;
5667
+ if (drag === null || drag.component === "Sphere" && drag.axis === axis) {
5668
+ setIsHovered(true);
5669
+ onHover({ component: "Sphere", axis, hovering: true });
5670
+ }
5671
+ }
6751
5672
  if (clickInfo.current) {
6752
5673
  const { clickPoint, dir, mPLG, mPLGInv, offsetMultiplier } = clickInfo.current;
6753
5674
  const [min, max] = scaleLimits?.[axis] || [1e-5, void 0];
@@ -6773,7 +5694,7 @@ const ScalingSphere = ({ direction, axis }) => {
6773
5694
  onDrag(scaleMatrix);
6774
5695
  }
6775
5696
  },
6776
- [annotations, position, onDrag, isHovered, scaleLimits, axis]
5697
+ [annotations, position, onDrag, onHover, dragState, isHovered, scaleLimits, axis]
6777
5698
  );
6778
5699
  const onPointerUp = React.useCallback(
6779
5700
  (e) => {
@@ -6790,10 +5711,16 @@ const ScalingSphere = ({ direction, axis }) => {
6790
5711
  },
6791
5712
  [annotations, camControls, onDragEnd, position]
6792
5713
  );
6793
- const onPointerOut = React.useCallback((e) => {
6794
- e.stopPropagation();
6795
- setIsHovered(false);
6796
- }, []);
5714
+ const onPointerOut = React.useCallback(
5715
+ (e) => {
5716
+ e.stopPropagation();
5717
+ if (isHovered) {
5718
+ setIsHovered(false);
5719
+ onHover({ component: "Sphere", axis, hovering: false });
5720
+ }
5721
+ },
5722
+ [onHover, axis, isHovered]
5723
+ );
6797
5724
  const { radius, matrixL } = React.useMemo(() => {
6798
5725
  const radius2 = fixed ? lineWidth / scale * 1.8 : scale / 22.5;
6799
5726
  const quaternion = new THREE.Quaternion().setFromUnitVectors(upV, direction.clone().normalize());
@@ -6811,7 +5738,7 @@ const ScalingSphere = ({ direction, axis }) => {
6811
5738
  onPointerUp,
6812
5739
  onPointerOut
6813
5740
  },
6814
- annotations && /* @__PURE__ */ React.createElement(Html$1, { position: [0, position / 2, 0] }, /* @__PURE__ */ React.createElement(
5741
+ annotations && /* @__PURE__ */ React.createElement(Html, { position: [0, position / 2, 0] }, /* @__PURE__ */ React.createElement(
6815
5742
  "div",
6816
5743
  {
6817
5744
  style: {
@@ -6863,9 +5790,11 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
6863
5790
  ({
6864
5791
  enabled = true,
6865
5792
  matrix,
5793
+ object,
6866
5794
  onDragStart,
6867
5795
  onDrag,
6868
5796
  onDragEnd,
5797
+ onHover,
6869
5798
  autoTransform = true,
6870
5799
  anchor,
6871
5800
  disableAxes = false,
@@ -6901,14 +5830,35 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
6901
5830
  const gizmoRef = React.useRef(null);
6902
5831
  const childrenRef = React.useRef(null);
6903
5832
  const translation = React.useRef([0, 0, 0]);
5833
+ const dragState = React.useRef(null);
6904
5834
  const cameraScale = React.useRef(new THREE.Vector3(1, 1, 1));
6905
5835
  const gizmoScale = React.useRef(new THREE.Vector3(1, 1, 1));
5836
+ React.useEffect(() => {
5837
+ if (object) {
5838
+ const target = resolveObject(object);
5839
+ if (target) {
5840
+ const pivot = ref.current;
5841
+ const didAutoUpdate = target.matrixAutoUpdate;
5842
+ target.updateWorldMatrix(true, true);
5843
+ target.matrixAutoUpdate = false;
5844
+ pivot.matrix.copy(target.matrix);
5845
+ return () => {
5846
+ if (didAutoUpdate) {
5847
+ target.matrixAutoUpdate = true;
5848
+ target.matrix.decompose(target.position, target.quaternion, target.scale);
5849
+ }
5850
+ };
5851
+ }
5852
+ }
5853
+ }, [object]);
6906
5854
  React.useLayoutEffect(() => {
6907
5855
  if (!anchor) return;
6908
- childrenRef.current.updateWorldMatrix(true, true);
6909
- mPInv.copy(childrenRef.current.matrixWorld).invert();
5856
+ const anchorTarget = resolveObject(object, childrenRef.current);
5857
+ if (!anchorTarget) return;
5858
+ anchorTarget.updateWorldMatrix(true, true);
5859
+ mPInv.copy(anchorTarget.matrixWorld).invert();
6910
5860
  bb.makeEmpty();
6911
- childrenRef.current.traverse((obj) => {
5861
+ anchorTarget.traverse((obj) => {
6912
5862
  if (!obj.geometry) return;
6913
5863
  if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox();
6914
5864
  mL.copy(obj.matrixWorld).premultiply(mPInv);
@@ -6923,9 +5873,17 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
6923
5873
  gizmoRef.current.position.copy(vPosition);
6924
5874
  invalidate();
6925
5875
  });
5876
+ const mergedUserData = React.useMemo(
5877
+ () => ({
5878
+ ...userData,
5879
+ ...depthTest === false && { interactivePriority: 1 }
5880
+ }),
5881
+ [userData, depthTest]
5882
+ );
6926
5883
  const config = React.useMemo(
6927
5884
  () => ({
6928
5885
  onDragStart: (props2) => {
5886
+ dragState.current = props2;
6929
5887
  mL0.copy(ref.current.matrix);
6930
5888
  mW0.copy(ref.current.matrixWorld);
6931
5889
  onDragStart && onDragStart(props2);
@@ -6941,13 +5899,20 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
6941
5899
  if (autoTransform) {
6942
5900
  ref.current.matrix.copy(mL);
6943
5901
  }
5902
+ const target = resolveObject(object);
5903
+ if (target) target.matrix.copy(mL);
6944
5904
  onDrag && onDrag(mL, mdL, mW, mdW);
6945
5905
  invalidate();
6946
5906
  },
6947
5907
  onDragEnd: () => {
5908
+ dragState.current = null;
6948
5909
  if (onDragEnd) onDragEnd();
6949
5910
  invalidate();
6950
5911
  },
5912
+ onHover: (props2) => {
5913
+ if (onHover) onHover(props2);
5914
+ },
5915
+ dragState,
6951
5916
  translation,
6952
5917
  translationLimits,
6953
5918
  rotationLimits,
@@ -6959,7 +5924,7 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
6959
5924
  fixed,
6960
5925
  depthTest,
6961
5926
  renderOrder,
6962
- userData,
5927
+ userData: mergedUserData,
6963
5928
  annotations,
6964
5929
  annotationsClass,
6965
5930
  LineComponent: LineComp
@@ -6968,6 +5933,7 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
6968
5933
  onDragStart,
6969
5934
  onDrag,
6970
5935
  onDragEnd,
5936
+ onHover,
6971
5937
  translation,
6972
5938
  translationLimits,
6973
5939
  rotationLimits,
@@ -6979,11 +5945,12 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
6979
5945
  ...axisColors,
6980
5946
  hoveredColor,
6981
5947
  opacity,
6982
- userData,
5948
+ mergedUserData,
6983
5949
  autoTransform,
6984
5950
  annotations,
6985
5951
  annotationsClass,
6986
- LineComp
5952
+ LineComp,
5953
+ object
6987
5954
  ]
6988
5955
  );
6989
5956
  const vec = new THREE.Vector3();
@@ -7118,6 +6085,9 @@ const TransformControls = /* @__PURE__ */ React.forwardRef(
7118
6085
  }
7119
6086
  );
7120
6087
 
6088
+ const getVersion = () => parseInt(REVISION.replace(/\D+/g, ""));
6089
+ const version = /* @__PURE__ */ getVersion();
6090
+
7121
6091
  const opaque_fragment = version >= 154 ? "opaque_fragment" : "output_fragment";
7122
6092
  class PointMaterialImpl extends THREE.PointsMaterial {
7123
6093
  constructor(props) {
@@ -7345,7 +6315,7 @@ function createInstances() {
7345
6315
  ];
7346
6316
  }
7347
6317
  const InstancedAttribute = React.forwardRef(
7348
- ({ name, defaultValue, normalized, usage = THREE.DynamicDrawUsage }, fref) => {
6318
+ ({ name, defaultValue, normalized, usage = THREE.DynamicDrawUsage, type = "float" }, fref) => {
7349
6319
  const ref = React.useRef(null);
7350
6320
  React.useImperativeHandle(fref, () => ref.current, []);
7351
6321
  React.useLayoutEffect(() => {
@@ -7353,7 +6323,26 @@ const InstancedAttribute = React.forwardRef(
7353
6323
  parent.geometry.attributes[name] = ref.current;
7354
6324
  const value = Array.isArray(defaultValue) ? defaultValue : [defaultValue];
7355
6325
  const array = Array.from({ length: parent.userData.limit }, () => value).flat();
7356
- ref.current.array = new Float32Array(array);
6326
+ switch (type) {
6327
+ case "float":
6328
+ ref.current.array = new Float32Array(array);
6329
+ break;
6330
+ case "int":
6331
+ ref.current.array = new Int32Array(array);
6332
+ break;
6333
+ case "uint":
6334
+ ref.current.array = new Uint32Array(array);
6335
+ break;
6336
+ case "short":
6337
+ ref.current.array = new Int16Array(array);
6338
+ break;
6339
+ case "ushort":
6340
+ ref.current.array = new Uint16Array(array);
6341
+ break;
6342
+ case "byte":
6343
+ ref.current.array = new Uint8Array(array);
6344
+ break;
6345
+ }
7357
6346
  ref.current.itemSize = value.length;
7358
6347
  ref.current.count = array.length / ref.current.itemSize;
7359
6348
  return () => {
@@ -8878,12 +7867,17 @@ const Gltf = /* @__PURE__ */ React.forwardRef(
8878
7867
  }
8879
7868
  );
8880
7869
 
8881
- const cdn = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master";
8882
- function useKTX2(input, basisPath = `${cdn}/basis/`) {
7870
+ let transcoderPath = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/basis/";
7871
+ function useKTX2(input, basisPath = true, extendLoader) {
8883
7872
  const renderer = useThree((state) => state.renderer);
8884
7873
  const textures = useLoader(KTX2Loader, IsObject(input) ? Object.values(input) : input, (loader) => {
7874
+ if (extendLoader) {
7875
+ extendLoader(loader);
7876
+ }
7877
+ if (basisPath) {
7878
+ loader.setTranscoderPath(typeof basisPath === "string" ? basisPath : transcoderPath);
7879
+ }
8885
7880
  loader.detectSupport(renderer);
8886
- loader.setTranscoderPath(basisPath);
8887
7881
  });
8888
7882
  useEffect(() => {
8889
7883
  const array = Array.isArray(textures) ? textures : [textures];
@@ -8898,16 +7892,20 @@ function useKTX2(input, basisPath = `${cdn}/basis/`) {
8898
7892
  return textures;
8899
7893
  }
8900
7894
  }
8901
- useKTX2.preload = (url, basisPath = `${cdn}/basis/`) => useLoader.preload(KTX2Loader, url, (loader) => {
8902
- loader.setTranscoderPath(basisPath);
7895
+ useKTX2.preload = (url, basisPath = true, extendLoader) => useLoader.preload(KTX2Loader, url, (loader) => {
7896
+ if (extendLoader) {
7897
+ extendLoader(loader);
7898
+ }
7899
+ if (basisPath) {
7900
+ loader.setTranscoderPath(typeof basisPath === "string" ? basisPath : transcoderPath);
7901
+ }
8903
7902
  });
8904
7903
  useKTX2.clear = (input) => useLoader.clear(KTX2Loader, input);
8905
- const Ktx2 = ({
8906
- children,
8907
- input,
8908
- basisPath
8909
- }) => {
8910
- const texture = useKTX2(input, basisPath);
7904
+ useKTX2.setTranscoderPath = (path) => {
7905
+ transcoderPath = path;
7906
+ };
7907
+ const Ktx2 = ({ children, input, basisPath, extendLoader }) => {
7908
+ const texture = useKTX2(input, basisPath, extendLoader);
8911
7909
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children?.(texture));
8912
7910
  };
8913
7911
 
@@ -9194,18 +8192,21 @@ function Fisheye({
9194
8192
  const normal = new THREE.Vector3();
9195
8193
  const sph = new THREE.Sphere(new THREE.Vector3(), radius);
9196
8194
  const normalMatrix = new THREE.Matrix3();
9197
- const compute = React.useCallback((event, state, prev) => {
9198
- state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
9199
- state.raycaster.setFromCamera(state.pointer, orthoC);
9200
- if (!state.raycaster.ray.intersectSphere(sph, normal)) return;
9201
- else normal.normalize();
9202
- normalMatrix.getNormalMatrix(cubeApi.current.camera.matrixWorld);
9203
- cubeApi.current.camera.getWorldPosition(state.raycaster.ray.origin);
9204
- state.raycaster.ray.direction.set(0, 0, 1).reflect(normal);
9205
- state.raycaster.ray.direction.x *= -1;
9206
- state.raycaster.ray.direction.applyNormalMatrix(normalMatrix).multiplyScalar(-1);
9207
- return void 0;
9208
- }, []);
8195
+ const compute = React.useCallback(
8196
+ (event, state, prev) => {
8197
+ state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
8198
+ state.raycaster.setFromCamera(state.pointer, orthoC);
8199
+ if (!state.raycaster.ray.intersectSphere(sph, normal)) return;
8200
+ else normal.normalize();
8201
+ normalMatrix.getNormalMatrix(cubeApi.current.camera.matrixWorld);
8202
+ cubeApi.current.camera.getWorldPosition(state.raycaster.ray.origin);
8203
+ state.raycaster.ray.direction.set(0, 0, 1).reflect(normal);
8204
+ state.raycaster.ray.direction.x *= -1;
8205
+ state.raycaster.ray.direction.applyNormalMatrix(normalMatrix).multiplyScalar(-1);
8206
+ return void 0;
8207
+ },
8208
+ [width, height]
8209
+ );
9209
8210
  useFrame(
9210
8211
  ({ gl }) => {
9211
8212
  if (renderPriority) gl.render(sphere.current, orthoC);
@@ -9311,14 +8312,22 @@ const isWebGPURenderer = (def) => !!def.isWebGPURenderer;
9311
8312
  const col = /* @__PURE__ */ new THREE.Color();
9312
8313
  const TUNNEL_KEY = "__drei_view_tunnel__";
9313
8314
  const tracked = globalThis[TUNNEL_KEY] || (globalThis[TUNNEL_KEY] = tunnel());
9314
- function computeContainerPosition(canvasSize, trackRect) {
8315
+ function computeContainerPosition(canvasSize, trackRect, forceEven) {
9315
8316
  const { right, top: trackTop, left: trackLeft, bottom: trackBottom, width, height } = trackRect;
9316
8317
  const isOffscreen = trackRect.bottom < 0 || trackTop > canvasSize.height || right < 0 || trackRect.left > canvasSize.width;
9317
8318
  const canvasBottom = canvasSize.top + canvasSize.height;
9318
- const bottom = canvasBottom - trackBottom;
9319
- const left = trackLeft - canvasSize.left;
9320
- const top = trackTop - canvasSize.top;
9321
- return { position: { width, height, left, top, bottom, right }, isOffscreen };
8319
+ const rawBottom = canvasBottom - trackBottom;
8320
+ const rawLeft = trackLeft - canvasSize.left;
8321
+ const rawTop = trackTop - canvasSize.top;
8322
+ const position = forceEven ? {
8323
+ width: roundEven(width),
8324
+ height: roundEven(height),
8325
+ left: roundEven(rawLeft),
8326
+ top: roundEven(rawTop),
8327
+ bottom: roundEven(rawBottom),
8328
+ right: roundEven(right)
8329
+ } : { width, height, left: rawLeft, top: rawTop, bottom: rawBottom, right };
8330
+ return { position, isOffscreen };
9322
8331
  }
9323
8332
  function prepareSkissor(renderer, camera, {
9324
8333
  left,
@@ -9358,6 +8367,7 @@ function clear(renderer) {
9358
8367
  }
9359
8368
  function Container({ visible = true, canvasSize, scene, index, children, frames, rect, track }) {
9360
8369
  const { scene: portalScene, camera: portalCamera, renderer, get, setEvents } = useThree();
8370
+ const forceEven = useThree((state) => state.internal.forceEven);
9361
8371
  const [isOffscreen, setOffscreen] = React.useState(false);
9362
8372
  const mountedRef = React.useRef(true);
9363
8373
  React.useEffect(() => {
@@ -9375,7 +8385,7 @@ function Container({ visible = true, canvasSize, scene, index, children, frames,
9375
8385
  frameCount++;
9376
8386
  }
9377
8387
  if (rect.current) {
9378
- const { position, isOffscreen: _isOffscreen } = computeContainerPosition(canvasSize, rect.current);
8388
+ const { position, isOffscreen: _isOffscreen } = computeContainerPosition(canvasSize, rect.current, forceEven);
9379
8389
  if (isOffscreen !== _isOffscreen) setOffscreen(_isOffscreen);
9380
8390
  if (visible && !_isOffscreen && rect.current) {
9381
8391
  const targetScene = children ? portalScene : scene;
@@ -9397,14 +8407,14 @@ function Container({ visible = true, canvasSize, scene, index, children, frames,
9397
8407
  React.useLayoutEffect(() => {
9398
8408
  const curRect = rect.current;
9399
8409
  if (curRect && (!visible || !isOffscreen)) {
9400
- const { position, isOffscreen: _isOffscreen } = computeContainerPosition(canvasSize, curRect);
8410
+ const { position, isOffscreen: _isOffscreen } = computeContainerPosition(canvasSize, curRect, forceEven);
9401
8411
  if (!_isOffscreen) {
9402
8412
  const autoClear = prepareSkissor(renderer, portalCamera, position);
9403
8413
  clear(renderer);
9404
8414
  finishSkissor(renderer, autoClear);
9405
8415
  }
9406
8416
  }
9407
- }, [visible, isOffscreen, renderer, portalCamera, canvasSize]);
8417
+ }, [visible, isOffscreen, renderer, portalCamera, canvasSize, forceEven]);
9408
8418
  React.useEffect(() => {
9409
8419
  if (!track) return;
9410
8420
  const curRect = rect.current;
@@ -9412,7 +8422,7 @@ function Container({ visible = true, canvasSize, scene, index, children, frames,
9412
8422
  setEvents({ connected: track.current });
9413
8423
  return () => {
9414
8424
  if (curRect) {
9415
- const { position, isOffscreen: _isOffscreen } = computeContainerPosition(canvasSize, curRect);
8425
+ const { position, isOffscreen: _isOffscreen } = computeContainerPosition(canvasSize, curRect, forceEven);
9416
8426
  if (!_isOffscreen) {
9417
8427
  const autoClear = prepareSkissor(renderer, portalCamera, position);
9418
8428
  clear(renderer);
@@ -9421,13 +8431,14 @@ function Container({ visible = true, canvasSize, scene, index, children, frames,
9421
8431
  }
9422
8432
  setEvents({ connected: old });
9423
8433
  };
9424
- }, [track, renderer, portalCamera, canvasSize, get, setEvents]);
8434
+ }, [track, renderer, portalCamera, canvasSize, get, setEvents, forceEven]);
9425
8435
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children, /* @__PURE__ */ React.createElement("group", { onPointerOver: () => null }));
9426
8436
  }
9427
8437
  const CanvasView = /* @__PURE__ */ React.forwardRef(
9428
8438
  ({ track, visible = true, index = 1, id, style, className, frames = Infinity, children, ...props }, fref) => {
9429
8439
  const rect = React.useRef(null);
9430
8440
  const { size, scene } = useThree();
8441
+ const forceEven = useThree((state) => state.internal.forceEven);
9431
8442
  const [virtualScene] = React.useState(() => new THREE.Scene());
9432
8443
  const [ready, toggle] = React.useReducer(() => true, false);
9433
8444
  const compute = React.useCallback(
@@ -9464,12 +8475,12 @@ const CanvasView = /* @__PURE__ */ React.forwardRef(
9464
8475
  {
9465
8476
  events: { compute, priority: index },
9466
8477
  size: {
9467
- width: rect.current?.width,
9468
- height: rect.current?.height,
8478
+ width: forceEven && rect.current?.width ? roundEven(rect.current.width) : rect.current?.width,
8479
+ height: forceEven && rect.current?.height ? roundEven(rect.current.height) : rect.current?.height,
9469
8480
  // @ts-ignore
9470
- top: rect.current?.top,
8481
+ top: forceEven && rect.current?.top ? roundEven(rect.current.top) : rect.current?.top,
9471
8482
  // @ts-ignore
9472
- left: rect.current?.left
8483
+ left: forceEven && rect.current?.left ? roundEven(rect.current.left) : rect.current?.left
9473
8484
  }
9474
8485
  }
9475
8486
  ));
@@ -9896,8 +8907,8 @@ function getLoader(extension) {
9896
8907
  return loader;
9897
8908
  }
9898
8909
 
9899
- const isRef = (obj) => obj.current && obj.current.isScene;
9900
- const resolveScene = (scene) => isRef(scene) ? scene.current : scene;
8910
+ const isRef$1 = (obj) => obj.current && obj.current.isScene;
8911
+ const resolveScene = (scene) => isRef$1(scene) ? scene.current : scene;
9901
8912
  function setEnvProps(background, scene, defaultScene, texture, sceneProps = {}) {
9902
8913
  sceneProps = {
9903
8914
  backgroundBlurriness: 0,
@@ -10644,1118 +9655,905 @@ function useSelect() {
10644
9655
  return React.useContext(context);
10645
9656
  }
10646
9657
 
10647
- function BakeShadows() {
10648
- const gl = useThree((state) => state.gl);
10649
- useEffect(() => {
10650
- gl.shadowMap.autoUpdate = false;
10651
- gl.shadowMap.needsUpdate = true;
10652
- return () => {
10653
- gl.shadowMap.autoUpdate = gl.shadowMap.needsUpdate = true;
10654
- };
10655
- }, [gl.shadowMap]);
10656
- return null;
10657
- }
10658
-
10659
- let ConvolutionMaterial$1 = class ConvolutionMaterial extends THREE.ShaderMaterial {
10660
- kernel;
10661
- constructor(texelSize = new THREE.Vector2()) {
10662
- super({
10663
- uniforms: {
10664
- inputBuffer: new THREE.Uniform(null),
10665
- depthBuffer: new THREE.Uniform(null),
10666
- resolution: new THREE.Uniform(new THREE.Vector2()),
10667
- texelSize: new THREE.Uniform(new THREE.Vector2()),
10668
- halfTexelSize: new THREE.Uniform(new THREE.Vector2()),
10669
- kernel: new THREE.Uniform(0),
10670
- scale: new THREE.Uniform(1),
10671
- cameraNear: new THREE.Uniform(0),
10672
- cameraFar: new THREE.Uniform(1),
10673
- minDepthThreshold: new THREE.Uniform(0),
10674
- maxDepthThreshold: new THREE.Uniform(1),
10675
- depthScale: new THREE.Uniform(0),
10676
- depthToBlurRatioBias: new THREE.Uniform(0.25)
10677
- },
10678
- fragmentShader: `#include <common>
10679
- #include <dithering_pars_fragment>
10680
- uniform sampler2D inputBuffer;
10681
- uniform sampler2D depthBuffer;
10682
- uniform float cameraNear;
10683
- uniform float cameraFar;
10684
- uniform float minDepthThreshold;
10685
- uniform float maxDepthThreshold;
10686
- uniform float depthScale;
10687
- uniform float depthToBlurRatioBias;
10688
- varying vec2 vUv;
10689
- varying vec2 vUv0;
10690
- varying vec2 vUv1;
10691
- varying vec2 vUv2;
10692
- varying vec2 vUv3;
10693
-
10694
- void main() {
10695
- float depthFactor = 0.0;
10696
-
10697
- #ifdef USE_DEPTH
10698
- vec4 depth = texture2D(depthBuffer, vUv);
10699
- depthFactor = smoothstep(minDepthThreshold, maxDepthThreshold, 1.0-(depth.r * depth.a));
10700
- depthFactor *= depthScale;
10701
- depthFactor = max(0.0, min(1.0, depthFactor + 0.25));
10702
- #endif
10703
-
10704
- vec4 sum = texture2D(inputBuffer, mix(vUv0, vUv, depthFactor));
10705
- sum += texture2D(inputBuffer, mix(vUv1, vUv, depthFactor));
10706
- sum += texture2D(inputBuffer, mix(vUv2, vUv, depthFactor));
10707
- sum += texture2D(inputBuffer, mix(vUv3, vUv, depthFactor));
10708
- gl_FragColor = sum * 0.25 ;
10709
-
10710
- #include <dithering_fragment>
10711
- #include <tonemapping_fragment>
10712
- #include <${version >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
10713
- }`,
10714
- vertexShader: `uniform vec2 texelSize;
10715
- uniform vec2 halfTexelSize;
10716
- uniform float kernel;
10717
- uniform float scale;
10718
- varying vec2 vUv;
10719
- varying vec2 vUv0;
10720
- varying vec2 vUv1;
10721
- varying vec2 vUv2;
10722
- varying vec2 vUv3;
10723
-
10724
- void main() {
10725
- vec2 uv = position.xy * 0.5 + 0.5;
10726
- vUv = uv;
10727
-
10728
- vec2 dUv = (texelSize * vec2(kernel) + halfTexelSize) * scale;
10729
- vUv0 = vec2(uv.x - dUv.x, uv.y + dUv.y);
10730
- vUv1 = vec2(uv.x + dUv.x, uv.y + dUv.y);
10731
- vUv2 = vec2(uv.x + dUv.x, uv.y - dUv.y);
10732
- vUv3 = vec2(uv.x - dUv.x, uv.y - dUv.y);
10733
-
10734
- gl_Position = vec4(position.xy, 1.0, 1.0);
10735
- }`,
10736
- blending: THREE.NoBlending,
10737
- depthWrite: false,
10738
- depthTest: false
10739
- });
10740
- this.toneMapped = false;
10741
- this.setTexelSize(texelSize.x, texelSize.y);
10742
- this.kernel = new Float32Array([0, 1, 2, 2, 3]);
9658
+ const aastep = /* @__PURE__ */ Fn((inputs) => {
9659
+ const [threshold, dist] = inputs;
9660
+ const afwidth = fwidth(dist).mul(0.5);
9661
+ return smoothstep(threshold.sub(afwidth), threshold.add(afwidth), dist);
9662
+ });
9663
+ const remap = /* @__PURE__ */ Fn((inputs) => {
9664
+ const [value, min1, max1, min2, max2] = inputs;
9665
+ return min2.add(value.sub(min1).mul(max2.sub(min2)).div(max1.sub(min1)));
9666
+ });
9667
+ class WireframeMaterialImpl extends MeshBasicNodeMaterial {
9668
+ //* Private Uniform Nodes --
9669
+ _strokeOpacity;
9670
+ _fillOpacity;
9671
+ _fillMix;
9672
+ _thickness;
9673
+ _colorBackfaces;
9674
+ // Using number as bool (0/1)
9675
+ _dashInvert;
9676
+ _dash;
9677
+ _dashRepeats;
9678
+ _dashLength;
9679
+ _squeeze;
9680
+ _squeezeMin;
9681
+ _squeezeMax;
9682
+ _stroke;
9683
+ _backfaceStroke;
9684
+ _fill;
9685
+ /** Type flag for identification */
9686
+ isWireframeMaterial = true;
9687
+ constructor() {
9688
+ super();
9689
+ this._strokeOpacity = uniform(1);
9690
+ this._fillOpacity = uniform(0.25);
9691
+ this._fillMix = uniform(0);
9692
+ this._thickness = uniform(0.05);
9693
+ this._colorBackfaces = uniform(0);
9694
+ this._dashInvert = uniform(1);
9695
+ this._dash = uniform(0);
9696
+ this._dashRepeats = uniform(4);
9697
+ this._dashLength = uniform(0.5);
9698
+ this._squeeze = uniform(0);
9699
+ this._squeezeMin = uniform(0.2);
9700
+ this._squeezeMax = uniform(1);
9701
+ this._stroke = uniform(new THREE.Color("#ff0000"));
9702
+ this._backfaceStroke = uniform(new THREE.Color("#0000ff"));
9703
+ this._fill = uniform(new THREE.Color("#00ff00"));
9704
+ this.transparent = true;
9705
+ this.side = THREE.DoubleSide;
9706
+ this._buildWireframeShader();
10743
9707
  }
10744
- setTexelSize(x, y) {
10745
- this.uniforms.texelSize.value.set(x, y);
10746
- this.uniforms.halfTexelSize.value.set(x, y).multiplyScalar(0.5);
9708
+ _buildWireframeShader() {
9709
+ const strokeOpacityUniform = this._strokeOpacity;
9710
+ const fillOpacityUniform = this._fillOpacity;
9711
+ const thicknessUniform = this._thickness;
9712
+ const colorBackfacesUniform = this._colorBackfaces;
9713
+ const dashInvertUniform = this._dashInvert;
9714
+ const dashUniform = this._dash;
9715
+ const dashRepeatsUniform = this._dashRepeats;
9716
+ const dashLengthUniform = this._dashLength;
9717
+ const squeezeUniform = this._squeeze;
9718
+ const squeezeMinUniform = this._squeezeMin;
9719
+ const squeezeMaxUniform = this._squeezeMax;
9720
+ const strokeUniform = this._stroke;
9721
+ const backfaceStrokeUniform = this._backfaceStroke;
9722
+ const fillUniform = this._fill;
9723
+ const barycentricAttr = attribute("barycentric", "vec3");
9724
+ const vBarycentric = varying(barycentricAttr, "v_barycentric");
9725
+ this.outputNode = Fn(() => {
9726
+ const barycentric = vBarycentric;
9727
+ const d = min(min(barycentric.x, barycentric.y), barycentric.z);
9728
+ const positionAlong = float(0).toVar();
9729
+ const maxXY = max(barycentric.x, barycentric.y);
9730
+ const isYSmallest = barycentric.y.lessThan(barycentric.x).and(barycentric.y.lessThan(barycentric.z));
9731
+ positionAlong.assign(select(isYSmallest, float(1).sub(maxXY), maxXY));
9732
+ const computedThickness = remap(thicknessUniform, float(0), float(1), float(0), float(0.34)).toVar();
9733
+ const squeezeEnabled = squeezeUniform.greaterThan(0.5);
9734
+ const squeezeFactor = mix(squeezeMinUniform, squeezeMaxUniform, float(1).sub(sin(positionAlong.mul(Math.PI))));
9735
+ computedThickness.assign(select(squeezeEnabled, computedThickness.mul(squeezeFactor), computedThickness));
9736
+ const dashEnabled = dashUniform.greaterThan(0.5);
9737
+ const dashInverted = dashInvertUniform.greaterThan(0.5);
9738
+ const baseOffset = float(1).div(dashRepeatsUniform).mul(dashLengthUniform).mul(0.5);
9739
+ const additionalOffset = float(1).div(dashRepeatsUniform).mul(0.5);
9740
+ const dashOffset = select(dashInverted, baseOffset, baseOffset.add(additionalOffset));
9741
+ const pattern = fract(positionAlong.add(dashOffset).mul(dashRepeatsUniform));
9742
+ const dashMask = float(1).sub(aastep(dashLengthUniform, pattern));
9743
+ computedThickness.assign(select(dashEnabled, computedThickness.mul(dashMask), computedThickness));
9744
+ const edge = float(1).sub(aastep(computedThickness, d));
9745
+ const useBackfaceColor = colorBackfacesUniform.greaterThan(0.5);
9746
+ const isFrontFace = frontFacing;
9747
+ const currentStroke = select(useBackfaceColor.and(isFrontFace.not()), backfaceStrokeUniform, strokeUniform);
9748
+ const colorStroke = vec4(currentStroke, edge);
9749
+ const colorFill = vec4(fillUniform, fillOpacityUniform);
9750
+ const outColor = mix(colorFill, colorStroke, edge.mul(strokeOpacityUniform));
9751
+ return outColor;
9752
+ })();
10747
9753
  }
10748
- setResolution(resolution) {
10749
- this.uniforms.resolution.value.copy(resolution);
9754
+ //* Uniform Accessors ==============================
9755
+ /** Stroke (edge) opacity, default: 1 */
9756
+ get strokeOpacity() {
9757
+ return this._strokeOpacity.value;
10750
9758
  }
10751
- };
10752
-
10753
- class BlurPass {
10754
- renderTargetA;
10755
- renderTargetB;
10756
- convolutionMaterial;
10757
- scene;
10758
- camera;
10759
- screen;
10760
- renderToScreen = false;
10761
- constructor({
10762
- gl,
10763
- resolution,
10764
- width = 500,
10765
- height = 500,
10766
- minDepthThreshold = 0,
10767
- maxDepthThreshold = 1,
10768
- depthScale = 0,
10769
- depthToBlurRatioBias = 0.25
10770
- }) {
10771
- this.renderTargetA = new WebGLRenderTarget(resolution, resolution, {
10772
- minFilter: LinearFilter,
10773
- magFilter: LinearFilter,
10774
- stencilBuffer: false,
10775
- depthBuffer: false,
10776
- type: HalfFloatType
10777
- });
10778
- this.renderTargetB = this.renderTargetA.clone();
10779
- this.convolutionMaterial = new ConvolutionMaterial$1();
10780
- this.convolutionMaterial.setTexelSize(1 / width, 1 / height);
10781
- this.convolutionMaterial.setResolution(new Vector2(width, height));
10782
- this.scene = new Scene();
10783
- this.camera = new Camera();
10784
- this.convolutionMaterial.uniforms.minDepthThreshold.value = minDepthThreshold;
10785
- this.convolutionMaterial.uniforms.maxDepthThreshold.value = maxDepthThreshold;
10786
- this.convolutionMaterial.uniforms.depthScale.value = depthScale;
10787
- this.convolutionMaterial.uniforms.depthToBlurRatioBias.value = depthToBlurRatioBias;
10788
- this.convolutionMaterial.defines.USE_DEPTH = depthScale > 0;
10789
- const vertices = new Float32Array([-1, -1, 0, 3, -1, 0, -1, 3, 0]);
10790
- const uvs = new Float32Array([0, 0, 2, 0, 0, 2]);
10791
- const geometry = new BufferGeometry();
10792
- geometry.setAttribute("position", new BufferAttribute(vertices, 3));
10793
- geometry.setAttribute("uv", new BufferAttribute(uvs, 2));
10794
- this.screen = new Mesh(geometry, this.convolutionMaterial);
10795
- this.screen.frustumCulled = false;
10796
- this.scene.add(this.screen);
10797
- }
10798
- render(renderer, inputBuffer, outputBuffer) {
10799
- const scene = this.scene;
10800
- const camera = this.camera;
10801
- const renderTargetA = this.renderTargetA;
10802
- const renderTargetB = this.renderTargetB;
10803
- let material = this.convolutionMaterial;
10804
- let uniforms = material.uniforms;
10805
- uniforms.depthBuffer.value = inputBuffer.depthTexture;
10806
- const kernel = material.kernel;
10807
- let lastRT = inputBuffer;
10808
- let destRT;
10809
- let i, l;
10810
- for (i = 0, l = kernel.length - 1; i < l; ++i) {
10811
- destRT = (i & 1) === 0 ? renderTargetA : renderTargetB;
10812
- uniforms.kernel.value = kernel[i];
10813
- uniforms.inputBuffer.value = lastRT.texture;
10814
- renderer.setRenderTarget(destRT);
10815
- renderer.render(scene, camera);
10816
- lastRT = destRT;
10817
- }
10818
- uniforms.kernel.value = kernel[i];
10819
- uniforms.inputBuffer.value = lastRT.texture;
10820
- renderer.setRenderTarget(this.renderToScreen ? null : outputBuffer);
10821
- renderer.render(scene, camera);
9759
+ set strokeOpacity(v) {
9760
+ this._strokeOpacity.value = v;
10822
9761
  }
10823
- }
10824
-
10825
- class ConvolutionMaterial extends MeshBasicNodeMaterial {
10826
- //* Private Uniform Nodes --
10827
- _inputBuffer;
10828
- _depthBuffer;
10829
- _resolution;
10830
- _texelSize;
10831
- _halfTexelSize;
10832
- _kernel;
10833
- _scale;
10834
- _cameraNear;
10835
- _cameraFar;
10836
- _minDepthThreshold;
10837
- _maxDepthThreshold;
10838
- _depthScale;
10839
- _depthToBlurRatioBias;
10840
- _useDepth;
10841
- /** Kernel weights for multi-pass blur */
10842
- kernel;
10843
- constructor(texelSize = new THREE.Vector2()) {
10844
- super();
10845
- this._inputBuffer = uniformTexture(new THREE.Texture());
10846
- this._depthBuffer = uniformTexture(new THREE.Texture());
10847
- this._resolution = uniform(new THREE.Vector2());
10848
- this._texelSize = uniform(new THREE.Vector2());
10849
- this._halfTexelSize = uniform(new THREE.Vector2());
10850
- this._kernel = uniform(0);
10851
- this._scale = uniform(1);
10852
- this._cameraNear = uniform(0);
10853
- this._cameraFar = uniform(1);
10854
- this._minDepthThreshold = uniform(0);
10855
- this._maxDepthThreshold = uniform(1);
10856
- this._depthScale = uniform(0);
10857
- this._depthToBlurRatioBias = uniform(0.25);
10858
- this._useDepth = uniform(0);
10859
- this.blending = THREE.NoBlending;
10860
- this.depthWrite = false;
10861
- this.depthTest = false;
10862
- this.toneMapped = false;
10863
- this.kernel = new Float32Array([0, 1, 2, 2, 3]);
10864
- this.setTexelSize(texelSize.x, texelSize.y);
10865
- this._buildShader();
10866
- }
10867
- _buildShader() {
10868
- const inputBufferTex = this._inputBuffer;
10869
- const depthBufferTex = this._depthBuffer;
10870
- const texelSizeUniform = this._texelSize;
10871
- const halfTexelSizeUniform = this._halfTexelSize;
10872
- const kernelUniform = this._kernel;
10873
- const scaleUniform = this._scale;
10874
- const minDepthThresholdUniform = this._minDepthThreshold;
10875
- const maxDepthThresholdUniform = this._maxDepthThreshold;
10876
- const depthScaleUniform = this._depthScale;
10877
- const useDepthUniform = this._useDepth;
10878
- const baseUv = varying(uv(), "vUv");
10879
- const dUv = varying(
10880
- Fn(() => {
10881
- return texelSizeUniform.mul(kernelUniform).add(halfTexelSizeUniform).mul(scaleUniform);
10882
- })(),
10883
- "vDuv"
10884
- );
10885
- const vUv0 = varying(Fn(() => vec2$2(baseUv.x.sub(dUv.x), baseUv.y.add(dUv.y)))(), "vUv0");
10886
- const vUv1 = varying(Fn(() => vec2$2(baseUv.x.add(dUv.x), baseUv.y.add(dUv.y)))(), "vUv1");
10887
- const vUv2 = varying(Fn(() => vec2$2(baseUv.x.add(dUv.x), baseUv.y.sub(dUv.y)))(), "vUv2");
10888
- const vUv3 = varying(Fn(() => vec2$2(baseUv.x.sub(dUv.x), baseUv.y.sub(dUv.y)))(), "vUv3");
10889
- this.colorNode = Fn(() => {
10890
- const depthFactor = float(0).toVar();
10891
- const isUsingDepth = useDepthUniform.greaterThan(0.5);
10892
- const depthSample = texture(depthBufferTex, baseUv);
10893
- const rawDepth = float(1).sub(depthSample.r.mul(depthSample.a));
10894
- const smoothedDepth = smoothstep(minDepthThresholdUniform, maxDepthThresholdUniform, rawDepth);
10895
- const scaledDepth = smoothedDepth.mul(depthScaleUniform);
10896
- const clampedDepth = max(float(0), min(float(1), scaledDepth.add(0.25)));
10897
- depthFactor.assign(select(isUsingDepth, clampedDepth, float(0)));
10898
- const sample0 = texture(inputBufferTex, mix(vUv0, baseUv, depthFactor));
10899
- const sample1 = texture(inputBufferTex, mix(vUv1, baseUv, depthFactor));
10900
- const sample2 = texture(inputBufferTex, mix(vUv2, baseUv, depthFactor));
10901
- const sample3 = texture(inputBufferTex, mix(vUv3, baseUv, depthFactor));
10902
- const sum = sample0.add(sample1).add(sample2).add(sample3);
10903
- return sum.mul(0.25);
10904
- })();
10905
- }
10906
- //* Utility Methods ==============================
10907
- /** Set texel size for blur calculations */
10908
- setTexelSize(x, y) {
10909
- this._texelSize.value.set(x, y);
10910
- this._halfTexelSize.value.set(x * 0.5, y * 0.5);
9762
+ /** Fill opacity (background), default: 0.25 */
9763
+ get fillOpacity() {
9764
+ return this._fillOpacity.value;
10911
9765
  }
10912
- /** Set render resolution */
10913
- setResolution(resolution) {
10914
- this._resolution.value.copy(resolution);
9766
+ set fillOpacity(v) {
9767
+ this._fillOpacity.value = v;
10915
9768
  }
10916
- //* Uniform Accessors ==============================
10917
- /** Input color buffer to blur */
10918
- get inputBuffer() {
10919
- return this._inputBuffer.value;
9769
+ /** Mix factor between material color and fill color, default: 0 */
9770
+ get fillMix() {
9771
+ return this._fillMix.value;
10920
9772
  }
10921
- set inputBuffer(v) {
10922
- this._inputBuffer.value = v ?? new THREE.Texture();
9773
+ set fillMix(v) {
9774
+ this._fillMix.value = v;
10923
9775
  }
10924
- /** Depth buffer for depth-aware blur */
10925
- get depthBuffer() {
10926
- return this._depthBuffer.value;
9776
+ /** Edge thickness 0-1, default: 0.05 */
9777
+ get thickness() {
9778
+ return this._thickness.value;
10927
9779
  }
10928
- set depthBuffer(v) {
10929
- this._depthBuffer.value = v ?? new THREE.Texture();
9780
+ set thickness(v) {
9781
+ this._thickness.value = v;
10930
9782
  }
10931
- /** Render resolution */
10932
- get resolution() {
10933
- return this._resolution.value;
9783
+ /** Use different color for backfaces */
9784
+ get colorBackfaces() {
9785
+ return this._colorBackfaces.value > 0.5;
10934
9786
  }
10935
- set resolution(v) {
10936
- this._resolution.value = v;
9787
+ set colorBackfaces(v) {
9788
+ this._colorBackfaces.value = v ? 1 : 0;
10937
9789
  }
10938
- /** Texel size (1/resolution) */
10939
- get texelSize() {
10940
- return this._texelSize.value;
9790
+ /** Invert dash pattern */
9791
+ get dashInvert() {
9792
+ return this._dashInvert.value > 0.5;
10941
9793
  }
10942
- set texelSize(v) {
10943
- this._texelSize.value = v;
9794
+ set dashInvert(v) {
9795
+ this._dashInvert.value = v ? 1 : 0;
10944
9796
  }
10945
- /** Half texel size for offset calculations */
10946
- get halfTexelSize() {
10947
- return this._halfTexelSize.value;
9797
+ /** Enable dashed lines */
9798
+ get dash() {
9799
+ return this._dash.value > 0.5;
10948
9800
  }
10949
- set halfTexelSize(v) {
10950
- this._halfTexelSize.value = v;
9801
+ set dash(v) {
9802
+ this._dash.value = v ? 1 : 0;
10951
9803
  }
10952
- /** Kernel offset multiplier (changes per blur pass) */
10953
- get kernelValue() {
10954
- return this._kernel.value;
9804
+ /** Number of dash repeats, default: 4 */
9805
+ get dashRepeats() {
9806
+ return this._dashRepeats.value;
10955
9807
  }
10956
- set kernelValue(v) {
10957
- this._kernel.value = v;
9808
+ set dashRepeats(v) {
9809
+ this._dashRepeats.value = v;
10958
9810
  }
10959
- /** Scale factor for blur spread */
10960
- get scale() {
10961
- return this._scale.value;
9811
+ /** Dash length 0-1, default: 0.5 */
9812
+ get dashLength() {
9813
+ return this._dashLength.value;
10962
9814
  }
10963
- set scale(v) {
10964
- this._scale.value = v;
9815
+ set dashLength(v) {
9816
+ this._dashLength.value = v;
10965
9817
  }
10966
- /** Camera near plane for depth calculations */
10967
- get cameraNear() {
10968
- return this._cameraNear.value;
9818
+ /** Squeeze thickness toward line center */
9819
+ get squeeze() {
9820
+ return this._squeeze.value > 0.5;
10969
9821
  }
10970
- set cameraNear(v) {
10971
- this._cameraNear.value = v;
9822
+ set squeeze(v) {
9823
+ this._squeeze.value = v ? 1 : 0;
10972
9824
  }
10973
- /** Camera far plane for depth calculations */
10974
- get cameraFar() {
10975
- return this._cameraFar.value;
9825
+ /** Minimum squeeze factor, default: 0.2 */
9826
+ get squeezeMin() {
9827
+ return this._squeezeMin.value;
10976
9828
  }
10977
- set cameraFar(v) {
10978
- this._cameraFar.value = v;
9829
+ set squeezeMin(v) {
9830
+ this._squeezeMin.value = v;
10979
9831
  }
10980
- /** Minimum depth threshold for blur (objects closer than this get less blur) */
10981
- get minDepthThreshold() {
10982
- return this._minDepthThreshold.value;
9832
+ /** Maximum squeeze factor, default: 1 */
9833
+ get squeezeMax() {
9834
+ return this._squeezeMax.value;
10983
9835
  }
10984
- set minDepthThreshold(v) {
10985
- this._minDepthThreshold.value = v;
9836
+ set squeezeMax(v) {
9837
+ this._squeezeMax.value = v;
10986
9838
  }
10987
- /** Maximum depth threshold for blur (objects farther than this get full blur) */
10988
- get maxDepthThreshold() {
10989
- return this._maxDepthThreshold.value;
9839
+ /** Stroke (edge) color */
9840
+ get stroke() {
9841
+ return this._stroke.value;
10990
9842
  }
10991
- set maxDepthThreshold(v) {
10992
- this._maxDepthThreshold.value = v;
9843
+ set stroke(v) {
9844
+ if (v instanceof THREE.Color) this._stroke.value = v;
9845
+ else this._stroke.value = new THREE.Color(v);
10993
9846
  }
10994
- /** Scale factor for depth-based blur adjustment */
10995
- get depthScale() {
10996
- return this._depthScale.value;
9847
+ /** Backface stroke color */
9848
+ get backfaceStroke() {
9849
+ return this._backfaceStroke.value;
10997
9850
  }
10998
- set depthScale(v) {
10999
- this._depthScale.value = v;
9851
+ set backfaceStroke(v) {
9852
+ if (v instanceof THREE.Color) this._backfaceStroke.value = v;
9853
+ else this._backfaceStroke.value = new THREE.Color(v);
11000
9854
  }
11001
- /** Bias added to depth-to-blur ratio */
11002
- get depthToBlurRatioBias() {
11003
- return this._depthToBlurRatioBias.value;
9855
+ /** Fill (background) color */
9856
+ get fill() {
9857
+ return this._fill.value;
11004
9858
  }
11005
- set depthToBlurRatioBias(v) {
11006
- this._depthToBlurRatioBias.value = v;
9859
+ set fill(v) {
9860
+ if (v instanceof THREE.Color) this._fill.value = v;
9861
+ else this._fill.value = new THREE.Color(v);
11007
9862
  }
11008
- /** Enable/disable depth-based blur (0 = off, 1 = on) */
11009
- get useDepth() {
11010
- return this._useDepth.value > 0.5;
9863
+ }
9864
+ function setBarycentricCoordinates(geometry) {
9865
+ const position = geometry.getAttribute("position");
9866
+ const count = position.count;
9867
+ if (geometry.index) {
9868
+ geometry = geometry.toNonIndexed();
11011
9869
  }
11012
- set useDepth(v) {
11013
- this._useDepth.value = v ? 1 : 0;
9870
+ const barycentricArray = new Float32Array(count * 3);
9871
+ for (let i = 0; i < count; i += 3) {
9872
+ barycentricArray[i * 3 + 0] = 1;
9873
+ barycentricArray[i * 3 + 1] = 0;
9874
+ barycentricArray[i * 3 + 2] = 0;
9875
+ barycentricArray[(i + 1) * 3 + 0] = 0;
9876
+ barycentricArray[(i + 1) * 3 + 1] = 1;
9877
+ barycentricArray[(i + 1) * 3 + 2] = 0;
9878
+ barycentricArray[(i + 2) * 3 + 0] = 0;
9879
+ barycentricArray[(i + 2) * 3 + 1] = 0;
9880
+ barycentricArray[(i + 2) * 3 + 2] = 1;
11014
9881
  }
9882
+ geometry.setAttribute("barycentric", new THREE.BufferAttribute(barycentricArray, 3));
9883
+ return geometry;
11015
9884
  }
11016
-
11017
- var GradientType = /* @__PURE__ */ ((GradientType2) => {
11018
- GradientType2["Linear"] = "linear";
11019
- GradientType2["Radial"] = "radial";
11020
- return GradientType2;
11021
- })(GradientType || {});
11022
- function GradientTexture({
11023
- stops,
11024
- colors,
11025
- size = 1024,
11026
- width = 16,
11027
- type = "linear" /* Linear */,
11028
- innerCircleRadius = 0,
11029
- outerCircleRadius = "auto",
11030
- ...props
11031
- }) {
11032
- const gl = useThree((state) => state.gl);
11033
- const canvas = React.useMemo(() => {
11034
- const canvas2 = document.createElement("canvas");
11035
- const context = canvas2.getContext("2d");
11036
- canvas2.width = width;
11037
- canvas2.height = size;
11038
- let gradient;
11039
- if (type === "linear" /* Linear */) {
11040
- gradient = context.createLinearGradient(0, 0, 0, size);
11041
- } else {
11042
- const canvasCenterX = canvas2.width / 2;
11043
- const canvasCenterY = canvas2.height / 2;
11044
- const radius = outerCircleRadius !== "auto" ? Math.abs(Number(outerCircleRadius)) : Math.sqrt(canvasCenterX ** 2 + canvasCenterY ** 2);
11045
- gradient = context.createRadialGradient(
11046
- canvasCenterX,
11047
- canvasCenterY,
11048
- Math.abs(innerCircleRadius),
11049
- canvasCenterX,
11050
- canvasCenterY,
11051
- radius
11052
- );
11053
- }
11054
- const tempColor = new THREE.Color();
11055
- let i = stops.length;
11056
- while (i--) {
11057
- gradient.addColorStop(stops[i], tempColor.set(colors[i]).getStyle());
11058
- }
11059
- context.save();
11060
- context.fillStyle = gradient;
11061
- context.fillRect(0, 0, width, size);
11062
- context.restore();
11063
- return canvas2;
11064
- }, [stops]);
11065
- return /* @__PURE__ */ React.createElement("canvasTexture", { colorSpace: gl.outputColorSpace, args: [canvas], attach: "map", ...props });
11066
- }
11067
-
11068
- const LUMA = /* @__PURE__ */ vec3(0.299, 0.587, 0.114);
11069
- const toGrayscale = /* @__PURE__ */ Fn(
11070
- ({ inputColor, intensity }) => {
11071
- const gray = vec3(dot(inputColor.rgb, LUMA));
11072
- return vec4(mix(inputColor.rgb, gray, intensity), inputColor.a);
11073
- }
11074
- );
11075
- const aspect = (size) => size.div(min(size.x, size.y));
11076
- const udRoundBox = /* @__PURE__ */ Fn(
11077
- ({ p, b, r }) => {
11078
- return length(max(abs(p).sub(b).add(r), float(0))).sub(r);
11079
- }
11080
- );
11081
- function useImageMaterial(tex, options) {
11082
- const uniforms = React.useMemo(
11083
- () => ({
11084
- color: uniform(new THREE.Color("white")),
11085
- scale: uniform(new THREE.Vector2(1, 1)),
11086
- imageBounds: uniform(new THREE.Vector2(1, 1)),
11087
- resolution: uniform(1024),
11088
- zoom: uniform(1),
11089
- radius: uniform(0),
11090
- grayscale: uniform(0),
11091
- opacity: uniform(1)
11092
- }),
11093
- []
11094
- );
11095
- const material = React.useMemo(() => {
11096
- const mat = new THREE.MeshBasicNodeMaterial();
11097
- mat.colorNode = Fn(() => {
11098
- const uvCoord = uv();
11099
- const s = aspect(uniforms.scale);
11100
- const i = aspect(uniforms.imageBounds);
11101
- const rs = s.x.div(s.y);
11102
- const ri = i.x.div(i.y);
11103
- const newX = select(rs.lessThan(ri), i.x.mul(s.y).div(i.y), s.x);
11104
- const newY = select(rs.lessThan(ri), s.y, i.y.mul(s.x).div(i.x));
11105
- const newSize = vec2$2(newX, newY);
11106
- const offsetX = select(rs.lessThan(ri), newX.sub(s.x).div(float(2)).div(newX), float(0));
11107
- const offsetY = select(rs.lessThan(ri), float(0), newY.sub(s.y).div(float(2)).div(newY));
11108
- const offset = vec2$2(offsetX, offsetY);
11109
- const transformedUv = uvCoord.mul(s).div(newSize).add(offset);
11110
- const zUv = transformedUv.sub(vec2$2(0.5, 0.5)).div(uniforms.zoom).add(vec2$2(0.5, 0.5));
11111
- const res = uniforms.scale.mul(uniforms.resolution);
11112
- const halfRes = res.mul(0.5);
11113
- const dist = udRoundBox({
11114
- p: uvCoord.mul(res).sub(halfRes),
11115
- b: halfRes,
11116
- r: uniforms.resolution.mul(uniforms.radius)
11117
- });
11118
- const edgeAlpha = smoothstep(float(1), float(0), dist);
11119
- const texColor = texture(tex, zUv);
11120
- const tintedRgb = texColor.rgb.mul(uniforms.color);
11121
- const finalAlpha = texColor.a.mul(uniforms.opacity).mul(edgeAlpha);
11122
- const tinted = vec4(tintedRgb, finalAlpha);
11123
- return toGrayscale({ inputColor: tinted, intensity: uniforms.grayscale });
11124
- })();
11125
- return mat;
11126
- }, [tex, uniforms]);
11127
- React.useLayoutEffect(() => {
11128
- uniforms.color.value.set(options.color);
11129
- uniforms.scale.value.set(options.scale[0], options.scale[1]);
11130
- uniforms.imageBounds.value.set(options.imageBounds[0], options.imageBounds[1]);
11131
- uniforms.resolution.value = options.resolution;
11132
- uniforms.zoom.value = options.zoom;
11133
- uniforms.radius.value = options.radius;
11134
- uniforms.grayscale.value = options.grayscale;
11135
- uniforms.opacity.value = options.opacity;
11136
- }, [
11137
- uniforms,
11138
- options.color,
11139
- options.scale[0],
11140
- options.scale[1],
11141
- options.imageBounds[0],
11142
- options.imageBounds[1],
11143
- options.resolution,
11144
- options.zoom,
11145
- options.radius,
11146
- options.grayscale,
11147
- options.opacity
11148
- ]);
11149
- React.useLayoutEffect(() => {
11150
- material.toneMapped = options.toneMapped ?? true;
11151
- material.transparent = options.transparent ?? false;
11152
- if (options.side !== void 0) material.side = options.side;
11153
- material.needsUpdate = true;
11154
- }, [material, options.toneMapped, options.transparent, options.side]);
11155
- return material;
11156
- }
11157
- const ImageBase = /* @__PURE__ */ React.forwardRef(
9885
+ const WireframeMaterial = /* @__PURE__ */ React.forwardRef(
11158
9886
  ({
11159
- children,
11160
- color = "white",
11161
- segments = 1,
11162
- scale = 1,
11163
- zoom = 1,
11164
- grayscale = 0,
11165
- opacity = 1,
11166
- radius = 0,
11167
- texture,
11168
- toneMapped,
11169
- transparent,
11170
- side,
9887
+ fillOpacity = 0.25,
9888
+ fillMix = 0,
9889
+ strokeOpacity = 1,
9890
+ thickness = 0.05,
9891
+ colorBackfaces = false,
9892
+ dashInvert = true,
9893
+ dash = false,
9894
+ dashRepeats = 4,
9895
+ dashLength = 0.5,
9896
+ squeeze = false,
9897
+ squeezeMin = 0.2,
9898
+ squeezeMax = 1,
9899
+ stroke = "#ff0000",
9900
+ backfaceStroke = "#0000ff",
9901
+ fill = "#00ff00",
11171
9902
  ...props
11172
9903
  }, fref) => {
9904
+ extend({ WireframeMaterial: WireframeMaterialImpl });
11173
9905
  const ref = React.useRef(null);
11174
- const size = useThree((state) => state.size);
11175
- const planeBounds = Array.isArray(scale) ? [scale[0], scale[1]] : [scale, scale];
11176
- const img = texture.image;
11177
- const imageBounds = [img.width, img.height];
11178
- const resolution = Math.max(size.width, size.height);
11179
- const material = useImageMaterial(texture, {
11180
- color,
11181
- zoom,
11182
- radius,
11183
- grayscale,
11184
- opacity,
11185
- scale: planeBounds,
11186
- imageBounds,
11187
- resolution,
11188
- toneMapped,
11189
- transparent,
11190
- side
11191
- });
11192
9906
  React.useImperativeHandle(fref, () => ref.current, []);
11193
- return /* @__PURE__ */ React.createElement("mesh", { ref, scale: Array.isArray(scale) ? [...scale, 1] : scale, ...props }, /* @__PURE__ */ React.createElement("planeGeometry", { args: [1, 1, segments, segments] }), /* @__PURE__ */ React.createElement("primitive", { object: material, attach: "material" }), children);
11194
- }
11195
- );
11196
- const ImageWithUrl = /* @__PURE__ */ React.forwardRef(
11197
- ({ url, ...props }, ref) => {
11198
- const texture = useTexture(url);
11199
- return /* @__PURE__ */ React.createElement(ImageBase, { ...props, texture, ref });
9907
+ return /* @__PURE__ */ React.createElement(
9908
+ "wireframeMaterial",
9909
+ {
9910
+ ref,
9911
+ ...props,
9912
+ fillOpacity,
9913
+ fillMix,
9914
+ strokeOpacity,
9915
+ thickness,
9916
+ colorBackfaces,
9917
+ dashInvert,
9918
+ dash,
9919
+ dashRepeats,
9920
+ dashLength,
9921
+ squeeze,
9922
+ squeezeMin,
9923
+ squeezeMax,
9924
+ stroke: stroke instanceof THREE.Color ? stroke : new THREE.Color(stroke),
9925
+ backfaceStroke: backfaceStroke instanceof THREE.Color ? backfaceStroke : new THREE.Color(backfaceStroke),
9926
+ fill: fill instanceof THREE.Color ? fill : new THREE.Color(fill)
9927
+ }
9928
+ );
11200
9929
  }
11201
9930
  );
11202
- const ImageWithTexture = /* @__PURE__ */ React.forwardRef(({ url: _url, ...props }, ref) => {
11203
- return /* @__PURE__ */ React.createElement(ImageBase, { ...props, ref });
11204
- });
11205
- const Image = /* @__PURE__ */ React.forwardRef((props, ref) => {
11206
- if (props.url) return /* @__PURE__ */ React.createElement(ImageWithUrl, { ...props, ref });
11207
- else if (props.texture) return /* @__PURE__ */ React.createElement(ImageWithTexture, { ...props, ref });
11208
- else throw new Error("<Image /> requires a url or texture");
11209
- });
11210
-
11211
- const pcss = ({ focus = 0, size = 25, samples = 10 } = {}) => `
11212
- #define PENUMBRA_FILTER_SIZE float(${size})
11213
- #define RGB_NOISE_FUNCTION(uv) (randRGB(uv))
11214
- vec3 randRGB(vec2 uv) {
11215
- return vec3(
11216
- fract(sin(dot(uv, vec2(12.75613, 38.12123))) * 13234.76575),
11217
- fract(sin(dot(uv, vec2(19.45531, 58.46547))) * 43678.23431),
11218
- fract(sin(dot(uv, vec2(23.67817, 78.23121))) * 93567.23423)
11219
- );
9931
+ const WireframeMaterialShaders = {
9932
+ uniforms: {
9933
+ strokeOpacity: 1,
9934
+ fillOpacity: 0.25,
9935
+ fillMix: 0,
9936
+ thickness: 0.05,
9937
+ colorBackfaces: false,
9938
+ dashInvert: true,
9939
+ dash: false,
9940
+ dashRepeats: 4,
9941
+ dashLength: 0.5,
9942
+ squeeze: false,
9943
+ squeezeMin: 0.2,
9944
+ squeezeMax: 1,
9945
+ stroke: /* @__PURE__ */ new THREE.Color("#ff0000"),
9946
+ backfaceStroke: /* @__PURE__ */ new THREE.Color("#0000ff"),
9947
+ fill: /* @__PURE__ */ new THREE.Color("#00ff00")
9948
+ },
9949
+ vertex: "// Converted to TSL - see WireframeMaterial",
9950
+ fragment: "// Converted to TSL - see WireframeMaterial"
9951
+ };
9952
+ function setWireframeOverride(_material, _uniforms) {
9953
+ console.warn("setWireframeOverride is deprecated. Use WireframeMaterial directly with TSL for WebGPU.");
9954
+ }
9955
+ function useWireframeUniforms(_uniforms, _props) {
9956
+ console.warn("useWireframeUniforms is deprecated. Use WireframeMaterial props directly with TSL for WebGPU.");
11220
9957
  }
11221
9958
 
11222
- vec3 lowPassRandRGB(vec2 uv) {
11223
- // 3x3 convolution (average)
11224
- // can be implemented as separable with an extra buffer for a total of 6 samples instead of 9
11225
- vec3 result = vec3(0);
11226
- result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, -1.0));
11227
- result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, 0.0));
11228
- result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, +1.0));
11229
- result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, -1.0));
11230
- result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, 0.0));
11231
- result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, +1.0));
11232
- result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, -1.0));
11233
- result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, 0.0));
11234
- result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, +1.0));
11235
- result *= 0.111111111; // 1.0 / 9.0
11236
- return result;
9959
+ function isWithGeometry(object) {
9960
+ return !!object?.geometry;
11237
9961
  }
11238
- vec3 highPassRandRGB(vec2 uv) {
11239
- // by subtracting the low-pass signal from the original signal, we're being left with the high-pass signal
11240
- // hp(x) = x - lp(x)
11241
- return RGB_NOISE_FUNCTION(uv) - lowPassRandRGB(uv) + 0.5;
9962
+ function isGeometry(object) {
9963
+ return !!object?.isBufferGeometry;
11242
9964
  }
11243
-
11244
-
11245
- vec2 vogelDiskSample(int sampleIndex, int sampleCount, float angle) {
11246
- const float goldenAngle = 2.399963f; // radians
11247
- float r = sqrt(float(sampleIndex) + 0.5f) / sqrt(float(sampleCount));
11248
- float theta = float(sampleIndex) * goldenAngle + angle;
11249
- float sine = sin(theta);
11250
- float cosine = cos(theta);
11251
- return vec2(cosine, sine) * r;
9965
+ function isRefObject(object) {
9966
+ return !!object?.current;
11252
9967
  }
11253
- float penumbraSize( const in float zReceiver, const in float zBlocker ) { // Parallel plane estimation
11254
- return (zReceiver - zBlocker) / zBlocker;
9968
+ function isRef(object) {
9969
+ return object?.current !== void 0;
11255
9970
  }
11256
- float findBlocker(sampler2D shadowMap, vec2 uv, float compare, float angle) {
11257
- float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
11258
- float blockerDepthSum = float(${focus});
11259
- float blockers = 0.0;
11260
-
11261
- int j = 0;
11262
- vec2 offset = vec2(0.);
11263
- float depth = 0.;
11264
-
11265
- #pragma unroll_loop_start
11266
- for(int i = 0; i < ${samples}; i ++) {
11267
- offset = (vogelDiskSample(j, ${samples}, angle) * texelSize) * 2.0 * PENUMBRA_FILTER_SIZE;
11268
- depth = unpackRGBAToDepth( texture2D( shadowMap, uv + offset));
11269
- if (depth < compare) {
11270
- blockerDepthSum += depth;
11271
- blockers++;
9971
+ function isWireframeGeometry(geometry) {
9972
+ return geometry.type === "WireframeGeometry";
9973
+ }
9974
+ function getInputGeometry(inputGeometry) {
9975
+ const geo = isRefObject(inputGeometry) ? inputGeometry.current : inputGeometry;
9976
+ if (!isGeometry(geo)) {
9977
+ if (isWireframeGeometry(geo)) {
9978
+ throw new Error("Wireframe: WireframeGeometry is not supported.");
11272
9979
  }
11273
- j++;
11274
- }
11275
- #pragma unroll_loop_end
11276
-
11277
- if (blockers > 0.0) {
11278
- return blockerDepthSum / blockers;
11279
- }
11280
- return -1.0;
11281
- }
11282
-
11283
-
11284
- float vogelFilter(sampler2D shadowMap, vec2 uv, float zReceiver, float filterRadius, float angle) {
11285
- float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
11286
- float shadow = 0.0f;
11287
- int j = 0;
11288
- vec2 vogelSample = vec2(0.0);
11289
- vec2 offset = vec2(0.0);
11290
- #pragma unroll_loop_start
11291
- for (int i = 0; i < ${samples}; i++) {
11292
- vogelSample = vogelDiskSample(j, ${samples}, angle) * texelSize;
11293
- offset = vogelSample * (1.0 + filterRadius * float(${size}));
11294
- shadow += step( zReceiver, unpackRGBAToDepth( texture2D( shadowMap, uv + offset ) ) );
11295
- j++;
11296
- }
11297
- #pragma unroll_loop_end
11298
- return shadow * 1.0 / ${samples}.0;
11299
- }
11300
-
11301
- float PCSS (sampler2D shadowMap, vec4 coords) {
11302
- vec2 uv = coords.xy;
11303
- float zReceiver = coords.z; // Assumed to be eye-space z in this code
11304
- float angle = highPassRandRGB(gl_FragCoord.xy).r * PI2;
11305
- float avgBlockerDepth = findBlocker(shadowMap, uv, zReceiver, angle);
11306
- if (avgBlockerDepth == -1.0) {
11307
- return 1.0;
11308
- }
11309
- float penumbraRatio = penumbraSize(zReceiver, avgBlockerDepth);
11310
- return vogelFilter(shadowMap, uv, zReceiver, 1.25 * penumbraRatio, angle);
11311
- }`;
11312
- function reset(gl, scene, camera) {
11313
- scene.traverse((object) => {
11314
- if (object.material) {
11315
- gl.properties.remove(object.material);
11316
- object.material.dispose?.();
9980
+ const parent = geo.parent;
9981
+ if (isWithGeometry(parent)) {
9982
+ if (isWireframeGeometry(parent.geometry)) {
9983
+ throw new Error("Wireframe: WireframeGeometry is not supported.");
9984
+ }
9985
+ return parent.geometry;
11317
9986
  }
11318
- });
11319
- gl.info.programs.length = 0;
11320
- gl.compile(scene, camera);
11321
- }
11322
- function SoftShadows({ focus = 0, samples = 10, size = 25 }) {
11323
- const gl = useThree((state) => state.gl);
11324
- const scene = useThree((state) => state.scene);
11325
- const camera = useThree((state) => state.camera);
11326
- React.useEffect(() => {
11327
- const original = THREE.ShaderChunk.shadowmap_pars_fragment;
11328
- THREE.ShaderChunk.shadowmap_pars_fragment = THREE.ShaderChunk.shadowmap_pars_fragment.replace("#ifdef USE_SHADOWMAP", "#ifdef USE_SHADOWMAP\n" + pcss({ size, samples, focus })).replace(
11329
- "#if defined( SHADOWMAP_TYPE_PCF )",
11330
- "\nreturn PCSS(shadowMap, shadowCoord);\n#if defined( SHADOWMAP_TYPE_PCF )"
11331
- );
11332
- reset(gl, scene, camera);
11333
- return () => {
11334
- THREE.ShaderChunk.shadowmap_pars_fragment = original;
11335
- reset(gl, scene, camera);
11336
- };
11337
- }, [focus, size, samples]);
11338
- return null;
9987
+ } else {
9988
+ return geo;
9989
+ }
11339
9990
  }
11340
-
11341
- class SpotLightMaterial extends MeshBasicNodeMaterial {
9991
+ function WireframeWithCustomGeo({
9992
+ geometry: customGeometry,
9993
+ simplify = false,
9994
+ ...props
9995
+ }) {
9996
+ const [geometry, setGeometry] = React.useState(null);
9997
+ React.useLayoutEffect(() => {
9998
+ let geom = getInputGeometry(customGeometry);
9999
+ if (!geom) {
10000
+ throw new Error("Wireframe: geometry prop must be a BufferGeometry or a ref to a BufferGeometry.");
10001
+ }
10002
+ geom = setBarycentricCoordinates(geom);
10003
+ if (isRef(customGeometry)) {
10004
+ setGeometry(geom);
10005
+ }
10006
+ }, [simplify, customGeometry]);
10007
+ const drawnGeo = isRef(customGeometry) ? geometry : customGeometry;
10008
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, drawnGeo && /* @__PURE__ */ React.createElement("mesh", { geometry: drawnGeo }, /* @__PURE__ */ React.createElement(WireframeMaterial, { ...props })));
10009
+ }
10010
+ function WireframeWithoutCustomGeo({
10011
+ simplify = false,
10012
+ ...props
10013
+ }) {
10014
+ const objectRef = React.useRef(null);
10015
+ React.useLayoutEffect(() => {
10016
+ let geom = getInputGeometry(objectRef);
10017
+ if (!geom) {
10018
+ throw new Error("Wireframe: Must be a child of a Mesh, Line or Points object or specify a geometry prop.");
10019
+ }
10020
+ const og = geom.clone();
10021
+ geom = setBarycentricCoordinates(geom);
10022
+ const parent = objectRef.current.parent;
10023
+ if (parent && parent.geometry !== geom) {
10024
+ parent.geometry = geom;
10025
+ }
10026
+ return () => {
10027
+ if (parent) {
10028
+ parent.geometry.dispose();
10029
+ parent.geometry = og;
10030
+ }
10031
+ };
10032
+ }, [simplify]);
10033
+ return /* @__PURE__ */ React.createElement("object3D", { ref: objectRef });
10034
+ }
10035
+ function Wireframe({ geometry: customGeometry, ...props }) {
10036
+ if (customGeometry) {
10037
+ return /* @__PURE__ */ React.createElement(WireframeWithCustomGeo, { geometry: customGeometry, ...props });
10038
+ }
10039
+ return /* @__PURE__ */ React.createElement(WireframeWithoutCustomGeo, { ...props });
10040
+ }
10041
+
10042
+ function BakeShadows() {
10043
+ const gl = useThree((state) => state.gl);
10044
+ useEffect(() => {
10045
+ gl.shadowMap.autoUpdate = false;
10046
+ gl.shadowMap.needsUpdate = true;
10047
+ return () => {
10048
+ gl.shadowMap.autoUpdate = gl.shadowMap.needsUpdate = true;
10049
+ };
10050
+ }, [gl.shadowMap]);
10051
+ return null;
10052
+ }
10053
+
10054
+ class ConvolutionMaterial extends MeshBasicNodeMaterial {
11342
10055
  //* Private Uniform Nodes --
11343
- _depth;
11344
- _opacity;
11345
- _attenuation;
11346
- _anglePower;
11347
- _spotPosition;
11348
- _lightColor;
10056
+ _inputBuffer;
10057
+ _depthBuffer;
10058
+ _resolution;
10059
+ _texelSize;
10060
+ _halfTexelSize;
10061
+ _kernel;
10062
+ _scale;
11349
10063
  _cameraNear;
11350
10064
  _cameraFar;
11351
- _resolution;
11352
- constructor() {
10065
+ _minDepthThreshold;
10066
+ _maxDepthThreshold;
10067
+ _depthScale;
10068
+ _depthToBlurRatioBias;
10069
+ _useDepth;
10070
+ /** Kernel weights for multi-pass blur */
10071
+ kernel;
10072
+ constructor(texelSize = new THREE.Vector2()) {
11353
10073
  super();
11354
- this._depth = uniformTexture(new THREE.Texture());
11355
- this._opacity = uniform(1);
11356
- this._attenuation = uniform(5);
11357
- this._anglePower = uniform(5);
11358
- this._spotPosition = uniform(new THREE.Vector3(0, 0, 0));
11359
- this._lightColor = uniform(new THREE.Color("white"));
11360
- this._cameraNear = uniform(0.1);
11361
- this._cameraFar = uniform(100);
11362
- this._resolution = uniform(new THREE.Vector2(0, 0));
11363
- this.transparent = true;
10074
+ this._inputBuffer = uniformTexture(new THREE.Texture());
10075
+ this._depthBuffer = uniformTexture(new THREE.Texture());
10076
+ this._resolution = uniform(new THREE.Vector2());
10077
+ this._texelSize = uniform(new THREE.Vector2());
10078
+ this._halfTexelSize = uniform(new THREE.Vector2());
10079
+ this._kernel = uniform(0);
10080
+ this._scale = uniform(1);
10081
+ this._cameraNear = uniform(0);
10082
+ this._cameraFar = uniform(1);
10083
+ this._minDepthThreshold = uniform(0);
10084
+ this._maxDepthThreshold = uniform(1);
10085
+ this._depthScale = uniform(0);
10086
+ this._depthToBlurRatioBias = uniform(0.25);
10087
+ this._useDepth = uniform(0);
10088
+ this.blending = THREE.NoBlending;
11364
10089
  this.depthWrite = false;
11365
- this.side = THREE.DoubleSide;
10090
+ this.depthTest = false;
10091
+ this.toneMapped = false;
10092
+ this.kernel = new Float32Array([0, 1, 2, 2, 3]);
10093
+ this.setTexelSize(texelSize.x, texelSize.y);
11366
10094
  this._buildShader();
11367
10095
  }
11368
- //* Build TSL Shader ==============================
11369
10096
  _buildShader() {
11370
- const depthTex = this._depth;
11371
- const opacityUniform = this._opacity;
11372
- const attenuationUniform = this._attenuation;
11373
- const anglePowerUniform = this._anglePower;
11374
- const spotPositionUniform = this._spotPosition;
11375
- const lightColorUniform = this._lightColor;
11376
- const cameraNearUniform = this._cameraNear;
11377
- const cameraFarUniform = this._cameraFar;
11378
- const resolutionUniform = this._resolution;
11379
- const vNormal = varying(normalize(modelViewMatrix.transformDirection(normalLocal)), "vNormal");
11380
- const vIntensity = varying(
11381
- saturate(float(1).sub(distance(positionWorld, spotPositionUniform).div(attenuationUniform))),
11382
- "vIntensity"
10097
+ const inputBufferTex = this._inputBuffer;
10098
+ const depthBufferTex = this._depthBuffer;
10099
+ const texelSizeUniform = this._texelSize;
10100
+ const halfTexelSizeUniform = this._halfTexelSize;
10101
+ const kernelUniform = this._kernel;
10102
+ const scaleUniform = this._scale;
10103
+ const minDepthThresholdUniform = this._minDepthThreshold;
10104
+ const maxDepthThresholdUniform = this._maxDepthThreshold;
10105
+ const depthScaleUniform = this._depthScale;
10106
+ const useDepthUniform = this._useDepth;
10107
+ const baseUv = varying(uv(), "vUv");
10108
+ const dUv = varying(
10109
+ Fn(() => {
10110
+ return texelSizeUniform.mul(kernelUniform).add(halfTexelSizeUniform).mul(scaleUniform);
10111
+ })(),
10112
+ "vDuv"
11383
10113
  );
11384
- const vViewZ = varying(positionView.z, "vViewZ");
10114
+ const vUv0 = varying(Fn(() => vec2$2(baseUv.x.sub(dUv.x), baseUv.y.add(dUv.y)))(), "vUv0");
10115
+ const vUv1 = varying(Fn(() => vec2$2(baseUv.x.add(dUv.x), baseUv.y.add(dUv.y)))(), "vUv1");
10116
+ const vUv2 = varying(Fn(() => vec2$2(baseUv.x.add(dUv.x), baseUv.y.sub(dUv.y)))(), "vUv2");
10117
+ const vUv3 = varying(Fn(() => vec2$2(baseUv.x.sub(dUv.x), baseUv.y.sub(dUv.y)))(), "vUv3");
11385
10118
  this.colorNode = Fn(() => {
11386
- const angleIntensity = pow(abs(vNormal.z), anglePowerUniform);
11387
- const intensity = vIntensity.mul(angleIntensity).toVar();
11388
- const hasDepth = resolutionUniform.x.greaterThan(0);
11389
- const screenUV = vec2$2(
11390
- screenCoordinate.x.div(resolutionUniform.x),
11391
- float(1).sub(screenCoordinate.y.div(resolutionUniform.y))
11392
- );
11393
- const sampledDepth = texture(depthTex, screenUV).r;
11394
- const near = cameraNearUniform;
11395
- const far = cameraFarUniform;
11396
- const sceneViewZ = near.mul(far).div(far.sub(near).mul(sampledDepth).sub(far));
11397
- const depthDiff = vViewZ.sub(sceneViewZ);
11398
- const softFactor = smoothstep(float(0), float(1), depthDiff);
11399
- intensity.assign(select(hasDepth, intensity.mul(softFactor), intensity));
11400
- return vec4(lightColorUniform, intensity.mul(opacityUniform));
10119
+ const depthFactor = float(0).toVar();
10120
+ const isUsingDepth = useDepthUniform.greaterThan(0.5);
10121
+ const depthSample = texture(depthBufferTex, baseUv);
10122
+ const rawDepth = float(1).sub(depthSample.r.mul(depthSample.a));
10123
+ const smoothedDepth = smoothstep(minDepthThresholdUniform, maxDepthThresholdUniform, rawDepth);
10124
+ const scaledDepth = smoothedDepth.mul(depthScaleUniform);
10125
+ const clampedDepth = max(float(0), min(float(1), scaledDepth.add(0.25)));
10126
+ depthFactor.assign(select(isUsingDepth, clampedDepth, float(0)));
10127
+ const sample0 = texture(inputBufferTex, mix(vUv0, baseUv, depthFactor));
10128
+ const sample1 = texture(inputBufferTex, mix(vUv1, baseUv, depthFactor));
10129
+ const sample2 = texture(inputBufferTex, mix(vUv2, baseUv, depthFactor));
10130
+ const sample3 = texture(inputBufferTex, mix(vUv3, baseUv, depthFactor));
10131
+ const sum = sample0.add(sample1).add(sample2).add(sample3);
10132
+ return sum.mul(0.25);
11401
10133
  })();
11402
10134
  }
10135
+ //* Utility Methods ==============================
10136
+ /** Set texel size for blur calculations */
10137
+ setTexelSize(x, y) {
10138
+ this._texelSize.value.set(x, y);
10139
+ this._halfTexelSize.value.set(x * 0.5, y * 0.5);
10140
+ }
10141
+ /** Set render resolution */
10142
+ setResolution(resolution) {
10143
+ this._resolution.value.copy(resolution);
10144
+ }
11403
10145
  //* Uniform Accessors ==============================
11404
- get depth() {
11405
- return this._depth?.value;
10146
+ /** Input color buffer to blur */
10147
+ get inputBuffer() {
10148
+ return this._inputBuffer.value;
11406
10149
  }
11407
- set depth(v) {
11408
- if (this._depth) this._depth.value = v ?? new THREE.Texture();
10150
+ set inputBuffer(v) {
10151
+ this._inputBuffer.value = v ?? new THREE.Texture();
11409
10152
  }
11410
- get opacity() {
11411
- return this._opacity?.value;
10153
+ /** Depth buffer for depth-aware blur */
10154
+ get depthBuffer() {
10155
+ return this._depthBuffer.value;
11412
10156
  }
11413
- set opacity(v) {
11414
- if (this._opacity) this._opacity.value = v;
10157
+ set depthBuffer(v) {
10158
+ this._depthBuffer.value = v ?? new THREE.Texture();
11415
10159
  }
11416
- get attenuation() {
11417
- return this._attenuation?.value;
10160
+ /** Render resolution */
10161
+ get resolution() {
10162
+ return this._resolution.value;
11418
10163
  }
11419
- set attenuation(v) {
11420
- if (this._attenuation) this._attenuation.value = v;
10164
+ set resolution(v) {
10165
+ this._resolution.value = v;
11421
10166
  }
11422
- get anglePower() {
11423
- return this._anglePower?.value;
10167
+ /** Texel size (1/resolution) */
10168
+ get texelSize() {
10169
+ return this._texelSize.value;
11424
10170
  }
11425
- set anglePower(v) {
11426
- if (this._anglePower) this._anglePower.value = v;
10171
+ set texelSize(v) {
10172
+ this._texelSize.value = v;
11427
10173
  }
11428
- get spotPosition() {
11429
- return this._spotPosition?.value;
10174
+ /** Half texel size for offset calculations */
10175
+ get halfTexelSize() {
10176
+ return this._halfTexelSize.value;
11430
10177
  }
11431
- set spotPosition(v) {
11432
- if (this._spotPosition) this._spotPosition.value = v;
10178
+ set halfTexelSize(v) {
10179
+ this._halfTexelSize.value = v;
11433
10180
  }
11434
- get lightColor() {
11435
- return this._lightColor?.value;
10181
+ /** Kernel offset multiplier (changes per blur pass) */
10182
+ get kernelValue() {
10183
+ return this._kernel.value;
11436
10184
  }
11437
- set lightColor(v) {
11438
- if (this._lightColor) this._lightColor.value = v;
10185
+ set kernelValue(v) {
10186
+ this._kernel.value = v;
10187
+ }
10188
+ /** Scale factor for blur spread */
10189
+ get scale() {
10190
+ return this._scale.value;
10191
+ }
10192
+ set scale(v) {
10193
+ this._scale.value = v;
11439
10194
  }
10195
+ /** Camera near plane for depth calculations */
11440
10196
  get cameraNear() {
11441
- return this._cameraNear?.value;
10197
+ return this._cameraNear.value;
11442
10198
  }
11443
10199
  set cameraNear(v) {
11444
- if (this._cameraNear) this._cameraNear.value = v;
10200
+ this._cameraNear.value = v;
11445
10201
  }
10202
+ /** Camera far plane for depth calculations */
11446
10203
  get cameraFar() {
11447
- return this._cameraFar?.value;
10204
+ return this._cameraFar.value;
11448
10205
  }
11449
10206
  set cameraFar(v) {
11450
- if (this._cameraFar) this._cameraFar.value = v;
10207
+ this._cameraFar.value = v;
11451
10208
  }
11452
- get resolution() {
11453
- return this._resolution?.value;
10209
+ /** Minimum depth threshold for blur (objects closer than this get less blur) */
10210
+ get minDepthThreshold() {
10211
+ return this._minDepthThreshold.value;
11454
10212
  }
11455
- set resolution(v) {
11456
- if (this._resolution) this._resolution.value = v;
11457
- }
11458
- }
11459
-
11460
- const aastep = /* @__PURE__ */ Fn((inputs) => {
11461
- const [threshold, dist] = inputs;
11462
- const afwidth = fwidth(dist).mul(0.5);
11463
- return smoothstep(threshold.sub(afwidth), threshold.add(afwidth), dist);
11464
- });
11465
- const remap = /* @__PURE__ */ Fn((inputs) => {
11466
- const [value, min1, max1, min2, max2] = inputs;
11467
- return min2.add(value.sub(min1).mul(max2.sub(min2)).div(max1.sub(min1)));
11468
- });
11469
- class WireframeMaterialImpl extends MeshBasicNodeMaterial {
11470
- //* Private Uniform Nodes --
11471
- _strokeOpacity;
11472
- _fillOpacity;
11473
- _fillMix;
11474
- _thickness;
11475
- _colorBackfaces;
11476
- // Using number as bool (0/1)
11477
- _dashInvert;
11478
- _dash;
11479
- _dashRepeats;
11480
- _dashLength;
11481
- _squeeze;
11482
- _squeezeMin;
11483
- _squeezeMax;
11484
- _stroke;
11485
- _backfaceStroke;
11486
- _fill;
11487
- /** Type flag for identification */
11488
- isWireframeMaterial = true;
11489
- constructor() {
11490
- super();
11491
- this._strokeOpacity = uniform(1);
11492
- this._fillOpacity = uniform(0.25);
11493
- this._fillMix = uniform(0);
11494
- this._thickness = uniform(0.05);
11495
- this._colorBackfaces = uniform(0);
11496
- this._dashInvert = uniform(1);
11497
- this._dash = uniform(0);
11498
- this._dashRepeats = uniform(4);
11499
- this._dashLength = uniform(0.5);
11500
- this._squeeze = uniform(0);
11501
- this._squeezeMin = uniform(0.2);
11502
- this._squeezeMax = uniform(1);
11503
- this._stroke = uniform(new THREE.Color("#ff0000"));
11504
- this._backfaceStroke = uniform(new THREE.Color("#0000ff"));
11505
- this._fill = uniform(new THREE.Color("#00ff00"));
11506
- this.transparent = true;
11507
- this.side = THREE.DoubleSide;
11508
- this._buildWireframeShader();
11509
- }
11510
- _buildWireframeShader() {
11511
- const strokeOpacityUniform = this._strokeOpacity;
11512
- const fillOpacityUniform = this._fillOpacity;
11513
- const thicknessUniform = this._thickness;
11514
- const colorBackfacesUniform = this._colorBackfaces;
11515
- const dashInvertUniform = this._dashInvert;
11516
- const dashUniform = this._dash;
11517
- const dashRepeatsUniform = this._dashRepeats;
11518
- const dashLengthUniform = this._dashLength;
11519
- const squeezeUniform = this._squeeze;
11520
- const squeezeMinUniform = this._squeezeMin;
11521
- const squeezeMaxUniform = this._squeezeMax;
11522
- const strokeUniform = this._stroke;
11523
- const backfaceStrokeUniform = this._backfaceStroke;
11524
- const fillUniform = this._fill;
11525
- const barycentricAttr = attribute("barycentric", "vec3");
11526
- const vBarycentric = varying(barycentricAttr, "v_barycentric");
11527
- this.outputNode = Fn(() => {
11528
- const barycentric = vBarycentric;
11529
- const d = min(min(barycentric.x, barycentric.y), barycentric.z);
11530
- const positionAlong = float(0).toVar();
11531
- const maxXY = max(barycentric.x, barycentric.y);
11532
- const isYSmallest = barycentric.y.lessThan(barycentric.x).and(barycentric.y.lessThan(barycentric.z));
11533
- positionAlong.assign(select(isYSmallest, float(1).sub(maxXY), maxXY));
11534
- const computedThickness = remap(thicknessUniform, float(0), float(1), float(0), float(0.34)).toVar();
11535
- const squeezeEnabled = squeezeUniform.greaterThan(0.5);
11536
- const squeezeFactor = mix(squeezeMinUniform, squeezeMaxUniform, float(1).sub(sin(positionAlong.mul(Math.PI))));
11537
- computedThickness.assign(select(squeezeEnabled, computedThickness.mul(squeezeFactor), computedThickness));
11538
- const dashEnabled = dashUniform.greaterThan(0.5);
11539
- const dashInverted = dashInvertUniform.greaterThan(0.5);
11540
- const baseOffset = float(1).div(dashRepeatsUniform).mul(dashLengthUniform).mul(0.5);
11541
- const additionalOffset = float(1).div(dashRepeatsUniform).mul(0.5);
11542
- const dashOffset = select(dashInverted, baseOffset, baseOffset.add(additionalOffset));
11543
- const pattern = fract(positionAlong.add(dashOffset).mul(dashRepeatsUniform));
11544
- const dashMask = float(1).sub(aastep(dashLengthUniform, pattern));
11545
- computedThickness.assign(select(dashEnabled, computedThickness.mul(dashMask), computedThickness));
11546
- const edge = float(1).sub(aastep(computedThickness, d));
11547
- const useBackfaceColor = colorBackfacesUniform.greaterThan(0.5);
11548
- const isFrontFace = frontFacing;
11549
- const currentStroke = select(useBackfaceColor.and(isFrontFace.not()), backfaceStrokeUniform, strokeUniform);
11550
- const colorStroke = vec4(currentStroke, edge);
11551
- const colorFill = vec4(fillUniform, fillOpacityUniform);
11552
- const outColor = mix(colorFill, colorStroke, edge.mul(strokeOpacityUniform));
11553
- return outColor;
11554
- })();
11555
- }
11556
- //* Uniform Accessors ==============================
11557
- /** Stroke (edge) opacity, default: 1 */
11558
- get strokeOpacity() {
11559
- return this._strokeOpacity.value;
10213
+ set minDepthThreshold(v) {
10214
+ this._minDepthThreshold.value = v;
11560
10215
  }
11561
- set strokeOpacity(v) {
11562
- this._strokeOpacity.value = v;
10216
+ /** Maximum depth threshold for blur (objects farther than this get full blur) */
10217
+ get maxDepthThreshold() {
10218
+ return this._maxDepthThreshold.value;
11563
10219
  }
11564
- /** Fill opacity (background), default: 0.25 */
11565
- get fillOpacity() {
11566
- return this._fillOpacity.value;
10220
+ set maxDepthThreshold(v) {
10221
+ this._maxDepthThreshold.value = v;
11567
10222
  }
11568
- set fillOpacity(v) {
11569
- this._fillOpacity.value = v;
10223
+ /** Scale factor for depth-based blur adjustment */
10224
+ get depthScale() {
10225
+ return this._depthScale.value;
11570
10226
  }
11571
- /** Mix factor between material color and fill color, default: 0 */
11572
- get fillMix() {
11573
- return this._fillMix.value;
10227
+ set depthScale(v) {
10228
+ this._depthScale.value = v;
11574
10229
  }
11575
- set fillMix(v) {
11576
- this._fillMix.value = v;
10230
+ /** Bias added to depth-to-blur ratio */
10231
+ get depthToBlurRatioBias() {
10232
+ return this._depthToBlurRatioBias.value;
11577
10233
  }
11578
- /** Edge thickness 0-1, default: 0.05 */
11579
- get thickness() {
11580
- return this._thickness.value;
10234
+ set depthToBlurRatioBias(v) {
10235
+ this._depthToBlurRatioBias.value = v;
11581
10236
  }
11582
- set thickness(v) {
11583
- this._thickness.value = v;
10237
+ /** Enable/disable depth-based blur (0 = off, 1 = on) */
10238
+ get useDepth() {
10239
+ return this._useDepth.value > 0.5;
11584
10240
  }
11585
- /** Use different color for backfaces */
11586
- get colorBackfaces() {
11587
- return this._colorBackfaces.value > 0.5;
10241
+ set useDepth(v) {
10242
+ this._useDepth.value = v ? 1 : 0;
11588
10243
  }
11589
- set colorBackfaces(v) {
11590
- this._colorBackfaces.value = v ? 1 : 0;
10244
+ }
10245
+
10246
+ var GradientType = /* @__PURE__ */ ((GradientType2) => {
10247
+ GradientType2["Linear"] = "linear";
10248
+ GradientType2["Radial"] = "radial";
10249
+ return GradientType2;
10250
+ })(GradientType || {});
10251
+ function GradientTexture({
10252
+ stops,
10253
+ colors,
10254
+ size = 1024,
10255
+ width = 16,
10256
+ type = "linear" /* Linear */,
10257
+ innerCircleRadius = 0,
10258
+ outerCircleRadius = "auto",
10259
+ ...props
10260
+ }) {
10261
+ const gl = useThree((state) => state.gl);
10262
+ const canvas = React.useMemo(() => {
10263
+ const canvas2 = document.createElement("canvas");
10264
+ const context = canvas2.getContext("2d");
10265
+ canvas2.width = width;
10266
+ canvas2.height = size;
10267
+ let gradient;
10268
+ if (type === "linear" /* Linear */) {
10269
+ gradient = context.createLinearGradient(0, 0, 0, size);
10270
+ } else {
10271
+ const canvasCenterX = canvas2.width / 2;
10272
+ const canvasCenterY = canvas2.height / 2;
10273
+ const radius = outerCircleRadius !== "auto" ? Math.abs(Number(outerCircleRadius)) : Math.sqrt(canvasCenterX ** 2 + canvasCenterY ** 2);
10274
+ gradient = context.createRadialGradient(
10275
+ canvasCenterX,
10276
+ canvasCenterY,
10277
+ Math.abs(innerCircleRadius),
10278
+ canvasCenterX,
10279
+ canvasCenterY,
10280
+ radius
10281
+ );
10282
+ }
10283
+ const tempColor = new THREE.Color();
10284
+ let i = stops.length;
10285
+ while (i--) {
10286
+ gradient.addColorStop(stops[i], tempColor.set(colors[i]).getStyle());
10287
+ }
10288
+ context.save();
10289
+ context.fillStyle = gradient;
10290
+ context.fillRect(0, 0, width, size);
10291
+ context.restore();
10292
+ return canvas2;
10293
+ }, [stops]);
10294
+ return /* @__PURE__ */ React.createElement("canvasTexture", { colorSpace: gl.outputColorSpace, args: [canvas], attach: "map", ...props });
10295
+ }
10296
+
10297
+ const LUMA = /* @__PURE__ */ vec3(0.299, 0.587, 0.114);
10298
+ const toGrayscale = /* @__PURE__ */ Fn(
10299
+ ({ inputColor, intensity }) => {
10300
+ const gray = vec3(dot(inputColor.rgb, LUMA));
10301
+ return vec4(mix(inputColor.rgb, gray, intensity), inputColor.a);
11591
10302
  }
11592
- /** Invert dash pattern */
11593
- get dashInvert() {
11594
- return this._dashInvert.value > 0.5;
10303
+ );
10304
+ const aspect = (size) => size.div(min(size.x, size.y));
10305
+ const udRoundBox = /* @__PURE__ */ Fn(
10306
+ ({ p, b, r }) => {
10307
+ return length(max(abs(p).sub(b).add(r), float(0))).sub(r);
11595
10308
  }
11596
- set dashInvert(v) {
11597
- this._dashInvert.value = v ? 1 : 0;
10309
+ );
10310
+ function useImageMaterial(tex, options) {
10311
+ const uniforms = React.useMemo(
10312
+ () => ({
10313
+ color: uniform(new THREE.Color("white")),
10314
+ scale: uniform(new THREE.Vector2(1, 1)),
10315
+ imageBounds: uniform(new THREE.Vector2(1, 1)),
10316
+ resolution: uniform(1024),
10317
+ zoom: uniform(1),
10318
+ radius: uniform(0),
10319
+ grayscale: uniform(0),
10320
+ opacity: uniform(1)
10321
+ }),
10322
+ []
10323
+ );
10324
+ const material = React.useMemo(() => {
10325
+ const mat = new THREE.MeshBasicNodeMaterial();
10326
+ mat.colorNode = Fn(() => {
10327
+ const uvCoord = uv();
10328
+ const s = aspect(uniforms.scale);
10329
+ const i = aspect(uniforms.imageBounds);
10330
+ const rs = s.x.div(s.y);
10331
+ const ri = i.x.div(i.y);
10332
+ const newX = select(rs.lessThan(ri), i.x.mul(s.y).div(i.y), s.x);
10333
+ const newY = select(rs.lessThan(ri), s.y, i.y.mul(s.x).div(i.x));
10334
+ const newSize = vec2$2(newX, newY);
10335
+ const offsetX = select(rs.lessThan(ri), newX.sub(s.x).div(float(2)).div(newX), float(0));
10336
+ const offsetY = select(rs.lessThan(ri), float(0), newY.sub(s.y).div(float(2)).div(newY));
10337
+ const offset = vec2$2(offsetX, offsetY);
10338
+ const transformedUv = uvCoord.mul(s).div(newSize).add(offset);
10339
+ const zUv = transformedUv.sub(vec2$2(0.5, 0.5)).div(uniforms.zoom).add(vec2$2(0.5, 0.5));
10340
+ const res = uniforms.scale.mul(uniforms.resolution);
10341
+ const halfRes = res.mul(0.5);
10342
+ const dist = udRoundBox({
10343
+ p: uvCoord.mul(res).sub(halfRes),
10344
+ b: halfRes,
10345
+ r: uniforms.resolution.mul(uniforms.radius)
10346
+ });
10347
+ const edgeAlpha = smoothstep(float(1), float(0), dist);
10348
+ const texColor = texture(tex, zUv);
10349
+ const tintedRgb = texColor.rgb.mul(uniforms.color);
10350
+ const finalAlpha = texColor.a.mul(uniforms.opacity).mul(edgeAlpha);
10351
+ const tinted = vec4(tintedRgb, finalAlpha);
10352
+ return toGrayscale({ inputColor: tinted, intensity: uniforms.grayscale });
10353
+ })();
10354
+ return mat;
10355
+ }, [tex, uniforms]);
10356
+ React.useLayoutEffect(() => {
10357
+ uniforms.color.value.set(options.color);
10358
+ uniforms.scale.value.set(options.scale[0], options.scale[1]);
10359
+ uniforms.imageBounds.value.set(options.imageBounds[0], options.imageBounds[1]);
10360
+ uniforms.resolution.value = options.resolution;
10361
+ uniforms.zoom.value = options.zoom;
10362
+ uniforms.radius.value = options.radius;
10363
+ uniforms.grayscale.value = options.grayscale;
10364
+ uniforms.opacity.value = options.opacity;
10365
+ }, [
10366
+ uniforms,
10367
+ options.color,
10368
+ options.scale[0],
10369
+ options.scale[1],
10370
+ options.imageBounds[0],
10371
+ options.imageBounds[1],
10372
+ options.resolution,
10373
+ options.zoom,
10374
+ options.radius,
10375
+ options.grayscale,
10376
+ options.opacity
10377
+ ]);
10378
+ React.useLayoutEffect(() => {
10379
+ material.toneMapped = options.toneMapped ?? true;
10380
+ material.transparent = options.transparent ?? false;
10381
+ if (options.side !== void 0) material.side = options.side;
10382
+ material.needsUpdate = true;
10383
+ }, [material, options.toneMapped, options.transparent, options.side]);
10384
+ return material;
10385
+ }
10386
+ const ImageBase = /* @__PURE__ */ React.forwardRef(
10387
+ ({
10388
+ children,
10389
+ color = "white",
10390
+ segments = 1,
10391
+ scale = 1,
10392
+ zoom = 1,
10393
+ grayscale = 0,
10394
+ opacity = 1,
10395
+ radius = 0,
10396
+ texture,
10397
+ toneMapped,
10398
+ transparent,
10399
+ side,
10400
+ ...props
10401
+ }, fref) => {
10402
+ const ref = React.useRef(null);
10403
+ const size = useThree((state) => state.size);
10404
+ const planeBounds = Array.isArray(scale) ? [scale[0], scale[1]] : [scale, scale];
10405
+ const img = texture.image;
10406
+ const imageBounds = [img.width, img.height];
10407
+ const resolution = Math.max(size.width, size.height);
10408
+ const material = useImageMaterial(texture, {
10409
+ color,
10410
+ zoom,
10411
+ radius,
10412
+ grayscale,
10413
+ opacity,
10414
+ scale: planeBounds,
10415
+ imageBounds,
10416
+ resolution,
10417
+ toneMapped,
10418
+ transparent,
10419
+ side
10420
+ });
10421
+ React.useImperativeHandle(fref, () => ref.current, []);
10422
+ return /* @__PURE__ */ React.createElement("mesh", { ref, scale: Array.isArray(scale) ? [...scale, 1] : scale, ...props }, /* @__PURE__ */ React.createElement("planeGeometry", { args: [1, 1, segments, segments] }), /* @__PURE__ */ React.createElement("primitive", { object: material, attach: "material" }), children);
11598
10423
  }
11599
- /** Enable dashed lines */
11600
- get dash() {
11601
- return this._dash.value > 0.5;
10424
+ );
10425
+ const ImageWithUrl = /* @__PURE__ */ React.forwardRef(
10426
+ ({ url, ...props }, ref) => {
10427
+ const texture = useTexture(url);
10428
+ return /* @__PURE__ */ React.createElement(ImageBase, { ...props, texture, ref });
11602
10429
  }
11603
- set dash(v) {
11604
- this._dash.value = v ? 1 : 0;
10430
+ );
10431
+ const ImageWithTexture = /* @__PURE__ */ React.forwardRef(({ url: _url, ...props }, ref) => {
10432
+ return /* @__PURE__ */ React.createElement(ImageBase, { ...props, ref });
10433
+ });
10434
+ const Image = /* @__PURE__ */ React.forwardRef((props, ref) => {
10435
+ if (props.url) return /* @__PURE__ */ React.createElement(ImageWithUrl, { ...props, ref });
10436
+ else if (props.texture) return /* @__PURE__ */ React.createElement(ImageWithTexture, { ...props, ref });
10437
+ else throw new Error("<Image /> requires a url or texture");
10438
+ });
10439
+
10440
+ class SpotLightMaterial extends MeshBasicNodeMaterial {
10441
+ //* Private Uniform Nodes --
10442
+ _depth;
10443
+ _opacity;
10444
+ _attenuation;
10445
+ _anglePower;
10446
+ _spotPosition;
10447
+ _lightColor;
10448
+ _cameraNear;
10449
+ _cameraFar;
10450
+ _resolution;
10451
+ constructor() {
10452
+ super();
10453
+ this._depth = uniformTexture(new THREE.Texture());
10454
+ this._opacity = uniform(1);
10455
+ this._attenuation = uniform(5);
10456
+ this._anglePower = uniform(5);
10457
+ this._spotPosition = uniform(new THREE.Vector3(0, 0, 0));
10458
+ this._lightColor = uniform(new THREE.Color("white"));
10459
+ this._cameraNear = uniform(0.1);
10460
+ this._cameraFar = uniform(100);
10461
+ this._resolution = uniform(new THREE.Vector2(0, 0));
10462
+ this.transparent = true;
10463
+ this.depthWrite = false;
10464
+ this.side = THREE.DoubleSide;
10465
+ this._buildShader();
11605
10466
  }
11606
- /** Number of dash repeats, default: 4 */
11607
- get dashRepeats() {
11608
- return this._dashRepeats.value;
10467
+ //* Build TSL Shader ==============================
10468
+ _buildShader() {
10469
+ const depthTex = this._depth;
10470
+ const opacityUniform = this._opacity;
10471
+ const attenuationUniform = this._attenuation;
10472
+ const anglePowerUniform = this._anglePower;
10473
+ const spotPositionUniform = this._spotPosition;
10474
+ const lightColorUniform = this._lightColor;
10475
+ const cameraNearUniform = this._cameraNear;
10476
+ const cameraFarUniform = this._cameraFar;
10477
+ const resolutionUniform = this._resolution;
10478
+ const vNormal = varying(normalize(modelViewMatrix.transformDirection(normalLocal)), "vNormal");
10479
+ const vIntensity = varying(
10480
+ saturate(float(1).sub(distance(positionWorld, spotPositionUniform).div(attenuationUniform))),
10481
+ "vIntensity"
10482
+ );
10483
+ const vViewZ = varying(positionView.z, "vViewZ");
10484
+ this.colorNode = Fn(() => {
10485
+ const angleIntensity = pow(abs(vNormal.z), anglePowerUniform);
10486
+ const intensity = vIntensity.mul(angleIntensity).toVar();
10487
+ const hasDepth = resolutionUniform.x.greaterThan(0);
10488
+ const screenUV = vec2$2(
10489
+ screenCoordinate.x.div(resolutionUniform.x),
10490
+ float(1).sub(screenCoordinate.y.div(resolutionUniform.y))
10491
+ );
10492
+ const sampledDepth = texture(depthTex, screenUV).r;
10493
+ const near = cameraNearUniform;
10494
+ const far = cameraFarUniform;
10495
+ const sceneViewZ = near.mul(far).div(far.sub(near).mul(sampledDepth).sub(far));
10496
+ const depthDiff = vViewZ.sub(sceneViewZ);
10497
+ const softFactor = smoothstep(float(0), float(1), depthDiff);
10498
+ intensity.assign(select(hasDepth, intensity.mul(softFactor), intensity));
10499
+ return vec4(lightColorUniform, intensity.mul(opacityUniform));
10500
+ })();
11609
10501
  }
11610
- set dashRepeats(v) {
11611
- this._dashRepeats.value = v;
10502
+ //* Uniform Accessors ==============================
10503
+ get depth() {
10504
+ return this._depth?.value;
11612
10505
  }
11613
- /** Dash length 0-1, default: 0.5 */
11614
- get dashLength() {
11615
- return this._dashLength.value;
10506
+ set depth(v) {
10507
+ if (this._depth) this._depth.value = v ?? new THREE.Texture();
11616
10508
  }
11617
- set dashLength(v) {
11618
- this._dashLength.value = v;
10509
+ get opacity() {
10510
+ return this._opacity?.value;
11619
10511
  }
11620
- /** Squeeze thickness toward line center */
11621
- get squeeze() {
11622
- return this._squeeze.value > 0.5;
10512
+ set opacity(v) {
10513
+ if (this._opacity) this._opacity.value = v;
11623
10514
  }
11624
- set squeeze(v) {
11625
- this._squeeze.value = v ? 1 : 0;
10515
+ get attenuation() {
10516
+ return this._attenuation?.value;
11626
10517
  }
11627
- /** Minimum squeeze factor, default: 0.2 */
11628
- get squeezeMin() {
11629
- return this._squeezeMin.value;
10518
+ set attenuation(v) {
10519
+ if (this._attenuation) this._attenuation.value = v;
11630
10520
  }
11631
- set squeezeMin(v) {
11632
- this._squeezeMin.value = v;
10521
+ get anglePower() {
10522
+ return this._anglePower?.value;
11633
10523
  }
11634
- /** Maximum squeeze factor, default: 1 */
11635
- get squeezeMax() {
11636
- return this._squeezeMax.value;
10524
+ set anglePower(v) {
10525
+ if (this._anglePower) this._anglePower.value = v;
11637
10526
  }
11638
- set squeezeMax(v) {
11639
- this._squeezeMax.value = v;
10527
+ get spotPosition() {
10528
+ return this._spotPosition?.value;
11640
10529
  }
11641
- /** Stroke (edge) color */
11642
- get stroke() {
11643
- return this._stroke.value;
10530
+ set spotPosition(v) {
10531
+ if (this._spotPosition) this._spotPosition.value = v;
11644
10532
  }
11645
- set stroke(v) {
11646
- if (v instanceof THREE.Color) this._stroke.value = v;
11647
- else this._stroke.value = new THREE.Color(v);
10533
+ get lightColor() {
10534
+ return this._lightColor?.value;
11648
10535
  }
11649
- /** Backface stroke color */
11650
- get backfaceStroke() {
11651
- return this._backfaceStroke.value;
10536
+ set lightColor(v) {
10537
+ if (this._lightColor) this._lightColor.value = v;
11652
10538
  }
11653
- set backfaceStroke(v) {
11654
- if (v instanceof THREE.Color) this._backfaceStroke.value = v;
11655
- else this._backfaceStroke.value = new THREE.Color(v);
10539
+ get cameraNear() {
10540
+ return this._cameraNear?.value;
11656
10541
  }
11657
- /** Fill (background) color */
11658
- get fill() {
11659
- return this._fill.value;
10542
+ set cameraNear(v) {
10543
+ if (this._cameraNear) this._cameraNear.value = v;
11660
10544
  }
11661
- set fill(v) {
11662
- if (v instanceof THREE.Color) this._fill.value = v;
11663
- else this._fill.value = new THREE.Color(v);
10545
+ get cameraFar() {
10546
+ return this._cameraFar?.value;
11664
10547
  }
11665
- }
11666
- function setBarycentricCoordinates(geometry) {
11667
- const position = geometry.getAttribute("position");
11668
- const count = position.count;
11669
- if (geometry.index) {
11670
- geometry = geometry.toNonIndexed();
10548
+ set cameraFar(v) {
10549
+ if (this._cameraFar) this._cameraFar.value = v;
11671
10550
  }
11672
- const barycentricArray = new Float32Array(count * 3);
11673
- for (let i = 0; i < count; i += 3) {
11674
- barycentricArray[i * 3 + 0] = 1;
11675
- barycentricArray[i * 3 + 1] = 0;
11676
- barycentricArray[i * 3 + 2] = 0;
11677
- barycentricArray[(i + 1) * 3 + 0] = 0;
11678
- barycentricArray[(i + 1) * 3 + 1] = 1;
11679
- barycentricArray[(i + 1) * 3 + 2] = 0;
11680
- barycentricArray[(i + 2) * 3 + 0] = 0;
11681
- barycentricArray[(i + 2) * 3 + 1] = 0;
11682
- barycentricArray[(i + 2) * 3 + 2] = 1;
10551
+ get resolution() {
10552
+ return this._resolution?.value;
11683
10553
  }
11684
- geometry.setAttribute("barycentric", new THREE.BufferAttribute(barycentricArray, 3));
11685
- return geometry;
11686
- }
11687
- const WireframeMaterial = /* @__PURE__ */ React.forwardRef(
11688
- ({
11689
- fillOpacity = 0.25,
11690
- fillMix = 0,
11691
- strokeOpacity = 1,
11692
- thickness = 0.05,
11693
- colorBackfaces = false,
11694
- dashInvert = true,
11695
- dash = false,
11696
- dashRepeats = 4,
11697
- dashLength = 0.5,
11698
- squeeze = false,
11699
- squeezeMin = 0.2,
11700
- squeezeMax = 1,
11701
- stroke = "#ff0000",
11702
- backfaceStroke = "#0000ff",
11703
- fill = "#00ff00",
11704
- ...props
11705
- }, fref) => {
11706
- extend({ WireframeMaterial: WireframeMaterialImpl });
11707
- const ref = React.useRef(null);
11708
- React.useImperativeHandle(fref, () => ref.current, []);
11709
- return /* @__PURE__ */ React.createElement(
11710
- "wireframeMaterial",
11711
- {
11712
- ref,
11713
- ...props,
11714
- fillOpacity,
11715
- fillMix,
11716
- strokeOpacity,
11717
- thickness,
11718
- colorBackfaces,
11719
- dashInvert,
11720
- dash,
11721
- dashRepeats,
11722
- dashLength,
11723
- squeeze,
11724
- squeezeMin,
11725
- squeezeMax,
11726
- stroke: stroke instanceof THREE.Color ? stroke : new THREE.Color(stroke),
11727
- backfaceStroke: backfaceStroke instanceof THREE.Color ? backfaceStroke : new THREE.Color(backfaceStroke),
11728
- fill: fill instanceof THREE.Color ? fill : new THREE.Color(fill)
11729
- }
11730
- );
10554
+ set resolution(v) {
10555
+ if (this._resolution) this._resolution.value = v;
11731
10556
  }
11732
- );
11733
- const WireframeMaterialShaders = {
11734
- uniforms: {
11735
- strokeOpacity: 1,
11736
- fillOpacity: 0.25,
11737
- fillMix: 0,
11738
- thickness: 0.05,
11739
- colorBackfaces: false,
11740
- dashInvert: true,
11741
- dash: false,
11742
- dashRepeats: 4,
11743
- dashLength: 0.5,
11744
- squeeze: false,
11745
- squeezeMin: 0.2,
11746
- squeezeMax: 1,
11747
- stroke: /* @__PURE__ */ new THREE.Color("#ff0000"),
11748
- backfaceStroke: /* @__PURE__ */ new THREE.Color("#0000ff"),
11749
- fill: /* @__PURE__ */ new THREE.Color("#00ff00")
11750
- },
11751
- vertex: "// Converted to TSL - see WireframeMaterial",
11752
- fragment: "// Converted to TSL - see WireframeMaterial"
11753
- };
11754
- function setWireframeOverride(_material, _uniforms) {
11755
- console.warn("setWireframeOverride is deprecated. Use WireframeMaterial directly with TSL for WebGPU.");
11756
- }
11757
- function useWireframeUniforms(_uniforms, _props) {
11758
- console.warn("useWireframeUniforms is deprecated. Use WireframeMaterial props directly with TSL for WebGPU.");
11759
10557
  }
11760
10558
 
11761
10559
  class StarfieldMaterial extends SpriteNodeMaterial {
@@ -12114,6 +10912,20 @@ const Grid = /* @__PURE__ */ React.forwardRef(
12114
10912
  }
12115
10913
  );
12116
10914
 
10915
+ let hasWarned = false;
10916
+ function warnOnce(message) {
10917
+ if (!hasWarned) {
10918
+ console.warn(message);
10919
+ hasWarned = true;
10920
+ }
10921
+ }
10922
+ function SoftShadows(props) {
10923
+ warnOnce(
10924
+ "drei: SoftShadows is not yet supported in WebGPU. It uses ShaderChunk to inject PCSS shaders which is WebGL-only. Import from @react-three/drei/legacy for WebGL."
10925
+ );
10926
+ return null;
10927
+ }
10928
+
12117
10929
  let spotlightIdCounter = 0;
12118
10930
  const generateSpotlightId = () => `spotlight_${spotlightIdCounter++}`;
12119
10931
  function VolumetricMesh({
@@ -12372,12 +11184,4 @@ const Sparkles = /* @__PURE__ */ React.forwardRef(({ noise = 1, count = 100, spe
12372
11184
  );
12373
11185
  });
12374
11186
 
12375
- function createUnsupportedComponent(name, reason) {
12376
- return function UnsupportedComponent() {
12377
- throw new Error(`[drei/native] ${name} is not supported: ${reason}`);
12378
- };
12379
- }
12380
- const Html = createUnsupportedComponent("Html", "HTML requires DOM which is not available on React Native");
12381
- const Caustics = createUnsupportedComponent("Caustics", "Caustics is not yet supported on React Native");
12382
-
12383
- export { AccumulativeShadows, AdaptiveDpr, AdaptiveEvents, ArcballControls, BBAnchor, Backdrop, BakeShadows, Billboard, BlurPass, Bounds, Box, CameraShake, Capsule, CatmullRomLine, Caustics, CausticsMaterial, CausticsNormalMaterial, CausticsProjectionMaterial, Center, Circle, Clone, Cloud, CloudInstance, Clouds, ComputedAttribute, Cone, ContactShadows, ConvolutionMaterial, CubeCamera, CubeTexture, CubicBezierLine, CurveModifier, CycleRaycast, Cylinder, Decal, Detailed, DetectGPU, DeviceOrientationControls, DiscardMaterial, Dodecahedron, DragControls, Edges, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, Example, Extrude, FakeCloudMaterial, Fbo, Fbx, FirstPersonControls, Fisheye, Float, FlyControls, GizmoHelper, GizmoViewcube, GizmoViewport, Gltf, GradientTexture, GradientType, Grid, Helper, Html, Hud, Icosahedron, Image, Instance, InstancedAttribute, Instances, IsObject, KeyboardControls, Ktx2, Lathe, Lightformer, Line, Loader, MapControls, Mask, MatcapTexture, Merged, MeshDistortMaterial, MeshPortalMaterial, MeshReflectorMaterial, MeshReflectorMaterial$1 as MeshReflectorMaterialImpl, MeshRefractionMaterial, MeshTransmissionMaterial, MeshWobbleMaterial, MotionPathControls, NormalTexture, Octahedron, OrbitControls, OrthographicCamera, Outlines, PerformanceMonitor, PerspectiveCamera, PivotControls, Plane, Point, PointMaterial, PointMaterialImpl, PointerLockControls, Points, PointsBuffer, Polyhedron, PositionMesh, PositionPoint, PositionalAudio, Preload, PresentationControls, Progress, QuadraticBezierLine, RandomizedLight, RenderCubeTexture, RenderTexture, Resize, Ring, RoundedBox, RoundedBoxGeometry, Sampler, ScreenQuad, ScreenSizer, ScreenSpace, ScreenVideoTexture, Scroll, ScrollControls, Segment, SegmentObject, Segments, Select, Shadow, Shape, Sky, SoftShadows, Sparkles, SparklesMaterial, Sphere, SpotLight, SpotLightMaterial, SpriteAnimator, Stage, StarfieldMaterial, Stars, Stats, StatsGl, Svg, Tetrahedron, Text3D, Texture, Torus, TorusKnot, TrackballControls, Trail, TrailTexture, TransformControls, Tube, VideoTexture, View, WebcamVideoTexture, Wireframe, WireframeMaterial, WireframeMaterialShaders, accumulativeContext, calcPosFromAngles, checkIfFrameIsEmpty, createInstances, getFirstFrame, meshBounds, presetsObj, setBarycentricCoordinates, setWireframeOverride, useAnimations, useAspect, useBounds, useContextBridge, useCubeCamera, useCubeTexture, useCursor, useCustomRaycast, useDepthBuffer, useDetectGPU, useEnvironment, useFBO, useFBX, useFont, useGLTF, useGizmoContext, useHelper, useIntersect, useKTX2, useKeyboardControls, useMask, useMatcapTexture, useMotion, useNormalTexture, usePerformanceMonitor, useProgress, useScroll, useSelect, useSpriteAnimator, useSpriteLoader, useSurfaceSampler, useTexture, useTrail, useTrailTexture, useVideoTexture, useWireframeUniforms };
11187
+ export { AccumulativeShadows, AdaptiveDpr, AdaptiveEvents, BBAnchor, Backdrop, BakeShadows, Billboard, Bounds, Box, CameraShake, Capsule, CatmullRomLine, CausticsMaterial, CausticsNormalMaterial, CausticsProjectionMaterial, Center, Circle, Clone, Cloud, CloudInstance, Clouds, ComputedAttribute, Cone, ContactShadows, ConvolutionMaterial, CubeCamera, CubeTexture, CubicBezierLine, CurveModifier, CycleRaycast, Cylinder, Decal, Detailed, DetectGPU, DeviceOrientationControls, DiscardMaterial, Dodecahedron, Edges, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, Example, Extrude, FakeCloudMaterial, Fbo, Fbx, Fisheye, Float, GizmoHelper, GizmoViewcube, GizmoViewport, Gltf, GradientTexture, GradientType, Grid, Helper, Hud, Icosahedron, Image, Instance, InstancedAttribute, Instances, IsObject, Ktx2, Lathe, Lightformer, Line, Loader, Mask, MatcapTexture, Merged, MeshDistortMaterial, MeshPortalMaterial, MeshReflectorMaterial, MeshReflectorMaterial$1 as MeshReflectorMaterialImpl, MeshRefractionMaterial, MeshTransmissionMaterial, MeshWobbleMaterial, MotionPathControls, NormalTexture, Octahedron, OrthographicCamera, Outlines, PerformanceMonitor, PerspectiveCamera, PivotControls, Plane, Point, PointMaterial, PointMaterialImpl, Points, PointsBuffer, Polyhedron, PositionMesh, PositionPoint, PositionalAudio, Preload, PresentationControls, Progress, QuadraticBezierLine, RandomizedLight, RenderCubeTexture, RenderTexture, Resize, Ring, RoundedBox, RoundedBoxGeometry, Sampler, ScreenQuad, ScreenSizer, ScreenSpace, ScreenVideoTexture, Scroll, Segment, SegmentObject, Segments, Select, Shadow, Shape, Sky, SoftShadows, Sparkles, SparklesMaterial, Sphere, SpotLight, SpotLightMaterial, SpriteAnimator, Stage, StarfieldMaterial, Stars, Stats, StatsGl, Svg, Tetrahedron, Text3D, Texture, Torus, TorusKnot, Trail, TrailTexture, TransformControls, Tube, VideoTexture, View, WebcamVideoTexture, Wireframe, WireframeMaterial, WireframeMaterialShaders, accumulativeContext, calcPosFromAngles, checkIfFrameIsEmpty, createInstances, getFirstFrame, meshBounds, presetsObj, setBarycentricCoordinates, setWireframeOverride, useAnimations, useAspect, useBounds, useContextBridge, useCubeCamera, useCubeTexture, useCursor, useCustomRaycast, useDepthBuffer, useDetectGPU, useEnvironment, useFBO, useFBX, useFont, useGLTF, useGizmoContext, useHelper, useIntersect, useKTX2, useKeyboardControls, useMask, useMatcapTexture, useMotion, useNormalTexture, usePerformanceMonitor, useProgress, useScroll, useSelect, useSpriteAnimator, useSpriteLoader, useSurfaceSampler, useTexture, useTrail, useTrailTexture, useVideoTexture, useWireframeUniforms };