@react-three/drei 11.0.0-alpha.5 → 11.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -1
- package/core/index.d.mts +194 -51
- package/core/index.d.ts +194 -51
- package/core/index.mjs +543 -240
- package/experimental/index.d.mts +20 -0
- package/experimental/index.d.ts +20 -0
- package/external/index.d.mts +38 -2
- package/external/index.d.ts +38 -2
- package/external/index.mjs +3 -4
- package/index.d.mts +211 -53
- package/index.d.ts +211 -53
- package/index.mjs +544 -241
- package/legacy/index.d.mts +211 -56
- package/legacy/index.d.ts +211 -56
- package/legacy/index.mjs +687 -260
- package/native/index.d.mts +219 -130
- package/native/index.d.ts +219 -130
- package/native/index.mjs +1225 -416
- package/package.json +7 -7
- package/webgpu/index.d.mts +249 -129
- package/webgpu/index.d.ts +249 -129
- package/webgpu/index.mjs +1468 -516
package/native/index.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
|
+
import { MeshBasicNodeMaterial, RenderTarget, MeshPhongNodeMaterial, MeshNormalNodeMaterial, MeshPhysicalNodeMaterial, Frustum, Matrix4, QuadMesh, CubeRenderTarget, Line2NodeMaterial, Vector3, Vector4, Vector2, Color, InstancedInterleavedBuffer, InterleavedBufferAttribute, Object3D, HalfFloatType, CubeCamera as CubeCamera$1, EventDispatcher, Euler, Quaternion, MathUtils, TextureLoader, Texture as Texture$1, MeshLambertMaterial, DynamicDrawUsage, CatmullRomCurve3, CubicBezierCurve3, QuadraticBezierCurve3, Shape as Shape$1, CanvasTexture, PerspectiveCamera as PerspectiveCamera$1, OrthographicCamera as OrthographicCamera$1, REVISION, AudioListener, AudioLoader, AnimationMixer, BufferAttribute, Box3, Sphere as Sphere$1, InstancedBufferAttribute, DoubleSide, DepthTexture, DepthFormat, UnsignedShortType, CubeTextureLoader, DefaultLoadingManager, Ray, Raycaster, Camera, CubeReflectionMapping, EquirectangularReflectionMapping, Scene, RepeatWrapping, SpriteNodeMaterial, AdditiveBlending, ShadowNode, CylinderGeometry } from 'three/webgpu';
|
|
3
|
+
import { uniform, Fn, float, vec4, uniformTexture, uv, vec2 as vec2$2, texture, Discard, max, sub, mix, output, mul, negate, add, dot, refract, div, length, cross, select, vec3, normalize, normalWorld, positionWorld, cameraPosition, screenCoordinate, mx_fractal_noise_vec3, int, thickness, pow, roughness, Loop, ior, screenUV, screenSize, cameraProjectionMatrix, cameraViewMatrix, attenuationColor, attenuationDistance, diffuseColor, transmission, fract, sin, modelWorldMatrix, log, exp, DFGLUT, reflector, clamp, equirectUV, reflect, smoothstep, round, distance, positionLocal, mx_noise_vec3, cos, mat3, normalLocal, attribute, modelViewMatrix, varying, min, frontFacing, fwidth, abs, saturate, positionView, positionGeometry, reference, renderGroup, interleavedGradientNoise, vogelDiskSample, step } from 'three/tsl';
|
|
1
4
|
import * as React from 'react';
|
|
2
5
|
import { forwardRef, useImperativeHandle, useRef, useMemo, useEffect, useCallback, useLayoutEffect, useState, Fragment, createContext, useContext } from 'react';
|
|
3
6
|
import { useThree, useFrame, extend, createPortal, applyProps, useInstanceHandle, context as context$a, useLoader, addEffect, addAfterEffect } from '@react-three/fiber';
|
|
4
|
-
import * as THREE from 'three/webgpu';
|
|
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';
|
|
6
7
|
import { SimplexNoise } from 'three/examples/jsm/math/SimplexNoise.js';
|
|
7
8
|
import { Line2 } from 'three/examples/jsm/lines/webgpu/Line2.js';
|
|
8
9
|
import { LineSegments2 } from 'three/examples/jsm/lines/webgpu/LineSegments2.js';
|
|
9
10
|
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
|
|
10
11
|
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
12
|
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils.js';
|
|
13
13
|
import { Flow } from 'three/examples/jsm/modifiers/CurveModifier.js';
|
|
14
14
|
import { DecalGeometry } from 'three/examples/jsm/geometries/DecalGeometry.js';
|
|
@@ -28,11 +28,11 @@ import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
|
|
|
28
28
|
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
|
|
29
29
|
import { create as create$1 } from 'zustand';
|
|
30
30
|
import { hashBlur } from 'three/examples/jsm/tsl/display/hashBlur.js';
|
|
31
|
+
import PhysicalLightingModel from 'three/src/nodes/functions/PhysicalLightingModel.js';
|
|
31
32
|
import { misc, easing } from 'maath';
|
|
32
33
|
import * as ReactDOM from 'react-dom/client';
|
|
33
34
|
import { useGesture } from '@use-gesture/react';
|
|
34
35
|
import { MeshSurfaceSampler } from 'three/examples/jsm/math/MeshSurfaceSampler.js';
|
|
35
|
-
import { Events } from 'hls.js';
|
|
36
36
|
import { SelectionBox } from 'three/examples/jsm/interactive/SelectionBox.js';
|
|
37
37
|
import { shallow } from 'zustand/shallow';
|
|
38
38
|
import { Sky as Sky$1 } from 'three/examples/jsm/objects/Sky.js';
|
|
@@ -231,28 +231,354 @@ const ContactShadows = /* @__PURE__ */ React.forwardRef(
|
|
|
231
231
|
}
|
|
232
232
|
);
|
|
233
233
|
|
|
234
|
+
const discardFragment = /* @__PURE__ */ Fn(() => {
|
|
235
|
+
Discard();
|
|
236
|
+
return vec4(0, 0, 0, 0);
|
|
237
|
+
});
|
|
238
|
+
const DiscardMaterial = /* @__PURE__ */ new MeshBasicNodeMaterial({
|
|
239
|
+
fragmentNode: discardFragment()
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
function isLight(object) {
|
|
243
|
+
return object.isLight;
|
|
244
|
+
}
|
|
245
|
+
function isGeometry$1(object) {
|
|
246
|
+
return !!object.geometry;
|
|
247
|
+
}
|
|
234
248
|
const accumulativeContext = /* @__PURE__ */ React.createContext(
|
|
235
249
|
null
|
|
236
250
|
);
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
251
|
+
class SoftShadowMaterialImpl extends MeshBasicNodeMaterial {
|
|
252
|
+
_color;
|
|
253
|
+
_blend;
|
|
254
|
+
_alphaTest;
|
|
255
|
+
_opacity;
|
|
256
|
+
_map;
|
|
257
|
+
constructor() {
|
|
258
|
+
super();
|
|
259
|
+
this._color = uniform(new THREE.Color());
|
|
260
|
+
this._blend = uniform(2);
|
|
261
|
+
this._alphaTest = uniform(0.75);
|
|
262
|
+
this._opacity = uniform(0);
|
|
263
|
+
this._map = uniformTexture(new THREE.Texture());
|
|
264
|
+
this.transparent = true;
|
|
265
|
+
this.depthWrite = false;
|
|
266
|
+
this._buildShader();
|
|
267
|
+
}
|
|
268
|
+
_buildShader() {
|
|
269
|
+
const colorUniform = this._color;
|
|
270
|
+
const blendUniform = this._blend;
|
|
271
|
+
const alphaTestUniform = this._alphaTest;
|
|
272
|
+
const opacityUniform = this._opacity;
|
|
273
|
+
const mapTex = this._map;
|
|
274
|
+
this.colorNode = Fn(() => {
|
|
275
|
+
const texCoord = uv();
|
|
276
|
+
const sampled = texture(mapTex, texCoord);
|
|
277
|
+
const rgb = colorUniform.mul(sampled.r).mul(blendUniform);
|
|
278
|
+
const sum = sampled.r.add(sampled.g).add(sampled.b);
|
|
279
|
+
const alpha = max(float(0), float(1).sub(sum.div(alphaTestUniform))).mul(opacityUniform);
|
|
280
|
+
return vec4(rgb, alpha);
|
|
281
|
+
})();
|
|
282
|
+
}
|
|
283
|
+
get shadowColor() {
|
|
284
|
+
return this._color.value;
|
|
285
|
+
}
|
|
286
|
+
set shadowColor(v) {
|
|
287
|
+
if (v instanceof THREE.Color) {
|
|
288
|
+
this._color.value.copy(v);
|
|
289
|
+
} else {
|
|
290
|
+
this._color.value.set(v);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
get blend() {
|
|
294
|
+
return this._blend.value;
|
|
295
|
+
}
|
|
296
|
+
set blend(v) {
|
|
297
|
+
this._blend.value = v;
|
|
298
|
+
}
|
|
299
|
+
get alphaTest() {
|
|
300
|
+
return this._alphaTest.value;
|
|
301
|
+
}
|
|
302
|
+
set alphaTest(v) {
|
|
303
|
+
this._alphaTest.value = v;
|
|
304
|
+
}
|
|
305
|
+
get opacity() {
|
|
306
|
+
return this._opacity.value;
|
|
307
|
+
}
|
|
308
|
+
set opacity(v) {
|
|
309
|
+
if (!this._opacity) this._opacity = uniform(v);
|
|
310
|
+
else this._opacity.value = v;
|
|
311
|
+
}
|
|
312
|
+
get map() {
|
|
313
|
+
if (!this._map) {
|
|
314
|
+
this._map = uniformTexture(new THREE.Texture());
|
|
315
|
+
}
|
|
316
|
+
return this._map.value;
|
|
317
|
+
}
|
|
318
|
+
set map(v) {
|
|
319
|
+
this._map.value = v;
|
|
242
320
|
}
|
|
243
321
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
322
|
+
class ProgressiveShadowMaterial extends MeshPhongNodeMaterial {
|
|
323
|
+
_previousShadowMap;
|
|
324
|
+
_averagingWindow;
|
|
325
|
+
constructor(initialTexture) {
|
|
326
|
+
super();
|
|
327
|
+
this._previousShadowMap = texture(initialTexture);
|
|
328
|
+
this._averagingWindow = uniform(100);
|
|
329
|
+
this.fog = false;
|
|
330
|
+
this._buildShader();
|
|
331
|
+
}
|
|
332
|
+
_buildShader() {
|
|
333
|
+
const previousMapTex = this._previousShadowMap;
|
|
334
|
+
const averagingWindowUniform = this._averagingWindow;
|
|
335
|
+
const uvNode = uv();
|
|
336
|
+
this.vertexNode = vec4(sub(uvNode, vec2$2(0.5)).mul(2), 1, 1);
|
|
337
|
+
this.outputNode = vec4(mix(previousMapTex.sample(uv()), output, float(1).div(averagingWindowUniform)));
|
|
338
|
+
}
|
|
339
|
+
get previousShadowMap() {
|
|
340
|
+
return this._previousShadowMap.value;
|
|
341
|
+
}
|
|
342
|
+
set previousShadowMap(v) {
|
|
343
|
+
this._previousShadowMap.value = v;
|
|
344
|
+
}
|
|
345
|
+
get averagingWindow() {
|
|
346
|
+
return this._averagingWindow.value;
|
|
347
|
+
}
|
|
348
|
+
set averagingWindow(v) {
|
|
349
|
+
this._averagingWindow.value = v;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
class ProgressiveLightMap {
|
|
353
|
+
renderer;
|
|
354
|
+
res;
|
|
355
|
+
scene;
|
|
356
|
+
object;
|
|
357
|
+
buffer1Active;
|
|
358
|
+
progressiveLightMap1;
|
|
359
|
+
progressiveLightMap2;
|
|
360
|
+
discardMat;
|
|
361
|
+
targetMat;
|
|
362
|
+
clearColor;
|
|
363
|
+
clearAlpha;
|
|
364
|
+
lights;
|
|
365
|
+
meshes;
|
|
366
|
+
constructor(renderer, scene, res = 1024) {
|
|
367
|
+
this.renderer = renderer;
|
|
368
|
+
this.res = res;
|
|
369
|
+
this.scene = scene;
|
|
370
|
+
this.buffer1Active = false;
|
|
371
|
+
this.lights = [];
|
|
372
|
+
this.meshes = [];
|
|
373
|
+
this.object = null;
|
|
374
|
+
this.clearColor = new THREE.Color();
|
|
375
|
+
this.clearAlpha = 0;
|
|
376
|
+
const textureParams = {
|
|
377
|
+
type: THREE.HalfFloatType,
|
|
378
|
+
magFilter: THREE.NearestFilter,
|
|
379
|
+
minFilter: THREE.NearestFilter
|
|
380
|
+
};
|
|
381
|
+
this.progressiveLightMap1 = new RenderTarget(this.res, this.res, textureParams);
|
|
382
|
+
this.progressiveLightMap2 = new RenderTarget(this.res, this.res, textureParams);
|
|
383
|
+
this.discardMat = DiscardMaterial;
|
|
384
|
+
this.targetMat = new ProgressiveShadowMaterial(this.progressiveLightMap1.texture);
|
|
385
|
+
}
|
|
386
|
+
clear() {
|
|
387
|
+
this.renderer.getClearColor(this.clearColor);
|
|
388
|
+
this.clearAlpha = this.renderer.getClearAlpha();
|
|
389
|
+
this.renderer.setClearColor("black", 1);
|
|
390
|
+
this.renderer.setRenderTarget(this.progressiveLightMap1);
|
|
391
|
+
this.renderer.clear();
|
|
392
|
+
this.renderer.setRenderTarget(this.progressiveLightMap2);
|
|
393
|
+
this.renderer.clear();
|
|
394
|
+
this.renderer.setRenderTarget(null);
|
|
395
|
+
this.renderer.setClearColor(this.clearColor, this.clearAlpha);
|
|
396
|
+
this.lights = [];
|
|
397
|
+
this.meshes = [];
|
|
398
|
+
this.scene.traverse((object) => {
|
|
399
|
+
if (isGeometry$1(object)) {
|
|
400
|
+
this.meshes.push({ object, material: object.material });
|
|
401
|
+
} else if (isLight(object)) {
|
|
402
|
+
this.lights.push({ object, intensity: object.intensity });
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
prepare() {
|
|
407
|
+
this.lights.forEach((light) => light.object.intensity = 0);
|
|
408
|
+
this.meshes.forEach((mesh) => mesh.object.material = this.discardMat);
|
|
409
|
+
}
|
|
410
|
+
finish() {
|
|
411
|
+
this.lights.forEach((light) => light.object.intensity = light.intensity);
|
|
412
|
+
this.meshes.forEach((mesh) => mesh.object.material = mesh.material);
|
|
413
|
+
}
|
|
414
|
+
configure(object) {
|
|
415
|
+
this.object = object;
|
|
416
|
+
}
|
|
417
|
+
update(camera, blendWindow = 100) {
|
|
418
|
+
if (!this.object) return;
|
|
419
|
+
this.targetMat.averagingWindow = blendWindow;
|
|
420
|
+
const originalMaterial = this.object.material;
|
|
421
|
+
this.object.material = this.targetMat;
|
|
422
|
+
const oldFrustumCulled = this.object.frustumCulled;
|
|
423
|
+
this.object.frustumCulled = false;
|
|
424
|
+
const activeMap = this.buffer1Active ? this.progressiveLightMap1 : this.progressiveLightMap2;
|
|
425
|
+
const inactiveMap = this.buffer1Active ? this.progressiveLightMap2 : this.progressiveLightMap1;
|
|
426
|
+
const oldBg = this.scene.background;
|
|
427
|
+
this.scene.background = null;
|
|
428
|
+
this.renderer.setRenderTarget(activeMap);
|
|
429
|
+
this.targetMat.previousShadowMap = inactiveMap.texture;
|
|
430
|
+
this.buffer1Active = !this.buffer1Active;
|
|
431
|
+
this.renderer.render(this.scene, camera);
|
|
432
|
+
this.renderer.setRenderTarget(null);
|
|
433
|
+
this.scene.background = oldBg;
|
|
434
|
+
this.object.frustumCulled = oldFrustumCulled;
|
|
435
|
+
this.object.material = originalMaterial;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const AccumulativeShadows = /* @__PURE__ */ React.forwardRef(
|
|
439
|
+
({
|
|
440
|
+
children,
|
|
441
|
+
temporal,
|
|
442
|
+
frames = 40,
|
|
443
|
+
limit = Infinity,
|
|
444
|
+
blend = 20,
|
|
445
|
+
scale = 10,
|
|
446
|
+
opacity = 1,
|
|
447
|
+
alphaTest = 0.75,
|
|
448
|
+
color = "black",
|
|
449
|
+
colorBlend = 2,
|
|
450
|
+
resolution = 1024,
|
|
451
|
+
toneMapped = true,
|
|
452
|
+
...props
|
|
453
|
+
}, forwardRef) => {
|
|
454
|
+
const gl = useThree((state) => state.gl);
|
|
455
|
+
const scene = useThree((state) => state.scene);
|
|
456
|
+
const camera = useThree((state) => state.camera);
|
|
457
|
+
const invalidate = useThree((state) => state.invalidate);
|
|
458
|
+
const gPlane = React.useRef(null);
|
|
459
|
+
const gLights = React.useRef(null);
|
|
460
|
+
const [softShadowMat] = React.useState(() => new SoftShadowMaterialImpl());
|
|
461
|
+
const [plm] = React.useState(() => new ProgressiveLightMap(gl, scene, resolution));
|
|
462
|
+
React.useLayoutEffect(() => {
|
|
463
|
+
plm.configure(gPlane.current);
|
|
464
|
+
}, [plm]);
|
|
465
|
+
React.useEffect(() => {
|
|
466
|
+
softShadowMat.shadowColor = color;
|
|
467
|
+
softShadowMat.blend = colorBlend;
|
|
468
|
+
softShadowMat.map = plm.progressiveLightMap2.texture;
|
|
469
|
+
softShadowMat.toneMapped = toneMapped;
|
|
470
|
+
}, [softShadowMat, color, colorBlend, plm, toneMapped]);
|
|
471
|
+
const api = React.useMemo(
|
|
472
|
+
() => ({
|
|
473
|
+
lights: /* @__PURE__ */ new Map(),
|
|
474
|
+
temporal: !!temporal,
|
|
475
|
+
frames: Math.max(2, frames),
|
|
476
|
+
blend: Math.max(2, frames === Infinity ? blend : frames),
|
|
477
|
+
count: 0,
|
|
478
|
+
getMesh: () => gPlane.current,
|
|
479
|
+
reset: () => {
|
|
480
|
+
plm.clear();
|
|
481
|
+
softShadowMat.opacity = 0;
|
|
482
|
+
softShadowMat.alphaTest = 0;
|
|
483
|
+
api.count = 0;
|
|
484
|
+
},
|
|
485
|
+
update: (frames2 = 1) => {
|
|
486
|
+
if (!api.temporal) {
|
|
487
|
+
softShadowMat.opacity = opacity;
|
|
488
|
+
softShadowMat.alphaTest = alphaTest;
|
|
489
|
+
} else {
|
|
490
|
+
softShadowMat.opacity = Math.min(opacity, softShadowMat.opacity + opacity / api.blend);
|
|
491
|
+
softShadowMat.alphaTest = Math.min(alphaTest, softShadowMat.alphaTest + alphaTest / api.blend);
|
|
492
|
+
}
|
|
493
|
+
gLights.current.visible = true;
|
|
494
|
+
plm.prepare();
|
|
495
|
+
for (let i = 0; i < frames2; i++) {
|
|
496
|
+
api.lights.forEach((light) => light.update());
|
|
497
|
+
plm.update(camera, api.blend);
|
|
498
|
+
}
|
|
499
|
+
gLights.current.visible = false;
|
|
500
|
+
plm.finish();
|
|
501
|
+
}
|
|
502
|
+
}),
|
|
503
|
+
[plm, camera, scene, temporal, frames, blend, opacity, alphaTest, softShadowMat]
|
|
504
|
+
);
|
|
505
|
+
React.useLayoutEffect(() => {
|
|
506
|
+
api.reset();
|
|
507
|
+
if (!api.temporal && api.frames !== Infinity) api.update(api.blend);
|
|
508
|
+
});
|
|
509
|
+
React.useImperativeHandle(forwardRef, () => api, [api]);
|
|
510
|
+
useFrame(() => {
|
|
511
|
+
if ((api.temporal || api.frames === Infinity) && api.count < api.frames && api.count < limit) {
|
|
512
|
+
invalidate();
|
|
513
|
+
api.update();
|
|
514
|
+
api.count++;
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
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("primitive", { object: softShadowMat, attach: "material" })));
|
|
518
|
+
}
|
|
519
|
+
);
|
|
520
|
+
const RandomizedLight = /* @__PURE__ */ React.forwardRef(
|
|
521
|
+
({
|
|
522
|
+
castShadow = true,
|
|
523
|
+
bias = 1e-3,
|
|
524
|
+
mapSize = 512,
|
|
525
|
+
size = 5,
|
|
526
|
+
near = 0.5,
|
|
527
|
+
far = 500,
|
|
528
|
+
frames = 1,
|
|
529
|
+
position = [0, 0, 0],
|
|
530
|
+
radius = 1,
|
|
531
|
+
amount = 8,
|
|
532
|
+
intensity = Math.PI,
|
|
533
|
+
ambient = 0.5,
|
|
534
|
+
...props
|
|
535
|
+
}, forwardRef) => {
|
|
536
|
+
const gLights = React.useRef(null);
|
|
537
|
+
const length = new THREE.Vector3(...position).length();
|
|
538
|
+
const parent = React.useContext(accumulativeContext);
|
|
539
|
+
const update = React.useCallback(() => {
|
|
540
|
+
let light;
|
|
541
|
+
if (gLights.current) {
|
|
542
|
+
for (let l = 0; l < gLights.current.children.length; l++) {
|
|
543
|
+
light = gLights.current.children[l];
|
|
544
|
+
if (Math.random() > ambient) {
|
|
545
|
+
light.position.set(
|
|
546
|
+
position[0] + THREE.MathUtils.randFloatSpread(radius),
|
|
547
|
+
position[1] + THREE.MathUtils.randFloatSpread(radius),
|
|
548
|
+
position[2] + THREE.MathUtils.randFloatSpread(radius)
|
|
549
|
+
);
|
|
550
|
+
} else {
|
|
551
|
+
let lambda = Math.acos(2 * Math.random() - 1) - Math.PI / 2;
|
|
552
|
+
let phi = 2 * Math.PI * Math.random();
|
|
553
|
+
light.position.set(
|
|
554
|
+
Math.cos(lambda) * Math.cos(phi) * length,
|
|
555
|
+
Math.abs(Math.cos(lambda) * Math.sin(phi) * length),
|
|
556
|
+
Math.sin(lambda) * length
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}, [radius, ambient, length, ...position]);
|
|
562
|
+
const api = React.useMemo(() => ({ update }), [update]);
|
|
563
|
+
React.useImperativeHandle(forwardRef, () => api, [api]);
|
|
564
|
+
React.useLayoutEffect(() => {
|
|
565
|
+
const group = gLights.current;
|
|
566
|
+
if (parent) parent.lights?.set(group.uuid, api);
|
|
567
|
+
return () => void parent?.lights?.delete(group.uuid);
|
|
568
|
+
}, [parent, api]);
|
|
569
|
+
return /* @__PURE__ */ React.createElement("group", { ref: gLights, ...props }, Array.from({ length: amount }, (_, index) => /* @__PURE__ */ React.createElement(
|
|
570
|
+
"directionalLight",
|
|
571
|
+
{
|
|
572
|
+
key: index,
|
|
573
|
+
castShadow,
|
|
574
|
+
"shadow-bias": bias,
|
|
575
|
+
"shadow-mapSize": [mapSize, mapSize],
|
|
576
|
+
intensity: intensity / amount
|
|
577
|
+
},
|
|
578
|
+
/* @__PURE__ */ React.createElement("orthographicCamera", { attach: "shadow-camera", args: [-size, size, size, -size, near, far] })
|
|
579
|
+
)));
|
|
580
|
+
}
|
|
581
|
+
);
|
|
256
582
|
|
|
257
583
|
function useFBO(width, height, settings) {
|
|
258
584
|
const size = useThree((state) => state.size);
|
|
@@ -401,10 +727,10 @@ class CausticsProjectionMaterial extends MeshBasicNodeMaterial {
|
|
|
401
727
|
this._causticsTextureB.value = v;
|
|
402
728
|
}
|
|
403
729
|
get color() {
|
|
404
|
-
return this._color
|
|
730
|
+
return this._color?.value;
|
|
405
731
|
}
|
|
406
732
|
set color(v) {
|
|
407
|
-
this._color.value = v;
|
|
733
|
+
if (this._color) this._color.value = v;
|
|
408
734
|
}
|
|
409
735
|
get lightProjMatrix() {
|
|
410
736
|
return this._lightProjMatrix.value;
|
|
@@ -645,29 +971,307 @@ class CausticsNormalMaterial extends MeshNormalNodeMaterial {
|
|
|
645
971
|
}
|
|
646
972
|
}
|
|
647
973
|
|
|
648
|
-
const
|
|
649
|
-
|
|
974
|
+
const EnvironmentBRDF = /* @__PURE__ */ Fn((inputs) => {
|
|
975
|
+
const { dotNV, specularColor, specularF90, roughness: roughness2 } = inputs;
|
|
976
|
+
const fab = DFGLUT({ dotNV, roughness: roughness2 });
|
|
977
|
+
return specularColor.mul(fab.x).add(specularF90.mul(fab.y));
|
|
650
978
|
});
|
|
651
|
-
|
|
652
|
-
const
|
|
979
|
+
const rand = /* @__PURE__ */ Fn((inputs) => {
|
|
980
|
+
const [seed, fragCoord] = inputs;
|
|
653
981
|
return fract(sin(dot(vec3(fragCoord.xy, seed), vec3(12.9898, 78.233, 45.164))).mul(43758.5453));
|
|
654
982
|
});
|
|
655
|
-
const applyVolumeAttenuation = /* @__PURE__ */ Fn(
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
983
|
+
const applyVolumeAttenuation = /* @__PURE__ */ Fn((inputs) => {
|
|
984
|
+
const [radiance, transmissionDistance, attColor, attDistance] = inputs;
|
|
985
|
+
const isInfinite = attDistance.greaterThan(1e10);
|
|
986
|
+
const safeColor = max(attColor, vec3(1e-4));
|
|
987
|
+
const attenuationCoefficient = log(safeColor).negate().div(attDistance);
|
|
988
|
+
const transmittance = exp(attenuationCoefficient.negate().mul(transmissionDistance));
|
|
989
|
+
return select(isInfinite, radiance, transmittance.mul(radiance));
|
|
990
|
+
});
|
|
991
|
+
const getVolumeTransmissionRay = /* @__PURE__ */ Fn((inputs) => {
|
|
992
|
+
const [n, v, thicknessVal, iorVal] = inputs;
|
|
993
|
+
const refractionVector = refract(v.negate(), normalize(n), float(1).div(iorVal));
|
|
994
|
+
const refractLen = length(refractionVector);
|
|
995
|
+
const safeRefractionVector = select(
|
|
996
|
+
refractLen.greaterThan(1e-3),
|
|
997
|
+
refractionVector,
|
|
998
|
+
v.negate()
|
|
999
|
+
// Fallback: ray goes straight through
|
|
1000
|
+
);
|
|
1001
|
+
const modelScale = vec3(
|
|
1002
|
+
length(modelWorldMatrix[0].xyz),
|
|
1003
|
+
length(modelWorldMatrix[1].xyz),
|
|
1004
|
+
length(modelWorldMatrix[2].xyz)
|
|
1005
|
+
);
|
|
1006
|
+
return normalize(safeRefractionVector).mul(thicknessVal.mul(modelScale));
|
|
1007
|
+
});
|
|
1008
|
+
const getRefractionUV = /* @__PURE__ */ Fn((inputs) => {
|
|
1009
|
+
const [norm, viewDir, iorVal, thicknessVal, position] = inputs;
|
|
1010
|
+
const transmissionRay = getVolumeTransmissionRay(norm, viewDir, thicknessVal, iorVal);
|
|
1011
|
+
const refractedRayExit = position.add(transmissionRay);
|
|
1012
|
+
const ndcPos = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(refractedRayExit, 1)));
|
|
1013
|
+
const safeW = max(ndcPos.w, float(1e-3));
|
|
1014
|
+
const refractionCoords = vec2$2(ndcPos.xy.div(safeW)).toVar();
|
|
1015
|
+
refractionCoords.addAssign(1);
|
|
1016
|
+
refractionCoords.divAssign(2);
|
|
1017
|
+
refractionCoords.assign(vec2$2(refractionCoords.x, refractionCoords.y.oneMinus()));
|
|
1018
|
+
refractionCoords.assign(refractionCoords.clamp(1e-3, 0.999));
|
|
1019
|
+
return refractionCoords;
|
|
1020
|
+
});
|
|
1021
|
+
class TransmissionLightingModel extends PhysicalLightingModel {
|
|
1022
|
+
_bufferTex;
|
|
1023
|
+
_chromaticAberration;
|
|
1024
|
+
_anisotropicBlur;
|
|
1025
|
+
_timeUniform;
|
|
1026
|
+
_distortion;
|
|
1027
|
+
_distortionScale;
|
|
1028
|
+
_temporalDistortion;
|
|
1029
|
+
_samples;
|
|
1030
|
+
_debugMode;
|
|
1031
|
+
constructor(options, transmissionUniforms) {
|
|
1032
|
+
super(
|
|
1033
|
+
options.clearcoat ?? false,
|
|
1034
|
+
options.sheen ?? false,
|
|
1035
|
+
options.iridescence ?? false,
|
|
1036
|
+
options.anisotropy ?? false,
|
|
1037
|
+
true,
|
|
1038
|
+
// transmission always true for our material
|
|
1039
|
+
options.dispersion ?? false
|
|
1040
|
+
);
|
|
1041
|
+
this._bufferTex = transmissionUniforms.bufferTex;
|
|
1042
|
+
this._chromaticAberration = transmissionUniforms.chromaticAberration;
|
|
1043
|
+
this._anisotropicBlur = transmissionUniforms.anisotropicBlur;
|
|
1044
|
+
this._timeUniform = transmissionUniforms.timeUniform;
|
|
1045
|
+
this._distortion = transmissionUniforms.distortion;
|
|
1046
|
+
this._distortionScale = transmissionUniforms.distortionScale;
|
|
1047
|
+
this._temporalDistortion = transmissionUniforms.temporalDistortion;
|
|
1048
|
+
this._samples = transmissionUniforms.samples;
|
|
1049
|
+
this._debugMode = transmissionUniforms.debugMode;
|
|
1050
|
+
}
|
|
1051
|
+
start(builder) {
|
|
1052
|
+
if (this.clearcoat === true) {
|
|
1053
|
+
this.clearcoatRadiance = vec3().toVar("clearcoatRadiance");
|
|
1054
|
+
this.clearcoatSpecularDirect = vec3().toVar("clearcoatSpecularDirect");
|
|
1055
|
+
this.clearcoatSpecularIndirect = vec3().toVar("clearcoatSpecularIndirect");
|
|
1056
|
+
}
|
|
1057
|
+
if (this.sheen === true) {
|
|
1058
|
+
this.sheenSpecularDirect = vec3().toVar("sheenSpecularDirect");
|
|
1059
|
+
this.sheenSpecularIndirect = vec3().toVar("sheenSpecularIndirect");
|
|
1060
|
+
}
|
|
1061
|
+
if (this.transmission === true) {
|
|
1062
|
+
const position = positionWorld;
|
|
1063
|
+
const v = normalize(cameraPosition.sub(positionWorld));
|
|
1064
|
+
const n = normalWorld;
|
|
1065
|
+
const context = builder.context;
|
|
1066
|
+
const bufferTex = this._bufferTex;
|
|
1067
|
+
const chromaticAberrationUniform = this._chromaticAberration;
|
|
1068
|
+
const anisotropicBlurUniform = this._anisotropicBlur;
|
|
1069
|
+
const timeUniform = this._timeUniform;
|
|
1070
|
+
const distortionUniform = this._distortion;
|
|
1071
|
+
const distortionScaleUniform = this._distortionScale;
|
|
1072
|
+
const temporalDistortionUniform = this._temporalDistortion;
|
|
1073
|
+
const sampleCount = this._samples;
|
|
1074
|
+
const debugModeUniform = this._debugMode;
|
|
1075
|
+
const getCustomTransmission = Fn(() => {
|
|
1076
|
+
const transmissionAccum = vec3(0).toVar("transmissionAccum");
|
|
1077
|
+
const fragCoord = screenCoordinate.xy;
|
|
1078
|
+
const runningSeed = float(0).toVar("runningSeed");
|
|
1079
|
+
const randomCoords = rand(runningSeed, fragCoord);
|
|
1080
|
+
runningSeed.addAssign(1);
|
|
1081
|
+
const temporalOffset = vec3(timeUniform, timeUniform.negate(), timeUniform.negate()).mul(
|
|
1082
|
+
temporalDistortionUniform
|
|
1083
|
+
);
|
|
1084
|
+
const noiseInput = position.mul(distortionScaleUniform).add(temporalOffset);
|
|
1085
|
+
const distortionNormal = select(
|
|
1086
|
+
distortionUniform.greaterThan(0),
|
|
1087
|
+
mx_fractal_noise_vec3(noiseInput, int(4), float(2), float(0.5)).mul(distortionUniform),
|
|
1088
|
+
vec3(0)
|
|
1089
|
+
);
|
|
1090
|
+
const thicknessSmear = thickness.mul(max(pow(roughness, 0.33), anisotropicBlurUniform));
|
|
1091
|
+
Loop(sampleCount, ({ i }) => {
|
|
1092
|
+
const fi = float(i);
|
|
1093
|
+
const progress = fi.add(randomCoords).div(float(sampleCount));
|
|
1094
|
+
const randX = rand(runningSeed, fragCoord).sub(0.5);
|
|
1095
|
+
runningSeed.addAssign(1);
|
|
1096
|
+
const randY = rand(runningSeed, fragCoord).sub(0.5);
|
|
1097
|
+
runningSeed.addAssign(1);
|
|
1098
|
+
const randZ = rand(runningSeed, fragCoord).sub(0.5);
|
|
1099
|
+
runningSeed.addAssign(1);
|
|
1100
|
+
const randW = rand(runningSeed, fragCoord);
|
|
1101
|
+
runningSeed.addAssign(1);
|
|
1102
|
+
const randomDir = normalize(vec3(randX, randY, randZ)).mul(pow(randW, 0.33));
|
|
1103
|
+
const sampleNorm = normalize(n.add(roughness.mul(roughness).mul(2).mul(randomDir)).add(distortionNormal));
|
|
1104
|
+
const sampleThickness = thickness.add(thicknessSmear.mul(progress));
|
|
1105
|
+
const iorR = ior;
|
|
1106
|
+
const iorG = ior.mul(float(1).add(chromaticAberrationUniform.mul(progress)));
|
|
1107
|
+
const iorB = ior.mul(float(1).add(chromaticAberrationUniform.mul(2).mul(progress)));
|
|
1108
|
+
const uvR = getRefractionUV(sampleNorm, v, iorR, sampleThickness, position);
|
|
1109
|
+
const uvG = getRefractionUV(sampleNorm, v, iorG, sampleThickness, position);
|
|
1110
|
+
const uvB = getRefractionUV(sampleNorm, v, iorB, sampleThickness, position);
|
|
1111
|
+
const sampleR = texture(bufferTex, uvR);
|
|
1112
|
+
const sampleG = texture(bufferTex, uvG);
|
|
1113
|
+
const sampleB = texture(bufferTex, uvB);
|
|
1114
|
+
transmissionAccum.x.addAssign(sampleR.r);
|
|
1115
|
+
transmissionAccum.y.addAssign(sampleG.g);
|
|
1116
|
+
transmissionAccum.z.addAssign(sampleB.b);
|
|
1117
|
+
});
|
|
1118
|
+
const avgTransmission = transmissionAccum.div(float(sampleCount));
|
|
1119
|
+
const debugUV = getRefractionUV(n, v, ior, thickness, position);
|
|
1120
|
+
const debugNdotV = n.dot(v);
|
|
1121
|
+
const isNeg = debugNdotV.lessThan(0);
|
|
1122
|
+
const sampleUVFlipped = vec2$2(screenUV.x, screenUV.y.oneMinus()).clamp(1e-3, 0.999);
|
|
1123
|
+
const directSampleFlipped = texture(bufferTex, sampleUVFlipped);
|
|
1124
|
+
const testRay = getVolumeTransmissionRay(n, v, thickness, ior);
|
|
1125
|
+
const rayLen = length(testRay);
|
|
1126
|
+
const manualUV = screenCoordinate.xy.div(screenSize);
|
|
1127
|
+
const noFlipUV = screenUV.clamp(1e-3, 0.999);
|
|
1128
|
+
const flippedUV = vec2$2(screenUV.x, screenUV.y.oneMinus()).clamp(1e-3, 0.999);
|
|
1129
|
+
const useFlipped = screenUV.x.greaterThan(0.5);
|
|
1130
|
+
const splitSampleUV = select(useFlipped, flippedUV, noFlipUV);
|
|
1131
|
+
const splitSample = texture(bufferTex, splitSampleUV);
|
|
1132
|
+
const directSampleNoFlip = texture(bufferTex, screenUV.clamp(1e-3, 0.999));
|
|
1133
|
+
const centerSample = texture(bufferTex, vec2$2(0.5, 0.5));
|
|
1134
|
+
const transmissionRayDbg = getVolumeTransmissionRay(n, v, thickness, ior);
|
|
1135
|
+
const refractedRayExitDbg = position.add(transmissionRayDbg);
|
|
1136
|
+
const ndcPosDbg = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(refractedRayExitDbg, 1)));
|
|
1137
|
+
const safeWDbg = max(ndcPosDbg.w, float(1e-3));
|
|
1138
|
+
const rawCoordsDbg = vec2$2(ndcPosDbg.xy.div(safeWDbg)).toVar();
|
|
1139
|
+
rawCoordsDbg.addAssign(1);
|
|
1140
|
+
rawCoordsDbg.divAssign(2);
|
|
1141
|
+
rawCoordsDbg.assign(vec2$2(rawCoordsDbg.x, rawCoordsDbg.y.oneMinus()));
|
|
1142
|
+
const outOfRange = rawCoordsDbg.x.lessThan(0).or(rawCoordsDbg.x.greaterThan(1)).or(rawCoordsDbg.y.lessThan(0)).or(rawCoordsDbg.y.greaterThan(1));
|
|
1143
|
+
const clipPosDbg = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(position, 1)));
|
|
1144
|
+
const safeWDbg2 = max(clipPosDbg.w, float(1e-3));
|
|
1145
|
+
const projUVDbg = vec2$2(clipPosDbg.xy.div(safeWDbg2)).toVar();
|
|
1146
|
+
projUVDbg.addAssign(1);
|
|
1147
|
+
projUVDbg.divAssign(2);
|
|
1148
|
+
projUVDbg.assign(vec2$2(projUVDbg.x, projUVDbg.y.oneMinus()));
|
|
1149
|
+
projUVDbg.assign(projUVDbg.clamp(1e-3, 0.999));
|
|
1150
|
+
const projectedSample = texture(bufferTex, projUVDbg);
|
|
1151
|
+
const wNorm = clipPosDbg.w.div(10).add(0.5).clamp(0, 1);
|
|
1152
|
+
const isBehind = clipPosDbg.w.lessThan(0);
|
|
1153
|
+
const rawNdcX = clipPosDbg.x.div(safeWDbg2);
|
|
1154
|
+
const rawNdcY = clipPosDbg.y.div(safeWDbg2);
|
|
1155
|
+
const result = vec4(0, 0, 0, 1).toVar();
|
|
1156
|
+
result.assign(
|
|
1157
|
+
select(
|
|
1158
|
+
debugModeUniform.equal(1),
|
|
1159
|
+
vec4(avgTransmission, float(1)),
|
|
1160
|
+
select(
|
|
1161
|
+
debugModeUniform.equal(2),
|
|
1162
|
+
vec4(debugUV.x, debugUV.y, float(0), float(1)),
|
|
1163
|
+
select(
|
|
1164
|
+
debugModeUniform.equal(3),
|
|
1165
|
+
vec4(
|
|
1166
|
+
select(isNeg, debugNdotV.abs(), float(0)),
|
|
1167
|
+
select(isNeg, float(0), debugNdotV),
|
|
1168
|
+
float(0),
|
|
1169
|
+
float(1)
|
|
1170
|
+
),
|
|
1171
|
+
select(
|
|
1172
|
+
debugModeUniform.equal(4),
|
|
1173
|
+
vec4(v.mul(0.5).add(0.5), float(1)),
|
|
1174
|
+
select(
|
|
1175
|
+
debugModeUniform.equal(5),
|
|
1176
|
+
vec4(n.mul(0.5).add(0.5), float(1)),
|
|
1177
|
+
select(
|
|
1178
|
+
debugModeUniform.equal(6),
|
|
1179
|
+
vec4(directSampleFlipped.rgb, float(1)),
|
|
1180
|
+
select(
|
|
1181
|
+
debugModeUniform.equal(7),
|
|
1182
|
+
vec4(rayLen, rayLen, rayLen, float(1)),
|
|
1183
|
+
select(
|
|
1184
|
+
debugModeUniform.equal(8),
|
|
1185
|
+
vec4(screenUV.x, screenUV.y, float(0), float(1)),
|
|
1186
|
+
select(
|
|
1187
|
+
debugModeUniform.equal(9),
|
|
1188
|
+
vec4(screenSize.x.div(2e3), screenSize.y.div(2e3), float(0), float(1)),
|
|
1189
|
+
select(
|
|
1190
|
+
debugModeUniform.equal(10),
|
|
1191
|
+
vec4(manualUV.x, manualUV.y, float(0), float(1)),
|
|
1192
|
+
select(
|
|
1193
|
+
debugModeUniform.equal(11),
|
|
1194
|
+
vec4(splitSample.rgb, float(1)),
|
|
1195
|
+
select(
|
|
1196
|
+
debugModeUniform.equal(12),
|
|
1197
|
+
vec4(directSampleNoFlip.rgb, float(1)),
|
|
1198
|
+
select(
|
|
1199
|
+
debugModeUniform.equal(13),
|
|
1200
|
+
vec4(
|
|
1201
|
+
select(outOfRange, float(1), float(0)),
|
|
1202
|
+
rawCoordsDbg.x.clamp(0, 1),
|
|
1203
|
+
rawCoordsDbg.y.clamp(0, 1),
|
|
1204
|
+
float(1)
|
|
1205
|
+
),
|
|
1206
|
+
select(
|
|
1207
|
+
debugModeUniform.equal(14),
|
|
1208
|
+
vec4(
|
|
1209
|
+
select(isBehind, float(1), float(0)),
|
|
1210
|
+
wNorm,
|
|
1211
|
+
select(isBehind, float(0), float(1)),
|
|
1212
|
+
float(1)
|
|
1213
|
+
),
|
|
1214
|
+
select(
|
|
1215
|
+
debugModeUniform.equal(15),
|
|
1216
|
+
vec4(centerSample.rgb, float(1)),
|
|
1217
|
+
select(
|
|
1218
|
+
debugModeUniform.equal(16),
|
|
1219
|
+
vec4(projectedSample.rgb, float(1)),
|
|
1220
|
+
select(
|
|
1221
|
+
debugModeUniform.equal(17),
|
|
1222
|
+
// Raw NDC as color: map [-1,1] to [0,1]
|
|
1223
|
+
vec4(rawNdcX.add(1).div(2), rawNdcY.add(1).div(2), float(0.5), float(1)),
|
|
1224
|
+
select(
|
|
1225
|
+
debugModeUniform.equal(18),
|
|
1226
|
+
// Solid magenta - if black here, shader isn't running
|
|
1227
|
+
vec4(1, 0, 1, 1),
|
|
1228
|
+
select(
|
|
1229
|
+
debugModeUniform.equal(19),
|
|
1230
|
+
// Tinted FBO sample: mix sample with UV color
|
|
1231
|
+
vec4(
|
|
1232
|
+
directSampleFlipped.r.add(screenUV.x.mul(0.3)),
|
|
1233
|
+
directSampleFlipped.g.add(screenUV.y.mul(0.3)),
|
|
1234
|
+
directSampleFlipped.b,
|
|
1235
|
+
float(1)
|
|
1236
|
+
),
|
|
1237
|
+
vec4(0, 0, 0, 1)
|
|
1238
|
+
// Placeholder for mode 0
|
|
1239
|
+
)
|
|
1240
|
+
)
|
|
1241
|
+
)
|
|
1242
|
+
)
|
|
1243
|
+
)
|
|
1244
|
+
)
|
|
1245
|
+
)
|
|
1246
|
+
)
|
|
1247
|
+
)
|
|
1248
|
+
)
|
|
1249
|
+
)
|
|
1250
|
+
)
|
|
1251
|
+
)
|
|
1252
|
+
)
|
|
1253
|
+
)
|
|
1254
|
+
)
|
|
1255
|
+
)
|
|
1256
|
+
)
|
|
1257
|
+
)
|
|
1258
|
+
);
|
|
1259
|
+
const attenuated = applyVolumeAttenuation(avgTransmission, thickness, attenuationColor, attenuationDistance);
|
|
1260
|
+
const NdotV = n.dot(v).abs().clamp(1e-3, 1);
|
|
1261
|
+
const glassF0 = vec3(0.04);
|
|
1262
|
+
const brdf = EnvironmentBRDF({ dotNV: NdotV, specularColor: glassF0, specularF90: float(1), roughness });
|
|
1263
|
+
const transmissionResult = brdf.oneMinus().mul(attenuated).mul(diffuseColor.rgb);
|
|
1264
|
+
const normalOutput = vec4(transmissionResult, float(1));
|
|
1265
|
+
return select(debugModeUniform.greaterThan(0), result, normalOutput);
|
|
1266
|
+
});
|
|
1267
|
+
context.backdrop = getCustomTransmission();
|
|
1268
|
+
context.backdropAlpha = transmission;
|
|
1269
|
+
diffuseColor.a.mulAssign(mix(1, context.backdrop.a, transmission));
|
|
1270
|
+
}
|
|
667
1271
|
}
|
|
668
|
-
|
|
1272
|
+
}
|
|
669
1273
|
class MeshTransmissionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
670
|
-
|
|
1274
|
+
// Custom uniforms
|
|
671
1275
|
_chromaticAberration;
|
|
672
1276
|
_anisotropicBlur;
|
|
673
1277
|
_time;
|
|
@@ -675,13 +1279,13 @@ class MeshTransmissionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
|
675
1279
|
_distortionScale;
|
|
676
1280
|
_temporalDistortion;
|
|
677
1281
|
_buffer;
|
|
1282
|
+
// Texture node
|
|
678
1283
|
_transmissionValue;
|
|
679
|
-
|
|
680
|
-
_attenuationColor;
|
|
681
|
-
_samples;
|
|
682
|
-
_transmissionSampler;
|
|
1284
|
+
_debugMode;
|
|
683
1285
|
/** Type flag for identification */
|
|
684
1286
|
isMeshTransmissionMaterial = true;
|
|
1287
|
+
_samples;
|
|
1288
|
+
_transmissionSampler;
|
|
685
1289
|
constructor(samples = 6, transmissionSampler = false) {
|
|
686
1290
|
super();
|
|
687
1291
|
this._samples = samples;
|
|
@@ -692,179 +1296,106 @@ class MeshTransmissionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
|
692
1296
|
this._distortion = uniform(0);
|
|
693
1297
|
this._distortionScale = uniform(0.5);
|
|
694
1298
|
this._temporalDistortion = uniform(0);
|
|
695
|
-
this.
|
|
1299
|
+
this._debugMode = uniform(0);
|
|
1300
|
+
const placeholderTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);
|
|
1301
|
+
placeholderTexture.needsUpdate = true;
|
|
1302
|
+
this._buffer = uniformTexture(placeholderTexture);
|
|
696
1303
|
this._transmissionValue = uniform(1);
|
|
697
|
-
this.
|
|
698
|
-
this._attenuationColor = uniform(new THREE.Color("white"));
|
|
699
|
-
this.transmission = transmissionSampler ? 1 : 0;
|
|
1304
|
+
this.transmission = transmissionSampler ? 1 : 1e-3;
|
|
700
1305
|
this.roughness = 0;
|
|
701
1306
|
this.thickness = 0;
|
|
702
|
-
this.
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
Loop(samples, ({ i }) => {
|
|
743
|
-
const fi = float(i);
|
|
744
|
-
const randX = rand({ seed: runningSeed, fragCoord }).sub(0.5);
|
|
745
|
-
runningSeed.addAssign(1);
|
|
746
|
-
const randY = rand({ seed: runningSeed, fragCoord }).sub(0.5);
|
|
747
|
-
runningSeed.addAssign(1);
|
|
748
|
-
const randZ = rand({ seed: runningSeed, fragCoord }).sub(0.5);
|
|
749
|
-
runningSeed.addAssign(1);
|
|
750
|
-
const randW = rand({ seed: runningSeed, fragCoord });
|
|
751
|
-
runningSeed.addAssign(1);
|
|
752
|
-
const randomDir = normalize(vec3(randX, randY, randZ)).mul(pow(randW, 0.33));
|
|
753
|
-
const sampleNorm = normalize(
|
|
754
|
-
n.add(roughnessFactor.mul(roughnessFactor).mul(2).mul(randomDir)).add(distortionNormal)
|
|
755
|
-
);
|
|
756
|
-
const refractionDir = refract(v.negate(), sampleNorm, float(1).div(iorVal));
|
|
757
|
-
const sampleThickness = thicknessVal.add(thicknessSmear.mul(fi.add(randomCoords)).div(float(samples)));
|
|
758
|
-
const refractedExit = pos.add(refractionDir.mul(sampleThickness));
|
|
759
|
-
const clipPos = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(refractedExit, 1)));
|
|
760
|
-
const ndcPos = clipPos.xyz.div(clipPos.w);
|
|
761
|
-
const refractionUV = ndcPos.xy.mul(0.5).add(0.5);
|
|
762
|
-
const sampledColor = texture(bufferTex, refractionUV);
|
|
763
|
-
const transmissionR = sampledColor.r;
|
|
764
|
-
const chromaticOffsetG = chromaticAberrationUniform.mul(fi.add(randomCoords)).div(float(samples));
|
|
765
|
-
const iorG = iorVal.mul(float(1).add(chromaticOffsetG));
|
|
766
|
-
const refractionDirG = refract(v.negate(), sampleNorm, float(1).div(iorG));
|
|
767
|
-
const refractedExitG = pos.add(refractionDirG.mul(sampleThickness));
|
|
768
|
-
const clipPosG = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(refractedExitG, 1)));
|
|
769
|
-
const ndcPosG = clipPosG.xyz.div(clipPosG.w);
|
|
770
|
-
const refractionUVG = ndcPosG.xy.mul(0.5).add(0.5);
|
|
771
|
-
const transmissionG = texture(bufferTex, refractionUVG).g;
|
|
772
|
-
const chromaticOffsetB = chromaticAberrationUniform.mul(2).mul(fi.add(randomCoords)).div(float(samples));
|
|
773
|
-
const iorB = iorVal.mul(float(1).add(chromaticOffsetB));
|
|
774
|
-
const refractionDirB = refract(v.negate(), sampleNorm, float(1).div(iorB));
|
|
775
|
-
const refractedExitB = pos.add(refractionDirB.mul(sampleThickness));
|
|
776
|
-
const clipPosB = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(refractedExitB, 1)));
|
|
777
|
-
const ndcPosB = clipPosB.xyz.div(clipPosB.w);
|
|
778
|
-
const refractionUVB = ndcPosB.xy.mul(0.5).add(0.5);
|
|
779
|
-
const transmissionB = texture(bufferTex, refractionUVB).b;
|
|
780
|
-
transmission.x.addAssign(transmissionR);
|
|
781
|
-
transmission.y.addAssign(transmissionG);
|
|
782
|
-
transmission.z.addAssign(transmissionB);
|
|
783
|
-
});
|
|
784
|
-
const avgTransmission = transmission.div(float(samples));
|
|
785
|
-
const transmissionRayLength = thicknessVal;
|
|
786
|
-
const attenuatedTransmission = applyVolumeAttenuation({
|
|
787
|
-
radiance: avgTransmission,
|
|
788
|
-
transmissionDistance: transmissionRayLength,
|
|
789
|
-
attenuationColor: attenuationColorUniform,
|
|
790
|
-
attenuationDistance: attenuationDistanceUniform
|
|
791
|
-
});
|
|
792
|
-
const baseDiffuse = diffuseColor.rgb;
|
|
793
|
-
const finalColor = mix(baseDiffuse, attenuatedTransmission, transmissionUniform);
|
|
794
|
-
return vec4(finalColor, diffuseColor.a);
|
|
795
|
-
})();
|
|
1307
|
+
this.ior = 1.5;
|
|
1308
|
+
this.transparent = true;
|
|
1309
|
+
}
|
|
1310
|
+
setupLightingModel() {
|
|
1311
|
+
if (this._transmissionSampler) {
|
|
1312
|
+
return super.setupLightingModel();
|
|
1313
|
+
}
|
|
1314
|
+
return new TransmissionLightingModel(
|
|
1315
|
+
{
|
|
1316
|
+
clearcoat: this.useClearcoat,
|
|
1317
|
+
sheen: this.useSheen,
|
|
1318
|
+
iridescence: this.useIridescence,
|
|
1319
|
+
anisotropy: this.useAnisotropy,
|
|
1320
|
+
dispersion: this.useDispersion
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
bufferTex: this._buffer,
|
|
1324
|
+
chromaticAberration: this._chromaticAberration,
|
|
1325
|
+
anisotropicBlur: this._anisotropicBlur,
|
|
1326
|
+
timeUniform: this._time,
|
|
1327
|
+
distortion: this._distortion,
|
|
1328
|
+
distortionScale: this._distortionScale,
|
|
1329
|
+
temporalDistortion: this._temporalDistortion,
|
|
1330
|
+
samples: this._samples,
|
|
1331
|
+
debugMode: this._debugMode
|
|
1332
|
+
}
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
//* Property Accessors ==============================
|
|
1336
|
+
get time() {
|
|
1337
|
+
return this._time.value;
|
|
1338
|
+
}
|
|
1339
|
+
set time(v) {
|
|
1340
|
+
this._time.value = v;
|
|
1341
|
+
}
|
|
1342
|
+
get buffer() {
|
|
1343
|
+
return this._buffer.value;
|
|
1344
|
+
}
|
|
1345
|
+
set buffer(v) {
|
|
1346
|
+
this._buffer.value = v;
|
|
796
1347
|
}
|
|
797
|
-
//* Uniform Accessors ==============================
|
|
798
|
-
/** Chromatic aberration strength, default: 0.05 */
|
|
799
1348
|
get chromaticAberration() {
|
|
800
1349
|
return this._chromaticAberration.value;
|
|
801
1350
|
}
|
|
802
1351
|
set chromaticAberration(v) {
|
|
803
1352
|
this._chromaticAberration.value = v;
|
|
804
1353
|
}
|
|
805
|
-
/** Anisotropic blur amount, default: 0.1 */
|
|
806
1354
|
get anisotropicBlur() {
|
|
807
1355
|
return this._anisotropicBlur.value;
|
|
808
1356
|
}
|
|
809
1357
|
set anisotropicBlur(v) {
|
|
810
1358
|
this._anisotropicBlur.value = v;
|
|
811
1359
|
}
|
|
812
|
-
/** Animation time (set from useFrame), default: 0 */
|
|
813
|
-
get time() {
|
|
814
|
-
return this._time.value;
|
|
815
|
-
}
|
|
816
|
-
set time(v) {
|
|
817
|
-
this._time.value = v;
|
|
818
|
-
}
|
|
819
|
-
/** Noise distortion amount, default: 0 */
|
|
820
1360
|
get distortion() {
|
|
821
1361
|
return this._distortion.value;
|
|
822
1362
|
}
|
|
823
1363
|
set distortion(v) {
|
|
824
1364
|
this._distortion.value = v;
|
|
825
1365
|
}
|
|
826
|
-
/** Distortion noise scale, default: 0.5 */
|
|
827
1366
|
get distortionScale() {
|
|
828
1367
|
return this._distortionScale.value;
|
|
829
1368
|
}
|
|
830
1369
|
set distortionScale(v) {
|
|
831
1370
|
this._distortionScale.value = v;
|
|
832
1371
|
}
|
|
833
|
-
/** Temporal distortion speed, default: 0 */
|
|
834
1372
|
get temporalDistortion() {
|
|
835
1373
|
return this._temporalDistortion.value;
|
|
836
1374
|
}
|
|
837
1375
|
set temporalDistortion(v) {
|
|
838
1376
|
this._temporalDistortion.value = v;
|
|
839
1377
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
return this._buffer.value;
|
|
1378
|
+
get debugMode() {
|
|
1379
|
+
return this._debugMode.value;
|
|
843
1380
|
}
|
|
844
|
-
set
|
|
845
|
-
this.
|
|
1381
|
+
set debugMode(v) {
|
|
1382
|
+
this._debugMode.value = v;
|
|
846
1383
|
}
|
|
847
|
-
|
|
1384
|
+
// Expose _transmission for legacy compatibility
|
|
1385
|
+
// This stores the user's intended transmission value, separate from the base class's transmission
|
|
1386
|
+
// which is kept at 0.001 to enable the transmission code path without triggering Three's internal rendering
|
|
848
1387
|
get _transmission() {
|
|
1388
|
+
if (!this._transmissionValue) {
|
|
1389
|
+
this._transmissionValue = uniform(1);
|
|
1390
|
+
}
|
|
849
1391
|
return this._transmissionValue.value;
|
|
850
1392
|
}
|
|
851
1393
|
set _transmission(v) {
|
|
1394
|
+
if (!this._transmissionValue) {
|
|
1395
|
+
this._transmissionValue = uniform(1);
|
|
1396
|
+
}
|
|
852
1397
|
this._transmissionValue.value = v;
|
|
853
1398
|
}
|
|
854
|
-
/** Attenuation distance for Beer's law absorption */
|
|
855
|
-
get attenuationDistance() {
|
|
856
|
-
return this._attenuationDistance.value;
|
|
857
|
-
}
|
|
858
|
-
set attenuationDistance(v) {
|
|
859
|
-
this._attenuationDistance.value = v;
|
|
860
|
-
}
|
|
861
|
-
/** Attenuation color for Beer's law absorption */
|
|
862
|
-
get attenuationColor() {
|
|
863
|
-
return this._attenuationColor.value;
|
|
864
|
-
}
|
|
865
|
-
set attenuationColor(v) {
|
|
866
|
-
this._attenuationColor.value = v;
|
|
867
|
-
}
|
|
868
1399
|
}
|
|
869
1400
|
const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
870
1401
|
({
|
|
@@ -872,8 +1403,8 @@ const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
872
1403
|
transmissionSampler = false,
|
|
873
1404
|
backside = false,
|
|
874
1405
|
side = THREE.FrontSide,
|
|
875
|
-
transmission = 1,
|
|
876
|
-
thickness = 0,
|
|
1406
|
+
transmission: transmission2 = 1,
|
|
1407
|
+
thickness: thickness2 = 0,
|
|
877
1408
|
backsideThickness = 0,
|
|
878
1409
|
backsideEnvMapIntensity = 1,
|
|
879
1410
|
samples = 10,
|
|
@@ -882,48 +1413,111 @@ const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
882
1413
|
background,
|
|
883
1414
|
anisotropy,
|
|
884
1415
|
anisotropicBlur,
|
|
1416
|
+
debugMode = 0,
|
|
885
1417
|
...props
|
|
886
1418
|
}, fref) => {
|
|
887
1419
|
extend({ MeshTransmissionMaterial: MeshTransmissionMaterialImpl });
|
|
888
1420
|
const ref = React.useRef(null);
|
|
889
|
-
const
|
|
890
|
-
const
|
|
891
|
-
const
|
|
1421
|
+
const backsideMaterialRef = React.useRef(null);
|
|
1422
|
+
const { size, viewport } = useThree();
|
|
1423
|
+
const screenWidth = size.width * viewport.dpr;
|
|
1424
|
+
const screenHeight = size.height * viewport.dpr;
|
|
1425
|
+
const fboWidth = resolution || screenWidth;
|
|
1426
|
+
const fboHeight = resolution ? Math.round(resolution / screenWidth * screenHeight) : screenHeight;
|
|
1427
|
+
const fboBack = useFBO(
|
|
1428
|
+
backsideResolution || fboWidth,
|
|
1429
|
+
backsideResolution ? Math.round(backsideResolution / screenWidth * screenHeight) : fboHeight
|
|
1430
|
+
);
|
|
1431
|
+
const fboMain = useFBO(fboWidth, fboHeight);
|
|
1432
|
+
React.useEffect(() => {
|
|
1433
|
+
if (backside && ref.current && !backsideMaterialRef.current) {
|
|
1434
|
+
backsideMaterialRef.current = new MeshTransmissionMaterialImpl(samples, transmissionSampler);
|
|
1435
|
+
backsideMaterialRef.current.buffer = fboBack.texture;
|
|
1436
|
+
}
|
|
1437
|
+
return () => {
|
|
1438
|
+
if (backsideMaterialRef.current) {
|
|
1439
|
+
backsideMaterialRef.current.dispose();
|
|
1440
|
+
backsideMaterialRef.current = null;
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
}, [backside, samples, transmissionSampler]);
|
|
1444
|
+
React.useEffect(() => {
|
|
1445
|
+
if (backsideMaterialRef.current) {
|
|
1446
|
+
backsideMaterialRef.current.buffer = fboBack.texture;
|
|
1447
|
+
}
|
|
1448
|
+
}, [fboBack.texture]);
|
|
892
1449
|
let oldBg;
|
|
893
1450
|
let oldEnvMapIntensity;
|
|
894
1451
|
let oldTone;
|
|
895
1452
|
let parent;
|
|
896
1453
|
useFrame((state) => {
|
|
897
1454
|
ref.current.time = state.elapsed;
|
|
1455
|
+
const renderer = state.renderer;
|
|
1456
|
+
if (backsideMaterialRef.current) {
|
|
1457
|
+
backsideMaterialRef.current.time = state.elapsed;
|
|
1458
|
+
}
|
|
898
1459
|
if (ref.current.buffer === fboMain.texture && !transmissionSampler) {
|
|
899
1460
|
parent = ref.current.__r3f?.parent?.object;
|
|
900
|
-
if (parent)
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
1461
|
+
if (!parent) return;
|
|
1462
|
+
oldTone = renderer.toneMapping;
|
|
1463
|
+
oldBg = state.scene.background;
|
|
1464
|
+
oldEnvMapIntensity = ref.current.envMapIntensity;
|
|
1465
|
+
renderer.toneMapping = THREE.NoToneMapping;
|
|
1466
|
+
if (background)
|
|
1467
|
+
state.scene.background = background;
|
|
1468
|
+
parent.material = DiscardMaterial;
|
|
1469
|
+
const camera = state.camera;
|
|
1470
|
+
const isOrtho = camera.isOrthographicCamera;
|
|
1471
|
+
let oldLeft, oldRight, oldTop, oldBottom;
|
|
1472
|
+
if (isOrtho) {
|
|
1473
|
+
oldLeft = camera.left;
|
|
1474
|
+
oldRight = camera.right;
|
|
1475
|
+
oldTop = camera.top;
|
|
1476
|
+
oldBottom = camera.bottom;
|
|
1477
|
+
const fboAspect = fboWidth / fboHeight;
|
|
1478
|
+
const screenAspect = screenWidth / screenHeight;
|
|
1479
|
+
if (Math.abs(fboAspect - screenAspect) > 1e-3) {
|
|
1480
|
+
const viewHeight = oldTop - oldBottom;
|
|
1481
|
+
const newHalfWidth = viewHeight * fboAspect / 2;
|
|
1482
|
+
const centerX = (oldLeft + oldRight) / 2;
|
|
1483
|
+
camera.left = centerX - newHalfWidth;
|
|
1484
|
+
camera.right = centerX + newHalfWidth;
|
|
1485
|
+
camera.updateProjectionMatrix();
|
|
915
1486
|
}
|
|
916
|
-
|
|
917
|
-
|
|
1487
|
+
}
|
|
1488
|
+
if (backside && backsideMaterialRef.current) {
|
|
1489
|
+
renderer.setRenderTarget(fboBack);
|
|
1490
|
+
renderer.clear();
|
|
1491
|
+
state.renderer.render(state.scene, state.camera);
|
|
1492
|
+
parent.material = backsideMaterialRef.current;
|
|
1493
|
+
backsideMaterialRef.current.thickness = backsideThickness;
|
|
1494
|
+
backsideMaterialRef.current.side = THREE.BackSide;
|
|
1495
|
+
backsideMaterialRef.current.envMapIntensity = backsideEnvMapIntensity;
|
|
1496
|
+
renderer.setRenderTarget(fboMain);
|
|
1497
|
+
renderer.clear();
|
|
1498
|
+
state.renderer.render(state.scene, state.camera);
|
|
918
1499
|
parent.material = ref.current;
|
|
919
|
-
ref.current.thickness =
|
|
1500
|
+
ref.current.thickness = thickness2;
|
|
920
1501
|
ref.current.side = side;
|
|
921
|
-
ref.current.buffer = fboMain.texture;
|
|
922
1502
|
ref.current.envMapIntensity = oldEnvMapIntensity;
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1503
|
+
} else {
|
|
1504
|
+
renderer.setRenderTarget(fboMain);
|
|
1505
|
+
renderer.clear();
|
|
1506
|
+
state.renderer.render(state.scene, state.camera);
|
|
1507
|
+
parent.material = ref.current;
|
|
1508
|
+
ref.current.thickness = thickness2;
|
|
1509
|
+
ref.current.side = side;
|
|
926
1510
|
}
|
|
1511
|
+
if (isOrtho && Math.abs(fboWidth / fboHeight - screenWidth / screenHeight) > 1e-3) {
|
|
1512
|
+
camera.left = oldLeft;
|
|
1513
|
+
camera.right = oldRight;
|
|
1514
|
+
camera.top = oldTop;
|
|
1515
|
+
camera.bottom = oldBottom;
|
|
1516
|
+
camera.updateProjectionMatrix();
|
|
1517
|
+
}
|
|
1518
|
+
state.scene.background = oldBg;
|
|
1519
|
+
renderer.setRenderTarget(null);
|
|
1520
|
+
renderer.toneMapping = oldTone;
|
|
927
1521
|
}
|
|
928
1522
|
});
|
|
929
1523
|
React.useImperativeHandle(fref, () => ref.current, []);
|
|
@@ -934,11 +1528,11 @@ const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
934
1528
|
ref,
|
|
935
1529
|
...props,
|
|
936
1530
|
buffer: buffer || fboMain.texture,
|
|
937
|
-
_transmission:
|
|
938
|
-
anisotropicBlur: anisotropicBlur ?? anisotropy
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
1531
|
+
_transmission: transmission2,
|
|
1532
|
+
anisotropicBlur: anisotropicBlur ?? anisotropy,
|
|
1533
|
+
thickness: thickness2,
|
|
1534
|
+
side,
|
|
1535
|
+
debugMode
|
|
942
1536
|
}
|
|
943
1537
|
);
|
|
944
1538
|
}
|
|
@@ -1189,25 +1783,16 @@ const MeshReflectorMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
1189
1783
|
}
|
|
1190
1784
|
);
|
|
1191
1785
|
|
|
1192
|
-
const fresnelEffect = /* @__PURE__ */ Fn((
|
|
1193
|
-
const [viewDir, normal, power] = inputs;
|
|
1786
|
+
const fresnelEffect = /* @__PURE__ */ Fn(([viewDir, normal, power]) => {
|
|
1194
1787
|
const NdotV = float(1).add(dot(viewDir, normal));
|
|
1195
1788
|
return pow(NdotV, power);
|
|
1196
1789
|
});
|
|
1197
|
-
const
|
|
1198
|
-
const [direction] = inputs;
|
|
1199
|
-
const dir = normalize(direction);
|
|
1200
|
-
const u = float(0.5).add(dir.z.atan2(dir.x).div(float(2).mul(Math.PI)));
|
|
1201
|
-
const v = float(0.5).sub(dir.y.asin().div(Math.PI));
|
|
1202
|
-
return vec2$2(u, v);
|
|
1203
|
-
});
|
|
1204
|
-
const approximateRefraction = /* @__PURE__ */ Fn((inputs) => {
|
|
1205
|
-
const [rayDir, normal, iorValue, bounceCount, thickness] = inputs;
|
|
1790
|
+
const approximateRefraction = /* @__PURE__ */ Fn(([rayDir, normal, iorValue, bounceCount]) => {
|
|
1206
1791
|
const entryDir = refract(rayDir, normal, float(1).div(iorValue)).toVar();
|
|
1207
1792
|
const entryValid = length(entryDir).greaterThan(0);
|
|
1208
1793
|
const exitNormal = normal.negate().toVar();
|
|
1209
1794
|
const currentDir = entryDir.toVar();
|
|
1210
|
-
Loop(int(bounceCount), ({ i }) => {
|
|
1795
|
+
Loop({ start: 0, end: int(bounceCount), type: "int" }, ({ i }) => {
|
|
1211
1796
|
const fi = float(i).add(1);
|
|
1212
1797
|
const exitDir = refract(currentDir, exitNormal, iorValue);
|
|
1213
1798
|
const canExit = length(exitDir).greaterThan(0);
|
|
@@ -1226,8 +1811,6 @@ class MeshRefractionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
|
1226
1811
|
_aberrationStrength;
|
|
1227
1812
|
_color;
|
|
1228
1813
|
_opacityValue;
|
|
1229
|
-
_resolution;
|
|
1230
|
-
_thickness;
|
|
1231
1814
|
_fastChroma;
|
|
1232
1815
|
/** Type flag for identification */
|
|
1233
1816
|
isMeshRefractionMaterial = true;
|
|
@@ -1241,8 +1824,6 @@ class MeshRefractionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
|
1241
1824
|
this._aberrationStrength = uniform(0.01);
|
|
1242
1825
|
this._color = uniform(new THREE.Color("white"));
|
|
1243
1826
|
this._opacityValue = uniform(1);
|
|
1244
|
-
this._resolution = uniform(new THREE.Vector2(1, 1));
|
|
1245
|
-
this._thickness = uniform(1);
|
|
1246
1827
|
this.transparent = true;
|
|
1247
1828
|
this.side = THREE.FrontSide;
|
|
1248
1829
|
this._buildRefractionShader();
|
|
@@ -1255,20 +1836,13 @@ class MeshRefractionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
|
1255
1836
|
const aberrationUniform = this._aberrationStrength;
|
|
1256
1837
|
const colorUniform = this._color;
|
|
1257
1838
|
const opacityUniform = this._opacityValue;
|
|
1258
|
-
const thicknessUniform = this._thickness;
|
|
1259
1839
|
const fastChroma = this._fastChroma;
|
|
1260
1840
|
this.outputNode = Fn(() => {
|
|
1261
1841
|
const worldPos = positionWorld;
|
|
1262
1842
|
const worldNormal = normalize(normalWorld);
|
|
1263
1843
|
const viewDir = normalize(worldPos.sub(cameraPosition));
|
|
1264
1844
|
const baseColor = colorUniform.toVar();
|
|
1265
|
-
const refractedDirG = approximateRefraction(
|
|
1266
|
-
viewDir,
|
|
1267
|
-
worldNormal,
|
|
1268
|
-
max(iorUniform, 1),
|
|
1269
|
-
bouncesUniform,
|
|
1270
|
-
thicknessUniform
|
|
1271
|
-
);
|
|
1845
|
+
const refractedDirG = approximateRefraction(viewDir, worldNormal, max(iorUniform, 1), bouncesUniform);
|
|
1272
1846
|
const aberration = aberrationUniform;
|
|
1273
1847
|
const refractedDirR = vec3(0, 0, 0).toVar();
|
|
1274
1848
|
const refractedDirB = vec3(0, 0, 0).toVar();
|
|
@@ -1282,8 +1856,7 @@ class MeshRefractionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
|
1282
1856
|
viewDir,
|
|
1283
1857
|
worldNormal,
|
|
1284
1858
|
max(iorUniform.mul(float(1).sub(aberration)), 1),
|
|
1285
|
-
bouncesUniform
|
|
1286
|
-
thicknessUniform
|
|
1859
|
+
bouncesUniform
|
|
1287
1860
|
)
|
|
1288
1861
|
);
|
|
1289
1862
|
refractedDirB.assign(
|
|
@@ -1291,14 +1864,13 @@ class MeshRefractionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
|
1291
1864
|
viewDir,
|
|
1292
1865
|
worldNormal,
|
|
1293
1866
|
max(iorUniform.mul(float(1).add(aberration)), 1),
|
|
1294
|
-
bouncesUniform
|
|
1295
|
-
thicknessUniform
|
|
1867
|
+
bouncesUniform
|
|
1296
1868
|
)
|
|
1297
1869
|
);
|
|
1298
1870
|
}
|
|
1299
|
-
const uvR =
|
|
1300
|
-
const uvG =
|
|
1301
|
-
const uvB =
|
|
1871
|
+
const uvR = equirectUV(refractedDirR);
|
|
1872
|
+
const uvG = equirectUV(refractedDirG);
|
|
1873
|
+
const uvB = equirectUV(refractedDirB);
|
|
1302
1874
|
const envColorR = texture(envMapTex, uvR).r;
|
|
1303
1875
|
const envColorG = texture(envMapTex, uvG).g;
|
|
1304
1876
|
const envColorB = texture(envMapTex, uvB).b;
|
|
@@ -1362,20 +1934,6 @@ class MeshRefractionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
|
1362
1934
|
set opacity(v) {
|
|
1363
1935
|
this._opacityValue.value = v;
|
|
1364
1936
|
}
|
|
1365
|
-
/** Resolution for screen-space calculations */
|
|
1366
|
-
get resolution() {
|
|
1367
|
-
return this._resolution.value;
|
|
1368
|
-
}
|
|
1369
|
-
set resolution(v) {
|
|
1370
|
-
this._resolution.value = v;
|
|
1371
|
-
}
|
|
1372
|
-
/** Approximate thickness for refraction calculations */
|
|
1373
|
-
get thickness() {
|
|
1374
|
-
return this._thickness.value;
|
|
1375
|
-
}
|
|
1376
|
-
set thickness(v) {
|
|
1377
|
-
this._thickness.value = v;
|
|
1378
|
-
}
|
|
1379
1937
|
}
|
|
1380
1938
|
const MeshRefractionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
1381
1939
|
({
|
|
@@ -1391,12 +1949,6 @@ const MeshRefractionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
1391
1949
|
}, fref) => {
|
|
1392
1950
|
extend({ MeshRefractionMaterial: MeshRefractionMaterialImpl });
|
|
1393
1951
|
const ref = React.useRef(null);
|
|
1394
|
-
const size = useThree((state) => state.size);
|
|
1395
|
-
React.useEffect(() => {
|
|
1396
|
-
if (ref.current) {
|
|
1397
|
-
ref.current.resolution = new THREE.Vector2(size.width, size.height);
|
|
1398
|
-
}
|
|
1399
|
-
}, [size]);
|
|
1400
1952
|
React.useEffect(() => {
|
|
1401
1953
|
if (ref.current && envMap) {
|
|
1402
1954
|
ref.current.envMap = envMap;
|
|
@@ -1648,10 +2200,10 @@ class PortalMaterialImpl extends MeshBasicNodeMaterial {
|
|
|
1648
2200
|
this._blur.value = v;
|
|
1649
2201
|
}
|
|
1650
2202
|
get map() {
|
|
1651
|
-
return this._map
|
|
2203
|
+
return this._map?.value;
|
|
1652
2204
|
}
|
|
1653
2205
|
set map(v) {
|
|
1654
|
-
this._map.value = v ?? new THREE.Texture();
|
|
2206
|
+
if (this._map) this._map.value = v ?? new THREE.Texture();
|
|
1655
2207
|
}
|
|
1656
2208
|
get sdf() {
|
|
1657
2209
|
return this._sdf.value;
|
|
@@ -2431,11 +2983,11 @@ const RenderCubeTexture = /* @__PURE__ */ React.forwardRef(
|
|
|
2431
2983
|
depthBuffer,
|
|
2432
2984
|
generateMipmaps
|
|
2433
2985
|
};
|
|
2434
|
-
const fboA2 = new
|
|
2986
|
+
const fboA2 = new CubeRenderTarget(fboSize, settings);
|
|
2435
2987
|
fboA2.texture.isRenderTargetTexture = !flip;
|
|
2436
2988
|
fboA2.texture.flipY = true;
|
|
2437
2989
|
fboA2.texture.type = THREE.HalfFloatType;
|
|
2438
|
-
const fboB2 = new
|
|
2990
|
+
const fboB2 = new CubeRenderTarget(fboSize, settings);
|
|
2439
2991
|
fboB2.texture.isRenderTargetTexture = !flip;
|
|
2440
2992
|
fboB2.texture.flipY = true;
|
|
2441
2993
|
fboB2.texture.type = THREE.HalfFloatType;
|
|
@@ -2885,7 +3437,7 @@ function useCubeCamera({ resolution = 256, near = 0.1, far = 1e3, envMap, fog }
|
|
|
2885
3437
|
const gl = useThree(({ gl: gl2 }) => gl2);
|
|
2886
3438
|
const scene = useThree(({ scene: scene2 }) => scene2);
|
|
2887
3439
|
const fbo = useMemo(() => {
|
|
2888
|
-
const fbo2 = new
|
|
3440
|
+
const fbo2 = new CubeRenderTarget(resolution);
|
|
2889
3441
|
fbo2.texture.type = HalfFloatType;
|
|
2890
3442
|
return fbo2;
|
|
2891
3443
|
}, [resolution]);
|
|
@@ -3268,9 +3820,8 @@ function PresentationControls({
|
|
|
3268
3820
|
azimuth = [-Infinity, Infinity],
|
|
3269
3821
|
damping = 0.25
|
|
3270
3822
|
}) {
|
|
3271
|
-
const events = useThree(
|
|
3272
|
-
const
|
|
3273
|
-
const explDomElement = domElement || events.connected || gl.domElement;
|
|
3823
|
+
const { events, renderer, invalidate } = useThree();
|
|
3824
|
+
const explDomElement = domElement || events.connected || renderer.domElement;
|
|
3274
3825
|
const { size } = useThree();
|
|
3275
3826
|
const rPolar = React.useMemo(
|
|
3276
3827
|
() => [rotation[0] + polar[0], rotation[0] + polar[1]],
|
|
@@ -3287,18 +3838,20 @@ function PresentationControls({
|
|
|
3287
3838
|
React.useEffect(() => {
|
|
3288
3839
|
if (global && cursor && enabled) {
|
|
3289
3840
|
explDomElement.style.cursor = "grab";
|
|
3290
|
-
|
|
3841
|
+
renderer.domElement.style.cursor = "";
|
|
3291
3842
|
return () => {
|
|
3292
3843
|
explDomElement.style.cursor = "default";
|
|
3293
|
-
|
|
3844
|
+
renderer.domElement.style.cursor = "default";
|
|
3294
3845
|
};
|
|
3295
3846
|
}
|
|
3296
3847
|
}, [global, cursor, explDomElement, enabled]);
|
|
3297
3848
|
const [animation] = React.useState({ scale: 1, rotation: rInitial, damping });
|
|
3298
3849
|
const ref = React.useRef(null);
|
|
3299
3850
|
useFrame((state, delta) => {
|
|
3300
|
-
|
|
3301
|
-
easing.
|
|
3851
|
+
let changed = false;
|
|
3852
|
+
changed ||= easing.damp3(ref.current.scale, animation.scale, animation.damping, delta);
|
|
3853
|
+
changed ||= easing.dampE(ref.current.rotation, animation.rotation, animation.damping, delta);
|
|
3854
|
+
if (changed) state.invalidate();
|
|
3302
3855
|
});
|
|
3303
3856
|
const bind = useGesture(
|
|
3304
3857
|
{
|
|
@@ -3306,6 +3859,7 @@ function PresentationControls({
|
|
|
3306
3859
|
if (cursor && !global && enabled) explDomElement.style.cursor = last ? "auto" : "grab";
|
|
3307
3860
|
},
|
|
3308
3861
|
onDrag: ({ down, delta: [x, y], memo: [oldY, oldX] = animation.rotation || rInitial }) => {
|
|
3862
|
+
invalidate();
|
|
3309
3863
|
if (!enabled) return [y, x];
|
|
3310
3864
|
if (cursor) explDomElement.style.cursor = down ? "grabbing" : "grab";
|
|
3311
3865
|
x = MathUtils.clamp(oldX + x / size.width * Math.PI * speed, ...rAzimuth);
|
|
@@ -3314,9 +3868,12 @@ function PresentationControls({
|
|
|
3314
3868
|
animation.rotation = snap && !down ? rInitial : [y, x, 0];
|
|
3315
3869
|
animation.damping = snap && !down && typeof snap !== "boolean" ? snap : damping;
|
|
3316
3870
|
return [y, x];
|
|
3871
|
+
},
|
|
3872
|
+
onDragEnd: () => {
|
|
3873
|
+
invalidate();
|
|
3317
3874
|
}
|
|
3318
3875
|
},
|
|
3319
|
-
{ target: global ? explDomElement : void 0 }
|
|
3876
|
+
{ target: global ? explDomElement : void 0, enabled }
|
|
3320
3877
|
);
|
|
3321
3878
|
return /* @__PURE__ */ React.createElement("group", { ref, ...bind?.() }, children);
|
|
3322
3879
|
}
|
|
@@ -3325,6 +3882,10 @@ function roundToPixelRatio(value) {
|
|
|
3325
3882
|
const ratio = window.devicePixelRatio || 1;
|
|
3326
3883
|
return Math.round(value * ratio) / ratio;
|
|
3327
3884
|
}
|
|
3885
|
+
function getMaxAnisotropy(renderer) {
|
|
3886
|
+
const r = renderer;
|
|
3887
|
+
return r?.getMaxAnisotropy?.() ?? r?.capabilities?.getMaxAnisotropy?.() ?? 1;
|
|
3888
|
+
}
|
|
3328
3889
|
|
|
3329
3890
|
const context$7 = /* @__PURE__ */ React.createContext(null);
|
|
3330
3891
|
const rootCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -3690,10 +4251,10 @@ const CloudInstance = /* @__PURE__ */ React.forwardRef(
|
|
|
3690
4251
|
return /* @__PURE__ */ React.createElement("group", { ref, ...props });
|
|
3691
4252
|
}
|
|
3692
4253
|
);
|
|
3693
|
-
const Cloud = /* @__PURE__ */ React.forwardRef((props, fref) => {
|
|
4254
|
+
const Cloud = /* @__PURE__ */ React.forwardRef(({ materialFactory, ...props }, fref) => {
|
|
3694
4255
|
const parent = React.useContext(context$6);
|
|
3695
4256
|
if (parent) return /* @__PURE__ */ React.createElement(CloudInstance, { ref: fref, ...props });
|
|
3696
|
-
return /* @__PURE__ */ React.createElement(Clouds,
|
|
4257
|
+
return /* @__PURE__ */ React.createElement(Clouds, { materialFactory }, /* @__PURE__ */ React.createElement(CloudInstance, { ref: fref, ...props }));
|
|
3697
4258
|
});
|
|
3698
4259
|
|
|
3699
4260
|
const CatmullRomLine = /* @__PURE__ */ React.forwardRef(function CatmullRomLine2({
|
|
@@ -4215,7 +4776,7 @@ const Text3D = /* @__PURE__ */ React.forwardRef(
|
|
|
4215
4776
|
return {
|
|
4216
4777
|
font,
|
|
4217
4778
|
size,
|
|
4218
|
-
height,
|
|
4779
|
+
depth: height,
|
|
4219
4780
|
bevelThickness,
|
|
4220
4781
|
bevelSize,
|
|
4221
4782
|
bevelEnabled,
|
|
@@ -4398,7 +4959,7 @@ const FaceMaterial = ({
|
|
|
4398
4959
|
"meshBasicMaterial",
|
|
4399
4960
|
{
|
|
4400
4961
|
map: texture,
|
|
4401
|
-
"map-anisotropy":
|
|
4962
|
+
"map-anisotropy": getMaxAnisotropy(renderer),
|
|
4402
4963
|
attach: `material-${index}`,
|
|
4403
4964
|
color: hover ? hoverColor : "white",
|
|
4404
4965
|
transparent: true,
|
|
@@ -4509,7 +5070,7 @@ function AxisHead({
|
|
|
4509
5070
|
"spriteMaterial",
|
|
4510
5071
|
{
|
|
4511
5072
|
map: texture,
|
|
4512
|
-
"map-anisotropy":
|
|
5073
|
+
"map-anisotropy": getMaxAnisotropy(renderer),
|
|
4513
5074
|
alphaTest: 0.3,
|
|
4514
5075
|
opacity: label ? 1 : 0.75,
|
|
4515
5076
|
toneMapped: false
|
|
@@ -4654,6 +5215,7 @@ const Html = /* @__PURE__ */ React.forwardRef(
|
|
|
4654
5215
|
}, ref) => {
|
|
4655
5216
|
const { gl, camera, scene, size, raycaster, events, viewport } = useThree();
|
|
4656
5217
|
const forceEven = useThree((state) => state.internal.forceEven);
|
|
5218
|
+
const { frustum } = useThree();
|
|
4657
5219
|
const [el] = React.useState(() => document.createElement(as));
|
|
4658
5220
|
const root = React.useRef(null);
|
|
4659
5221
|
const group = React.useRef(null);
|
|
@@ -4683,22 +5245,18 @@ const Html = /* @__PURE__ */ React.forwardRef(
|
|
|
4683
5245
|
if (group.current) {
|
|
4684
5246
|
if (!root.current) {
|
|
4685
5247
|
root.current = ReactDOM.createRoot(el);
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
5248
|
+
scene.updateMatrixWorld();
|
|
5249
|
+
if (transform) {
|
|
5250
|
+
el.style.cssText = `position:absolute;top:0;left:0;pointer-events:none;overflow:hidden;`;
|
|
5251
|
+
} else {
|
|
5252
|
+
el.style.cssText = `position:absolute;top:0;left:0;transform:translate3d(0,-9999px,0);transform-origin:0 0;`;
|
|
5253
|
+
}
|
|
4692
5254
|
}
|
|
4693
5255
|
if (target) {
|
|
4694
5256
|
if (prepend) target.prepend(el);
|
|
4695
5257
|
else target.appendChild(el);
|
|
4696
5258
|
}
|
|
4697
5259
|
return () => {
|
|
4698
|
-
if (root.current) {
|
|
4699
|
-
root.current.unmount();
|
|
4700
|
-
root.current = null;
|
|
4701
|
-
}
|
|
4702
5260
|
if (target && target.contains(el)) {
|
|
4703
5261
|
target.removeChild(el);
|
|
4704
5262
|
}
|
|
@@ -4832,8 +5390,7 @@ const Html = /* @__PURE__ */ React.forwardRef(
|
|
|
4832
5390
|
if (transformOuterRef.current) {
|
|
4833
5391
|
const el2 = transformOuterRef.current.children[0];
|
|
4834
5392
|
if (el2?.clientWidth && el2?.clientHeight) {
|
|
4835
|
-
|
|
4836
|
-
if (isOrthographicCamera || geometry) {
|
|
5393
|
+
if (geometry) {
|
|
4837
5394
|
if (props.scale) {
|
|
4838
5395
|
if (!Array.isArray(props.scale)) {
|
|
4839
5396
|
occlusionMeshRef.current.scale.setScalar(1 / props.scale);
|
|
@@ -4865,64 +5422,7 @@ const Html = /* @__PURE__ */ React.forwardRef(
|
|
|
4865
5422
|
}
|
|
4866
5423
|
}
|
|
4867
5424
|
});
|
|
4868
|
-
|
|
4869
|
-
() => ({
|
|
4870
|
-
vertexShader: !transform ? (
|
|
4871
|
-
/* glsl */
|
|
4872
|
-
`
|
|
4873
|
-
/*
|
|
4874
|
-
This shader is from the THREE's SpriteMaterial.
|
|
4875
|
-
We need to turn the backing plane into a Sprite
|
|
4876
|
-
(make it always face the camera) if "transfrom"
|
|
4877
|
-
is false.
|
|
4878
|
-
*/
|
|
4879
|
-
#include <common>
|
|
4880
|
-
|
|
4881
|
-
void main() {
|
|
4882
|
-
vec2 center = vec2(0., 1.);
|
|
4883
|
-
float rotation = 0.0;
|
|
4884
|
-
|
|
4885
|
-
// This is somewhat arbitrary, but it seems to work well
|
|
4886
|
-
// Need to figure out how to derive this dynamically if it even matters
|
|
4887
|
-
float size = 0.03;
|
|
4888
|
-
|
|
4889
|
-
vec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );
|
|
4890
|
-
vec2 scale;
|
|
4891
|
-
scale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );
|
|
4892
|
-
scale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );
|
|
4893
|
-
|
|
4894
|
-
bool isPerspective = isPerspectiveMatrix( projectionMatrix );
|
|
4895
|
-
if ( isPerspective ) scale *= - mvPosition.z;
|
|
4896
|
-
|
|
4897
|
-
vec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale * size;
|
|
4898
|
-
vec2 rotatedPosition;
|
|
4899
|
-
rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;
|
|
4900
|
-
rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;
|
|
4901
|
-
mvPosition.xy += rotatedPosition;
|
|
4902
|
-
|
|
4903
|
-
gl_Position = projectionMatrix * mvPosition;
|
|
4904
|
-
}
|
|
4905
|
-
`
|
|
4906
|
-
) : void 0,
|
|
4907
|
-
fragmentShader: (
|
|
4908
|
-
/* glsl */
|
|
4909
|
-
`
|
|
4910
|
-
void main() {
|
|
4911
|
-
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
4912
|
-
}
|
|
4913
|
-
`
|
|
4914
|
-
)
|
|
4915
|
-
}),
|
|
4916
|
-
[transform]
|
|
4917
|
-
);
|
|
4918
|
-
return /* @__PURE__ */ React.createElement("group", { ...props, ref: group }, occlude && !isRayCastOcclusion && /* @__PURE__ */ React.createElement("mesh", { castShadow, receiveShadow, ref: occlusionMeshRef }, geometry || /* @__PURE__ */ React.createElement("planeGeometry", null), material || /* @__PURE__ */ React.createElement(
|
|
4919
|
-
"shaderMaterial",
|
|
4920
|
-
{
|
|
4921
|
-
side: DoubleSide,
|
|
4922
|
-
vertexShader: shaders.vertexShader,
|
|
4923
|
-
fragmentShader: shaders.fragmentShader
|
|
4924
|
-
}
|
|
4925
|
-
)));
|
|
5425
|
+
return /* @__PURE__ */ React.createElement("group", { ...props, ref: group }, occlude && !isRayCastOcclusion && /* @__PURE__ */ React.createElement("mesh", { castShadow, receiveShadow, ref: occlusionMeshRef }, geometry || /* @__PURE__ */ React.createElement("planeGeometry", null), material));
|
|
4926
5426
|
}
|
|
4927
5427
|
);
|
|
4928
5428
|
|
|
@@ -5775,6 +6275,7 @@ const mW = /* @__PURE__ */ new THREE.Matrix4();
|
|
|
5775
6275
|
const mL = /* @__PURE__ */ new THREE.Matrix4();
|
|
5776
6276
|
const mL0Inv = /* @__PURE__ */ new THREE.Matrix4();
|
|
5777
6277
|
const mdL = /* @__PURE__ */ new THREE.Matrix4();
|
|
6278
|
+
const mdW = /* @__PURE__ */ new THREE.Matrix4();
|
|
5778
6279
|
const mG = /* @__PURE__ */ new THREE.Matrix4();
|
|
5779
6280
|
const bb = /* @__PURE__ */ new THREE.Box3();
|
|
5780
6281
|
const bbObj = /* @__PURE__ */ new THREE.Box3();
|
|
@@ -5889,7 +6390,8 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
|
|
|
5889
6390
|
onDragStart && onDragStart(props2);
|
|
5890
6391
|
invalidate();
|
|
5891
6392
|
},
|
|
5892
|
-
onDrag: (
|
|
6393
|
+
onDrag: (mdW_) => {
|
|
6394
|
+
mdW.copy(mdW_);
|
|
5893
6395
|
mP.copy(parentRef.current.matrixWorld);
|
|
5894
6396
|
mPInv.copy(mP).invert();
|
|
5895
6397
|
mW.copy(mW0).premultiply(mdW);
|
|
@@ -5901,12 +6403,12 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
|
|
|
5901
6403
|
}
|
|
5902
6404
|
const target = resolveObject(object);
|
|
5903
6405
|
if (target) target.matrix.copy(mL);
|
|
5904
|
-
onDrag && onDrag(mL, mdL, mW, mdW);
|
|
6406
|
+
onDrag && onDrag({ local: mL, deltaLocal: mdL, world: mW, deltaWorld: mdW });
|
|
5905
6407
|
invalidate();
|
|
5906
6408
|
},
|
|
5907
6409
|
onDragEnd: () => {
|
|
5908
6410
|
dragState.current = null;
|
|
5909
|
-
if (onDragEnd) onDragEnd();
|
|
6411
|
+
if (onDragEnd) onDragEnd({ local: mL, deltaLocal: mdL, world: mW, deltaWorld: mdW });
|
|
5910
6412
|
invalidate();
|
|
5911
6413
|
},
|
|
5912
6414
|
onHover: (props2) => {
|
|
@@ -6017,7 +6519,9 @@ const TransformControls = /* @__PURE__ */ React.forwardRef(
|
|
|
6017
6519
|
const group = React.useRef(null);
|
|
6018
6520
|
React.useLayoutEffect(() => {
|
|
6019
6521
|
if (object) {
|
|
6020
|
-
controls.attach(
|
|
6522
|
+
controls.attach(
|
|
6523
|
+
object instanceof THREE.Object3D ? object : object.current
|
|
6524
|
+
);
|
|
6021
6525
|
} else if (group.current instanceof THREE.Object3D) {
|
|
6022
6526
|
controls.attach(group.current);
|
|
6023
6527
|
}
|
|
@@ -6116,7 +6620,7 @@ const PointMaterial = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
|
6116
6620
|
return /* @__PURE__ */ React.createElement("primitive", { ...props, object: material, ref, attach: "material" });
|
|
6117
6621
|
});
|
|
6118
6622
|
|
|
6119
|
-
const PositionalAudio = /* @__PURE__ */ React.forwardRef(({ url, distance = 1, loop =
|
|
6623
|
+
const PositionalAudio = /* @__PURE__ */ React.forwardRef(({ url, distance = 1, loop = false, autoplay, ...props }, ref) => {
|
|
6120
6624
|
const sound = React.useRef(null);
|
|
6121
6625
|
React.useImperativeHandle(ref, () => sound.current, []);
|
|
6122
6626
|
const camera = useThree(({ camera: camera2 }) => camera2);
|
|
@@ -6128,7 +6632,9 @@ const PositionalAudio = /* @__PURE__ */ React.forwardRef(({ url, distance = 1, l
|
|
|
6128
6632
|
_sound.setBuffer(Array.isArray(buffer) ? buffer[0] : buffer);
|
|
6129
6633
|
_sound.setRefDistance(distance);
|
|
6130
6634
|
_sound.setLoop(loop);
|
|
6131
|
-
if (autoplay && !_sound.isPlaying)
|
|
6635
|
+
if (autoplay && !_sound.isPlaying) {
|
|
6636
|
+
_sound.play();
|
|
6637
|
+
}
|
|
6132
6638
|
}
|
|
6133
6639
|
}, [buffer, camera, distance, loop]);
|
|
6134
6640
|
React.useEffect(() => {
|
|
@@ -6197,7 +6703,6 @@ const tempMatrix = /* @__PURE__ */ new THREE.Matrix4();
|
|
|
6197
6703
|
const translation = /* @__PURE__ */ new THREE.Vector3();
|
|
6198
6704
|
const rotation = /* @__PURE__ */ new THREE.Quaternion();
|
|
6199
6705
|
const scale = /* @__PURE__ */ new THREE.Vector3();
|
|
6200
|
-
const isInstancedBufferAttribute = (attr) => attr.isInstancedBufferAttribute;
|
|
6201
6706
|
const Instance = /* @__PURE__ */ React.forwardRef(({ context, children, ...props }, ref) => {
|
|
6202
6707
|
React.useMemo(() => extend({ PositionMesh }), []);
|
|
6203
6708
|
const group = React.useRef(null);
|
|
@@ -6217,24 +6722,20 @@ const Instances = /* @__PURE__ */ React.forwardRef(({ context, children, range,
|
|
|
6217
6722
|
const parentRef = React.useRef(null);
|
|
6218
6723
|
React.useImperativeHandle(ref, () => parentRef.current, []);
|
|
6219
6724
|
const [instances, setInstances] = React.useState([]);
|
|
6725
|
+
const boundsDirty = React.useRef(true);
|
|
6220
6726
|
const [[matrices, colors]] = React.useState(() => {
|
|
6221
6727
|
const mArray = new Float32Array(limit * 16);
|
|
6222
6728
|
for (let i = 0; i < limit; i++) tempMatrix.identity().toArray(mArray, i * 16);
|
|
6223
6729
|
return [mArray, new Float32Array([...new Array(limit * 3)].map(() => 1))];
|
|
6224
6730
|
});
|
|
6225
6731
|
React.useEffect(() => {
|
|
6226
|
-
parentRef.current.instanceMatrix.needsUpdate = true;
|
|
6732
|
+
if (parentRef.current) parentRef.current.instanceMatrix.needsUpdate = true;
|
|
6227
6733
|
});
|
|
6228
6734
|
let iterations = 0;
|
|
6229
6735
|
let count = 0;
|
|
6230
|
-
const attributes = React.useRef([]);
|
|
6231
|
-
React.useLayoutEffect(() => {
|
|
6232
|
-
attributes.current = Object.entries(parentRef.current.geometry.attributes).filter(
|
|
6233
|
-
([_name, value]) => isInstancedBufferAttribute(value)
|
|
6234
|
-
);
|
|
6235
|
-
});
|
|
6236
6736
|
useFrame(() => {
|
|
6237
6737
|
if (frames === Infinity || iterations < frames) {
|
|
6738
|
+
if (!parentRef.current) return;
|
|
6238
6739
|
parentRef.current.updateMatrix();
|
|
6239
6740
|
parentRef.current.updateMatrixWorld();
|
|
6240
6741
|
parentMatrix.copy(parentRef.current.matrixWorld).invert();
|
|
@@ -6255,13 +6756,22 @@ const Instances = /* @__PURE__ */ React.forwardRef(({ context, children, range,
|
|
|
6255
6756
|
}
|
|
6256
6757
|
iterations++;
|
|
6257
6758
|
}
|
|
6759
|
+
if (boundsDirty.current && (frames === Infinity || iterations === frames)) {
|
|
6760
|
+
boundsDirty.current = false;
|
|
6761
|
+
if (parentRef.current.boundingBox) parentRef.current.computeBoundingBox();
|
|
6762
|
+
if (parentRef.current.boundingSphere) parentRef.current.computeBoundingSphere();
|
|
6763
|
+
}
|
|
6258
6764
|
});
|
|
6259
6765
|
const api = React.useMemo(
|
|
6260
6766
|
() => ({
|
|
6261
6767
|
getParent: () => parentRef,
|
|
6262
6768
|
subscribe: (ref2) => {
|
|
6263
6769
|
setInstances((instances2) => [...instances2, ref2]);
|
|
6264
|
-
|
|
6770
|
+
boundsDirty.current = true;
|
|
6771
|
+
return () => {
|
|
6772
|
+
setInstances((instances2) => instances2.filter((item) => item.current !== ref2.current));
|
|
6773
|
+
boundsDirty.current = true;
|
|
6774
|
+
};
|
|
6265
6775
|
}
|
|
6266
6776
|
}),
|
|
6267
6777
|
[]
|
|
@@ -6286,10 +6796,23 @@ const Merged = /* @__PURE__ */ React.forwardRef(function Merged2({ meshes, child
|
|
|
6286
6796
|
if (!isArray) {
|
|
6287
6797
|
for (const key of Object.keys(meshes)) if (!meshes[key].isMesh) delete meshes[key];
|
|
6288
6798
|
}
|
|
6289
|
-
const render = (args) =>
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6799
|
+
const render = (args) => {
|
|
6800
|
+
if (isArray) {
|
|
6801
|
+
return children(
|
|
6802
|
+
...args
|
|
6803
|
+
);
|
|
6804
|
+
}
|
|
6805
|
+
const instanceMap = {};
|
|
6806
|
+
const keys = Object.keys(meshes).filter((key) => meshes[key].isMesh);
|
|
6807
|
+
keys.forEach((key, i) => {
|
|
6808
|
+
instanceMap[key] = args[i];
|
|
6809
|
+
});
|
|
6810
|
+
return children(instanceMap);
|
|
6811
|
+
};
|
|
6812
|
+
const components = (isArray ? meshes : Object.values(meshes)).map((mesh) => {
|
|
6813
|
+
const { geometry, material } = mesh;
|
|
6814
|
+
return /* @__PURE__ */ React.createElement(Instances, { key: geometry.uuid, geometry, material, ...props });
|
|
6815
|
+
});
|
|
6293
6816
|
return /* @__PURE__ */ React.createElement("group", { ref }, renderRecursive(render, components));
|
|
6294
6817
|
});
|
|
6295
6818
|
function renderRecursive(render, components, results = []) {
|
|
@@ -7363,12 +7886,13 @@ function Sampler({ children, weight, transform, instances, mesh, count = 16, ...
|
|
|
7363
7886
|
return /* @__PURE__ */ React.createElement("group", { ref: group, ...props }, children);
|
|
7364
7887
|
}
|
|
7365
7888
|
|
|
7889
|
+
const pathStyle = (path) => path.userData?.style;
|
|
7366
7890
|
const Svg = /* @__PURE__ */ forwardRef(
|
|
7367
7891
|
function R3FSvg({ src, skipFill, skipStrokes, fillMaterial, strokeMaterial, fillMeshProps, strokeMeshProps, ...props }, ref) {
|
|
7368
7892
|
const svg = useLoader(SVGLoader, !src.startsWith("<svg") ? src : `data:image/svg+xml;utf8,${src}`);
|
|
7369
7893
|
const strokeGeometries = useMemo(
|
|
7370
7894
|
() => skipStrokes ? [] : svg.paths.map(
|
|
7371
|
-
(path) => path
|
|
7895
|
+
(path) => pathStyle(path)?.stroke === void 0 || pathStyle(path).stroke === "none" ? null : path.subPaths.map((subPath) => SVGLoader.pointsToStroke(subPath.getPoints(), pathStyle(path)))
|
|
7372
7896
|
),
|
|
7373
7897
|
[svg, skipStrokes]
|
|
7374
7898
|
);
|
|
@@ -7376,21 +7900,21 @@ const Svg = /* @__PURE__ */ forwardRef(
|
|
|
7376
7900
|
return () => strokeGeometries.forEach((group) => group && group.map((g) => g.dispose()));
|
|
7377
7901
|
}, [strokeGeometries]);
|
|
7378
7902
|
let renderOrder = 0;
|
|
7379
|
-
return /* @__PURE__ */ React.createElement("object3D", { ref, ...props }, /* @__PURE__ */ React.createElement("object3D", { scale: [1, -1, 1] }, svg.paths.map((path, p) => /* @__PURE__ */ React.createElement(Fragment, { key: p }, !skipFill && path
|
|
7903
|
+
return /* @__PURE__ */ React.createElement("object3D", { ref, ...props }, /* @__PURE__ */ React.createElement("object3D", { scale: [1, -1, 1] }, svg.paths.map((path, p) => /* @__PURE__ */ React.createElement(Fragment, { key: p }, !skipFill && pathStyle(path)?.fill !== void 0 && pathStyle(path).fill !== "none" && SVGLoader.createShapes(path).map((shape, s) => /* @__PURE__ */ React.createElement("mesh", { key: s, ...fillMeshProps, renderOrder: renderOrder++ }, /* @__PURE__ */ React.createElement("shapeGeometry", { args: [shape] }), /* @__PURE__ */ React.createElement(
|
|
7380
7904
|
"meshBasicMaterial",
|
|
7381
7905
|
{
|
|
7382
|
-
color: path.
|
|
7383
|
-
opacity: path.
|
|
7906
|
+
color: pathStyle(path).fill,
|
|
7907
|
+
opacity: pathStyle(path).fillOpacity,
|
|
7384
7908
|
transparent: true,
|
|
7385
7909
|
side: DoubleSide,
|
|
7386
7910
|
depthWrite: false,
|
|
7387
7911
|
...fillMaterial
|
|
7388
7912
|
}
|
|
7389
|
-
))), !skipStrokes && path
|
|
7913
|
+
))), !skipStrokes && pathStyle(path)?.stroke !== void 0 && pathStyle(path).stroke !== "none" && path.subPaths.map((_subPath, s) => /* @__PURE__ */ React.createElement("mesh", { key: s, geometry: strokeGeometries[p][s], ...strokeMeshProps, renderOrder: renderOrder++ }, /* @__PURE__ */ React.createElement(
|
|
7390
7914
|
"meshBasicMaterial",
|
|
7391
7915
|
{
|
|
7392
|
-
color: path.
|
|
7393
|
-
opacity: path.
|
|
7916
|
+
color: pathStyle(path).stroke,
|
|
7917
|
+
opacity: pathStyle(path).strokeOpacity,
|
|
7394
7918
|
transparent: true,
|
|
7395
7919
|
side: DoubleSide,
|
|
7396
7920
|
depthWrite: false,
|
|
@@ -7561,7 +8085,7 @@ function Preload({ all, scene, camera }) {
|
|
|
7561
8085
|
});
|
|
7562
8086
|
}
|
|
7563
8087
|
gl.compile(scene || dScene, camera || dCamera);
|
|
7564
|
-
const cubeRenderTarget = new
|
|
8088
|
+
const cubeRenderTarget = new CubeRenderTarget(128);
|
|
7565
8089
|
const cubeCamera = new CubeCamera$1(0.01, 1e5, cubeRenderTarget);
|
|
7566
8090
|
cubeCamera.update(gl, scene || dScene);
|
|
7567
8091
|
cubeRenderTarget.dispose();
|
|
@@ -7613,8 +8137,8 @@ function useVideoTexture(srcOrSrcObject, {
|
|
|
7613
8137
|
});
|
|
7614
8138
|
if (src && IS_BROWSER && src.endsWith(".m3u8")) {
|
|
7615
8139
|
const hls = hlsRef.current = await getHls(hlsConfig);
|
|
7616
|
-
if (hls) {
|
|
7617
|
-
hls.on(Events.MEDIA_ATTACHED, () => void hls.loadSource(src));
|
|
8140
|
+
if (hls && _HLSModule) {
|
|
8141
|
+
hls.on(_HLSModule.Events.MEDIA_ATTACHED, () => void hls.loadSource(src));
|
|
7618
8142
|
hls.attachMedia(video2);
|
|
7619
8143
|
}
|
|
7620
8144
|
}
|
|
@@ -7834,9 +8358,125 @@ function Fbx({
|
|
|
7834
8358
|
return /* @__PURE__ */ React.createElement(Clone, { ...props, object });
|
|
7835
8359
|
}
|
|
7836
8360
|
|
|
8361
|
+
const SERVICE_KEY = "__drei_ktx2_service__";
|
|
8362
|
+
const DEFAULT_TRANSCODER_PATH = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/basis/";
|
|
8363
|
+
class KTX2LoaderServiceImpl {
|
|
8364
|
+
loader = null;
|
|
8365
|
+
renderer = null;
|
|
8366
|
+
_isReady = false;
|
|
8367
|
+
transcoderPath = DEFAULT_TRANSCODER_PATH;
|
|
8368
|
+
pendingCallbacks = [];
|
|
8369
|
+
/**
|
|
8370
|
+
* Get or create the singleton KTX2Loader instance.
|
|
8371
|
+
* The loader is created lazily on first access.
|
|
8372
|
+
*/
|
|
8373
|
+
getLoader() {
|
|
8374
|
+
if (!this.loader) {
|
|
8375
|
+
this.loader = new KTX2Loader();
|
|
8376
|
+
this.loader.setTranscoderPath(this.transcoderPath);
|
|
8377
|
+
}
|
|
8378
|
+
return this.loader;
|
|
8379
|
+
}
|
|
8380
|
+
/**
|
|
8381
|
+
* Register a renderer and call detectSupport.
|
|
8382
|
+
* Should be called from within React context (useLayoutEffect).
|
|
8383
|
+
* Flushes any queued callbacks.
|
|
8384
|
+
*/
|
|
8385
|
+
registerRenderer(renderer) {
|
|
8386
|
+
if (this._isReady && this.renderer === renderer) {
|
|
8387
|
+
return;
|
|
8388
|
+
}
|
|
8389
|
+
this.renderer = renderer;
|
|
8390
|
+
const loader = this.getLoader();
|
|
8391
|
+
loader.detectSupport(renderer);
|
|
8392
|
+
this._isReady = true;
|
|
8393
|
+
this.flushPendingCallbacks();
|
|
8394
|
+
}
|
|
8395
|
+
/**
|
|
8396
|
+
* Check if the service is ready (has renderer registered).
|
|
8397
|
+
*/
|
|
8398
|
+
isReady() {
|
|
8399
|
+
return this._isReady;
|
|
8400
|
+
}
|
|
8401
|
+
/**
|
|
8402
|
+
* Get the registered renderer, if any.
|
|
8403
|
+
*/
|
|
8404
|
+
getRenderer() {
|
|
8405
|
+
return this.renderer;
|
|
8406
|
+
}
|
|
8407
|
+
/**
|
|
8408
|
+
* Register a callback to run when renderer becomes available.
|
|
8409
|
+
* If renderer is already available, runs immediately.
|
|
8410
|
+
*/
|
|
8411
|
+
onReady(callback) {
|
|
8412
|
+
if (this._isReady) {
|
|
8413
|
+
callback();
|
|
8414
|
+
} else {
|
|
8415
|
+
this.pendingCallbacks.push(callback);
|
|
8416
|
+
}
|
|
8417
|
+
}
|
|
8418
|
+
/**
|
|
8419
|
+
* Process all pending callbacks.
|
|
8420
|
+
*/
|
|
8421
|
+
flushPendingCallbacks() {
|
|
8422
|
+
const callbacks = this.pendingCallbacks;
|
|
8423
|
+
this.pendingCallbacks = [];
|
|
8424
|
+
for (const callback of callbacks) {
|
|
8425
|
+
try {
|
|
8426
|
+
callback();
|
|
8427
|
+
} catch (error) {
|
|
8428
|
+
console.error("KTX2LoaderService: Error in pending callback:", error);
|
|
8429
|
+
}
|
|
8430
|
+
}
|
|
8431
|
+
}
|
|
8432
|
+
/**
|
|
8433
|
+
* Set the transcoder path for basis/ktx2 decoding.
|
|
8434
|
+
*/
|
|
8435
|
+
setTranscoderPath(path) {
|
|
8436
|
+
this.transcoderPath = path;
|
|
8437
|
+
if (this.loader) {
|
|
8438
|
+
this.loader.setTranscoderPath(path);
|
|
8439
|
+
}
|
|
8440
|
+
}
|
|
8441
|
+
/**
|
|
8442
|
+
* Get the current transcoder path.
|
|
8443
|
+
*/
|
|
8444
|
+
getTranscoderPath() {
|
|
8445
|
+
return this.transcoderPath;
|
|
8446
|
+
}
|
|
8447
|
+
/**
|
|
8448
|
+
* Dispose of the loader and reset state.
|
|
8449
|
+
* Useful for testing or cleanup.
|
|
8450
|
+
*/
|
|
8451
|
+
dispose() {
|
|
8452
|
+
if (this.loader) {
|
|
8453
|
+
this.loader.dispose();
|
|
8454
|
+
}
|
|
8455
|
+
const path = this.transcoderPath;
|
|
8456
|
+
this.loader = null;
|
|
8457
|
+
this.renderer = null;
|
|
8458
|
+
this._isReady = false;
|
|
8459
|
+
this.transcoderPath = path;
|
|
8460
|
+
this.pendingCallbacks = [];
|
|
8461
|
+
}
|
|
8462
|
+
}
|
|
8463
|
+
const KTX2LoaderService = globalThis[SERVICE_KEY] || (globalThis[SERVICE_KEY] = new KTX2LoaderServiceImpl());
|
|
8464
|
+
|
|
7837
8465
|
let dracoLoader = null;
|
|
7838
8466
|
let decoderPath = "https://www.gstatic.com/draco/versioned/decoders/1.5.5/";
|
|
7839
|
-
|
|
8467
|
+
let legacyApiWarned = false;
|
|
8468
|
+
function isOptionsObject(arg) {
|
|
8469
|
+
return typeof arg === "object" && arg !== null && !Array.isArray(arg);
|
|
8470
|
+
}
|
|
8471
|
+
function warnLegacyApi() {
|
|
8472
|
+
if (!legacyApiWarned) {
|
|
8473
|
+
legacyApiWarned = true;
|
|
8474
|
+
console.warn(
|
|
8475
|
+
"useGLTF: Boolean arguments are deprecated. Use options object instead:\n useGLTF(path, { draco: true, meshopt: true, ktx2: true })"
|
|
8476
|
+
);
|
|
8477
|
+
}
|
|
8478
|
+
}
|
|
8479
|
+
function extensions(useDraco = true, useMeshopt = true, useKTX2 = false, extendLoader, renderer) {
|
|
7840
8480
|
return (loader) => {
|
|
7841
8481
|
if (extendLoader) {
|
|
7842
8482
|
extendLoader(loader);
|
|
@@ -7852,36 +8492,110 @@ function extensions(useDraco = true, useMeshopt = true, extendLoader) {
|
|
|
7852
8492
|
const decoder = typeof MeshoptDecoder === "function" ? MeshoptDecoder() : MeshoptDecoder;
|
|
7853
8493
|
loader.setMeshoptDecoder(decoder);
|
|
7854
8494
|
}
|
|
8495
|
+
if (useKTX2) {
|
|
8496
|
+
const ktx2Loader = KTX2LoaderService.getLoader();
|
|
8497
|
+
if (typeof useKTX2 === "string") {
|
|
8498
|
+
ktx2Loader.setTranscoderPath(useKTX2);
|
|
8499
|
+
}
|
|
8500
|
+
if (renderer) {
|
|
8501
|
+
ktx2Loader.detectSupport(renderer);
|
|
8502
|
+
}
|
|
8503
|
+
loader.setKTX2Loader(ktx2Loader);
|
|
8504
|
+
}
|
|
7855
8505
|
};
|
|
7856
8506
|
}
|
|
7857
|
-
|
|
7858
|
-
|
|
8507
|
+
function useGLTF(path, optionsOrDraco, useMeshoptArg, useKTX2Arg, extendLoaderArg) {
|
|
8508
|
+
let draco = true;
|
|
8509
|
+
let meshopt = true;
|
|
8510
|
+
let ktx2 = false;
|
|
8511
|
+
let extendLoader;
|
|
8512
|
+
if (isOptionsObject(optionsOrDraco)) {
|
|
8513
|
+
draco = optionsOrDraco.draco ?? true;
|
|
8514
|
+
meshopt = optionsOrDraco.meshopt ?? true;
|
|
8515
|
+
ktx2 = optionsOrDraco.ktx2 ?? false;
|
|
8516
|
+
extendLoader = optionsOrDraco.extendLoader;
|
|
8517
|
+
} else if (optionsOrDraco !== void 0) {
|
|
8518
|
+
warnLegacyApi();
|
|
8519
|
+
draco = optionsOrDraco;
|
|
8520
|
+
meshopt = useMeshoptArg ?? true;
|
|
8521
|
+
ktx2 = useKTX2Arg ?? false;
|
|
8522
|
+
extendLoader = extendLoaderArg;
|
|
8523
|
+
}
|
|
8524
|
+
const renderer = useThree((state) => state.renderer);
|
|
8525
|
+
useLayoutEffect(() => {
|
|
8526
|
+
if (ktx2) {
|
|
8527
|
+
KTX2LoaderService.registerRenderer(renderer);
|
|
8528
|
+
}
|
|
8529
|
+
}, [ktx2, renderer]);
|
|
8530
|
+
return useLoader(GLTFLoader, path, extensions(draco, meshopt, ktx2, extendLoader, ktx2 ? renderer : void 0));
|
|
8531
|
+
}
|
|
8532
|
+
useGLTF.preload = (path, optionsOrDraco, useMeshoptArg, useKTX2Arg, extendLoaderArg) => {
|
|
8533
|
+
let draco = true;
|
|
8534
|
+
let meshopt = true;
|
|
8535
|
+
let ktx2 = false;
|
|
8536
|
+
let extendLoader;
|
|
8537
|
+
if (isOptionsObject(optionsOrDraco)) {
|
|
8538
|
+
draco = optionsOrDraco.draco ?? true;
|
|
8539
|
+
meshopt = optionsOrDraco.meshopt ?? true;
|
|
8540
|
+
ktx2 = optionsOrDraco.ktx2 ?? false;
|
|
8541
|
+
extendLoader = optionsOrDraco.extendLoader;
|
|
8542
|
+
} else if (optionsOrDraco !== void 0) {
|
|
8543
|
+
warnLegacyApi();
|
|
8544
|
+
draco = optionsOrDraco;
|
|
8545
|
+
meshopt = useMeshoptArg ?? true;
|
|
8546
|
+
ktx2 = useKTX2Arg ?? false;
|
|
8547
|
+
extendLoader = extendLoaderArg;
|
|
8548
|
+
}
|
|
8549
|
+
if (ktx2) {
|
|
8550
|
+
KTX2LoaderService.onReady(() => {
|
|
8551
|
+
const renderer = KTX2LoaderService.getRenderer();
|
|
8552
|
+
useLoader.preload(GLTFLoader, path, extensions(draco, meshopt, ktx2, extendLoader, renderer));
|
|
8553
|
+
});
|
|
8554
|
+
} else {
|
|
8555
|
+
useLoader.preload(GLTFLoader, path, extensions(draco, meshopt, false, extendLoader));
|
|
8556
|
+
}
|
|
8557
|
+
};
|
|
7859
8558
|
useGLTF.clear = (path) => useLoader.clear(GLTFLoader, path);
|
|
7860
8559
|
useGLTF.setDecoderPath = (path) => {
|
|
7861
8560
|
decoderPath = path;
|
|
7862
8561
|
};
|
|
8562
|
+
useGLTF.setKTX2TranscoderPath = (path) => {
|
|
8563
|
+
KTX2LoaderService.setTranscoderPath(path);
|
|
8564
|
+
};
|
|
7863
8565
|
const Gltf = /* @__PURE__ */ React.forwardRef(
|
|
7864
|
-
({ src, useDraco, useMeshOpt, extendLoader, ...props }, ref) => {
|
|
7865
|
-
const
|
|
8566
|
+
({ src, useDraco, useMeshOpt, extendLoader, options, ...props }, ref) => {
|
|
8567
|
+
const opts = options ?? {
|
|
8568
|
+
draco: useDraco,
|
|
8569
|
+
meshopt: useMeshOpt,
|
|
8570
|
+
extendLoader
|
|
8571
|
+
};
|
|
8572
|
+
const { scene } = useGLTF(src, opts);
|
|
7866
8573
|
return /* @__PURE__ */ React.createElement(Clone, { ref, ...props, object: scene });
|
|
7867
8574
|
}
|
|
7868
8575
|
);
|
|
7869
8576
|
|
|
7870
|
-
let transcoderPath = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/basis/";
|
|
7871
8577
|
function useKTX2(input, basisPath = true, extendLoader) {
|
|
7872
8578
|
const renderer = useThree((state) => state.renderer);
|
|
8579
|
+
useLayoutEffect(() => {
|
|
8580
|
+
KTX2LoaderService.registerRenderer(renderer);
|
|
8581
|
+
}, [renderer]);
|
|
7873
8582
|
const textures = useLoader(KTX2Loader, IsObject(input) ? Object.values(input) : input, (loader) => {
|
|
7874
8583
|
if (extendLoader) {
|
|
7875
8584
|
extendLoader(loader);
|
|
7876
8585
|
}
|
|
7877
8586
|
if (basisPath) {
|
|
7878
|
-
|
|
8587
|
+
const path = typeof basisPath === "string" ? basisPath : KTX2LoaderService.getTranscoderPath();
|
|
8588
|
+
loader.setTranscoderPath(path);
|
|
7879
8589
|
}
|
|
7880
8590
|
loader.detectSupport(renderer);
|
|
7881
8591
|
});
|
|
7882
8592
|
useEffect(() => {
|
|
7883
8593
|
const array = Array.isArray(textures) ? textures : [textures];
|
|
7884
|
-
array.forEach((texture) =>
|
|
8594
|
+
array.forEach((texture) => {
|
|
8595
|
+
if ("initTexture" in renderer) {
|
|
8596
|
+
renderer.initTexture(texture);
|
|
8597
|
+
}
|
|
8598
|
+
});
|
|
7885
8599
|
}, [renderer, textures]);
|
|
7886
8600
|
if (IsObject(input)) {
|
|
7887
8601
|
const keys = Object.keys(input);
|
|
@@ -7892,17 +8606,26 @@ function useKTX2(input, basisPath = true, extendLoader) {
|
|
|
7892
8606
|
return textures;
|
|
7893
8607
|
}
|
|
7894
8608
|
}
|
|
7895
|
-
useKTX2.preload = (url, basisPath = true, extendLoader) =>
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
8609
|
+
useKTX2.preload = (url, basisPath = true, extendLoader) => {
|
|
8610
|
+
KTX2LoaderService.onReady(() => {
|
|
8611
|
+
const renderer = KTX2LoaderService.getRenderer();
|
|
8612
|
+
useLoader.preload(KTX2Loader, url, (loader) => {
|
|
8613
|
+
if (extendLoader) {
|
|
8614
|
+
extendLoader(loader);
|
|
8615
|
+
}
|
|
8616
|
+
if (basisPath) {
|
|
8617
|
+
const path = typeof basisPath === "string" ? basisPath : KTX2LoaderService.getTranscoderPath();
|
|
8618
|
+
loader.setTranscoderPath(path);
|
|
8619
|
+
}
|
|
8620
|
+
if (renderer) {
|
|
8621
|
+
loader.detectSupport(renderer);
|
|
8622
|
+
}
|
|
8623
|
+
});
|
|
8624
|
+
});
|
|
8625
|
+
};
|
|
7903
8626
|
useKTX2.clear = (input) => useLoader.clear(KTX2Loader, input);
|
|
7904
8627
|
useKTX2.setTranscoderPath = (path) => {
|
|
7905
|
-
|
|
8628
|
+
KTX2LoaderService.setTranscoderPath(path);
|
|
7906
8629
|
};
|
|
7907
8630
|
const Ktx2 = ({ children, input, basisPath, extendLoader }) => {
|
|
7908
8631
|
const texture = useKTX2(input, basisPath, extendLoader);
|
|
@@ -8096,6 +8819,7 @@ function useEffectfulState(fn, deps = [], cb) {
|
|
|
8096
8819
|
}
|
|
8097
8820
|
|
|
8098
8821
|
function Stats({ showPanel = 0, className, parent }) {
|
|
8822
|
+
React.useEffect(() => void console.warn("drei: <Stats /> is deprecated, use <StatsGl /> instead."), []);
|
|
8099
8823
|
const stats = useEffectfulState(() => new StatsImpl(), []);
|
|
8100
8824
|
React.useEffect(() => {
|
|
8101
8825
|
if (stats) {
|
|
@@ -8124,6 +8848,7 @@ const StatsGl = /* @__PURE__ */ React.forwardRef(
|
|
|
8124
8848
|
const stats2 = new Stats$1({
|
|
8125
8849
|
...props
|
|
8126
8850
|
});
|
|
8851
|
+
stats2.init(renderer);
|
|
8127
8852
|
return stats2;
|
|
8128
8853
|
}, [renderer]);
|
|
8129
8854
|
React.useImperativeHandle(fref, () => stats.domElement, [stats]);
|
|
@@ -8141,7 +8866,7 @@ const StatsGl = /* @__PURE__ */ React.forwardRef(
|
|
|
8141
8866
|
return () => {
|
|
8142
8867
|
if (classNames.length) stats.domElement.classList.remove(...classNames);
|
|
8143
8868
|
node?.removeChild(stats.domElement);
|
|
8144
|
-
stats.
|
|
8869
|
+
stats.dispose();
|
|
8145
8870
|
};
|
|
8146
8871
|
}
|
|
8147
8872
|
}, [parent, stats, className, id, clearStatsGlStyle]);
|
|
@@ -8149,7 +8874,7 @@ const StatsGl = /* @__PURE__ */ React.forwardRef(
|
|
|
8149
8874
|
() => {
|
|
8150
8875
|
stats.begin();
|
|
8151
8876
|
},
|
|
8152
|
-
{ before: "
|
|
8877
|
+
{ before: "update" }
|
|
8153
8878
|
);
|
|
8154
8879
|
useFrame(
|
|
8155
8880
|
() => {
|
|
@@ -8314,8 +9039,9 @@ const TUNNEL_KEY = "__drei_view_tunnel__";
|
|
|
8314
9039
|
const tracked = globalThis[TUNNEL_KEY] || (globalThis[TUNNEL_KEY] = tunnel());
|
|
8315
9040
|
function computeContainerPosition(canvasSize, trackRect, forceEven) {
|
|
8316
9041
|
const { right, top: trackTop, left: trackLeft, bottom: trackBottom, width, height } = trackRect;
|
|
8317
|
-
const isOffscreen = trackRect.bottom < 0 || trackTop > canvasSize.height || right < 0 || trackRect.left > canvasSize.width;
|
|
8318
9042
|
const canvasBottom = canvasSize.top + canvasSize.height;
|
|
9043
|
+
const canvasRight = canvasSize.left + canvasSize.width;
|
|
9044
|
+
const isOffscreen = trackBottom < canvasSize.top || trackTop > canvasBottom || right < canvasSize.left || trackLeft > canvasRight;
|
|
8319
9045
|
const rawBottom = canvasBottom - trackBottom;
|
|
8320
9046
|
const rawLeft = trackLeft - canvasSize.left;
|
|
8321
9047
|
const rawTop = trackTop - canvasSize.top;
|
|
@@ -8875,12 +9601,12 @@ useEnvironment.preload = (preloadOptions) => {
|
|
|
8875
9601
|
if (extensions) extensions(loader2);
|
|
8876
9602
|
});
|
|
8877
9603
|
};
|
|
8878
|
-
const
|
|
9604
|
+
const clearDefaultOptions = {
|
|
8879
9605
|
files: defaultFiles,
|
|
8880
9606
|
preset: void 0
|
|
8881
9607
|
};
|
|
8882
9608
|
useEnvironment.clear = (clearOptions) => {
|
|
8883
|
-
const options = { ...
|
|
9609
|
+
const options = { ...clearDefaultOptions, ...clearOptions };
|
|
8884
9610
|
let { files } = options;
|
|
8885
9611
|
const { preset } = options;
|
|
8886
9612
|
if (preset) {
|
|
@@ -9003,7 +9729,7 @@ function EnvironmentPortal({
|
|
|
9003
9729
|
const camera = React.useRef(null);
|
|
9004
9730
|
const [virtualScene] = React.useState(() => new Scene());
|
|
9005
9731
|
const fbo = React.useMemo(() => {
|
|
9006
|
-
const fbo2 = new
|
|
9732
|
+
const fbo2 = new CubeRenderTarget(resolution);
|
|
9007
9733
|
fbo2.texture.type = HalfFloatType;
|
|
9008
9734
|
return fbo2;
|
|
9009
9735
|
}, [resolution]);
|
|
@@ -9574,9 +10300,14 @@ function Select({
|
|
|
9574
10300
|
const oldControlsEnabled = controls?.enabled;
|
|
9575
10301
|
let isDown = false;
|
|
9576
10302
|
function prepareRay(event, vec) {
|
|
9577
|
-
const
|
|
10303
|
+
const canvas = gl.domElement;
|
|
10304
|
+
const rect = canvas.getBoundingClientRect();
|
|
10305
|
+
const x = event.clientX - rect.left;
|
|
10306
|
+
const y = event.clientY - rect.top;
|
|
9578
10307
|
const { width, height } = size;
|
|
9579
|
-
|
|
10308
|
+
const normalizedX = x / width * 2 - 1;
|
|
10309
|
+
const normalizedY = -(y / height) * 2 + 1;
|
|
10310
|
+
vec.set(normalizedX, normalizedY, -1);
|
|
9580
10311
|
}
|
|
9581
10312
|
function onSelectStart(event) {
|
|
9582
10313
|
if (controls) controls.enabled = false;
|
|
@@ -10428,7 +11159,7 @@ const ImageWithUrl = /* @__PURE__ */ React.forwardRef(
|
|
|
10428
11159
|
return /* @__PURE__ */ React.createElement(ImageBase, { ...props, texture, ref });
|
|
10429
11160
|
}
|
|
10430
11161
|
);
|
|
10431
|
-
const ImageWithTexture = /* @__PURE__ */ React.forwardRef(({
|
|
11162
|
+
const ImageWithTexture = /* @__PURE__ */ React.forwardRef(({ ...props }, ref) => {
|
|
10432
11163
|
return /* @__PURE__ */ React.createElement(ImageBase, { ...props, ref });
|
|
10433
11164
|
});
|
|
10434
11165
|
const Image = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
@@ -10632,16 +11363,16 @@ class SparklesMaterial extends SpriteNodeMaterial {
|
|
|
10632
11363
|
return pos;
|
|
10633
11364
|
})();
|
|
10634
11365
|
this.scaleNode = Fn(() => {
|
|
10635
|
-
const
|
|
10636
|
-
const
|
|
10637
|
-
const
|
|
10638
|
-
const size =
|
|
11366
|
+
const pixelSize = particleSize.mul(25).mul(this._pixelRatio);
|
|
11367
|
+
const projY = cameraProjectionMatrix.element(1).y;
|
|
11368
|
+
const viewportH = screenSize.y;
|
|
11369
|
+
const size = pixelSize.mul(2).div(projY.mul(viewportH));
|
|
10639
11370
|
return vec2$2(size);
|
|
10640
11371
|
})();
|
|
10641
11372
|
this.colorNode = Fn(() => {
|
|
10642
11373
|
const quadUV = uv();
|
|
10643
11374
|
const distanceToCenter = length(quadUV.sub(vec2$2(0.5)));
|
|
10644
|
-
const strength = float(0.05).div(distanceToCenter).sub(0.1);
|
|
11375
|
+
const strength = clamp(float(0.05).div(distanceToCenter).sub(0.1), 0, 1);
|
|
10645
11376
|
return vec4(particleColor, strength.mul(particleOpacity));
|
|
10646
11377
|
})();
|
|
10647
11378
|
}
|
|
@@ -10912,17 +11643,95 @@ const Grid = /* @__PURE__ */ React.forwardRef(
|
|
|
10912
11643
|
}
|
|
10913
11644
|
);
|
|
10914
11645
|
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
11646
|
+
const createPCSSFilter = (size, samples, focus) => {
|
|
11647
|
+
const sampleCount = Math.min(Math.max(samples, 1), 20);
|
|
11648
|
+
return Fn(({ depthTexture, shadowCoord, shadow, depthLayer }) => {
|
|
11649
|
+
const sampleDepth = (uv2) => {
|
|
11650
|
+
const tex = texture(depthTexture, uv2);
|
|
11651
|
+
const depth = depthTexture.isArrayTexture ? tex.depth(depthLayer) : tex;
|
|
11652
|
+
return depth.r;
|
|
11653
|
+
};
|
|
11654
|
+
const mapSize = reference("mapSize", "vec2", shadow).setGroup(renderGroup);
|
|
11655
|
+
const texelSize = vec2$2(1).div(mapSize);
|
|
11656
|
+
const phi = interleavedGradientNoise(screenCoordinate.xy).mul(6.28318530718);
|
|
11657
|
+
const uv = shadowCoord.xy;
|
|
11658
|
+
const zReceiver = shadowCoord.z.add(1).mul(0.5);
|
|
11659
|
+
const blockerSearchRadius = texelSize.x.mul(size).mul(2);
|
|
11660
|
+
const blockerDepthSum = float(focus).toVar("blockerDepthSum");
|
|
11661
|
+
const blockerCount = float(0).toVar("blockerCount");
|
|
11662
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
11663
|
+
const offset = vogelDiskSample(int(i), int(sampleCount), phi).mul(blockerSearchRadius);
|
|
11664
|
+
const sampleUV = uv.add(offset);
|
|
11665
|
+
const sampleDepthVal = sampleDepth(sampleUV);
|
|
11666
|
+
const isBlocker = step(sampleDepthVal, zReceiver).sub(step(zReceiver, sampleDepthVal)).max(0);
|
|
11667
|
+
blockerDepthSum.addAssign(sampleDepthVal.mul(isBlocker));
|
|
11668
|
+
blockerCount.addAssign(isBlocker);
|
|
11669
|
+
}
|
|
11670
|
+
const avgBlockerDepth = blockerDepthSum.div(blockerCount.max(1));
|
|
11671
|
+
const penumbraRatio = zReceiver.sub(avgBlockerDepth).div(avgBlockerDepth.max(1e-4));
|
|
11672
|
+
const filterRadius = texelSize.x.mul(float(1).add(penumbraRatio.mul(1.25).mul(size)));
|
|
11673
|
+
const shadowSum = float(0).toVar("shadowSum");
|
|
11674
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
11675
|
+
const offset = vogelDiskSample(int(i), int(sampleCount), phi).mul(filterRadius);
|
|
11676
|
+
const sampleUV = uv.add(offset);
|
|
11677
|
+
const sampleDepthVal = sampleDepth(sampleUV);
|
|
11678
|
+
shadowSum.addAssign(step(zReceiver, sampleDepthVal));
|
|
11679
|
+
}
|
|
11680
|
+
const shadowResult = shadowSum.div(sampleCount);
|
|
11681
|
+
const hasBlockers = blockerCount.greaterThan(0.5);
|
|
11682
|
+
return hasBlockers.select(shadowResult, float(1));
|
|
11683
|
+
});
|
|
11684
|
+
};
|
|
11685
|
+
class PCSSShadowNode extends ShadowNode {
|
|
11686
|
+
size;
|
|
11687
|
+
samples;
|
|
11688
|
+
focus;
|
|
11689
|
+
constructor(light, { size = 25, samples = 10, focus = 0 } = {}) {
|
|
11690
|
+
super(light, light.shadow);
|
|
11691
|
+
this.size = size;
|
|
11692
|
+
this.samples = samples;
|
|
11693
|
+
this.focus = focus;
|
|
11694
|
+
}
|
|
11695
|
+
/**
|
|
11696
|
+
* Override to disable hardware depth comparison.
|
|
11697
|
+
* PCSS needs raw depth values for blocker search, so we can't use comparison samplers.
|
|
11698
|
+
*/
|
|
11699
|
+
setupRenderTarget(shadow, builder) {
|
|
11700
|
+
const parentMethod = Object.getPrototypeOf(Object.getPrototypeOf(this)).setupRenderTarget;
|
|
11701
|
+
const result = parentMethod.call(this, shadow, builder);
|
|
11702
|
+
if (result.depthTexture) {
|
|
11703
|
+
result.depthTexture.compareFunction = null;
|
|
11704
|
+
}
|
|
11705
|
+
return result;
|
|
11706
|
+
}
|
|
11707
|
+
/**
|
|
11708
|
+
* Override to use our PCSS filter instead of the default filter.
|
|
11709
|
+
*/
|
|
11710
|
+
getShadowFilterFn(_type) {
|
|
11711
|
+
return createPCSSFilter(this.size, this.samples, this.focus);
|
|
10920
11712
|
}
|
|
10921
11713
|
}
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
)
|
|
11714
|
+
|
|
11715
|
+
function SoftShadows({ size = 25, samples = 10, focus = 0 }) {
|
|
11716
|
+
const scene = useThree((state) => state.scene);
|
|
11717
|
+
React.useLayoutEffect(() => {
|
|
11718
|
+
const originalShadowNodes = /* @__PURE__ */ new Map();
|
|
11719
|
+
scene.traverse((obj) => {
|
|
11720
|
+
const light = obj;
|
|
11721
|
+
if (light.isLight && light.castShadow && light.shadow) {
|
|
11722
|
+
originalShadowNodes.set(light.uuid, light.shadow.shadowNode);
|
|
11723
|
+
light.shadow.shadowNode = new PCSSShadowNode(light, { size, samples, focus });
|
|
11724
|
+
}
|
|
11725
|
+
});
|
|
11726
|
+
return () => {
|
|
11727
|
+
scene.traverse((obj) => {
|
|
11728
|
+
const light = obj;
|
|
11729
|
+
if (originalShadowNodes.has(light.uuid)) {
|
|
11730
|
+
light.shadow.shadowNode = originalShadowNodes.get(light.uuid);
|
|
11731
|
+
}
|
|
11732
|
+
});
|
|
11733
|
+
};
|
|
11734
|
+
}, [scene, size, samples, focus]);
|
|
10926
11735
|
return null;
|
|
10927
11736
|
}
|
|
10928
11737
|
|