@react-three/drei 11.0.0-alpha.5 → 11.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -3
- package/core/index.d.mts +195 -52
- package/core/index.d.ts +195 -52
- 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 +212 -54
- package/index.d.ts +212 -54
- 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 +321 -392
- package/native/index.d.ts +321 -392
- package/native/index.mjs +1843 -1815
- package/package.json +7 -7
- package/webgpu/chunks/inspector-runtime.mjs +112 -0
- package/webgpu/index.d.mts +418 -398
- package/webgpu/index.d.ts +418 -398
- package/webgpu/index.mjs +2392 -1953
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, AdditiveBlending, SpriteNodeMaterial, ShadowNode, CylinderGeometry } from 'three/webgpu';
|
|
3
|
+
import { Fn, float, vec4, uv, vec2 as vec2$2, uniform, uniformTexture, Discard, materialReference, context as context$a, max, materialAlphaTest, sub, mix, output, mul, negate, add, dot, refract, div, length, cross, select, vec3, normalize, normalWorld, positionWorld, materialColor, cameraPosition, screenCoordinate, mx_fractal_noise_vec3, int, thickness, pow, roughness, Loop, ior, screenUV, screenSize, cameraProjectionMatrix, cameraViewMatrix, attenuationColor, attenuationDistance, diffuseColor, transmission, fract, sin, modelWorldMatrix, log, exp, DFGLUT, reflector, clamp, materialIOR, equirectUV, materialOpacity, reflect, smoothstep, round, distance, positionLocal, mx_noise_vec3, cos, mat3, normalLocal, attribute, modelViewMatrix, varying, min, frontFacing, fwidth, texture, abs, saturate, positionView, positionGeometry, reference, renderGroup, interleavedGradientNoise, vogelDiskSample, step } from 'three/tsl';
|
|
1
4
|
import * as React from 'react';
|
|
2
5
|
import { forwardRef, useImperativeHandle, useRef, useMemo, useEffect, useCallback, useLayoutEffect, useState, Fragment, createContext, useContext } from 'react';
|
|
3
|
-
import { useThree, useFrame, extend, createPortal, applyProps, useInstanceHandle, context as context$
|
|
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
|
+
import { useThree, useFrame, extend, createPortal, applyProps, useInstanceHandle, context as context$b, useLoader, addEffect, addAfterEffect } from '@react-three/fiber';
|
|
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';
|
|
@@ -44,43 +44,150 @@ import { TransformControls as TransformControls$1 } from 'three/examples/jsm/con
|
|
|
44
44
|
import tunnel from 'tunnel-rat';
|
|
45
45
|
import 'zustand/middleware';
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
function assignUniform(node, factory, v) {
|
|
48
|
+
const current = node.value;
|
|
49
|
+
if (v === null || v === void 0) {
|
|
50
|
+
if (current && current.isTexture) node.value = factory().value;
|
|
51
|
+
else node.value = v;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (typeof current === "number") {
|
|
55
|
+
node.value = typeof v === "boolean" ? v ? 1 : 0 : v;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (typeof current === "boolean") {
|
|
59
|
+
node.value = !!v;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (current && typeof current === "object") {
|
|
63
|
+
if (typeof v === "object" && !Array.isArray(v)) {
|
|
64
|
+
node.value = v;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (Array.isArray(v) && typeof current.fromArray === "function") {
|
|
68
|
+
current.fromArray(v);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (current.isColor) {
|
|
72
|
+
current.set(v);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (typeof v === "number" && typeof current.setScalar === "function") {
|
|
76
|
+
current.setScalar(v);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
node.value = v;
|
|
81
|
+
}
|
|
82
|
+
function withUniforms(Base, table) {
|
|
83
|
+
const keys = Object.keys(table);
|
|
84
|
+
const factories = table;
|
|
85
|
+
let installed = false;
|
|
86
|
+
const install = (instance) => {
|
|
87
|
+
for (const key of keys) {
|
|
88
|
+
if (key.startsWith("_") || key in instance) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`withUniforms: "${key}" is reserved on ${Base.name}. Read three's own node for it (materialOpacity, materialColor, materialReference(...)) instead of declaring a uniform named "${key}".`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const key of keys) {
|
|
95
|
+
Object.defineProperty(Wrapped.prototype, key, {
|
|
96
|
+
get() {
|
|
97
|
+
return this._uniforms?.[key]?.value;
|
|
98
|
+
},
|
|
99
|
+
set(v) {
|
|
100
|
+
const node = this._uniforms?.[key];
|
|
101
|
+
if (node) assignUniform(node, factories[key], v);
|
|
102
|
+
},
|
|
103
|
+
enumerable: false,
|
|
104
|
+
configurable: true
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
installed = true;
|
|
108
|
+
};
|
|
109
|
+
const splitParameters = (args) => {
|
|
110
|
+
const params = args[0];
|
|
111
|
+
if (!params || typeof params !== "object" || Array.isArray(params)) return { args, own: null };
|
|
112
|
+
const own = {};
|
|
113
|
+
const rest = {};
|
|
114
|
+
let hasOwn = false;
|
|
115
|
+
for (const k in params) {
|
|
116
|
+
if (Object.prototype.hasOwnProperty.call(factories, k)) {
|
|
117
|
+
own[k] = params[k];
|
|
118
|
+
hasOwn = true;
|
|
119
|
+
} else rest[k] = params[k];
|
|
120
|
+
}
|
|
121
|
+
return hasOwn ? { args: [rest, ...args.slice(1)], own } : { args, own: null };
|
|
122
|
+
};
|
|
123
|
+
class Wrapped extends Base {
|
|
124
|
+
constructor(...args) {
|
|
125
|
+
const { args: baseArgs, own } = splitParameters(args);
|
|
126
|
+
super(...baseArgs);
|
|
127
|
+
if (!installed) install(this);
|
|
128
|
+
const nodes = {};
|
|
129
|
+
for (const key of keys) nodes[key] = factories[key]();
|
|
130
|
+
Object.defineProperty(this, "_uniforms", { value: nodes, enumerable: false, writable: false });
|
|
131
|
+
if (own) for (const key in own) this[key] = own[key];
|
|
132
|
+
}
|
|
133
|
+
get uniforms() {
|
|
134
|
+
return this._uniforms;
|
|
135
|
+
}
|
|
136
|
+
/** Copies values for inherited accessors that NodeMaterial.copy does not visit. */
|
|
137
|
+
copy(source) {
|
|
138
|
+
super.copy(source);
|
|
139
|
+
const from = source._uniforms;
|
|
140
|
+
if (!from) return this;
|
|
141
|
+
for (const key of keys) {
|
|
142
|
+
const value = from[key]?.value;
|
|
143
|
+
const node = this._uniforms[key];
|
|
144
|
+
const own = node.value;
|
|
145
|
+
if (value && value.isTexture) node.value = value;
|
|
146
|
+
else if (own && typeof own.copy === "function") own.copy(value);
|
|
147
|
+
else node.value = value;
|
|
148
|
+
}
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return Wrapped;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
class DepthNodeMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
156
|
+
/** Shadow strength, 1 = full darkening, 0 = none */
|
|
157
|
+
shadowOpacity: () => uniform(1)
|
|
158
|
+
}) {
|
|
49
159
|
constructor(opacity = 1) {
|
|
50
160
|
super();
|
|
51
|
-
this.
|
|
161
|
+
this.shadowOpacity = opacity;
|
|
52
162
|
this.depthTest = false;
|
|
53
163
|
this.depthWrite = false;
|
|
54
164
|
this._buildShader();
|
|
55
165
|
}
|
|
56
166
|
_buildShader() {
|
|
57
|
-
const
|
|
167
|
+
const { shadowOpacity } = this.uniforms;
|
|
58
168
|
this.colorNode = Fn(() => {
|
|
59
|
-
const shadowStrength =
|
|
169
|
+
const shadowStrength = shadowOpacity.mul(0.7);
|
|
60
170
|
const gray = float(1).sub(shadowStrength);
|
|
61
171
|
return vec4(gray, gray, gray, 1);
|
|
62
172
|
})();
|
|
63
173
|
}
|
|
64
|
-
set shadowOpacity(value) {
|
|
65
|
-
this._opacity.value = value;
|
|
66
|
-
}
|
|
67
174
|
}
|
|
68
|
-
class BlurNodeMaterial extends MeshBasicNodeMaterial {
|
|
69
|
-
|
|
70
|
-
|
|
175
|
+
class BlurNodeMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
176
|
+
/** Texture to blur */
|
|
177
|
+
inputTexture: () => uniformTexture(new THREE.Texture()),
|
|
178
|
+
/** Per-tap UV offset */
|
|
179
|
+
blurAmount: () => uniform(0)
|
|
180
|
+
}) {
|
|
71
181
|
_direction;
|
|
72
182
|
constructor(direction = "horizontal") {
|
|
73
183
|
super();
|
|
74
|
-
this._inputTexture = uniformTexture(new THREE.Texture());
|
|
75
|
-
this._blurAmount = uniform(0);
|
|
76
184
|
this._direction = direction;
|
|
77
185
|
this.depthTest = false;
|
|
78
186
|
this.depthWrite = false;
|
|
79
187
|
this._buildShader();
|
|
80
188
|
}
|
|
81
189
|
_buildShader() {
|
|
82
|
-
const inputTex = this.
|
|
83
|
-
const blurAmountUniform = this._blurAmount;
|
|
190
|
+
const { inputTexture: inputTex, blurAmount: blurAmountUniform } = this.uniforms;
|
|
84
191
|
const isHorizontal = this._direction === "horizontal";
|
|
85
192
|
const weights = [0.051, 0.0918, 0.12245, 0.1531, 0.1633, 0.1531, 0.12245, 0.0918, 0.051];
|
|
86
193
|
this.colorNode = Fn(() => {
|
|
@@ -89,18 +196,12 @@ class BlurNodeMaterial extends MeshBasicNodeMaterial {
|
|
|
89
196
|
for (let i = 0; i < 9; i++) {
|
|
90
197
|
const offset = float(i - 4).mul(blurAmountUniform);
|
|
91
198
|
const sampleUV = isHorizontal ? texCoord.add(vec2$2(offset, 0)) : texCoord.add(vec2$2(0, offset));
|
|
92
|
-
const sampledColor =
|
|
199
|
+
const sampledColor = inputTex.sample(sampleUV);
|
|
93
200
|
result.addAssign(sampledColor.mul(weights[i]));
|
|
94
201
|
}
|
|
95
202
|
return result;
|
|
96
203
|
})();
|
|
97
204
|
}
|
|
98
|
-
set inputTexture(value) {
|
|
99
|
-
this._inputTexture.value = value;
|
|
100
|
-
}
|
|
101
|
-
set blurAmount(value) {
|
|
102
|
-
this._blurAmount.value = value;
|
|
103
|
-
}
|
|
104
205
|
}
|
|
105
206
|
const ContactShadows = /* @__PURE__ */ React.forwardRef(
|
|
106
207
|
({
|
|
@@ -231,28 +332,304 @@ const ContactShadows = /* @__PURE__ */ React.forwardRef(
|
|
|
231
332
|
}
|
|
232
333
|
);
|
|
233
334
|
|
|
335
|
+
const discardFragment = /* @__PURE__ */ Fn(() => {
|
|
336
|
+
Discard();
|
|
337
|
+
return vec4(0, 0, 0, 0);
|
|
338
|
+
});
|
|
339
|
+
class DiscardNodeMaterial extends MeshBasicNodeMaterial {
|
|
340
|
+
constructor() {
|
|
341
|
+
super();
|
|
342
|
+
this.fragmentNode = discardFragment();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const DiscardMaterial = /* @__PURE__ */ new DiscardNodeMaterial();
|
|
346
|
+
|
|
347
|
+
function isLight(object) {
|
|
348
|
+
return object.isLight;
|
|
349
|
+
}
|
|
350
|
+
function isGeometry$1(object) {
|
|
351
|
+
return !!object.geometry;
|
|
352
|
+
}
|
|
234
353
|
const accumulativeContext = /* @__PURE__ */ React.createContext(
|
|
235
354
|
null
|
|
236
355
|
);
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
356
|
+
class SoftShadowMaterialImpl extends withUniforms(MeshBasicNodeMaterial, {
|
|
357
|
+
/** Shadow color, black */
|
|
358
|
+
shadowColor: () => uniform(new THREE.Color()),
|
|
359
|
+
/** Colorblend, how much colors turn to black, 0 is black */
|
|
360
|
+
blend: () => uniform(2)
|
|
361
|
+
}) {
|
|
362
|
+
constructor() {
|
|
363
|
+
super();
|
|
364
|
+
this.transparent = true;
|
|
365
|
+
this.depthWrite = false;
|
|
366
|
+
this.opacity = 0;
|
|
367
|
+
this.alphaTest = 0.75;
|
|
368
|
+
this.map = new THREE.Texture();
|
|
369
|
+
this.alphaTestNode = float(0);
|
|
370
|
+
this._buildShader();
|
|
371
|
+
}
|
|
372
|
+
_buildShader() {
|
|
373
|
+
const { shadowColor, blend } = this.uniforms;
|
|
374
|
+
const map = materialReference("map", "texture", this);
|
|
375
|
+
this.colorNode = Fn(() => {
|
|
376
|
+
const sampled = context$a(map, { getUV: () => uv() });
|
|
377
|
+
const rgb = shadowColor.mul(sampled.r).mul(blend);
|
|
378
|
+
const sum = sampled.r.add(sampled.g).add(sampled.b);
|
|
379
|
+
const alpha = max(float(0), float(1).sub(sum.div(materialAlphaTest)));
|
|
380
|
+
return vec4(rgb, alpha);
|
|
381
|
+
})();
|
|
242
382
|
}
|
|
243
383
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
384
|
+
class ProgressiveShadowMaterial extends withUniforms(MeshPhongNodeMaterial, {
|
|
385
|
+
/** Accumulation buffer from the previous frame, blended with the current shading */
|
|
386
|
+
previousShadowMap: () => uniformTexture(new THREE.Texture()),
|
|
387
|
+
/** Mix 1/averagingWindow of the new shading into the accumulated frames */
|
|
388
|
+
averagingWindow: () => uniform(100)
|
|
389
|
+
}) {
|
|
390
|
+
constructor(initialTexture) {
|
|
391
|
+
super();
|
|
392
|
+
this.previousShadowMap = initialTexture;
|
|
393
|
+
this.fog = false;
|
|
394
|
+
this._buildShader();
|
|
395
|
+
}
|
|
396
|
+
_buildShader() {
|
|
397
|
+
const { previousShadowMap, averagingWindow } = this.uniforms;
|
|
398
|
+
const uvNode = uv();
|
|
399
|
+
this.vertexNode = vec4(sub(uvNode, vec2$2(0.5)).mul(2), 1, 1);
|
|
400
|
+
this.outputNode = vec4(mix(previousShadowMap.sample(uv()), output, float(1).div(averagingWindow)));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
class ProgressiveLightMap {
|
|
404
|
+
renderer;
|
|
405
|
+
res;
|
|
406
|
+
scene;
|
|
407
|
+
object;
|
|
408
|
+
buffer1Active;
|
|
409
|
+
progressiveLightMap1;
|
|
410
|
+
progressiveLightMap2;
|
|
411
|
+
discardMat;
|
|
412
|
+
targetMat;
|
|
413
|
+
clearColor;
|
|
414
|
+
clearAlpha;
|
|
415
|
+
lights;
|
|
416
|
+
meshes;
|
|
417
|
+
constructor(renderer, scene, res = 1024) {
|
|
418
|
+
this.renderer = renderer;
|
|
419
|
+
this.res = res;
|
|
420
|
+
this.scene = scene;
|
|
421
|
+
this.buffer1Active = false;
|
|
422
|
+
this.lights = [];
|
|
423
|
+
this.meshes = [];
|
|
424
|
+
this.object = null;
|
|
425
|
+
this.clearColor = new THREE.Color();
|
|
426
|
+
this.clearAlpha = 0;
|
|
427
|
+
const textureParams = {
|
|
428
|
+
type: THREE.HalfFloatType,
|
|
429
|
+
magFilter: THREE.NearestFilter,
|
|
430
|
+
minFilter: THREE.NearestFilter
|
|
431
|
+
};
|
|
432
|
+
this.progressiveLightMap1 = new RenderTarget(this.res, this.res, textureParams);
|
|
433
|
+
this.progressiveLightMap2 = new RenderTarget(this.res, this.res, textureParams);
|
|
434
|
+
this.discardMat = DiscardMaterial;
|
|
435
|
+
this.targetMat = new ProgressiveShadowMaterial(this.progressiveLightMap1.texture);
|
|
436
|
+
}
|
|
437
|
+
clear() {
|
|
438
|
+
this.renderer.getClearColor(this.clearColor);
|
|
439
|
+
this.clearAlpha = this.renderer.getClearAlpha();
|
|
440
|
+
this.renderer.setClearColor("black", 1);
|
|
441
|
+
this.renderer.setRenderTarget(this.progressiveLightMap1);
|
|
442
|
+
this.renderer.clear();
|
|
443
|
+
this.renderer.setRenderTarget(this.progressiveLightMap2);
|
|
444
|
+
this.renderer.clear();
|
|
445
|
+
this.renderer.setRenderTarget(null);
|
|
446
|
+
this.renderer.setClearColor(this.clearColor, this.clearAlpha);
|
|
447
|
+
this.lights = [];
|
|
448
|
+
this.meshes = [];
|
|
449
|
+
this.scene.traverse((object) => {
|
|
450
|
+
if (isGeometry$1(object)) {
|
|
451
|
+
this.meshes.push({ object, material: object.material });
|
|
452
|
+
} else if (isLight(object)) {
|
|
453
|
+
this.lights.push({ object, intensity: object.intensity });
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
prepare() {
|
|
458
|
+
this.lights.forEach((light) => light.object.intensity = 0);
|
|
459
|
+
this.meshes.forEach((mesh) => mesh.object.material = this.discardMat);
|
|
460
|
+
}
|
|
461
|
+
finish() {
|
|
462
|
+
this.lights.forEach((light) => light.object.intensity = light.intensity);
|
|
463
|
+
this.meshes.forEach((mesh) => mesh.object.material = mesh.material);
|
|
464
|
+
}
|
|
465
|
+
configure(object) {
|
|
466
|
+
this.object = object;
|
|
467
|
+
}
|
|
468
|
+
update(camera, blendWindow = 100) {
|
|
469
|
+
if (!this.object) return;
|
|
470
|
+
this.targetMat.averagingWindow = blendWindow;
|
|
471
|
+
const originalMaterial = this.object.material;
|
|
472
|
+
this.object.material = this.targetMat;
|
|
473
|
+
const oldFrustumCulled = this.object.frustumCulled;
|
|
474
|
+
this.object.frustumCulled = false;
|
|
475
|
+
const activeMap = this.buffer1Active ? this.progressiveLightMap1 : this.progressiveLightMap2;
|
|
476
|
+
const inactiveMap = this.buffer1Active ? this.progressiveLightMap2 : this.progressiveLightMap1;
|
|
477
|
+
const oldBg = this.scene.background;
|
|
478
|
+
this.scene.background = null;
|
|
479
|
+
this.renderer.setRenderTarget(activeMap);
|
|
480
|
+
this.targetMat.previousShadowMap = inactiveMap.texture;
|
|
481
|
+
this.buffer1Active = !this.buffer1Active;
|
|
482
|
+
this.renderer.render(this.scene, camera);
|
|
483
|
+
this.renderer.setRenderTarget(null);
|
|
484
|
+
this.scene.background = oldBg;
|
|
485
|
+
this.object.frustumCulled = oldFrustumCulled;
|
|
486
|
+
this.object.material = originalMaterial;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
const AccumulativeShadows = /* @__PURE__ */ React.forwardRef(
|
|
490
|
+
({
|
|
491
|
+
children,
|
|
492
|
+
temporal,
|
|
493
|
+
frames = 40,
|
|
494
|
+
limit = Infinity,
|
|
495
|
+
blend = 20,
|
|
496
|
+
scale = 10,
|
|
497
|
+
opacity = 1,
|
|
498
|
+
alphaTest = 0.75,
|
|
499
|
+
color = "black",
|
|
500
|
+
colorBlend = 2,
|
|
501
|
+
resolution = 1024,
|
|
502
|
+
toneMapped = true,
|
|
503
|
+
...props
|
|
504
|
+
}, forwardRef) => {
|
|
505
|
+
const gl = useThree((state) => state.gl);
|
|
506
|
+
const scene = useThree((state) => state.scene);
|
|
507
|
+
const camera = useThree((state) => state.camera);
|
|
508
|
+
const invalidate = useThree((state) => state.invalidate);
|
|
509
|
+
const gPlane = React.useRef(null);
|
|
510
|
+
const gLights = React.useRef(null);
|
|
511
|
+
const [softShadowMat] = React.useState(() => new SoftShadowMaterialImpl());
|
|
512
|
+
const [plm] = React.useState(() => new ProgressiveLightMap(gl, scene, resolution));
|
|
513
|
+
React.useLayoutEffect(() => {
|
|
514
|
+
plm.configure(gPlane.current);
|
|
515
|
+
}, [plm]);
|
|
516
|
+
React.useEffect(() => {
|
|
517
|
+
softShadowMat.shadowColor.set(color);
|
|
518
|
+
softShadowMat.blend = colorBlend;
|
|
519
|
+
softShadowMat.map = plm.progressiveLightMap2.texture;
|
|
520
|
+
softShadowMat.toneMapped = toneMapped;
|
|
521
|
+
}, [softShadowMat, color, colorBlend, plm, toneMapped]);
|
|
522
|
+
const api = React.useMemo(
|
|
523
|
+
() => ({
|
|
524
|
+
lights: /* @__PURE__ */ new Map(),
|
|
525
|
+
temporal: !!temporal,
|
|
526
|
+
frames: Math.max(2, frames),
|
|
527
|
+
blend: Math.max(2, frames === Infinity ? blend : frames),
|
|
528
|
+
count: 0,
|
|
529
|
+
getMesh: () => gPlane.current,
|
|
530
|
+
reset: () => {
|
|
531
|
+
plm.clear();
|
|
532
|
+
softShadowMat.opacity = 0;
|
|
533
|
+
softShadowMat.alphaTest = 0;
|
|
534
|
+
api.count = 0;
|
|
535
|
+
},
|
|
536
|
+
update: (frames2 = 1) => {
|
|
537
|
+
if (!api.temporal) {
|
|
538
|
+
softShadowMat.opacity = opacity;
|
|
539
|
+
softShadowMat.alphaTest = alphaTest;
|
|
540
|
+
} else {
|
|
541
|
+
softShadowMat.opacity = Math.min(opacity, softShadowMat.opacity + opacity / api.blend);
|
|
542
|
+
softShadowMat.alphaTest = Math.min(alphaTest, softShadowMat.alphaTest + alphaTest / api.blend);
|
|
543
|
+
}
|
|
544
|
+
gLights.current.visible = true;
|
|
545
|
+
plm.prepare();
|
|
546
|
+
for (let i = 0; i < frames2; i++) {
|
|
547
|
+
api.lights.forEach((light) => light.update());
|
|
548
|
+
plm.update(camera, api.blend);
|
|
549
|
+
}
|
|
550
|
+
gLights.current.visible = false;
|
|
551
|
+
plm.finish();
|
|
552
|
+
}
|
|
553
|
+
}),
|
|
554
|
+
[plm, camera, scene, temporal, frames, blend, opacity, alphaTest, softShadowMat]
|
|
555
|
+
);
|
|
556
|
+
React.useLayoutEffect(() => {
|
|
557
|
+
api.reset();
|
|
558
|
+
if (!api.temporal && api.frames !== Infinity) api.update(api.blend);
|
|
559
|
+
});
|
|
560
|
+
React.useImperativeHandle(forwardRef, () => api, [api]);
|
|
561
|
+
useFrame(() => {
|
|
562
|
+
if ((api.temporal || api.frames === Infinity) && api.count < api.frames && api.count < limit) {
|
|
563
|
+
invalidate();
|
|
564
|
+
api.update();
|
|
565
|
+
api.count++;
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
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" })));
|
|
569
|
+
}
|
|
570
|
+
);
|
|
571
|
+
const RandomizedLight = /* @__PURE__ */ React.forwardRef(
|
|
572
|
+
({
|
|
573
|
+
castShadow = true,
|
|
574
|
+
bias = 1e-3,
|
|
575
|
+
mapSize = 512,
|
|
576
|
+
size = 5,
|
|
577
|
+
near = 0.5,
|
|
578
|
+
far = 500,
|
|
579
|
+
frames = 1,
|
|
580
|
+
position = [0, 0, 0],
|
|
581
|
+
radius = 1,
|
|
582
|
+
amount = 8,
|
|
583
|
+
intensity = Math.PI,
|
|
584
|
+
ambient = 0.5,
|
|
585
|
+
...props
|
|
586
|
+
}, forwardRef) => {
|
|
587
|
+
const gLights = React.useRef(null);
|
|
588
|
+
const length = new THREE.Vector3(...position).length();
|
|
589
|
+
const parent = React.useContext(accumulativeContext);
|
|
590
|
+
const update = React.useCallback(() => {
|
|
591
|
+
let light;
|
|
592
|
+
if (gLights.current) {
|
|
593
|
+
for (let l = 0; l < gLights.current.children.length; l++) {
|
|
594
|
+
light = gLights.current.children[l];
|
|
595
|
+
if (Math.random() > ambient) {
|
|
596
|
+
light.position.set(
|
|
597
|
+
position[0] + THREE.MathUtils.randFloatSpread(radius),
|
|
598
|
+
position[1] + THREE.MathUtils.randFloatSpread(radius),
|
|
599
|
+
position[2] + THREE.MathUtils.randFloatSpread(radius)
|
|
600
|
+
);
|
|
601
|
+
} else {
|
|
602
|
+
let lambda = Math.acos(2 * Math.random() - 1) - Math.PI / 2;
|
|
603
|
+
let phi = 2 * Math.PI * Math.random();
|
|
604
|
+
light.position.set(
|
|
605
|
+
Math.cos(lambda) * Math.cos(phi) * length,
|
|
606
|
+
Math.abs(Math.cos(lambda) * Math.sin(phi) * length),
|
|
607
|
+
Math.sin(lambda) * length
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}, [radius, ambient, length, ...position]);
|
|
613
|
+
const api = React.useMemo(() => ({ update }), [update]);
|
|
614
|
+
React.useImperativeHandle(forwardRef, () => api, [api]);
|
|
615
|
+
React.useLayoutEffect(() => {
|
|
616
|
+
const group = gLights.current;
|
|
617
|
+
if (parent) parent.lights?.set(group.uuid, api);
|
|
618
|
+
return () => void parent?.lights?.delete(group.uuid);
|
|
619
|
+
}, [parent, api]);
|
|
620
|
+
return /* @__PURE__ */ React.createElement("group", { ref: gLights, ...props }, Array.from({ length: amount }, (_, index) => /* @__PURE__ */ React.createElement(
|
|
621
|
+
"directionalLight",
|
|
622
|
+
{
|
|
623
|
+
key: index,
|
|
624
|
+
castShadow,
|
|
625
|
+
"shadow-bias": bias,
|
|
626
|
+
"shadow-mapSize": [mapSize, mapSize],
|
|
627
|
+
intensity: intensity / amount
|
|
628
|
+
},
|
|
629
|
+
/* @__PURE__ */ React.createElement("orthographicCamera", { attach: "shadow-camera", args: [-size, size, size, -size, near, far] })
|
|
630
|
+
)));
|
|
631
|
+
}
|
|
632
|
+
);
|
|
256
633
|
|
|
257
634
|
function useFBO(width, height, settings) {
|
|
258
635
|
const size = useThree((state) => state.size);
|
|
@@ -350,19 +727,18 @@ const Edges = /* @__PURE__ */ React.forwardRef(
|
|
|
350
727
|
}
|
|
351
728
|
);
|
|
352
729
|
|
|
353
|
-
class CausticsProjectionMaterial extends MeshBasicNodeMaterial {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
730
|
+
class CausticsProjectionMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
731
|
+
/** Front-face caustics, rendered by CausticsMaterial */
|
|
732
|
+
causticsTexture: () => uniformTexture(new THREE.Texture()),
|
|
733
|
+
/** Back-face caustics, rendered by CausticsMaterial when `backside` is enabled */
|
|
734
|
+
causticsTextureB: () => uniformTexture(new THREE.Texture()),
|
|
735
|
+
/** Projection matrix of the light camera */
|
|
736
|
+
lightProjMatrix: () => uniform(new THREE.Matrix4()),
|
|
737
|
+
/** View matrix (matrixWorldInverse) of the light camera */
|
|
738
|
+
lightViewMatrix: () => uniform(new THREE.Matrix4())
|
|
739
|
+
}) {
|
|
359
740
|
constructor() {
|
|
360
741
|
super();
|
|
361
|
-
this._causticsTexture = uniformTexture(new THREE.Texture());
|
|
362
|
-
this._causticsTextureB = uniformTexture(new THREE.Texture());
|
|
363
|
-
this._color = uniform(new THREE.Color(1, 1, 1));
|
|
364
|
-
this._lightProjMatrix = uniform(new THREE.Matrix4());
|
|
365
|
-
this._lightViewMatrix = uniform(new THREE.Matrix4());
|
|
366
742
|
this.transparent = true;
|
|
367
743
|
this.blending = THREE.CustomBlending;
|
|
368
744
|
this.blendSrc = THREE.OneFactor;
|
|
@@ -371,100 +747,68 @@ class CausticsProjectionMaterial extends MeshBasicNodeMaterial {
|
|
|
371
747
|
this._buildShader();
|
|
372
748
|
}
|
|
373
749
|
_buildShader() {
|
|
374
|
-
const causticsTexture = this.
|
|
375
|
-
const causticsTextureB = this._causticsTextureB;
|
|
376
|
-
const colorUniform = this._color;
|
|
377
|
-
const lightProjMatrix = this._lightProjMatrix;
|
|
378
|
-
const lightViewMatrix = this._lightViewMatrix;
|
|
750
|
+
const { causticsTexture, causticsTextureB, lightProjMatrix, lightViewMatrix } = this.uniforms;
|
|
379
751
|
this.colorNode = Fn(() => {
|
|
380
752
|
const worldPos = positionWorld;
|
|
381
753
|
const worldPos4 = vec4(worldPos, 1);
|
|
382
754
|
const lightSpacePos = mul(lightProjMatrix, mul(lightViewMatrix, worldPos4)).toVar();
|
|
383
755
|
const xyz = lightSpacePos.xyz.div(lightSpacePos.w);
|
|
384
756
|
const lightUv = xyz.mul(0.5).add(0.5).xy;
|
|
385
|
-
const front =
|
|
386
|
-
const back =
|
|
387
|
-
return vec4(add(front, back).mul(
|
|
757
|
+
const front = causticsTexture.sample(lightUv).rgb;
|
|
758
|
+
const back = causticsTextureB.sample(lightUv).rgb;
|
|
759
|
+
return vec4(add(front, back).mul(materialColor), 1);
|
|
388
760
|
})();
|
|
389
761
|
}
|
|
390
|
-
//* Uniform Accessors ==============================
|
|
391
|
-
get causticsTexture() {
|
|
392
|
-
return this._causticsTexture.value;
|
|
393
|
-
}
|
|
394
|
-
set causticsTexture(v) {
|
|
395
|
-
this._causticsTexture.value = v;
|
|
396
|
-
}
|
|
397
|
-
get causticsTextureB() {
|
|
398
|
-
return this._causticsTextureB.value;
|
|
399
|
-
}
|
|
400
|
-
set causticsTextureB(v) {
|
|
401
|
-
this._causticsTextureB.value = v;
|
|
402
|
-
}
|
|
403
|
-
get color() {
|
|
404
|
-
return this._color.value;
|
|
405
|
-
}
|
|
406
|
-
set color(v) {
|
|
407
|
-
this._color.value = v;
|
|
408
|
-
}
|
|
409
|
-
get lightProjMatrix() {
|
|
410
|
-
return this._lightProjMatrix.value;
|
|
411
|
-
}
|
|
412
|
-
set lightProjMatrix(v) {
|
|
413
|
-
this._lightProjMatrix.value = v;
|
|
414
|
-
}
|
|
415
|
-
get lightViewMatrix() {
|
|
416
|
-
return this._lightViewMatrix.value;
|
|
417
|
-
}
|
|
418
|
-
set lightViewMatrix(v) {
|
|
419
|
-
this._lightViewMatrix.value = v;
|
|
420
|
-
}
|
|
421
762
|
}
|
|
422
|
-
class CausticsMaterial extends MeshBasicNodeMaterial {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
763
|
+
class CausticsMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
764
|
+
/** World matrix of the light camera */
|
|
765
|
+
cameraMatrixWorld: () => uniform(new THREE.Matrix4()),
|
|
766
|
+
/** Inverse projection matrix of the light camera, for depth reconstruction */
|
|
767
|
+
cameraProjectionMatrixInv: () => uniform(new THREE.Matrix4()),
|
|
768
|
+
/** World-space normals of the refractive geometry, rendered by CausticsNormalMaterial */
|
|
769
|
+
normalTexture: () => uniformTexture(new THREE.Texture()),
|
|
770
|
+
/** Depth of the refractive geometry, from the same render target as `normalTexture` */
|
|
771
|
+
depthTexture: () => uniformTexture(new THREE.Texture()),
|
|
772
|
+
/** Direction light travels in (inverse of the light position direction) */
|
|
773
|
+
lightDir: () => uniform(new THREE.Vector3(0, 1, 0)),
|
|
774
|
+
/** Normal of the receiving plane in light space */
|
|
775
|
+
lightPlaneNormal: () => uniform(new THREE.Vector3(0, 1, 0)),
|
|
776
|
+
/** Plane constant of the receiving plane */
|
|
777
|
+
lightPlaneConstant: () => uniform(0),
|
|
778
|
+
/** Light camera near plane */
|
|
779
|
+
near: () => uniform(0.1),
|
|
780
|
+
/** Light camera far plane */
|
|
781
|
+
far: () => uniform(100),
|
|
782
|
+
/** The texel size in world units */
|
|
783
|
+
worldRadius: () => uniform(1 / 40),
|
|
784
|
+
/** Refraction index of the surface */
|
|
785
|
+
ior: () => uniform(1.1),
|
|
786
|
+
/** Buffer resolution in pixels */
|
|
787
|
+
resolution: () => uniform(1024),
|
|
788
|
+
/** Half-extent of the light camera frustum */
|
|
789
|
+
size: () => uniform(10),
|
|
790
|
+
/** Intensity of the projected caustics */
|
|
791
|
+
intensity: () => uniform(0.5)
|
|
792
|
+
}) {
|
|
437
793
|
constructor() {
|
|
438
794
|
super();
|
|
439
|
-
this._cameraMatrixWorld = uniform(new THREE.Matrix4());
|
|
440
|
-
this._cameraProjectionMatrixInv = uniform(new THREE.Matrix4());
|
|
441
|
-
this._normalTexture = uniformTexture(new THREE.Texture());
|
|
442
|
-
this._depthTexture = uniformTexture(new THREE.Texture());
|
|
443
|
-
this._lightDir = uniform(new THREE.Vector3(0, 1, 0));
|
|
444
|
-
this._lightPlaneNormal = uniform(new THREE.Vector3(0, 1, 0));
|
|
445
|
-
this._lightPlaneConstant = uniform(0);
|
|
446
|
-
this._near = uniform(0.1);
|
|
447
|
-
this._far = uniform(100);
|
|
448
|
-
this._worldRadius = uniform(1 / 40);
|
|
449
|
-
this._ior = uniform(1.1);
|
|
450
|
-
this._resolution = uniform(1024);
|
|
451
|
-
this._size = uniform(10);
|
|
452
|
-
this._intensity = uniform(0.5);
|
|
453
795
|
this._buildShader();
|
|
454
796
|
}
|
|
455
797
|
_buildShader() {
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
798
|
+
const {
|
|
799
|
+
cameraMatrixWorld,
|
|
800
|
+
cameraProjectionMatrixInv,
|
|
801
|
+
normalTexture,
|
|
802
|
+
depthTexture,
|
|
803
|
+
lightDir,
|
|
804
|
+
lightPlaneNormal,
|
|
805
|
+
lightPlaneConstant,
|
|
806
|
+
worldRadius,
|
|
807
|
+
ior,
|
|
808
|
+
resolution,
|
|
809
|
+
size,
|
|
810
|
+
intensity
|
|
811
|
+
} = this.uniforms;
|
|
468
812
|
const worldPosFromDepth = Fn(({ depth, coord }) => {
|
|
469
813
|
const z = depth.mul(2).sub(1);
|
|
470
814
|
const clipSpacePos = vec4(coord.mul(2).sub(1), z, 1);
|
|
@@ -491,7 +835,7 @@ class CausticsMaterial extends MeshBasicNodeMaterial {
|
|
|
491
835
|
);
|
|
492
836
|
this.colorNode = Fn(() => {
|
|
493
837
|
const baseUv = uv();
|
|
494
|
-
const centerDepth =
|
|
838
|
+
const centerDepth = depthTexture.sample(baseUv).x;
|
|
495
839
|
const causticTexelSize = div(float(1), resolution).mul(size).mul(2);
|
|
496
840
|
const texelsNeeded = div(worldRadius, causticTexelSize);
|
|
497
841
|
const sampleRadius = div(texelsNeeded, resolution);
|
|
@@ -503,14 +847,14 @@ class CausticsMaterial extends MeshBasicNodeMaterial {
|
|
|
503
847
|
const uv2 = add(baseUv, mul(offset2, sampleRadius));
|
|
504
848
|
const uv3 = add(baseUv, mul(offset3, sampleRadius));
|
|
505
849
|
const uv4 = add(baseUv, mul(offset4, sampleRadius));
|
|
506
|
-
const normal1 = sub(mul(
|
|
507
|
-
const normal2 = sub(mul(
|
|
508
|
-
const normal3 = sub(mul(
|
|
509
|
-
const normal4 = sub(mul(
|
|
510
|
-
const depth1 =
|
|
511
|
-
const depth2 =
|
|
512
|
-
const depth3 =
|
|
513
|
-
const depth4 =
|
|
850
|
+
const normal1 = sub(mul(normalTexture.sample(uv1).rgb, 2), 1);
|
|
851
|
+
const normal2 = sub(mul(normalTexture.sample(uv2).rgb, 2), 1);
|
|
852
|
+
const normal3 = sub(mul(normalTexture.sample(uv3).rgb, 2), 1);
|
|
853
|
+
const normal4 = sub(mul(normalTexture.sample(uv4).rgb, 2), 1);
|
|
854
|
+
const depth1 = depthTexture.sample(uv1).x;
|
|
855
|
+
const depth2 = depthTexture.sample(uv2).x;
|
|
856
|
+
const depth3 = depthTexture.sample(uv3).x;
|
|
857
|
+
const depth4 = depthTexture.sample(uv4).x;
|
|
514
858
|
const pos1 = worldPosFromDepth({ depth: depth1, coord: uv1 });
|
|
515
859
|
const pos2 = worldPosFromDepth({ depth: depth2, coord: uv2 });
|
|
516
860
|
const pos3 = worldPosFromDepth({ depth: depth3, coord: uv3 });
|
|
@@ -549,91 +893,6 @@ class CausticsMaterial extends MeshBasicNodeMaterial {
|
|
|
549
893
|
return vec4(vec3(finalCaustic), 1);
|
|
550
894
|
})();
|
|
551
895
|
}
|
|
552
|
-
//* Uniform Accessors ==============================
|
|
553
|
-
get cameraMatrixWorld() {
|
|
554
|
-
return this._cameraMatrixWorld.value;
|
|
555
|
-
}
|
|
556
|
-
set cameraMatrixWorld(v) {
|
|
557
|
-
this._cameraMatrixWorld.value = v;
|
|
558
|
-
}
|
|
559
|
-
get cameraProjectionMatrixInv() {
|
|
560
|
-
return this._cameraProjectionMatrixInv.value;
|
|
561
|
-
}
|
|
562
|
-
set cameraProjectionMatrixInv(v) {
|
|
563
|
-
this._cameraProjectionMatrixInv.value = v;
|
|
564
|
-
}
|
|
565
|
-
get normalTexture() {
|
|
566
|
-
return this._normalTexture.value;
|
|
567
|
-
}
|
|
568
|
-
set normalTexture(v) {
|
|
569
|
-
this._normalTexture.value = v ?? new THREE.Texture();
|
|
570
|
-
}
|
|
571
|
-
get depthTexture() {
|
|
572
|
-
return this._depthTexture.value;
|
|
573
|
-
}
|
|
574
|
-
set depthTexture(v) {
|
|
575
|
-
this._depthTexture.value = v ?? new THREE.Texture();
|
|
576
|
-
}
|
|
577
|
-
get lightDir() {
|
|
578
|
-
return this._lightDir.value;
|
|
579
|
-
}
|
|
580
|
-
set lightDir(v) {
|
|
581
|
-
this._lightDir.value = v;
|
|
582
|
-
}
|
|
583
|
-
get lightPlaneNormal() {
|
|
584
|
-
return this._lightPlaneNormal.value;
|
|
585
|
-
}
|
|
586
|
-
set lightPlaneNormal(v) {
|
|
587
|
-
this._lightPlaneNormal.value = v;
|
|
588
|
-
}
|
|
589
|
-
get lightPlaneConstant() {
|
|
590
|
-
return this._lightPlaneConstant.value;
|
|
591
|
-
}
|
|
592
|
-
set lightPlaneConstant(v) {
|
|
593
|
-
this._lightPlaneConstant.value = v;
|
|
594
|
-
}
|
|
595
|
-
get near() {
|
|
596
|
-
return this._near.value;
|
|
597
|
-
}
|
|
598
|
-
set near(v) {
|
|
599
|
-
this._near.value = v;
|
|
600
|
-
}
|
|
601
|
-
get far() {
|
|
602
|
-
return this._far.value;
|
|
603
|
-
}
|
|
604
|
-
set far(v) {
|
|
605
|
-
this._far.value = v;
|
|
606
|
-
}
|
|
607
|
-
get worldRadius() {
|
|
608
|
-
return this._worldRadius.value;
|
|
609
|
-
}
|
|
610
|
-
set worldRadius(v) {
|
|
611
|
-
this._worldRadius.value = v;
|
|
612
|
-
}
|
|
613
|
-
get ior() {
|
|
614
|
-
return this._ior.value;
|
|
615
|
-
}
|
|
616
|
-
set ior(v) {
|
|
617
|
-
this._ior.value = v;
|
|
618
|
-
}
|
|
619
|
-
get resolution() {
|
|
620
|
-
return this._resolution.value;
|
|
621
|
-
}
|
|
622
|
-
set resolution(v) {
|
|
623
|
-
this._resolution.value = v;
|
|
624
|
-
}
|
|
625
|
-
get size() {
|
|
626
|
-
return this._size.value;
|
|
627
|
-
}
|
|
628
|
-
set size(v) {
|
|
629
|
-
this._size.value = v;
|
|
630
|
-
}
|
|
631
|
-
get intensity() {
|
|
632
|
-
return this._intensity.value;
|
|
633
|
-
}
|
|
634
|
-
set intensity(v) {
|
|
635
|
-
this._intensity.value = v;
|
|
636
|
-
}
|
|
637
896
|
}
|
|
638
897
|
class CausticsNormalMaterial extends MeshNormalNodeMaterial {
|
|
639
898
|
constructor(side = THREE.FrontSide) {
|
|
@@ -645,225 +904,376 @@ class CausticsNormalMaterial extends MeshNormalNodeMaterial {
|
|
|
645
904
|
}
|
|
646
905
|
}
|
|
647
906
|
|
|
648
|
-
const
|
|
649
|
-
|
|
907
|
+
const EnvironmentBRDF = /* @__PURE__ */ Fn((inputs) => {
|
|
908
|
+
const { dotNV, specularColor, specularF90, roughness: roughness2 } = inputs;
|
|
909
|
+
const fab = DFGLUT({ dotNV, roughness: roughness2 });
|
|
910
|
+
return specularColor.mul(fab.x).add(specularF90.mul(fab.y));
|
|
650
911
|
});
|
|
651
|
-
|
|
652
|
-
const
|
|
912
|
+
const rand = /* @__PURE__ */ Fn((inputs) => {
|
|
913
|
+
const [seed, fragCoord] = inputs;
|
|
653
914
|
return fract(sin(dot(vec3(fragCoord.xy, seed), vec3(12.9898, 78.233, 45.164))).mul(43758.5453));
|
|
654
915
|
});
|
|
655
|
-
const applyVolumeAttenuation = /* @__PURE__ */ Fn(
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
)
|
|
669
|
-
|
|
670
|
-
|
|
916
|
+
const applyVolumeAttenuation = /* @__PURE__ */ Fn((inputs) => {
|
|
917
|
+
const [radiance, transmissionDistance, attColor, attDistance] = inputs;
|
|
918
|
+
const isInfinite = attDistance.greaterThan(1e10);
|
|
919
|
+
const safeColor = max(attColor, vec3(1e-4));
|
|
920
|
+
const attenuationCoefficient = log(safeColor).negate().div(attDistance);
|
|
921
|
+
const transmittance = exp(attenuationCoefficient.negate().mul(transmissionDistance));
|
|
922
|
+
return select(isInfinite, radiance, transmittance.mul(radiance));
|
|
923
|
+
});
|
|
924
|
+
const getVolumeTransmissionRay = /* @__PURE__ */ Fn((inputs) => {
|
|
925
|
+
const [n, v, thicknessVal, iorVal] = inputs;
|
|
926
|
+
const refractionVector = refract(v.negate(), normalize(n), float(1).div(iorVal));
|
|
927
|
+
const refractLen = length(refractionVector);
|
|
928
|
+
const safeRefractionVector = select(
|
|
929
|
+
refractLen.greaterThan(1e-3),
|
|
930
|
+
refractionVector,
|
|
931
|
+
v.negate()
|
|
932
|
+
// Fallback: ray goes straight through
|
|
933
|
+
);
|
|
934
|
+
const modelScale = vec3(
|
|
935
|
+
length(modelWorldMatrix[0].xyz),
|
|
936
|
+
length(modelWorldMatrix[1].xyz),
|
|
937
|
+
length(modelWorldMatrix[2].xyz)
|
|
938
|
+
);
|
|
939
|
+
return normalize(safeRefractionVector).mul(thicknessVal.mul(modelScale));
|
|
940
|
+
});
|
|
941
|
+
const getRefractionUV = /* @__PURE__ */ Fn((inputs) => {
|
|
942
|
+
const [norm, viewDir, iorVal, thicknessVal, position] = inputs;
|
|
943
|
+
const transmissionRay = getVolumeTransmissionRay(norm, viewDir, thicknessVal, iorVal);
|
|
944
|
+
const refractedRayExit = position.add(transmissionRay);
|
|
945
|
+
const ndcPos = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(refractedRayExit, 1)));
|
|
946
|
+
const safeW = max(ndcPos.w, float(1e-3));
|
|
947
|
+
const refractionCoords = vec2$2(ndcPos.xy.div(safeW)).toVar();
|
|
948
|
+
refractionCoords.addAssign(1);
|
|
949
|
+
refractionCoords.divAssign(2);
|
|
950
|
+
refractionCoords.assign(vec2$2(refractionCoords.x, refractionCoords.y.oneMinus()));
|
|
951
|
+
refractionCoords.assign(refractionCoords.clamp(1e-3, 0.999));
|
|
952
|
+
return refractionCoords;
|
|
953
|
+
});
|
|
954
|
+
class TransmissionLightingModel extends PhysicalLightingModel {
|
|
955
|
+
_bufferTex;
|
|
671
956
|
_chromaticAberration;
|
|
672
957
|
_anisotropicBlur;
|
|
673
|
-
|
|
958
|
+
_timeUniform;
|
|
674
959
|
_distortion;
|
|
675
960
|
_distortionScale;
|
|
676
961
|
_temporalDistortion;
|
|
677
|
-
_buffer;
|
|
678
|
-
_transmissionValue;
|
|
679
|
-
_attenuationDistance;
|
|
680
|
-
_attenuationColor;
|
|
681
962
|
_samples;
|
|
682
|
-
|
|
963
|
+
_debugMode;
|
|
964
|
+
constructor(options, transmissionUniforms) {
|
|
965
|
+
super(
|
|
966
|
+
options.clearcoat ?? false,
|
|
967
|
+
options.sheen ?? false,
|
|
968
|
+
options.iridescence ?? false,
|
|
969
|
+
options.anisotropy ?? false,
|
|
970
|
+
true,
|
|
971
|
+
// transmission always true for our material
|
|
972
|
+
options.dispersion ?? false
|
|
973
|
+
);
|
|
974
|
+
this._bufferTex = transmissionUniforms.bufferTex;
|
|
975
|
+
this._chromaticAberration = transmissionUniforms.chromaticAberration;
|
|
976
|
+
this._anisotropicBlur = transmissionUniforms.anisotropicBlur;
|
|
977
|
+
this._timeUniform = transmissionUniforms.timeUniform;
|
|
978
|
+
this._distortion = transmissionUniforms.distortion;
|
|
979
|
+
this._distortionScale = transmissionUniforms.distortionScale;
|
|
980
|
+
this._temporalDistortion = transmissionUniforms.temporalDistortion;
|
|
981
|
+
this._samples = transmissionUniforms.samples;
|
|
982
|
+
this._debugMode = transmissionUniforms.debugMode;
|
|
983
|
+
}
|
|
984
|
+
start(builder) {
|
|
985
|
+
if (this.clearcoat === true) {
|
|
986
|
+
this.clearcoatRadiance = vec3().toVar("clearcoatRadiance");
|
|
987
|
+
this.clearcoatSpecularDirect = vec3().toVar("clearcoatSpecularDirect");
|
|
988
|
+
this.clearcoatSpecularIndirect = vec3().toVar("clearcoatSpecularIndirect");
|
|
989
|
+
}
|
|
990
|
+
if (this.sheen === true) {
|
|
991
|
+
this.sheenSpecularDirect = vec3().toVar("sheenSpecularDirect");
|
|
992
|
+
this.sheenSpecularIndirect = vec3().toVar("sheenSpecularIndirect");
|
|
993
|
+
}
|
|
994
|
+
if (this.transmission === true) {
|
|
995
|
+
const position = positionWorld;
|
|
996
|
+
const v = normalize(cameraPosition.sub(positionWorld));
|
|
997
|
+
const n = normalWorld;
|
|
998
|
+
const context = builder.context;
|
|
999
|
+
const bufferTex = this._bufferTex;
|
|
1000
|
+
const chromaticAberrationUniform = this._chromaticAberration;
|
|
1001
|
+
const anisotropicBlurUniform = this._anisotropicBlur;
|
|
1002
|
+
const timeUniform = this._timeUniform;
|
|
1003
|
+
const distortionUniform = this._distortion;
|
|
1004
|
+
const distortionScaleUniform = this._distortionScale;
|
|
1005
|
+
const temporalDistortionUniform = this._temporalDistortion;
|
|
1006
|
+
const sampleCount = this._samples;
|
|
1007
|
+
const debugModeUniform = this._debugMode;
|
|
1008
|
+
const getCustomTransmission = Fn(() => {
|
|
1009
|
+
const transmissionAccum = vec3(0).toVar("transmissionAccum");
|
|
1010
|
+
const fragCoord = screenCoordinate.xy;
|
|
1011
|
+
const runningSeed = float(0).toVar("runningSeed");
|
|
1012
|
+
const randomCoords = rand(runningSeed, fragCoord);
|
|
1013
|
+
runningSeed.addAssign(1);
|
|
1014
|
+
const temporalOffset = vec3(timeUniform, timeUniform.negate(), timeUniform.negate()).mul(
|
|
1015
|
+
temporalDistortionUniform
|
|
1016
|
+
);
|
|
1017
|
+
const noiseInput = position.mul(distortionScaleUniform).add(temporalOffset);
|
|
1018
|
+
const distortionNormal = select(
|
|
1019
|
+
distortionUniform.greaterThan(0),
|
|
1020
|
+
mx_fractal_noise_vec3(noiseInput, int(4), float(2), float(0.5)).mul(distortionUniform),
|
|
1021
|
+
vec3(0)
|
|
1022
|
+
);
|
|
1023
|
+
const thicknessSmear = thickness.mul(max(pow(roughness, 0.33), anisotropicBlurUniform));
|
|
1024
|
+
Loop(sampleCount, ({ i }) => {
|
|
1025
|
+
const fi = float(i);
|
|
1026
|
+
const progress = fi.add(randomCoords).div(float(sampleCount));
|
|
1027
|
+
const randX = rand(runningSeed, fragCoord).sub(0.5);
|
|
1028
|
+
runningSeed.addAssign(1);
|
|
1029
|
+
const randY = rand(runningSeed, fragCoord).sub(0.5);
|
|
1030
|
+
runningSeed.addAssign(1);
|
|
1031
|
+
const randZ = rand(runningSeed, fragCoord).sub(0.5);
|
|
1032
|
+
runningSeed.addAssign(1);
|
|
1033
|
+
const randW = rand(runningSeed, fragCoord);
|
|
1034
|
+
runningSeed.addAssign(1);
|
|
1035
|
+
const randomDir = normalize(vec3(randX, randY, randZ)).mul(pow(randW, 0.33));
|
|
1036
|
+
const sampleNorm = normalize(n.add(roughness.mul(roughness).mul(2).mul(randomDir)).add(distortionNormal));
|
|
1037
|
+
const sampleThickness = thickness.add(thicknessSmear.mul(progress));
|
|
1038
|
+
const iorR = ior;
|
|
1039
|
+
const iorG = ior.mul(float(1).add(chromaticAberrationUniform.mul(progress)));
|
|
1040
|
+
const iorB = ior.mul(float(1).add(chromaticAberrationUniform.mul(2).mul(progress)));
|
|
1041
|
+
const uvR = getRefractionUV(sampleNorm, v, iorR, sampleThickness, position);
|
|
1042
|
+
const uvG = getRefractionUV(sampleNorm, v, iorG, sampleThickness, position);
|
|
1043
|
+
const uvB = getRefractionUV(sampleNorm, v, iorB, sampleThickness, position);
|
|
1044
|
+
const sampleR = bufferTex.sample(uvR);
|
|
1045
|
+
const sampleG = bufferTex.sample(uvG);
|
|
1046
|
+
const sampleB = bufferTex.sample(uvB);
|
|
1047
|
+
transmissionAccum.x.addAssign(sampleR.r);
|
|
1048
|
+
transmissionAccum.y.addAssign(sampleG.g);
|
|
1049
|
+
transmissionAccum.z.addAssign(sampleB.b);
|
|
1050
|
+
});
|
|
1051
|
+
const avgTransmission = transmissionAccum.div(float(sampleCount));
|
|
1052
|
+
const debugUV = getRefractionUV(n, v, ior, thickness, position);
|
|
1053
|
+
const debugNdotV = n.dot(v);
|
|
1054
|
+
const isNeg = debugNdotV.lessThan(0);
|
|
1055
|
+
const sampleUVFlipped = vec2$2(screenUV.x, screenUV.y.oneMinus()).clamp(1e-3, 0.999);
|
|
1056
|
+
const directSampleFlipped = bufferTex.sample(sampleUVFlipped);
|
|
1057
|
+
const testRay = getVolumeTransmissionRay(n, v, thickness, ior);
|
|
1058
|
+
const rayLen = length(testRay);
|
|
1059
|
+
const manualUV = screenCoordinate.xy.div(screenSize);
|
|
1060
|
+
const noFlipUV = screenUV.clamp(1e-3, 0.999);
|
|
1061
|
+
const flippedUV = vec2$2(screenUV.x, screenUV.y.oneMinus()).clamp(1e-3, 0.999);
|
|
1062
|
+
const useFlipped = screenUV.x.greaterThan(0.5);
|
|
1063
|
+
const splitSampleUV = select(useFlipped, flippedUV, noFlipUV);
|
|
1064
|
+
const splitSample = bufferTex.sample(splitSampleUV);
|
|
1065
|
+
const directSampleNoFlip = bufferTex.sample(screenUV.clamp(1e-3, 0.999));
|
|
1066
|
+
const centerSample = bufferTex.sample(vec2$2(0.5, 0.5));
|
|
1067
|
+
const transmissionRayDbg = getVolumeTransmissionRay(n, v, thickness, ior);
|
|
1068
|
+
const refractedRayExitDbg = position.add(transmissionRayDbg);
|
|
1069
|
+
const ndcPosDbg = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(refractedRayExitDbg, 1)));
|
|
1070
|
+
const safeWDbg = max(ndcPosDbg.w, float(1e-3));
|
|
1071
|
+
const rawCoordsDbg = vec2$2(ndcPosDbg.xy.div(safeWDbg)).toVar();
|
|
1072
|
+
rawCoordsDbg.addAssign(1);
|
|
1073
|
+
rawCoordsDbg.divAssign(2);
|
|
1074
|
+
rawCoordsDbg.assign(vec2$2(rawCoordsDbg.x, rawCoordsDbg.y.oneMinus()));
|
|
1075
|
+
const outOfRange = rawCoordsDbg.x.lessThan(0).or(rawCoordsDbg.x.greaterThan(1)).or(rawCoordsDbg.y.lessThan(0)).or(rawCoordsDbg.y.greaterThan(1));
|
|
1076
|
+
const clipPosDbg = cameraProjectionMatrix.mul(cameraViewMatrix.mul(vec4(position, 1)));
|
|
1077
|
+
const safeWDbg2 = max(clipPosDbg.w, float(1e-3));
|
|
1078
|
+
const projUVDbg = vec2$2(clipPosDbg.xy.div(safeWDbg2)).toVar();
|
|
1079
|
+
projUVDbg.addAssign(1);
|
|
1080
|
+
projUVDbg.divAssign(2);
|
|
1081
|
+
projUVDbg.assign(vec2$2(projUVDbg.x, projUVDbg.y.oneMinus()));
|
|
1082
|
+
projUVDbg.assign(projUVDbg.clamp(1e-3, 0.999));
|
|
1083
|
+
const projectedSample = bufferTex.sample(projUVDbg);
|
|
1084
|
+
const wNorm = clipPosDbg.w.div(10).add(0.5).clamp(0, 1);
|
|
1085
|
+
const isBehind = clipPosDbg.w.lessThan(0);
|
|
1086
|
+
const rawNdcX = clipPosDbg.x.div(safeWDbg2);
|
|
1087
|
+
const rawNdcY = clipPosDbg.y.div(safeWDbg2);
|
|
1088
|
+
const result = vec4(0, 0, 0, 1).toVar();
|
|
1089
|
+
result.assign(
|
|
1090
|
+
select(
|
|
1091
|
+
debugModeUniform.equal(1),
|
|
1092
|
+
vec4(avgTransmission, float(1)),
|
|
1093
|
+
select(
|
|
1094
|
+
debugModeUniform.equal(2),
|
|
1095
|
+
vec4(debugUV.x, debugUV.y, float(0), float(1)),
|
|
1096
|
+
select(
|
|
1097
|
+
debugModeUniform.equal(3),
|
|
1098
|
+
vec4(
|
|
1099
|
+
select(isNeg, debugNdotV.abs(), float(0)),
|
|
1100
|
+
select(isNeg, float(0), debugNdotV),
|
|
1101
|
+
float(0),
|
|
1102
|
+
float(1)
|
|
1103
|
+
),
|
|
1104
|
+
select(
|
|
1105
|
+
debugModeUniform.equal(4),
|
|
1106
|
+
vec4(v.mul(0.5).add(0.5), float(1)),
|
|
1107
|
+
select(
|
|
1108
|
+
debugModeUniform.equal(5),
|
|
1109
|
+
vec4(n.mul(0.5).add(0.5), float(1)),
|
|
1110
|
+
select(
|
|
1111
|
+
debugModeUniform.equal(6),
|
|
1112
|
+
vec4(directSampleFlipped.rgb, float(1)),
|
|
1113
|
+
select(
|
|
1114
|
+
debugModeUniform.equal(7),
|
|
1115
|
+
vec4(rayLen, rayLen, rayLen, float(1)),
|
|
1116
|
+
select(
|
|
1117
|
+
debugModeUniform.equal(8),
|
|
1118
|
+
vec4(screenUV.x, screenUV.y, float(0), float(1)),
|
|
1119
|
+
select(
|
|
1120
|
+
debugModeUniform.equal(9),
|
|
1121
|
+
vec4(screenSize.x.div(2e3), screenSize.y.div(2e3), float(0), float(1)),
|
|
1122
|
+
select(
|
|
1123
|
+
debugModeUniform.equal(10),
|
|
1124
|
+
vec4(manualUV.x, manualUV.y, float(0), float(1)),
|
|
1125
|
+
select(
|
|
1126
|
+
debugModeUniform.equal(11),
|
|
1127
|
+
vec4(splitSample.rgb, float(1)),
|
|
1128
|
+
select(
|
|
1129
|
+
debugModeUniform.equal(12),
|
|
1130
|
+
vec4(directSampleNoFlip.rgb, float(1)),
|
|
1131
|
+
select(
|
|
1132
|
+
debugModeUniform.equal(13),
|
|
1133
|
+
vec4(
|
|
1134
|
+
select(outOfRange, float(1), float(0)),
|
|
1135
|
+
rawCoordsDbg.x.clamp(0, 1),
|
|
1136
|
+
rawCoordsDbg.y.clamp(0, 1),
|
|
1137
|
+
float(1)
|
|
1138
|
+
),
|
|
1139
|
+
select(
|
|
1140
|
+
debugModeUniform.equal(14),
|
|
1141
|
+
vec4(
|
|
1142
|
+
select(isBehind, float(1), float(0)),
|
|
1143
|
+
wNorm,
|
|
1144
|
+
select(isBehind, float(0), float(1)),
|
|
1145
|
+
float(1)
|
|
1146
|
+
),
|
|
1147
|
+
select(
|
|
1148
|
+
debugModeUniform.equal(15),
|
|
1149
|
+
vec4(centerSample.rgb, float(1)),
|
|
1150
|
+
select(
|
|
1151
|
+
debugModeUniform.equal(16),
|
|
1152
|
+
vec4(projectedSample.rgb, float(1)),
|
|
1153
|
+
select(
|
|
1154
|
+
debugModeUniform.equal(17),
|
|
1155
|
+
// Raw NDC as color: map [-1,1] to [0,1]
|
|
1156
|
+
vec4(rawNdcX.add(1).div(2), rawNdcY.add(1).div(2), float(0.5), float(1)),
|
|
1157
|
+
select(
|
|
1158
|
+
debugModeUniform.equal(18),
|
|
1159
|
+
// Solid magenta - if black here, shader isn't running
|
|
1160
|
+
vec4(1, 0, 1, 1),
|
|
1161
|
+
select(
|
|
1162
|
+
debugModeUniform.equal(19),
|
|
1163
|
+
// Tinted FBO sample: mix sample with UV color
|
|
1164
|
+
vec4(
|
|
1165
|
+
directSampleFlipped.r.add(screenUV.x.mul(0.3)),
|
|
1166
|
+
directSampleFlipped.g.add(screenUV.y.mul(0.3)),
|
|
1167
|
+
directSampleFlipped.b,
|
|
1168
|
+
float(1)
|
|
1169
|
+
),
|
|
1170
|
+
vec4(0, 0, 0, 1)
|
|
1171
|
+
// Placeholder for mode 0
|
|
1172
|
+
)
|
|
1173
|
+
)
|
|
1174
|
+
)
|
|
1175
|
+
)
|
|
1176
|
+
)
|
|
1177
|
+
)
|
|
1178
|
+
)
|
|
1179
|
+
)
|
|
1180
|
+
)
|
|
1181
|
+
)
|
|
1182
|
+
)
|
|
1183
|
+
)
|
|
1184
|
+
)
|
|
1185
|
+
)
|
|
1186
|
+
)
|
|
1187
|
+
)
|
|
1188
|
+
)
|
|
1189
|
+
)
|
|
1190
|
+
)
|
|
1191
|
+
);
|
|
1192
|
+
const attenuated = applyVolumeAttenuation(avgTransmission, thickness, attenuationColor, attenuationDistance);
|
|
1193
|
+
const NdotV = n.dot(v).abs().clamp(1e-3, 1);
|
|
1194
|
+
const glassF0 = vec3(0.04);
|
|
1195
|
+
const brdf = EnvironmentBRDF({ dotNV: NdotV, specularColor: glassF0, specularF90: float(1), roughness });
|
|
1196
|
+
const transmissionResult = brdf.oneMinus().mul(attenuated).mul(diffuseColor.rgb);
|
|
1197
|
+
const normalOutput = vec4(transmissionResult, float(1));
|
|
1198
|
+
return select(debugModeUniform.greaterThan(0), result, normalOutput);
|
|
1199
|
+
});
|
|
1200
|
+
context.backdrop = getCustomTransmission();
|
|
1201
|
+
context.backdropAlpha = transmission;
|
|
1202
|
+
diffuseColor.a.mulAssign(mix(1, context.backdrop.a, transmission));
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
function createPlaceholderTexture() {
|
|
1207
|
+
const placeholder = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);
|
|
1208
|
+
placeholder.needsUpdate = true;
|
|
1209
|
+
return placeholder;
|
|
1210
|
+
}
|
|
1211
|
+
class MeshTransmissionMaterialImpl extends withUniforms(MeshPhysicalNodeMaterial, {
|
|
1212
|
+
/** Chromatic aberration, default: 0.05 */
|
|
1213
|
+
chromaticAberration: () => uniform(0.05),
|
|
1214
|
+
/** Anisotropic blur, default: 0.1 */
|
|
1215
|
+
anisotropicBlur: () => uniform(0.1),
|
|
1216
|
+
/** Elapsed time, drives the temporal distortion */
|
|
1217
|
+
time: () => uniform(0),
|
|
1218
|
+
/** Distortion, default: 0 */
|
|
1219
|
+
distortion: () => uniform(0),
|
|
1220
|
+
/** Distortion scale, default: 0.5 */
|
|
1221
|
+
distortionScale: () => uniform(0.5),
|
|
1222
|
+
/** Temporal distortion (speed of movement), default: 0 */
|
|
1223
|
+
temporalDistortion: () => uniform(0),
|
|
1224
|
+
/** The scene rendered into a texture (use it to share a texture between materials) */
|
|
1225
|
+
buffer: () => uniformTexture(createPlaceholderTexture()),
|
|
1226
|
+
/** Debug mode for development (0 = normal, 1-19 = various debug outputs), default: 0 */
|
|
1227
|
+
debugMode: () => uniform(0)
|
|
1228
|
+
}) {
|
|
683
1229
|
/** Type flag for identification */
|
|
684
1230
|
isMeshTransmissionMaterial = true;
|
|
1231
|
+
_samples;
|
|
1232
|
+
_transmissionSampler;
|
|
685
1233
|
constructor(samples = 6, transmissionSampler = false) {
|
|
686
1234
|
super();
|
|
687
1235
|
this._samples = samples;
|
|
688
1236
|
this._transmissionSampler = transmissionSampler;
|
|
689
|
-
this.
|
|
690
|
-
this._anisotropicBlur = uniform(0.1);
|
|
691
|
-
this._time = uniform(0);
|
|
692
|
-
this._distortion = uniform(0);
|
|
693
|
-
this._distortionScale = uniform(0.5);
|
|
694
|
-
this._temporalDistortion = uniform(0);
|
|
695
|
-
this._buffer = uniformTexture(new THREE.Texture());
|
|
696
|
-
this._transmissionValue = uniform(1);
|
|
697
|
-
this._attenuationDistance = uniform(Infinity);
|
|
698
|
-
this._attenuationColor = uniform(new THREE.Color("white"));
|
|
699
|
-
this.transmission = transmissionSampler ? 1 : 0;
|
|
1237
|
+
this.transmission = 1;
|
|
700
1238
|
this.roughness = 0;
|
|
701
1239
|
this.thickness = 0;
|
|
702
|
-
this.
|
|
703
|
-
|
|
704
|
-
this._buildTransmissionShader();
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
_buildTransmissionShader() {
|
|
708
|
-
const chromaticAberrationUniform = this._chromaticAberration;
|
|
709
|
-
const anisotropicBlurUniform = this._anisotropicBlur;
|
|
710
|
-
const timeUniform = this._time;
|
|
711
|
-
const distortionUniform = this._distortion;
|
|
712
|
-
const distortionScaleUniform = this._distortionScale;
|
|
713
|
-
const temporalDistortionUniform = this._temporalDistortion;
|
|
714
|
-
const bufferTex = this._buffer;
|
|
715
|
-
const transmissionUniform = this._transmissionValue;
|
|
716
|
-
const attenuationDistanceUniform = this._attenuationDistance;
|
|
717
|
-
const attenuationColorUniform = this._attenuationColor;
|
|
718
|
-
const samples = this._samples;
|
|
719
|
-
const materialRef = this;
|
|
720
|
-
this.outputNode = Fn(() => {
|
|
721
|
-
const pos = positionWorld;
|
|
722
|
-
const fragCoord = screenCoordinate.xy;
|
|
723
|
-
const v = normalize(cameraPosition.sub(pos));
|
|
724
|
-
const n = normalWorld;
|
|
725
|
-
const transmission = vec3(0, 0, 0).toVar();
|
|
726
|
-
const runningSeed = float(0).toVar();
|
|
727
|
-
const randomCoords = rand({ seed: runningSeed, fragCoord });
|
|
728
|
-
runningSeed.addAssign(1);
|
|
729
|
-
const roughnessFactor = float(materialRef.roughness).toVar();
|
|
730
|
-
const thicknessVal = float(materialRef.thickness);
|
|
731
|
-
const iorVal = float(materialRef.ior);
|
|
732
|
-
const thicknessSmear = thicknessVal.mul(max(pow(roughnessFactor, 0.33), anisotropicBlurUniform));
|
|
733
|
-
const distortionNormal = vec3(0, 0, 0).toVar();
|
|
734
|
-
const distortEnabled = distortionUniform.greaterThan(0);
|
|
735
|
-
const temporalOffset = vec3(timeUniform, timeUniform.negate(), timeUniform.negate()).mul(
|
|
736
|
-
temporalDistortionUniform
|
|
737
|
-
);
|
|
738
|
-
const noiseInput = pos.mul(distortionScaleUniform).add(temporalOffset);
|
|
739
|
-
const noiseResult = mx_fractal_noise_vec3(noiseInput, int(4), float(2), float(0.5));
|
|
740
|
-
const computedDistortion = noiseResult.mul(distortionUniform);
|
|
741
|
-
distortionNormal.assign(select(distortEnabled, computedDistortion, vec3(0)));
|
|
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
|
-
})();
|
|
796
|
-
}
|
|
797
|
-
//* Uniform Accessors ==============================
|
|
798
|
-
/** Chromatic aberration strength, default: 0.05 */
|
|
799
|
-
get chromaticAberration() {
|
|
800
|
-
return this._chromaticAberration.value;
|
|
801
|
-
}
|
|
802
|
-
set chromaticAberration(v) {
|
|
803
|
-
this._chromaticAberration.value = v;
|
|
804
|
-
}
|
|
805
|
-
/** Anisotropic blur amount, default: 0.1 */
|
|
806
|
-
get anisotropicBlur() {
|
|
807
|
-
return this._anisotropicBlur.value;
|
|
808
|
-
}
|
|
809
|
-
set anisotropicBlur(v) {
|
|
810
|
-
this._anisotropicBlur.value = v;
|
|
811
|
-
}
|
|
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
|
-
get distortion() {
|
|
821
|
-
return this._distortion.value;
|
|
822
|
-
}
|
|
823
|
-
set distortion(v) {
|
|
824
|
-
this._distortion.value = v;
|
|
825
|
-
}
|
|
826
|
-
/** Distortion noise scale, default: 0.5 */
|
|
827
|
-
get distortionScale() {
|
|
828
|
-
return this._distortionScale.value;
|
|
829
|
-
}
|
|
830
|
-
set distortionScale(v) {
|
|
831
|
-
this._distortionScale.value = v;
|
|
832
|
-
}
|
|
833
|
-
/** Temporal distortion speed, default: 0 */
|
|
834
|
-
get temporalDistortion() {
|
|
835
|
-
return this._temporalDistortion.value;
|
|
836
|
-
}
|
|
837
|
-
set temporalDistortion(v) {
|
|
838
|
-
this._temporalDistortion.value = v;
|
|
839
|
-
}
|
|
840
|
-
/** Scene buffer texture for refraction sampling */
|
|
841
|
-
get buffer() {
|
|
842
|
-
return this._buffer.value;
|
|
843
|
-
}
|
|
844
|
-
set buffer(v) {
|
|
845
|
-
this._buffer.value = v ?? new THREE.Texture();
|
|
846
|
-
}
|
|
847
|
-
/** Internal transmission value (use transmission prop instead) */
|
|
848
|
-
get _transmission() {
|
|
849
|
-
return this._transmissionValue.value;
|
|
850
|
-
}
|
|
851
|
-
set _transmission(v) {
|
|
852
|
-
this._transmissionValue.value = v;
|
|
853
|
-
}
|
|
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;
|
|
1240
|
+
this.ior = 1.5;
|
|
1241
|
+
this.transparent = true;
|
|
864
1242
|
}
|
|
865
|
-
|
|
866
|
-
this.
|
|
1243
|
+
setupLightingModel() {
|
|
1244
|
+
if (this._transmissionSampler || !this.useTransmission) {
|
|
1245
|
+
return super.setupLightingModel();
|
|
1246
|
+
}
|
|
1247
|
+
const {
|
|
1248
|
+
buffer,
|
|
1249
|
+
chromaticAberration,
|
|
1250
|
+
anisotropicBlur,
|
|
1251
|
+
time,
|
|
1252
|
+
distortion,
|
|
1253
|
+
distortionScale,
|
|
1254
|
+
temporalDistortion,
|
|
1255
|
+
debugMode
|
|
1256
|
+
} = this.uniforms;
|
|
1257
|
+
return new TransmissionLightingModel(
|
|
1258
|
+
{
|
|
1259
|
+
clearcoat: this.useClearcoat,
|
|
1260
|
+
sheen: this.useSheen,
|
|
1261
|
+
iridescence: this.useIridescence,
|
|
1262
|
+
anisotropy: this.useAnisotropy,
|
|
1263
|
+
dispersion: this.useDispersion
|
|
1264
|
+
},
|
|
1265
|
+
{
|
|
1266
|
+
bufferTex: buffer,
|
|
1267
|
+
chromaticAberration,
|
|
1268
|
+
anisotropicBlur,
|
|
1269
|
+
timeUniform: time,
|
|
1270
|
+
distortion,
|
|
1271
|
+
distortionScale,
|
|
1272
|
+
temporalDistortion,
|
|
1273
|
+
samples: this._samples,
|
|
1274
|
+
debugMode
|
|
1275
|
+
}
|
|
1276
|
+
);
|
|
867
1277
|
}
|
|
868
1278
|
}
|
|
869
1279
|
const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
@@ -872,8 +1282,8 @@ const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
872
1282
|
transmissionSampler = false,
|
|
873
1283
|
backside = false,
|
|
874
1284
|
side = THREE.FrontSide,
|
|
875
|
-
transmission = 1,
|
|
876
|
-
thickness = 0,
|
|
1285
|
+
transmission: transmission2 = 1,
|
|
1286
|
+
thickness: thickness2 = 0,
|
|
877
1287
|
backsideThickness = 0,
|
|
878
1288
|
backsideEnvMapIntensity = 1,
|
|
879
1289
|
samples = 10,
|
|
@@ -882,48 +1292,111 @@ const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
882
1292
|
background,
|
|
883
1293
|
anisotropy,
|
|
884
1294
|
anisotropicBlur,
|
|
1295
|
+
debugMode = 0,
|
|
885
1296
|
...props
|
|
886
1297
|
}, fref) => {
|
|
887
1298
|
extend({ MeshTransmissionMaterial: MeshTransmissionMaterialImpl });
|
|
888
1299
|
const ref = React.useRef(null);
|
|
889
|
-
const
|
|
890
|
-
const
|
|
891
|
-
const
|
|
1300
|
+
const backsideMaterialRef = React.useRef(null);
|
|
1301
|
+
const { size, viewport } = useThree();
|
|
1302
|
+
const screenWidth = size.width * viewport.dpr;
|
|
1303
|
+
const screenHeight = size.height * viewport.dpr;
|
|
1304
|
+
const fboWidth = resolution || screenWidth;
|
|
1305
|
+
const fboHeight = resolution ? Math.round(resolution / screenWidth * screenHeight) : screenHeight;
|
|
1306
|
+
const fboBack = useFBO(
|
|
1307
|
+
backsideResolution || fboWidth,
|
|
1308
|
+
backsideResolution ? Math.round(backsideResolution / screenWidth * screenHeight) : fboHeight
|
|
1309
|
+
);
|
|
1310
|
+
const fboMain = useFBO(fboWidth, fboHeight);
|
|
1311
|
+
React.useEffect(() => {
|
|
1312
|
+
if (backside && ref.current && !backsideMaterialRef.current) {
|
|
1313
|
+
backsideMaterialRef.current = new MeshTransmissionMaterialImpl(samples, transmissionSampler);
|
|
1314
|
+
backsideMaterialRef.current.buffer = fboBack.texture;
|
|
1315
|
+
}
|
|
1316
|
+
return () => {
|
|
1317
|
+
if (backsideMaterialRef.current) {
|
|
1318
|
+
backsideMaterialRef.current.dispose();
|
|
1319
|
+
backsideMaterialRef.current = null;
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
}, [backside, samples, transmissionSampler]);
|
|
1323
|
+
React.useEffect(() => {
|
|
1324
|
+
if (backsideMaterialRef.current) {
|
|
1325
|
+
backsideMaterialRef.current.buffer = fboBack.texture;
|
|
1326
|
+
}
|
|
1327
|
+
}, [fboBack.texture]);
|
|
892
1328
|
let oldBg;
|
|
893
1329
|
let oldEnvMapIntensity;
|
|
894
1330
|
let oldTone;
|
|
895
1331
|
let parent;
|
|
896
1332
|
useFrame((state) => {
|
|
897
1333
|
ref.current.time = state.elapsed;
|
|
1334
|
+
const renderer = state.renderer;
|
|
1335
|
+
if (backsideMaterialRef.current) {
|
|
1336
|
+
backsideMaterialRef.current.time = state.elapsed;
|
|
1337
|
+
}
|
|
898
1338
|
if (ref.current.buffer === fboMain.texture && !transmissionSampler) {
|
|
899
1339
|
parent = ref.current.__r3f?.parent?.object;
|
|
900
|
-
if (parent)
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
1340
|
+
if (!parent) return;
|
|
1341
|
+
oldTone = renderer.toneMapping;
|
|
1342
|
+
oldBg = state.scene.background;
|
|
1343
|
+
oldEnvMapIntensity = ref.current.envMapIntensity;
|
|
1344
|
+
renderer.toneMapping = THREE.NoToneMapping;
|
|
1345
|
+
if (background)
|
|
1346
|
+
state.scene.background = background;
|
|
1347
|
+
parent.material = DiscardMaterial;
|
|
1348
|
+
const camera = state.camera;
|
|
1349
|
+
const isOrtho = camera.isOrthographicCamera;
|
|
1350
|
+
let oldLeft, oldRight, oldTop, oldBottom;
|
|
1351
|
+
if (isOrtho) {
|
|
1352
|
+
oldLeft = camera.left;
|
|
1353
|
+
oldRight = camera.right;
|
|
1354
|
+
oldTop = camera.top;
|
|
1355
|
+
oldBottom = camera.bottom;
|
|
1356
|
+
const fboAspect = fboWidth / fboHeight;
|
|
1357
|
+
const screenAspect = screenWidth / screenHeight;
|
|
1358
|
+
if (Math.abs(fboAspect - screenAspect) > 1e-3) {
|
|
1359
|
+
const viewHeight = oldTop - oldBottom;
|
|
1360
|
+
const newHalfWidth = viewHeight * fboAspect / 2;
|
|
1361
|
+
const centerX = (oldLeft + oldRight) / 2;
|
|
1362
|
+
camera.left = centerX - newHalfWidth;
|
|
1363
|
+
camera.right = centerX + newHalfWidth;
|
|
1364
|
+
camera.updateProjectionMatrix();
|
|
915
1365
|
}
|
|
916
|
-
|
|
917
|
-
|
|
1366
|
+
}
|
|
1367
|
+
if (backside && backsideMaterialRef.current) {
|
|
1368
|
+
renderer.setRenderTarget(fboBack);
|
|
1369
|
+
renderer.clear();
|
|
1370
|
+
state.renderer.render(state.scene, state.camera);
|
|
1371
|
+
parent.material = backsideMaterialRef.current;
|
|
1372
|
+
backsideMaterialRef.current.thickness = backsideThickness;
|
|
1373
|
+
backsideMaterialRef.current.side = THREE.BackSide;
|
|
1374
|
+
backsideMaterialRef.current.envMapIntensity = backsideEnvMapIntensity;
|
|
1375
|
+
renderer.setRenderTarget(fboMain);
|
|
1376
|
+
renderer.clear();
|
|
1377
|
+
state.renderer.render(state.scene, state.camera);
|
|
918
1378
|
parent.material = ref.current;
|
|
919
|
-
ref.current.thickness =
|
|
1379
|
+
ref.current.thickness = thickness2;
|
|
920
1380
|
ref.current.side = side;
|
|
921
|
-
ref.current.buffer = fboMain.texture;
|
|
922
1381
|
ref.current.envMapIntensity = oldEnvMapIntensity;
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1382
|
+
} else {
|
|
1383
|
+
renderer.setRenderTarget(fboMain);
|
|
1384
|
+
renderer.clear();
|
|
1385
|
+
state.renderer.render(state.scene, state.camera);
|
|
1386
|
+
parent.material = ref.current;
|
|
1387
|
+
ref.current.thickness = thickness2;
|
|
1388
|
+
ref.current.side = side;
|
|
926
1389
|
}
|
|
1390
|
+
if (isOrtho && Math.abs(fboWidth / fboHeight - screenWidth / screenHeight) > 1e-3) {
|
|
1391
|
+
camera.left = oldLeft;
|
|
1392
|
+
camera.right = oldRight;
|
|
1393
|
+
camera.top = oldTop;
|
|
1394
|
+
camera.bottom = oldBottom;
|
|
1395
|
+
camera.updateProjectionMatrix();
|
|
1396
|
+
}
|
|
1397
|
+
state.scene.background = oldBg;
|
|
1398
|
+
renderer.setRenderTarget(null);
|
|
1399
|
+
renderer.toneMapping = oldTone;
|
|
927
1400
|
}
|
|
928
1401
|
});
|
|
929
1402
|
React.useImperativeHandle(fref, () => ref.current, []);
|
|
@@ -934,33 +1407,46 @@ const MeshTransmissionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
934
1407
|
ref,
|
|
935
1408
|
...props,
|
|
936
1409
|
buffer: buffer || fboMain.texture,
|
|
937
|
-
|
|
938
|
-
anisotropicBlur: anisotropicBlur ?? anisotropy
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
1410
|
+
transmission: transmission2,
|
|
1411
|
+
anisotropicBlur: anisotropicBlur ?? anisotropy,
|
|
1412
|
+
thickness: thickness2,
|
|
1413
|
+
side,
|
|
1414
|
+
debugMode
|
|
942
1415
|
}
|
|
943
1416
|
);
|
|
944
1417
|
}
|
|
945
1418
|
);
|
|
946
1419
|
|
|
947
|
-
let MeshReflectorMaterial$1 = class MeshReflectorMaterial extends THREE.MeshStandardNodeMaterial {
|
|
1420
|
+
let MeshReflectorMaterial$1 = class MeshReflectorMaterial extends withUniforms(THREE.MeshStandardNodeMaterial, {
|
|
1421
|
+
/** Mirror strength, 0 = base material only, 1 = pure reflection */
|
|
1422
|
+
mirror: () => uniform(0),
|
|
1423
|
+
/** Positive values enable the blurred reflection sample */
|
|
1424
|
+
mixBlur: () => uniform(0),
|
|
1425
|
+
/** Strength of the reflection added on top of the base colour */
|
|
1426
|
+
mixStrength: () => uniform(1),
|
|
1427
|
+
/** Lower depth threshold for depth-based blur */
|
|
1428
|
+
minDepthThreshold: () => uniform(0.9),
|
|
1429
|
+
/** Upper depth threshold for depth-based blur */
|
|
1430
|
+
maxDepthThreshold: () => uniform(1),
|
|
1431
|
+
/** Depth scale for depth-based blur, 0 = disabled */
|
|
1432
|
+
depthScale: () => uniform(0),
|
|
1433
|
+
/** Bias added to the depth-to-blur ratio */
|
|
1434
|
+
depthToBlurRatioBias: () => uniform(0.25),
|
|
1435
|
+
/** Distortion strength */
|
|
1436
|
+
distortion: () => uniform(1),
|
|
1437
|
+
/** Contrast applied to the (clamped) reflection colour */
|
|
1438
|
+
mixContrast: () => uniform(1),
|
|
1439
|
+
/** Blur radius in the 0-1 range, scaled to 0.01-0.15 in the shader */
|
|
1440
|
+
blurRadius: () => uniform(0.1)
|
|
1441
|
+
}) {
|
|
948
1442
|
//* Reflector Node ----------------------------------------
|
|
949
1443
|
reflection;
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
depthScaleUniform;
|
|
957
|
-
depthToBlurRatioBiasUniform;
|
|
958
|
-
distortionUniform;
|
|
959
|
-
mixContrastUniform;
|
|
960
|
-
blurRadiusUniform;
|
|
961
|
-
// Feature flags
|
|
962
|
-
hasBlurUniform;
|
|
963
|
-
hasDepthUniform;
|
|
1444
|
+
/**
|
|
1445
|
+
* Add this target to the scene and align it with the reflective surface.
|
|
1446
|
+
*/
|
|
1447
|
+
get reflectorTarget() {
|
|
1448
|
+
return this.reflection?.target;
|
|
1449
|
+
}
|
|
964
1450
|
constructor(options = {}, parameters = {}) {
|
|
965
1451
|
super();
|
|
966
1452
|
const { distortionMap, ...validParams } = parameters;
|
|
@@ -984,109 +1470,37 @@ let MeshReflectorMaterial$1 = class MeshReflectorMaterial extends THREE.MeshStan
|
|
|
984
1470
|
resolutionScale,
|
|
985
1471
|
generateMipmaps: true
|
|
986
1472
|
});
|
|
987
|
-
this.
|
|
988
|
-
this.
|
|
989
|
-
this.
|
|
990
|
-
this.
|
|
991
|
-
this.
|
|
992
|
-
this.
|
|
993
|
-
this.
|
|
994
|
-
this.
|
|
995
|
-
this.
|
|
996
|
-
this.blurRadiusUniform = uniform(0.1);
|
|
997
|
-
this.hasBlurUniform = uniform(mixBlur > 0 ? 1 : 0);
|
|
998
|
-
this.hasDepthUniform = uniform(depthScale > 0 ? 1 : 0);
|
|
1473
|
+
this.mirror = mirror;
|
|
1474
|
+
this.mixBlur = mixBlur;
|
|
1475
|
+
this.mixStrength = mixStrength;
|
|
1476
|
+
this.minDepthThreshold = minDepthThreshold;
|
|
1477
|
+
this.maxDepthThreshold = maxDepthThreshold;
|
|
1478
|
+
this.depthScale = depthScale;
|
|
1479
|
+
this.depthToBlurRatioBias = depthToBlurRatioBias;
|
|
1480
|
+
this.distortion = distortion;
|
|
1481
|
+
this.mixContrast = mixContrast;
|
|
999
1482
|
this.setupNodes();
|
|
1000
1483
|
}
|
|
1001
1484
|
setupNodes() {
|
|
1485
|
+
const { mirror, mixBlur, mixStrength, mixContrast, blurRadius } = this.uniforms;
|
|
1002
1486
|
this.colorNode = Fn(() => {
|
|
1003
1487
|
const reflectionSample = this.reflection.sample(this.reflection.uvNode);
|
|
1004
|
-
const
|
|
1005
|
-
const reflectionBlurred = hashBlur(this.reflection,
|
|
1488
|
+
const radius = mix(float(0.01), float(0.15), blurRadius);
|
|
1489
|
+
const reflectionBlurred = hashBlur(this.reflection, radius, {
|
|
1006
1490
|
repeats: float(20),
|
|
1007
1491
|
premultipliedAlpha: false
|
|
1008
1492
|
});
|
|
1009
|
-
const reflectionColor =
|
|
1493
|
+
const reflectionColor = select(mixBlur.greaterThan(0), reflectionBlurred.rgb, reflectionSample.rgb);
|
|
1010
1494
|
const reflectionClamped = clamp(reflectionColor, 0, 1);
|
|
1011
1495
|
const contrastAdjusted = vec3(
|
|
1012
|
-
reflectionClamped.x.sub(0.5).mul(
|
|
1013
|
-
reflectionClamped.y.sub(0.5).mul(
|
|
1014
|
-
reflectionClamped.z.sub(0.5).mul(
|
|
1496
|
+
reflectionClamped.x.sub(0.5).mul(mixContrast).add(0.5),
|
|
1497
|
+
reflectionClamped.y.sub(0.5).mul(mixContrast).add(0.5),
|
|
1498
|
+
reflectionClamped.z.sub(0.5).mul(mixContrast).add(0.5)
|
|
1015
1499
|
);
|
|
1016
|
-
const mirrorClamped = clamp(
|
|
1017
|
-
return vec4(vec3(1).sub(vec3(mirrorClamped)).add(contrastAdjusted.mul(
|
|
1500
|
+
const mirrorClamped = clamp(mirror, 0, 1);
|
|
1501
|
+
return vec4(vec3(1).sub(vec3(mirrorClamped)).add(contrastAdjusted.mul(mixStrength)), 1);
|
|
1018
1502
|
})();
|
|
1019
1503
|
}
|
|
1020
|
-
//* Getters and Setters ----------------------------------------
|
|
1021
|
-
get mirror() {
|
|
1022
|
-
return this.mirrorUniform.value;
|
|
1023
|
-
}
|
|
1024
|
-
set mirror(v) {
|
|
1025
|
-
this.mirrorUniform.value = v;
|
|
1026
|
-
}
|
|
1027
|
-
get mixBlur() {
|
|
1028
|
-
return this.mixBlurUniform.value;
|
|
1029
|
-
}
|
|
1030
|
-
set mixBlur(v) {
|
|
1031
|
-
this.mixBlurUniform.value = v;
|
|
1032
|
-
this.hasBlurUniform.value = v > 0 ? 1 : 0;
|
|
1033
|
-
}
|
|
1034
|
-
get mixStrength() {
|
|
1035
|
-
return this.mixStrengthUniform.value;
|
|
1036
|
-
}
|
|
1037
|
-
set mixStrength(v) {
|
|
1038
|
-
this.mixStrengthUniform.value = v;
|
|
1039
|
-
}
|
|
1040
|
-
get minDepthThreshold() {
|
|
1041
|
-
return this.minDepthThresholdUniform.value;
|
|
1042
|
-
}
|
|
1043
|
-
set minDepthThreshold(v) {
|
|
1044
|
-
this.minDepthThresholdUniform.value = v;
|
|
1045
|
-
}
|
|
1046
|
-
get maxDepthThreshold() {
|
|
1047
|
-
return this.maxDepthThresholdUniform.value;
|
|
1048
|
-
}
|
|
1049
|
-
set maxDepthThreshold(v) {
|
|
1050
|
-
this.maxDepthThresholdUniform.value = v;
|
|
1051
|
-
}
|
|
1052
|
-
get depthScale() {
|
|
1053
|
-
return this.depthScaleUniform.value;
|
|
1054
|
-
}
|
|
1055
|
-
set depthScale(v) {
|
|
1056
|
-
this.depthScaleUniform.value = v;
|
|
1057
|
-
this.hasDepthUniform.value = v > 0 ? 1 : 0;
|
|
1058
|
-
}
|
|
1059
|
-
get depthToBlurRatioBias() {
|
|
1060
|
-
return this.depthToBlurRatioBiasUniform.value;
|
|
1061
|
-
}
|
|
1062
|
-
set depthToBlurRatioBias(v) {
|
|
1063
|
-
this.depthToBlurRatioBiasUniform.value = v;
|
|
1064
|
-
}
|
|
1065
|
-
get distortion() {
|
|
1066
|
-
return this.distortionUniform.value;
|
|
1067
|
-
}
|
|
1068
|
-
set distortion(v) {
|
|
1069
|
-
this.distortionUniform.value = v;
|
|
1070
|
-
}
|
|
1071
|
-
get mixContrast() {
|
|
1072
|
-
return this.mixContrastUniform.value;
|
|
1073
|
-
}
|
|
1074
|
-
set mixContrast(v) {
|
|
1075
|
-
this.mixContrastUniform.value = v;
|
|
1076
|
-
}
|
|
1077
|
-
get blurRadius() {
|
|
1078
|
-
return this.blurRadiusUniform.value;
|
|
1079
|
-
}
|
|
1080
|
-
set blurRadius(v) {
|
|
1081
|
-
this.blurRadiusUniform.value = v;
|
|
1082
|
-
}
|
|
1083
|
-
/**
|
|
1084
|
-
* Get the reflector target mesh that needs to be added to the scene.
|
|
1085
|
-
* The target should be positioned and rotated to match the reflective surface.
|
|
1086
|
-
*/
|
|
1087
|
-
get reflectorTarget() {
|
|
1088
|
-
return this.reflection.target;
|
|
1089
|
-
}
|
|
1090
1504
|
};
|
|
1091
1505
|
|
|
1092
1506
|
const MeshReflectorMaterial = /* @__PURE__ */ React.forwardRef(
|
|
@@ -1189,25 +1603,16 @@ const MeshReflectorMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
1189
1603
|
}
|
|
1190
1604
|
);
|
|
1191
1605
|
|
|
1192
|
-
const fresnelEffect = /* @__PURE__ */ Fn((
|
|
1193
|
-
const [viewDir, normal, power] = inputs;
|
|
1606
|
+
const fresnelEffect = /* @__PURE__ */ Fn(([viewDir, normal, power]) => {
|
|
1194
1607
|
const NdotV = float(1).add(dot(viewDir, normal));
|
|
1195
1608
|
return pow(NdotV, power);
|
|
1196
1609
|
});
|
|
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;
|
|
1610
|
+
const approximateRefraction = /* @__PURE__ */ Fn(([rayDir, normal, iorValue, bounceCount]) => {
|
|
1206
1611
|
const entryDir = refract(rayDir, normal, float(1).div(iorValue)).toVar();
|
|
1207
1612
|
const entryValid = length(entryDir).greaterThan(0);
|
|
1208
1613
|
const exitNormal = normal.negate().toVar();
|
|
1209
1614
|
const currentDir = entryDir.toVar();
|
|
1210
|
-
Loop(int(bounceCount), ({ i }) => {
|
|
1615
|
+
Loop({ start: 0, end: int(bounceCount), type: "int" }, ({ i }) => {
|
|
1211
1616
|
const fi = float(i).add(1);
|
|
1212
1617
|
const exitDir = refract(currentDir, exitNormal, iorValue);
|
|
1213
1618
|
const canExit = length(exitDir).greaterThan(0);
|
|
@@ -1217,165 +1622,64 @@ const approximateRefraction = /* @__PURE__ */ Fn((inputs) => {
|
|
|
1217
1622
|
});
|
|
1218
1623
|
return select(entryValid, currentDir, reflect(rayDir, normal));
|
|
1219
1624
|
});
|
|
1220
|
-
class MeshRefractionMaterialImpl extends MeshPhysicalNodeMaterial {
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
_thickness;
|
|
1625
|
+
class MeshRefractionMaterialImpl extends withUniforms(MeshPhysicalNodeMaterial, {
|
|
1626
|
+
/** Number of internal bounces, default: 3 */
|
|
1627
|
+
bounces: () => uniform(3),
|
|
1628
|
+
/** Fresnel intensity, default: 0 */
|
|
1629
|
+
fresnel: () => uniform(0),
|
|
1630
|
+
/** Chromatic aberration strength, default: 0.01 */
|
|
1631
|
+
aberrationStrength: () => uniform(0.01),
|
|
1632
|
+
/** Tint applied to the refracted environment, default: white */
|
|
1633
|
+
tintColor: () => uniform(new THREE.Color("white"))
|
|
1634
|
+
}) {
|
|
1231
1635
|
_fastChroma;
|
|
1232
1636
|
/** Type flag for identification */
|
|
1233
1637
|
isMeshRefractionMaterial = true;
|
|
1234
1638
|
constructor(fastChroma = true) {
|
|
1235
1639
|
super();
|
|
1236
1640
|
this._fastChroma = fastChroma;
|
|
1237
|
-
this.
|
|
1238
|
-
this.
|
|
1239
|
-
this.
|
|
1240
|
-
this._fresnel = uniform(0);
|
|
1241
|
-
this._aberrationStrength = uniform(0.01);
|
|
1242
|
-
this._color = uniform(new THREE.Color("white"));
|
|
1243
|
-
this._opacityValue = uniform(1);
|
|
1244
|
-
this._resolution = uniform(new THREE.Vector2(1, 1));
|
|
1245
|
-
this._thickness = uniform(1);
|
|
1641
|
+
this.ior = 2.4;
|
|
1642
|
+
this.envMap = new THREE.Texture();
|
|
1643
|
+
this.lights = false;
|
|
1246
1644
|
this.transparent = true;
|
|
1247
1645
|
this.side = THREE.FrontSide;
|
|
1248
1646
|
this._buildRefractionShader();
|
|
1249
1647
|
}
|
|
1250
1648
|
_buildRefractionShader() {
|
|
1251
|
-
const
|
|
1252
|
-
const bouncesUniform = this._bounces;
|
|
1253
|
-
const iorUniform = this._ior;
|
|
1254
|
-
const fresnelUniform = this._fresnel;
|
|
1255
|
-
const aberrationUniform = this._aberrationStrength;
|
|
1256
|
-
const colorUniform = this._color;
|
|
1257
|
-
const opacityUniform = this._opacityValue;
|
|
1258
|
-
const thicknessUniform = this._thickness;
|
|
1649
|
+
const { bounces, fresnel, aberrationStrength, tintColor } = this.uniforms;
|
|
1259
1650
|
const fastChroma = this._fastChroma;
|
|
1651
|
+
const envSample = (uvNode) => context$a(materialReference("envMap", "texture", this), { getUV: () => uvNode });
|
|
1260
1652
|
this.outputNode = Fn(() => {
|
|
1261
1653
|
const worldPos = positionWorld;
|
|
1262
1654
|
const worldNormal = normalize(normalWorld);
|
|
1263
1655
|
const viewDir = normalize(worldPos.sub(cameraPosition));
|
|
1264
|
-
const baseColor =
|
|
1265
|
-
const
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
max(iorUniform, 1),
|
|
1269
|
-
bouncesUniform,
|
|
1270
|
-
thicknessUniform
|
|
1271
|
-
);
|
|
1272
|
-
const aberration = aberrationUniform;
|
|
1656
|
+
const baseColor = tintColor.toVar();
|
|
1657
|
+
const iorValue = max(materialIOR, 1);
|
|
1658
|
+
const refractedDirG = approximateRefraction(viewDir, worldNormal, iorValue, bounces);
|
|
1659
|
+
const aberration = aberrationStrength;
|
|
1273
1660
|
const refractedDirR = vec3(0, 0, 0).toVar();
|
|
1274
1661
|
const refractedDirB = vec3(0, 0, 0).toVar();
|
|
1275
|
-
|
|
1276
|
-
if (useFastChroma) {
|
|
1662
|
+
if (fastChroma) {
|
|
1277
1663
|
refractedDirR.assign(normalize(refractedDirG.add(vec3(aberration.mul(0.5)))));
|
|
1278
1664
|
refractedDirB.assign(normalize(refractedDirG.sub(vec3(aberration.mul(0.5)))));
|
|
1279
1665
|
} else {
|
|
1280
1666
|
refractedDirR.assign(
|
|
1281
|
-
approximateRefraction(
|
|
1282
|
-
viewDir,
|
|
1283
|
-
worldNormal,
|
|
1284
|
-
max(iorUniform.mul(float(1).sub(aberration)), 1),
|
|
1285
|
-
bouncesUniform,
|
|
1286
|
-
thicknessUniform
|
|
1287
|
-
)
|
|
1667
|
+
approximateRefraction(viewDir, worldNormal, max(materialIOR.mul(float(1).sub(aberration)), 1), bounces)
|
|
1288
1668
|
);
|
|
1289
1669
|
refractedDirB.assign(
|
|
1290
|
-
approximateRefraction(
|
|
1291
|
-
viewDir,
|
|
1292
|
-
worldNormal,
|
|
1293
|
-
max(iorUniform.mul(float(1).add(aberration)), 1),
|
|
1294
|
-
bouncesUniform,
|
|
1295
|
-
thicknessUniform
|
|
1296
|
-
)
|
|
1670
|
+
approximateRefraction(viewDir, worldNormal, max(materialIOR.mul(float(1).add(aberration)), 1), bounces)
|
|
1297
1671
|
);
|
|
1298
1672
|
}
|
|
1299
|
-
const
|
|
1300
|
-
const
|
|
1301
|
-
const
|
|
1302
|
-
const envColorR = texture(envMapTex, uvR).r;
|
|
1303
|
-
const envColorG = texture(envMapTex, uvG).g;
|
|
1304
|
-
const envColorB = texture(envMapTex, uvB).b;
|
|
1673
|
+
const envColorR = envSample(equirectUV(refractedDirR)).r;
|
|
1674
|
+
const envColorG = envSample(equirectUV(refractedDirG)).g;
|
|
1675
|
+
const envColorB = envSample(equirectUV(refractedDirB)).b;
|
|
1305
1676
|
const envColor = vec3(envColorR, envColorG, envColorB);
|
|
1306
1677
|
const tintedColor = envColor.mul(baseColor);
|
|
1307
|
-
const fresnelValue = fresnelEffect(viewDir, worldNormal, float(10)).mul(
|
|
1678
|
+
const fresnelValue = fresnelEffect(viewDir, worldNormal, float(10)).mul(fresnel);
|
|
1308
1679
|
const finalColor = mix(tintedColor, vec3(1), fresnelValue);
|
|
1309
|
-
return vec4(finalColor,
|
|
1680
|
+
return vec4(finalColor, materialOpacity);
|
|
1310
1681
|
})();
|
|
1311
1682
|
}
|
|
1312
|
-
//* Uniform Accessors ==============================
|
|
1313
|
-
/** Environment map texture */
|
|
1314
|
-
get envMap() {
|
|
1315
|
-
return this._envMap.value;
|
|
1316
|
-
}
|
|
1317
|
-
set envMap(v) {
|
|
1318
|
-
if (v) {
|
|
1319
|
-
this._envMap.value = v;
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
/** Number of internal bounces, default: 3 */
|
|
1323
|
-
get bounces() {
|
|
1324
|
-
return this._bounces.value;
|
|
1325
|
-
}
|
|
1326
|
-
set bounces(v) {
|
|
1327
|
-
this._bounces.value = v;
|
|
1328
|
-
}
|
|
1329
|
-
/** Index of refraction, default: 2.4 (diamond) */
|
|
1330
|
-
get ior() {
|
|
1331
|
-
return this._ior.value;
|
|
1332
|
-
}
|
|
1333
|
-
set ior(v) {
|
|
1334
|
-
this._ior.value = v;
|
|
1335
|
-
}
|
|
1336
|
-
/** Fresnel intensity, default: 0 */
|
|
1337
|
-
get fresnel() {
|
|
1338
|
-
return this._fresnel.value;
|
|
1339
|
-
}
|
|
1340
|
-
set fresnel(v) {
|
|
1341
|
-
this._fresnel.value = v;
|
|
1342
|
-
}
|
|
1343
|
-
/** Chromatic aberration strength, default: 0.01 */
|
|
1344
|
-
get aberrationStrength() {
|
|
1345
|
-
return this._aberrationStrength.value;
|
|
1346
|
-
}
|
|
1347
|
-
set aberrationStrength(v) {
|
|
1348
|
-
this._aberrationStrength.value = v;
|
|
1349
|
-
}
|
|
1350
|
-
/** Tint color - use tintColor to avoid base class conflict */
|
|
1351
|
-
get tintColor() {
|
|
1352
|
-
return this._color.value;
|
|
1353
|
-
}
|
|
1354
|
-
set tintColor(v) {
|
|
1355
|
-
if (v instanceof THREE.Color) this._color.value = v;
|
|
1356
|
-
else this._color.value = new THREE.Color(v);
|
|
1357
|
-
}
|
|
1358
|
-
/** Opacity, default: 1 */
|
|
1359
|
-
get opacity() {
|
|
1360
|
-
return this._opacityValue.value;
|
|
1361
|
-
}
|
|
1362
|
-
set opacity(v) {
|
|
1363
|
-
this._opacityValue.value = v;
|
|
1364
|
-
}
|
|
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
1683
|
}
|
|
1380
1684
|
const MeshRefractionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
1381
1685
|
({
|
|
@@ -1391,12 +1695,6 @@ const MeshRefractionMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
1391
1695
|
}, fref) => {
|
|
1392
1696
|
extend({ MeshRefractionMaterial: MeshRefractionMaterialImpl });
|
|
1393
1697
|
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
1698
|
React.useEffect(() => {
|
|
1401
1699
|
if (ref.current && envMap) {
|
|
1402
1700
|
ref.current.envMap = envMap;
|
|
@@ -1604,175 +1902,88 @@ function Container$2({
|
|
|
1604
1902
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
|
|
1605
1903
|
}
|
|
1606
1904
|
|
|
1607
|
-
class PortalMaterialImpl extends MeshBasicNodeMaterial {
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1905
|
+
class PortalMaterialImpl extends withUniforms(MeshBasicNodeMaterial, {
|
|
1906
|
+
/** Edge fade blur, 0 = no blur */
|
|
1907
|
+
blur: () => uniform(0),
|
|
1908
|
+
/** Signed distance field of the parent geometry, generated on demand */
|
|
1909
|
+
sdf: () => uniformTexture(new THREE.Texture()),
|
|
1910
|
+
/** 0 = world scene, 0.5 = both, 1 = portal scene */
|
|
1911
|
+
blend: () => uniform(0),
|
|
1912
|
+
/** Largest SDF distance, used to normalise the field */
|
|
1913
|
+
size: () => uniform(0),
|
|
1914
|
+
/** Drawing-buffer size in pixels */
|
|
1915
|
+
resolution: () => uniform(new THREE.Vector2())
|
|
1916
|
+
}) {
|
|
1614
1917
|
constructor() {
|
|
1615
1918
|
super();
|
|
1616
|
-
this.
|
|
1617
|
-
this._map = uniformTexture(new THREE.Texture());
|
|
1618
|
-
this._sdf = uniformTexture(new THREE.Texture());
|
|
1619
|
-
this._blend = uniform(0);
|
|
1620
|
-
this._size = uniform(0);
|
|
1621
|
-
this._resolution = uniform(new THREE.Vector2());
|
|
1919
|
+
this.map = new THREE.Texture();
|
|
1622
1920
|
this._buildShader();
|
|
1623
1921
|
}
|
|
1624
1922
|
_buildShader() {
|
|
1625
|
-
const
|
|
1626
|
-
const
|
|
1627
|
-
const sdfTex = this._sdf;
|
|
1628
|
-
const sizeUniform = this._size;
|
|
1629
|
-
const resolutionUniform = this._resolution;
|
|
1923
|
+
const { blur, sdf, size, resolution } = this.uniforms;
|
|
1924
|
+
const map = materialReference("map", "texture", this);
|
|
1630
1925
|
this.colorNode = Fn(() => {
|
|
1631
|
-
const screenUv = screenCoordinate.xy.div(
|
|
1632
|
-
const t =
|
|
1633
|
-
const
|
|
1634
|
-
const
|
|
1635
|
-
const k = blurUniform;
|
|
1636
|
-
const edgeFactor = clamp(d.div(k).add(1), 0, 1);
|
|
1926
|
+
const screenUv = screenCoordinate.xy.div(resolution);
|
|
1927
|
+
const t = context$a(map, { getUV: () => screenUv });
|
|
1928
|
+
const d = sdf.sample(uv()).r.div(size);
|
|
1929
|
+
const edgeFactor = clamp(d.div(blur).add(1), 0, 1);
|
|
1637
1930
|
const alpha = float(1).sub(smoothstep(float(0), float(1), edgeFactor));
|
|
1638
|
-
const
|
|
1639
|
-
const finalAlpha = select(isBlurZero, t.a, t.a.mul(alpha));
|
|
1931
|
+
const finalAlpha = select(blur.equal(0), t.a, t.a.mul(alpha));
|
|
1640
1932
|
return vec4(t.rgb, finalAlpha);
|
|
1641
1933
|
})();
|
|
1642
1934
|
}
|
|
1643
|
-
//* Uniform Accessors --
|
|
1644
|
-
get blur() {
|
|
1645
|
-
return this._blur.value;
|
|
1646
|
-
}
|
|
1647
|
-
set blur(v) {
|
|
1648
|
-
this._blur.value = v;
|
|
1649
|
-
}
|
|
1650
|
-
get map() {
|
|
1651
|
-
return this._map.value;
|
|
1652
|
-
}
|
|
1653
|
-
set map(v) {
|
|
1654
|
-
this._map.value = v ?? new THREE.Texture();
|
|
1655
|
-
}
|
|
1656
|
-
get sdf() {
|
|
1657
|
-
return this._sdf.value;
|
|
1658
|
-
}
|
|
1659
|
-
set sdf(v) {
|
|
1660
|
-
if (v) this._sdf.value = v;
|
|
1661
|
-
}
|
|
1662
|
-
get blend() {
|
|
1663
|
-
return this._blend.value;
|
|
1664
|
-
}
|
|
1665
|
-
set blend(v) {
|
|
1666
|
-
this._blend.value = v;
|
|
1667
|
-
}
|
|
1668
|
-
get size() {
|
|
1669
|
-
return this._size.value;
|
|
1670
|
-
}
|
|
1671
|
-
set size(v) {
|
|
1672
|
-
this._size.value = v;
|
|
1673
|
-
}
|
|
1674
|
-
get resolution() {
|
|
1675
|
-
return this._resolution.value;
|
|
1676
|
-
}
|
|
1677
|
-
set resolution(v) {
|
|
1678
|
-
if (Array.isArray(v)) this._resolution.value.set(v[0], v[1]);
|
|
1679
|
-
else this._resolution.value.copy(v);
|
|
1680
|
-
}
|
|
1681
1935
|
}
|
|
1682
|
-
class BlendMaterial extends MeshBasicNodeMaterial {
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1936
|
+
class BlendMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
1937
|
+
textureA: () => uniformTexture(new THREE.Texture()),
|
|
1938
|
+
textureB: () => uniformTexture(new THREE.Texture()),
|
|
1939
|
+
blend: () => uniform(0)
|
|
1940
|
+
}) {
|
|
1686
1941
|
constructor() {
|
|
1687
1942
|
super();
|
|
1688
|
-
|
|
1689
|
-
this._textureB = uniformTexture(new THREE.Texture());
|
|
1690
|
-
this._blend = uniform(0);
|
|
1691
|
-
this._buildShader();
|
|
1692
|
-
}
|
|
1693
|
-
_buildShader() {
|
|
1694
|
-
const texA = this._textureA;
|
|
1695
|
-
const texB = this._textureB;
|
|
1696
|
-
const blendUniform = this._blend;
|
|
1943
|
+
const { textureA, textureB, blend } = this.uniforms;
|
|
1697
1944
|
this.colorNode = Fn(() => {
|
|
1698
1945
|
const uvCoord = uv();
|
|
1699
|
-
|
|
1700
|
-
const tb = texture(texB, uvCoord);
|
|
1701
|
-
return mix(tb, ta, blendUniform);
|
|
1946
|
+
return mix(textureB.sample(uvCoord), textureA.sample(uvCoord), blend);
|
|
1702
1947
|
})();
|
|
1703
1948
|
}
|
|
1704
|
-
get textureA() {
|
|
1705
|
-
return this._textureA.value;
|
|
1706
|
-
}
|
|
1707
|
-
set textureA(v) {
|
|
1708
|
-
this._textureA.value = v;
|
|
1709
|
-
}
|
|
1710
|
-
get textureB() {
|
|
1711
|
-
return this._textureB.value;
|
|
1712
|
-
}
|
|
1713
|
-
set textureB(v) {
|
|
1714
|
-
this._textureB.value = v;
|
|
1715
|
-
}
|
|
1716
|
-
get blend() {
|
|
1717
|
-
return this._blend.value;
|
|
1718
|
-
}
|
|
1719
|
-
set blend(v) {
|
|
1720
|
-
this._blend.value = v;
|
|
1721
|
-
}
|
|
1722
1949
|
}
|
|
1723
|
-
class UVRenderMaterial extends MeshBasicNodeMaterial {
|
|
1724
|
-
|
|
1725
|
-
|
|
1950
|
+
class UVRenderMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
1951
|
+
tex: () => uniformTexture(new THREE.Texture()),
|
|
1952
|
+
/** 1 = pack the inside of the mask, 0 = the outside */
|
|
1953
|
+
inside: () => uniform(0)
|
|
1954
|
+
}) {
|
|
1726
1955
|
constructor(inside = false) {
|
|
1727
|
-
super();
|
|
1728
|
-
this.
|
|
1729
|
-
|
|
1730
|
-
this.
|
|
1731
|
-
}
|
|
1732
|
-
_buildShader() {
|
|
1733
|
-
const tex = this._tex;
|
|
1734
|
-
const insideUniform = this._inside;
|
|
1735
|
-
this.colorNode = Fn(() => {
|
|
1956
|
+
super({ toneMapped: false });
|
|
1957
|
+
this.inside = inside ? 1 : 0;
|
|
1958
|
+
const { tex, inside: insideUniform } = this.uniforms;
|
|
1959
|
+
this.fragmentNode = Fn(() => {
|
|
1736
1960
|
const uvCoord = uv();
|
|
1737
|
-
const
|
|
1738
|
-
const roundedMask = round(mask);
|
|
1961
|
+
const roundedMask = round(tex.sample(uvCoord).x);
|
|
1739
1962
|
const isInside = insideUniform.greaterThan(0.5);
|
|
1740
1963
|
const factor = select(isInside, float(1).sub(roundedMask), roundedMask);
|
|
1741
1964
|
const packedUv = uvCoord.mul(factor);
|
|
1742
1965
|
return vec4(packedUv.x, packedUv.y, 0, 1);
|
|
1743
1966
|
})();
|
|
1744
1967
|
}
|
|
1745
|
-
get tex() {
|
|
1746
|
-
return this._tex.value;
|
|
1747
|
-
}
|
|
1748
|
-
set tex(v) {
|
|
1749
|
-
this._tex.value = v;
|
|
1750
|
-
}
|
|
1751
1968
|
}
|
|
1752
|
-
class JumpFloodMaterial extends MeshBasicNodeMaterial {
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1969
|
+
class JumpFloodMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
1970
|
+
tex: () => uniformTexture(new THREE.Texture()),
|
|
1971
|
+
offset: () => uniform(0),
|
|
1972
|
+
texelSize: () => uniform(new THREE.Vector2(1, 1))
|
|
1973
|
+
}) {
|
|
1756
1974
|
constructor(clientWidth, clientHeight) {
|
|
1757
|
-
super();
|
|
1758
|
-
this.
|
|
1759
|
-
|
|
1760
|
-
this.
|
|
1761
|
-
this._buildShader();
|
|
1762
|
-
}
|
|
1763
|
-
_buildShader() {
|
|
1764
|
-
const tex = this._tex;
|
|
1765
|
-
const offsetUniform = this._offset;
|
|
1766
|
-
const texelSizeUniform = this._texelSize;
|
|
1767
|
-
this.colorNode = Fn(() => {
|
|
1975
|
+
super({ toneMapped: false });
|
|
1976
|
+
this.uniforms.texelSize.value.set(1 / clientWidth, 1 / clientHeight);
|
|
1977
|
+
const { tex, offset, texelSize } = this.uniforms;
|
|
1978
|
+
this.fragmentNode = Fn(() => {
|
|
1768
1979
|
const uvCoord = uv();
|
|
1769
1980
|
const closestDist = float(99999999e-1).toVar();
|
|
1770
1981
|
const closestPos = vec2$2(0, 0).toVar();
|
|
1771
1982
|
Loop({ start: int(-1), end: int(2), type: "int", condition: "<" }, ({ i: x }) => {
|
|
1772
1983
|
Loop({ start: int(-1), end: int(2), type: "int", condition: "<" }, ({ i: y }) => {
|
|
1773
|
-
const sampleOffset = vec2$2(float(x), float(y)).mul(
|
|
1984
|
+
const sampleOffset = vec2$2(float(x), float(y)).mul(texelSize).mul(offset);
|
|
1774
1985
|
const sampleUv = uvCoord.add(sampleOffset);
|
|
1775
|
-
const pos =
|
|
1986
|
+
const pos = tex.sample(sampleUv).xy;
|
|
1776
1987
|
const dist = distance(pos, uvCoord);
|
|
1777
1988
|
const isValid = pos.x.notEqual(0).and(pos.y.notEqual(0));
|
|
1778
1989
|
const isCloser = dist.lessThan(closestDist);
|
|
@@ -1784,88 +1995,40 @@ class JumpFloodMaterial extends MeshBasicNodeMaterial {
|
|
|
1784
1995
|
return vec4(closestPos, 0, 1);
|
|
1785
1996
|
})();
|
|
1786
1997
|
}
|
|
1787
|
-
get tex() {
|
|
1788
|
-
return this._tex.value;
|
|
1789
|
-
}
|
|
1790
|
-
set tex(v) {
|
|
1791
|
-
this._tex.value = v;
|
|
1792
|
-
}
|
|
1793
|
-
get offset() {
|
|
1794
|
-
return this._offset.value;
|
|
1795
|
-
}
|
|
1796
|
-
set offset(v) {
|
|
1797
|
-
this._offset.value = v;
|
|
1798
|
-
}
|
|
1799
1998
|
}
|
|
1800
|
-
class DistanceFieldMaterial extends MeshBasicNodeMaterial {
|
|
1801
|
-
|
|
1802
|
-
|
|
1999
|
+
class DistanceFieldMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
2000
|
+
tex: () => uniformTexture(new THREE.Texture()),
|
|
2001
|
+
size: () => uniform(new THREE.Vector2(1, 1))
|
|
2002
|
+
}) {
|
|
1803
2003
|
constructor(clientWidth, clientHeight) {
|
|
1804
|
-
super();
|
|
1805
|
-
this.
|
|
1806
|
-
|
|
1807
|
-
this.
|
|
1808
|
-
}
|
|
1809
|
-
_buildShader() {
|
|
1810
|
-
const tex = this._tex;
|
|
1811
|
-
const sizeUniform = this._size;
|
|
1812
|
-
this.colorNode = Fn(() => {
|
|
2004
|
+
super({ toneMapped: false });
|
|
2005
|
+
this.uniforms.size.value.set(clientWidth, clientHeight);
|
|
2006
|
+
const { tex, size } = this.uniforms;
|
|
2007
|
+
this.fragmentNode = Fn(() => {
|
|
1813
2008
|
const uvCoord = uv();
|
|
1814
|
-
const pos =
|
|
1815
|
-
const dist = distance(
|
|
2009
|
+
const pos = tex.sample(uvCoord).xy;
|
|
2010
|
+
const dist = distance(size.mul(pos), size.mul(uvCoord));
|
|
1816
2011
|
return vec4(dist, 0, 0, 1);
|
|
1817
2012
|
})();
|
|
1818
2013
|
}
|
|
1819
|
-
get tex() {
|
|
1820
|
-
return this._tex.value;
|
|
1821
|
-
}
|
|
1822
|
-
set tex(v) {
|
|
1823
|
-
this._tex.value = v;
|
|
1824
|
-
}
|
|
1825
2014
|
}
|
|
1826
|
-
class CompositeMaterial extends MeshBasicNodeMaterial {
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
2015
|
+
class CompositeMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
2016
|
+
inside: () => uniformTexture(new THREE.Texture()),
|
|
2017
|
+
outside: () => uniformTexture(new THREE.Texture()),
|
|
2018
|
+
mask: () => uniformTexture(new THREE.Texture())
|
|
2019
|
+
}) {
|
|
1830
2020
|
constructor() {
|
|
1831
|
-
super();
|
|
1832
|
-
|
|
1833
|
-
this.
|
|
1834
|
-
this._mask = uniformTexture(new THREE.Texture());
|
|
1835
|
-
this._buildShader();
|
|
1836
|
-
}
|
|
1837
|
-
_buildShader() {
|
|
1838
|
-
const insideTex = this._inside;
|
|
1839
|
-
const outsideTex = this._outside;
|
|
1840
|
-
const maskTex = this._mask;
|
|
1841
|
-
this.colorNode = Fn(() => {
|
|
2021
|
+
super({ toneMapped: false });
|
|
2022
|
+
const { inside, outside, mask } = this.uniforms;
|
|
2023
|
+
this.fragmentNode = Fn(() => {
|
|
1842
2024
|
const uvCoord = uv();
|
|
1843
|
-
const i =
|
|
1844
|
-
const o =
|
|
1845
|
-
const maskVal =
|
|
1846
|
-
const
|
|
1847
|
-
const result = select(isOutside, o, i.negate());
|
|
2025
|
+
const i = inside.sample(uvCoord).x;
|
|
2026
|
+
const o = outside.sample(uvCoord).x;
|
|
2027
|
+
const maskVal = mask.sample(uvCoord).x;
|
|
2028
|
+
const result = select(maskVal.equal(0), o, i.negate());
|
|
1848
2029
|
return vec4(result, 0, 0, 1);
|
|
1849
2030
|
})();
|
|
1850
2031
|
}
|
|
1851
|
-
get inside() {
|
|
1852
|
-
return this._inside.value;
|
|
1853
|
-
}
|
|
1854
|
-
set inside(v) {
|
|
1855
|
-
this._inside.value = v;
|
|
1856
|
-
}
|
|
1857
|
-
get outside() {
|
|
1858
|
-
return this._outside.value;
|
|
1859
|
-
}
|
|
1860
|
-
set outside(v) {
|
|
1861
|
-
this._outside.value = v;
|
|
1862
|
-
}
|
|
1863
|
-
get mask() {
|
|
1864
|
-
return this._mask.value;
|
|
1865
|
-
}
|
|
1866
|
-
set mask(v) {
|
|
1867
|
-
this._mask.value = v;
|
|
1868
|
-
}
|
|
1869
2032
|
}
|
|
1870
2033
|
const makeSDFGenerator = (clientWidth, clientHeight, renderer) => {
|
|
1871
2034
|
const finalTarget = new RenderTarget(clientWidth, clientHeight, {
|
|
@@ -1913,7 +2076,7 @@ const makeSDFGenerator = (clientWidth, clientHeight, renderer) => {
|
|
|
1913
2076
|
const jumpFloodQuad = new QuadMesh(jumpFloodMat);
|
|
1914
2077
|
const distanceFieldQuad = new QuadMesh(distanceFieldMat);
|
|
1915
2078
|
const compositeQuad = new QuadMesh(compositeMat);
|
|
1916
|
-
|
|
2079
|
+
const generate = (image) => {
|
|
1917
2080
|
image.minFilter = THREE.NearestFilter;
|
|
1918
2081
|
image.magFilter = THREE.NearestFilter;
|
|
1919
2082
|
uvRenderMat.tex = image;
|
|
@@ -1955,9 +2118,28 @@ const makeSDFGenerator = (clientWidth, clientHeight, renderer) => {
|
|
|
1955
2118
|
compositeMat.outside = outsideRenderTargetFinal.texture;
|
|
1956
2119
|
compositeMat.mask = image;
|
|
1957
2120
|
compositeQuad.render(renderer);
|
|
1958
|
-
renderer.setRenderTarget(null);
|
|
1959
2121
|
return finalTarget;
|
|
1960
2122
|
};
|
|
2123
|
+
return {
|
|
2124
|
+
generate,
|
|
2125
|
+
dispose() {
|
|
2126
|
+
for (const resource of [
|
|
2127
|
+
finalTarget,
|
|
2128
|
+
outsideRenderTarget,
|
|
2129
|
+
insideRenderTarget,
|
|
2130
|
+
outsideRenderTarget2,
|
|
2131
|
+
insideRenderTarget2,
|
|
2132
|
+
outsideRenderTargetFinal,
|
|
2133
|
+
insideRenderTargetFinal,
|
|
2134
|
+
uvRenderMat,
|
|
2135
|
+
uvRenderInsideMat,
|
|
2136
|
+
jumpFloodMat,
|
|
2137
|
+
distanceFieldMat,
|
|
2138
|
+
compositeMat
|
|
2139
|
+
])
|
|
2140
|
+
resource.dispose();
|
|
2141
|
+
}
|
|
2142
|
+
};
|
|
1961
2143
|
};
|
|
1962
2144
|
const MeshPortalMaterial = /* @__PURE__ */ React.forwardRef(
|
|
1963
2145
|
({
|
|
@@ -1972,7 +2154,7 @@ const MeshPortalMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
1972
2154
|
}, fref) => {
|
|
1973
2155
|
extend({ PortalMaterialImpl });
|
|
1974
2156
|
const ref = React.useRef(null);
|
|
1975
|
-
const { scene,
|
|
2157
|
+
const { scene, renderer, size, viewport, setEvents, invalidate } = useThree();
|
|
1976
2158
|
const maskRenderTarget = useFBO(resolution, resolution);
|
|
1977
2159
|
const [priority, setPriority] = React.useState(0);
|
|
1978
2160
|
useFrame(() => {
|
|
@@ -1983,43 +2165,69 @@ const MeshPortalMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
1983
2165
|
if (events !== void 0) setEvents({ enabled: !events });
|
|
1984
2166
|
}, [events]);
|
|
1985
2167
|
const [visible, setVisible] = React.useState(true);
|
|
2168
|
+
const needsSdf = blur !== 0;
|
|
1986
2169
|
const parent = useIntersect(setVisible);
|
|
1987
2170
|
React.useLayoutEffect(() => {
|
|
1988
2171
|
parent.current = ref.current?.__r3f?.parent?.object;
|
|
1989
2172
|
}, []);
|
|
1990
2173
|
React.useLayoutEffect(() => {
|
|
1991
|
-
if (!parent.current) return;
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
)
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2174
|
+
if (!parent.current || !needsSdf) return;
|
|
2175
|
+
const material = ref.current;
|
|
2176
|
+
const previousSdf = material.sdf;
|
|
2177
|
+
const previousSize = material.size;
|
|
2178
|
+
const gpuRenderer = renderer;
|
|
2179
|
+
const tempMesh = new THREE.Mesh(parent.current.geometry, new THREE.MeshBasicMaterial());
|
|
2180
|
+
const boundingBox = new THREE.Box3().setFromBufferAttribute(
|
|
2181
|
+
tempMesh.geometry.attributes.position
|
|
2182
|
+
);
|
|
2183
|
+
const orthoCam = new THREE.OrthographicCamera(
|
|
2184
|
+
boundingBox.min.x * (1 + 2 / resolution),
|
|
2185
|
+
boundingBox.max.x * (1 + 2 / resolution),
|
|
2186
|
+
boundingBox.max.y * (1 + 2 / resolution),
|
|
2187
|
+
boundingBox.min.y * (1 + 2 / resolution),
|
|
2188
|
+
0.1,
|
|
2189
|
+
1e3
|
|
2190
|
+
);
|
|
2191
|
+
orthoCam.position.set(0, 0, 1);
|
|
2192
|
+
orthoCam.lookAt(0, 0, 0);
|
|
2193
|
+
const sg = makeSDFGenerator(resolution, resolution, gpuRenderer);
|
|
2194
|
+
const previousTarget = gpuRenderer.getRenderTarget();
|
|
2195
|
+
const previousClearColor = gpuRenderer.getClearColor(new THREE.Color());
|
|
2196
|
+
const previousClearAlpha = gpuRenderer.getClearAlpha();
|
|
2197
|
+
let sdf;
|
|
2198
|
+
try {
|
|
2199
|
+
gpuRenderer.setClearColor(0, 0);
|
|
2200
|
+
gpuRenderer.setRenderTarget(maskRenderTarget);
|
|
2201
|
+
gpuRenderer.render(tempMesh, orthoCam);
|
|
2202
|
+
sdf = sg.generate(maskRenderTarget.texture);
|
|
2203
|
+
} catch (error) {
|
|
2204
|
+
sg.dispose();
|
|
2205
|
+
throw error;
|
|
2206
|
+
} finally {
|
|
2207
|
+
gpuRenderer.setRenderTarget(previousTarget);
|
|
2208
|
+
gpuRenderer.setClearColor(previousClearColor, previousClearAlpha);
|
|
2209
|
+
tempMesh.material.dispose();
|
|
2210
|
+
}
|
|
2211
|
+
let cancelled = false;
|
|
2212
|
+
gpuRenderer.readRenderTargetPixelsAsync(sdf, 0, 0, resolution, resolution).then((readSdf) => {
|
|
2213
|
+
if (cancelled) return;
|
|
2013
2214
|
let min = Infinity;
|
|
2014
2215
|
for (let i = 0; i < readSdf.length; i++) {
|
|
2015
2216
|
if (readSdf[i] < min) min = readSdf[i];
|
|
2016
2217
|
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2218
|
+
material.size = -min;
|
|
2219
|
+
material.sdf = sdf.texture;
|
|
2220
|
+
invalidate();
|
|
2221
|
+
}).catch((error) => {
|
|
2222
|
+
if (!cancelled) console.error("MeshPortalMaterial: SDF readback failed.", error);
|
|
2223
|
+
});
|
|
2224
|
+
return () => {
|
|
2225
|
+
cancelled = true;
|
|
2226
|
+
material.sdf = previousSdf;
|
|
2227
|
+
material.size = previousSize;
|
|
2228
|
+
sg.dispose();
|
|
2229
|
+
};
|
|
2230
|
+
}, [resolution, needsSdf, renderer, maskRenderTarget, invalidate]);
|
|
2023
2231
|
React.useImperativeHandle(fref, () => ref.current);
|
|
2024
2232
|
const compute = React.useCallback(
|
|
2025
2233
|
(event, state, _previous) => {
|
|
@@ -2124,44 +2332,27 @@ function ManagePortalScene({
|
|
|
2124
2332
|
return /* @__PURE__ */ React.createElement(React.Fragment, null);
|
|
2125
2333
|
}
|
|
2126
2334
|
|
|
2127
|
-
class DistortMaterialImplWebGPU extends THREE.MeshPhysicalNodeMaterial {
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2335
|
+
class DistortMaterialImplWebGPU extends withUniforms(THREE.MeshPhysicalNodeMaterial, {
|
|
2336
|
+
/** Animation time, advanced by the component each frame */
|
|
2337
|
+
time: () => uniform(0),
|
|
2338
|
+
/** Distortion intensity */
|
|
2339
|
+
distort: () => uniform(0.4),
|
|
2340
|
+
/** Base scale the distortion is added to */
|
|
2341
|
+
radius: () => uniform(1)
|
|
2342
|
+
}) {
|
|
2131
2343
|
constructor(parameters = {}) {
|
|
2132
2344
|
super(parameters);
|
|
2133
|
-
this.
|
|
2134
|
-
this.timeUniform = uniform(0);
|
|
2135
|
-
this.distortUniform = uniform(0.4);
|
|
2136
|
-
this.radiusUniform = uniform(1);
|
|
2345
|
+
const { time, distort, radius } = this.uniforms;
|
|
2137
2346
|
this.positionNode = Fn(() => {
|
|
2138
2347
|
const pos = positionLocal.toVar();
|
|
2139
|
-
const updateTime =
|
|
2348
|
+
const updateTime = time.div(50);
|
|
2140
2349
|
const noiseInput = pos.div(2).add(updateTime.mul(5));
|
|
2141
2350
|
const noiseVec = mx_noise_vec3(noiseInput);
|
|
2142
2351
|
const noise = noiseVec.x;
|
|
2143
|
-
const distortFactor = noise.mul(pow(
|
|
2352
|
+
const distortFactor = noise.mul(pow(distort, float(2))).add(radius);
|
|
2144
2353
|
return pos.mul(distortFactor);
|
|
2145
2354
|
})();
|
|
2146
2355
|
}
|
|
2147
|
-
get time() {
|
|
2148
|
-
return this.timeUniform.value;
|
|
2149
|
-
}
|
|
2150
|
-
set time(v) {
|
|
2151
|
-
this.timeUniform.value = v;
|
|
2152
|
-
}
|
|
2153
|
-
get distort() {
|
|
2154
|
-
return this.distortUniform.value;
|
|
2155
|
-
}
|
|
2156
|
-
set distort(v) {
|
|
2157
|
-
this.distortUniform.value = v;
|
|
2158
|
-
}
|
|
2159
|
-
get radius() {
|
|
2160
|
-
return this.radiusUniform.value;
|
|
2161
|
-
}
|
|
2162
|
-
set radius(v) {
|
|
2163
|
-
this.radiusUniform.value = v;
|
|
2164
|
-
}
|
|
2165
2356
|
}
|
|
2166
2357
|
const MeshDistortMaterial = /* @__PURE__ */ React.forwardRef(({ speed = 1, ...props }, ref) => {
|
|
2167
2358
|
const [material] = React.useState(() => new DistortMaterialImplWebGPU());
|
|
@@ -2169,17 +2360,18 @@ const MeshDistortMaterial = /* @__PURE__ */ React.forwardRef(({ speed = 1, ...pr
|
|
|
2169
2360
|
return /* @__PURE__ */ React.createElement("primitive", { object: material, ref, attach: "material", ...props });
|
|
2170
2361
|
});
|
|
2171
2362
|
|
|
2172
|
-
class WobbleMaterialImpl extends THREE.MeshStandardNodeMaterial {
|
|
2173
|
-
|
|
2174
|
-
|
|
2363
|
+
class WobbleMaterialImpl extends withUniforms(THREE.MeshStandardNodeMaterial, {
|
|
2364
|
+
/** Animation time, advanced by the component each frame */
|
|
2365
|
+
time: () => uniform(0),
|
|
2366
|
+
/** Wobble strength */
|
|
2367
|
+
factor: () => uniform(1)
|
|
2368
|
+
}) {
|
|
2175
2369
|
constructor(parameters = {}) {
|
|
2176
2370
|
super(parameters);
|
|
2177
|
-
this.
|
|
2178
|
-
this.timeUniform = uniform(0);
|
|
2179
|
-
this.factorUniform = uniform(1);
|
|
2371
|
+
const { time, factor } = this.uniforms;
|
|
2180
2372
|
this.positionNode = Fn(() => {
|
|
2181
2373
|
const pos = positionLocal.toVar();
|
|
2182
|
-
const theta = sin(
|
|
2374
|
+
const theta = sin(time.add(pos.y)).div(2).mul(factor);
|
|
2183
2375
|
const c = cos(theta);
|
|
2184
2376
|
const s = sin(theta);
|
|
2185
2377
|
const rotMatrix = mat3(c, float(0), s, float(0), float(1), float(0), s.negate(), float(0), c);
|
|
@@ -2188,25 +2380,13 @@ class WobbleMaterialImpl extends THREE.MeshStandardNodeMaterial {
|
|
|
2188
2380
|
this.normalNode = Fn(() => {
|
|
2189
2381
|
const pos = positionLocal.toVar();
|
|
2190
2382
|
const norm = normalLocal.toVar();
|
|
2191
|
-
const theta = sin(
|
|
2383
|
+
const theta = sin(time.add(pos.y)).div(2).mul(factor);
|
|
2192
2384
|
const c = cos(theta);
|
|
2193
2385
|
const s = sin(theta);
|
|
2194
2386
|
const rotMatrix = mat3(c, float(0), s, float(0), float(1), float(0), s.negate(), float(0), c);
|
|
2195
2387
|
return norm.mul(rotMatrix);
|
|
2196
2388
|
})();
|
|
2197
2389
|
}
|
|
2198
|
-
get time() {
|
|
2199
|
-
return this.timeUniform.value;
|
|
2200
|
-
}
|
|
2201
|
-
set time(v) {
|
|
2202
|
-
this.timeUniform.value = v;
|
|
2203
|
-
}
|
|
2204
|
-
get factor() {
|
|
2205
|
-
return this.factorUniform.value;
|
|
2206
|
-
}
|
|
2207
|
-
set factor(v) {
|
|
2208
|
-
this.factorUniform.value = v;
|
|
2209
|
-
}
|
|
2210
2390
|
}
|
|
2211
2391
|
const MeshWobbleMaterial = /* @__PURE__ */ React.forwardRef(({ speed = 1, ...props }, ref) => {
|
|
2212
2392
|
const [material] = React.useState(() => new WobbleMaterialImpl());
|
|
@@ -2225,84 +2405,36 @@ function FakeCloudMaterial(BaseMaterial) {
|
|
|
2225
2405
|
return mat;
|
|
2226
2406
|
}
|
|
2227
2407
|
|
|
2228
|
-
class OutlinesMaterial extends MeshBasicNodeMaterial {
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2408
|
+
class OutlinesMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
2409
|
+
/** Whether thickness is constant in screen pixels */
|
|
2410
|
+
screenspace: () => uniform(false),
|
|
2411
|
+
/** Outline thickness */
|
|
2412
|
+
thickness: () => uniform(0.05),
|
|
2413
|
+
/** Drawing-buffer size, for screenspace thickness */
|
|
2414
|
+
size: () => uniform(new THREE.Vector2(1, 1))
|
|
2415
|
+
}) {
|
|
2236
2416
|
/** Type flag for identification */
|
|
2237
2417
|
isOutlinesMaterial = true;
|
|
2238
2418
|
constructor() {
|
|
2239
2419
|
super();
|
|
2240
|
-
this.
|
|
2241
|
-
this._color = uniform(new THREE.Color("black"));
|
|
2242
|
-
this._opacityValue = uniform(1);
|
|
2243
|
-
this._thickness = uniform(0.05);
|
|
2244
|
-
this._size = uniform(new THREE.Vector2(1, 1));
|
|
2420
|
+
this.color.set("black");
|
|
2245
2421
|
this.side = THREE.BackSide;
|
|
2246
2422
|
this.transparent = false;
|
|
2247
2423
|
this._buildOutlineShader();
|
|
2248
2424
|
}
|
|
2249
2425
|
_buildOutlineShader() {
|
|
2250
|
-
const
|
|
2251
|
-
const colorUniform = this._color;
|
|
2252
|
-
const opacityUniform = this._opacityValue;
|
|
2253
|
-
const thicknessUniform = this._thickness;
|
|
2254
|
-
const sizeUniform = this._size;
|
|
2426
|
+
const { screenspace, thickness, size } = this.uniforms;
|
|
2255
2427
|
this.positionNode = Fn(() => {
|
|
2256
2428
|
const position = positionLocal.toVar();
|
|
2257
2429
|
const normal = normalLocal.toVar();
|
|
2258
|
-
const
|
|
2259
|
-
const screenspacePos = position.add(normal.mul(thicknessUniform));
|
|
2430
|
+
const screenspacePos = position.add(normal.mul(thickness));
|
|
2260
2431
|
const clipPos = cameraProjectionMatrix.mul(modelViewMatrix.mul(vec4(position, 1)));
|
|
2261
2432
|
const clipNormal = cameraProjectionMatrix.mul(modelViewMatrix.mul(vec4(normal, 0)));
|
|
2262
|
-
normalize(clipNormal.xy).mul(
|
|
2263
|
-
const worldOffset = normal.mul(
|
|
2264
|
-
return select(
|
|
2265
|
-
})();
|
|
2266
|
-
this.outputNode = Fn(() => {
|
|
2267
|
-
return vec4(colorUniform, opacityUniform);
|
|
2433
|
+
normalize(clipNormal.xy).mul(thickness).div(size).mul(clipPos.w).mul(2);
|
|
2434
|
+
const worldOffset = normal.mul(thickness);
|
|
2435
|
+
return select(screenspace, screenspacePos, position.add(worldOffset));
|
|
2268
2436
|
})();
|
|
2269
|
-
|
|
2270
|
-
//* Uniform Accessors ==============================
|
|
2271
|
-
/** Whether to use screenspace thickness */
|
|
2272
|
-
get screenspace() {
|
|
2273
|
-
return this._screenspace.value > 0.5;
|
|
2274
|
-
}
|
|
2275
|
-
set screenspace(v) {
|
|
2276
|
-
this._screenspace.value = v ? 1 : 0;
|
|
2277
|
-
}
|
|
2278
|
-
/** Outline color */
|
|
2279
|
-
get color() {
|
|
2280
|
-
return this._color.value;
|
|
2281
|
-
}
|
|
2282
|
-
set color(v) {
|
|
2283
|
-
if (v instanceof THREE.Color) this._color.value = v;
|
|
2284
|
-
else this._color.value = new THREE.Color(v);
|
|
2285
|
-
}
|
|
2286
|
-
/** Outline opacity */
|
|
2287
|
-
get opacity() {
|
|
2288
|
-
return this._opacityValue.value;
|
|
2289
|
-
}
|
|
2290
|
-
set opacity(v) {
|
|
2291
|
-
this._opacityValue.value = v;
|
|
2292
|
-
}
|
|
2293
|
-
/** Outline thickness */
|
|
2294
|
-
get thickness() {
|
|
2295
|
-
return this._thickness.value;
|
|
2296
|
-
}
|
|
2297
|
-
set thickness(v) {
|
|
2298
|
-
this._thickness.value = v;
|
|
2299
|
-
}
|
|
2300
|
-
/** Screen size for screenspace calculations */
|
|
2301
|
-
get size() {
|
|
2302
|
-
return this._size.value;
|
|
2303
|
-
}
|
|
2304
|
-
set size(v) {
|
|
2305
|
-
this._size.value = v;
|
|
2437
|
+
this.outputNode = Fn(() => vec4(materialColor, materialOpacity))();
|
|
2306
2438
|
}
|
|
2307
2439
|
}
|
|
2308
2440
|
function Outlines({
|
|
@@ -2431,11 +2563,11 @@ const RenderCubeTexture = /* @__PURE__ */ React.forwardRef(
|
|
|
2431
2563
|
depthBuffer,
|
|
2432
2564
|
generateMipmaps
|
|
2433
2565
|
};
|
|
2434
|
-
const fboA2 = new
|
|
2566
|
+
const fboA2 = new CubeRenderTarget(fboSize, settings);
|
|
2435
2567
|
fboA2.texture.isRenderTargetTexture = !flip;
|
|
2436
2568
|
fboA2.texture.flipY = true;
|
|
2437
2569
|
fboA2.texture.type = THREE.HalfFloatType;
|
|
2438
|
-
const fboB2 = new
|
|
2570
|
+
const fboB2 = new CubeRenderTarget(fboSize, settings);
|
|
2439
2571
|
fboB2.texture.isRenderTargetTexture = !flip;
|
|
2440
2572
|
fboB2.texture.flipY = true;
|
|
2441
2573
|
fboB2.texture.type = THREE.HalfFloatType;
|
|
@@ -2885,7 +3017,7 @@ function useCubeCamera({ resolution = 256, near = 0.1, far = 1e3, envMap, fog }
|
|
|
2885
3017
|
const gl = useThree(({ gl: gl2 }) => gl2);
|
|
2886
3018
|
const scene = useThree(({ scene: scene2 }) => scene2);
|
|
2887
3019
|
const fbo = useMemo(() => {
|
|
2888
|
-
const fbo2 = new
|
|
3020
|
+
const fbo2 = new CubeRenderTarget(resolution);
|
|
2889
3021
|
fbo2.texture.type = HalfFloatType;
|
|
2890
3022
|
return fbo2;
|
|
2891
3023
|
}, [resolution]);
|
|
@@ -3268,9 +3400,8 @@ function PresentationControls({
|
|
|
3268
3400
|
azimuth = [-Infinity, Infinity],
|
|
3269
3401
|
damping = 0.25
|
|
3270
3402
|
}) {
|
|
3271
|
-
const events = useThree(
|
|
3272
|
-
const
|
|
3273
|
-
const explDomElement = domElement || events.connected || gl.domElement;
|
|
3403
|
+
const { events, renderer, invalidate } = useThree();
|
|
3404
|
+
const explDomElement = domElement || events.connected || renderer.domElement;
|
|
3274
3405
|
const { size } = useThree();
|
|
3275
3406
|
const rPolar = React.useMemo(
|
|
3276
3407
|
() => [rotation[0] + polar[0], rotation[0] + polar[1]],
|
|
@@ -3287,18 +3418,20 @@ function PresentationControls({
|
|
|
3287
3418
|
React.useEffect(() => {
|
|
3288
3419
|
if (global && cursor && enabled) {
|
|
3289
3420
|
explDomElement.style.cursor = "grab";
|
|
3290
|
-
|
|
3421
|
+
renderer.domElement.style.cursor = "";
|
|
3291
3422
|
return () => {
|
|
3292
3423
|
explDomElement.style.cursor = "default";
|
|
3293
|
-
|
|
3424
|
+
renderer.domElement.style.cursor = "default";
|
|
3294
3425
|
};
|
|
3295
3426
|
}
|
|
3296
3427
|
}, [global, cursor, explDomElement, enabled]);
|
|
3297
3428
|
const [animation] = React.useState({ scale: 1, rotation: rInitial, damping });
|
|
3298
3429
|
const ref = React.useRef(null);
|
|
3299
3430
|
useFrame((state, delta) => {
|
|
3300
|
-
|
|
3301
|
-
easing.
|
|
3431
|
+
let changed = false;
|
|
3432
|
+
changed ||= easing.damp3(ref.current.scale, animation.scale, animation.damping, delta);
|
|
3433
|
+
changed ||= easing.dampE(ref.current.rotation, animation.rotation, animation.damping, delta);
|
|
3434
|
+
if (changed) state.invalidate();
|
|
3302
3435
|
});
|
|
3303
3436
|
const bind = useGesture(
|
|
3304
3437
|
{
|
|
@@ -3306,6 +3439,7 @@ function PresentationControls({
|
|
|
3306
3439
|
if (cursor && !global && enabled) explDomElement.style.cursor = last ? "auto" : "grab";
|
|
3307
3440
|
},
|
|
3308
3441
|
onDrag: ({ down, delta: [x, y], memo: [oldY, oldX] = animation.rotation || rInitial }) => {
|
|
3442
|
+
invalidate();
|
|
3309
3443
|
if (!enabled) return [y, x];
|
|
3310
3444
|
if (cursor) explDomElement.style.cursor = down ? "grabbing" : "grab";
|
|
3311
3445
|
x = MathUtils.clamp(oldX + x / size.width * Math.PI * speed, ...rAzimuth);
|
|
@@ -3314,9 +3448,12 @@ function PresentationControls({
|
|
|
3314
3448
|
animation.rotation = snap && !down ? rInitial : [y, x, 0];
|
|
3315
3449
|
animation.damping = snap && !down && typeof snap !== "boolean" ? snap : damping;
|
|
3316
3450
|
return [y, x];
|
|
3451
|
+
},
|
|
3452
|
+
onDragEnd: () => {
|
|
3453
|
+
invalidate();
|
|
3317
3454
|
}
|
|
3318
3455
|
},
|
|
3319
|
-
{ target: global ? explDomElement : void 0 }
|
|
3456
|
+
{ target: global ? explDomElement : void 0, enabled }
|
|
3320
3457
|
);
|
|
3321
3458
|
return /* @__PURE__ */ React.createElement("group", { ref, ...bind?.() }, children);
|
|
3322
3459
|
}
|
|
@@ -3325,6 +3462,10 @@ function roundToPixelRatio(value) {
|
|
|
3325
3462
|
const ratio = window.devicePixelRatio || 1;
|
|
3326
3463
|
return Math.round(value * ratio) / ratio;
|
|
3327
3464
|
}
|
|
3465
|
+
function getMaxAnisotropy(renderer) {
|
|
3466
|
+
const r = renderer;
|
|
3467
|
+
return r?.getMaxAnisotropy?.() ?? r?.capabilities?.getMaxAnisotropy?.() ?? 1;
|
|
3468
|
+
}
|
|
3328
3469
|
|
|
3329
3470
|
const context$7 = /* @__PURE__ */ React.createContext(null);
|
|
3330
3471
|
const rootCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -3350,7 +3491,7 @@ const ScrollHtml = React.forwardRef(
|
|
|
3350
3491
|
const group = React.useRef(null);
|
|
3351
3492
|
React.useImperativeHandle(ref, () => group.current, []);
|
|
3352
3493
|
const { width, height } = useThree((state2) => state2.size);
|
|
3353
|
-
const fiberState = React.useContext(context$
|
|
3494
|
+
const fiberState = React.useContext(context$b);
|
|
3354
3495
|
const root = React.useMemo(() => {
|
|
3355
3496
|
let root2 = rootCache.get(state.fixed);
|
|
3356
3497
|
if (!root2) {
|
|
@@ -3378,7 +3519,7 @@ const ScrollHtml = React.forwardRef(
|
|
|
3378
3519
|
style: { ...style, position: "absolute", top: 0, left: 0, willChange: "transform" },
|
|
3379
3520
|
...props
|
|
3380
3521
|
},
|
|
3381
|
-
/* @__PURE__ */ React.createElement(context$7.Provider, { value: state }, /* @__PURE__ */ React.createElement(context$
|
|
3522
|
+
/* @__PURE__ */ React.createElement(context$7.Provider, { value: state }, /* @__PURE__ */ React.createElement(context$b.Provider, { value: fiberState }, children))
|
|
3382
3523
|
)
|
|
3383
3524
|
);
|
|
3384
3525
|
return null;
|
|
@@ -3690,10 +3831,10 @@ const CloudInstance = /* @__PURE__ */ React.forwardRef(
|
|
|
3690
3831
|
return /* @__PURE__ */ React.createElement("group", { ref, ...props });
|
|
3691
3832
|
}
|
|
3692
3833
|
);
|
|
3693
|
-
const Cloud = /* @__PURE__ */ React.forwardRef((props, fref) => {
|
|
3834
|
+
const Cloud = /* @__PURE__ */ React.forwardRef(({ materialFactory, ...props }, fref) => {
|
|
3694
3835
|
const parent = React.useContext(context$6);
|
|
3695
3836
|
if (parent) return /* @__PURE__ */ React.createElement(CloudInstance, { ref: fref, ...props });
|
|
3696
|
-
return /* @__PURE__ */ React.createElement(Clouds,
|
|
3837
|
+
return /* @__PURE__ */ React.createElement(Clouds, { materialFactory }, /* @__PURE__ */ React.createElement(CloudInstance, { ref: fref, ...props }));
|
|
3697
3838
|
});
|
|
3698
3839
|
|
|
3699
3840
|
const CatmullRomLine = /* @__PURE__ */ React.forwardRef(function CatmullRomLine2({
|
|
@@ -4215,7 +4356,7 @@ const Text3D = /* @__PURE__ */ React.forwardRef(
|
|
|
4215
4356
|
return {
|
|
4216
4357
|
font,
|
|
4217
4358
|
size,
|
|
4218
|
-
height,
|
|
4359
|
+
depth: height,
|
|
4219
4360
|
bevelThickness,
|
|
4220
4361
|
bevelSize,
|
|
4221
4362
|
bevelEnabled,
|
|
@@ -4398,7 +4539,7 @@ const FaceMaterial = ({
|
|
|
4398
4539
|
"meshBasicMaterial",
|
|
4399
4540
|
{
|
|
4400
4541
|
map: texture,
|
|
4401
|
-
"map-anisotropy":
|
|
4542
|
+
"map-anisotropy": getMaxAnisotropy(renderer),
|
|
4402
4543
|
attach: `material-${index}`,
|
|
4403
4544
|
color: hover ? hoverColor : "white",
|
|
4404
4545
|
transparent: true,
|
|
@@ -4509,7 +4650,7 @@ function AxisHead({
|
|
|
4509
4650
|
"spriteMaterial",
|
|
4510
4651
|
{
|
|
4511
4652
|
map: texture,
|
|
4512
|
-
"map-anisotropy":
|
|
4653
|
+
"map-anisotropy": getMaxAnisotropy(renderer),
|
|
4513
4654
|
alphaTest: 0.3,
|
|
4514
4655
|
opacity: label ? 1 : 0.75,
|
|
4515
4656
|
toneMapped: false
|
|
@@ -4654,6 +4795,7 @@ const Html = /* @__PURE__ */ React.forwardRef(
|
|
|
4654
4795
|
}, ref) => {
|
|
4655
4796
|
const { gl, camera, scene, size, raycaster, events, viewport } = useThree();
|
|
4656
4797
|
const forceEven = useThree((state) => state.internal.forceEven);
|
|
4798
|
+
const { frustum } = useThree();
|
|
4657
4799
|
const [el] = React.useState(() => document.createElement(as));
|
|
4658
4800
|
const root = React.useRef(null);
|
|
4659
4801
|
const group = React.useRef(null);
|
|
@@ -4683,22 +4825,18 @@ const Html = /* @__PURE__ */ React.forwardRef(
|
|
|
4683
4825
|
if (group.current) {
|
|
4684
4826
|
if (!root.current) {
|
|
4685
4827
|
root.current = ReactDOM.createRoot(el);
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4828
|
+
scene.updateMatrixWorld();
|
|
4829
|
+
if (transform) {
|
|
4830
|
+
el.style.cssText = `position:absolute;top:0;left:0;pointer-events:none;overflow:hidden;`;
|
|
4831
|
+
} else {
|
|
4832
|
+
el.style.cssText = `position:absolute;top:0;left:0;transform:translate3d(0,-9999px,0);transform-origin:0 0;`;
|
|
4833
|
+
}
|
|
4692
4834
|
}
|
|
4693
4835
|
if (target) {
|
|
4694
4836
|
if (prepend) target.prepend(el);
|
|
4695
4837
|
else target.appendChild(el);
|
|
4696
4838
|
}
|
|
4697
4839
|
return () => {
|
|
4698
|
-
if (root.current) {
|
|
4699
|
-
root.current.unmount();
|
|
4700
|
-
root.current = null;
|
|
4701
|
-
}
|
|
4702
4840
|
if (target && target.contains(el)) {
|
|
4703
4841
|
target.removeChild(el);
|
|
4704
4842
|
}
|
|
@@ -4832,8 +4970,7 @@ const Html = /* @__PURE__ */ React.forwardRef(
|
|
|
4832
4970
|
if (transformOuterRef.current) {
|
|
4833
4971
|
const el2 = transformOuterRef.current.children[0];
|
|
4834
4972
|
if (el2?.clientWidth && el2?.clientHeight) {
|
|
4835
|
-
|
|
4836
|
-
if (isOrthographicCamera || geometry) {
|
|
4973
|
+
if (geometry) {
|
|
4837
4974
|
if (props.scale) {
|
|
4838
4975
|
if (!Array.isArray(props.scale)) {
|
|
4839
4976
|
occlusionMeshRef.current.scale.setScalar(1 / props.scale);
|
|
@@ -4865,64 +5002,7 @@ const Html = /* @__PURE__ */ React.forwardRef(
|
|
|
4865
5002
|
}
|
|
4866
5003
|
}
|
|
4867
5004
|
});
|
|
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
|
-
)));
|
|
5005
|
+
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
5006
|
}
|
|
4927
5007
|
);
|
|
4928
5008
|
|
|
@@ -5775,6 +5855,7 @@ const mW = /* @__PURE__ */ new THREE.Matrix4();
|
|
|
5775
5855
|
const mL = /* @__PURE__ */ new THREE.Matrix4();
|
|
5776
5856
|
const mL0Inv = /* @__PURE__ */ new THREE.Matrix4();
|
|
5777
5857
|
const mdL = /* @__PURE__ */ new THREE.Matrix4();
|
|
5858
|
+
const mdW = /* @__PURE__ */ new THREE.Matrix4();
|
|
5778
5859
|
const mG = /* @__PURE__ */ new THREE.Matrix4();
|
|
5779
5860
|
const bb = /* @__PURE__ */ new THREE.Box3();
|
|
5780
5861
|
const bbObj = /* @__PURE__ */ new THREE.Box3();
|
|
@@ -5889,7 +5970,8 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
|
|
|
5889
5970
|
onDragStart && onDragStart(props2);
|
|
5890
5971
|
invalidate();
|
|
5891
5972
|
},
|
|
5892
|
-
onDrag: (
|
|
5973
|
+
onDrag: (mdW_) => {
|
|
5974
|
+
mdW.copy(mdW_);
|
|
5893
5975
|
mP.copy(parentRef.current.matrixWorld);
|
|
5894
5976
|
mPInv.copy(mP).invert();
|
|
5895
5977
|
mW.copy(mW0).premultiply(mdW);
|
|
@@ -5901,12 +5983,12 @@ const PivotControls = /* @__PURE__ */ React.forwardRef(
|
|
|
5901
5983
|
}
|
|
5902
5984
|
const target = resolveObject(object);
|
|
5903
5985
|
if (target) target.matrix.copy(mL);
|
|
5904
|
-
onDrag && onDrag(mL, mdL, mW, mdW);
|
|
5986
|
+
onDrag && onDrag({ local: mL, deltaLocal: mdL, world: mW, deltaWorld: mdW });
|
|
5905
5987
|
invalidate();
|
|
5906
5988
|
},
|
|
5907
5989
|
onDragEnd: () => {
|
|
5908
5990
|
dragState.current = null;
|
|
5909
|
-
if (onDragEnd) onDragEnd();
|
|
5991
|
+
if (onDragEnd) onDragEnd({ local: mL, deltaLocal: mdL, world: mW, deltaWorld: mdW });
|
|
5910
5992
|
invalidate();
|
|
5911
5993
|
},
|
|
5912
5994
|
onHover: (props2) => {
|
|
@@ -6017,7 +6099,9 @@ const TransformControls = /* @__PURE__ */ React.forwardRef(
|
|
|
6017
6099
|
const group = React.useRef(null);
|
|
6018
6100
|
React.useLayoutEffect(() => {
|
|
6019
6101
|
if (object) {
|
|
6020
|
-
controls.attach(
|
|
6102
|
+
controls.attach(
|
|
6103
|
+
object instanceof THREE.Object3D ? object : object.current
|
|
6104
|
+
);
|
|
6021
6105
|
} else if (group.current instanceof THREE.Object3D) {
|
|
6022
6106
|
controls.attach(group.current);
|
|
6023
6107
|
}
|
|
@@ -6116,7 +6200,7 @@ const PointMaterial = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
|
6116
6200
|
return /* @__PURE__ */ React.createElement("primitive", { ...props, object: material, ref, attach: "material" });
|
|
6117
6201
|
});
|
|
6118
6202
|
|
|
6119
|
-
const PositionalAudio = /* @__PURE__ */ React.forwardRef(({ url, distance = 1, loop =
|
|
6203
|
+
const PositionalAudio = /* @__PURE__ */ React.forwardRef(({ url, distance = 1, loop = false, autoplay, ...props }, ref) => {
|
|
6120
6204
|
const sound = React.useRef(null);
|
|
6121
6205
|
React.useImperativeHandle(ref, () => sound.current, []);
|
|
6122
6206
|
const camera = useThree(({ camera: camera2 }) => camera2);
|
|
@@ -6128,7 +6212,9 @@ const PositionalAudio = /* @__PURE__ */ React.forwardRef(({ url, distance = 1, l
|
|
|
6128
6212
|
_sound.setBuffer(Array.isArray(buffer) ? buffer[0] : buffer);
|
|
6129
6213
|
_sound.setRefDistance(distance);
|
|
6130
6214
|
_sound.setLoop(loop);
|
|
6131
|
-
if (autoplay && !_sound.isPlaying)
|
|
6215
|
+
if (autoplay && !_sound.isPlaying) {
|
|
6216
|
+
_sound.play();
|
|
6217
|
+
}
|
|
6132
6218
|
}
|
|
6133
6219
|
}, [buffer, camera, distance, loop]);
|
|
6134
6220
|
React.useEffect(() => {
|
|
@@ -6197,7 +6283,6 @@ const tempMatrix = /* @__PURE__ */ new THREE.Matrix4();
|
|
|
6197
6283
|
const translation = /* @__PURE__ */ new THREE.Vector3();
|
|
6198
6284
|
const rotation = /* @__PURE__ */ new THREE.Quaternion();
|
|
6199
6285
|
const scale = /* @__PURE__ */ new THREE.Vector3();
|
|
6200
|
-
const isInstancedBufferAttribute = (attr) => attr.isInstancedBufferAttribute;
|
|
6201
6286
|
const Instance = /* @__PURE__ */ React.forwardRef(({ context, children, ...props }, ref) => {
|
|
6202
6287
|
React.useMemo(() => extend({ PositionMesh }), []);
|
|
6203
6288
|
const group = React.useRef(null);
|
|
@@ -6217,24 +6302,20 @@ const Instances = /* @__PURE__ */ React.forwardRef(({ context, children, range,
|
|
|
6217
6302
|
const parentRef = React.useRef(null);
|
|
6218
6303
|
React.useImperativeHandle(ref, () => parentRef.current, []);
|
|
6219
6304
|
const [instances, setInstances] = React.useState([]);
|
|
6305
|
+
const boundsDirty = React.useRef(true);
|
|
6220
6306
|
const [[matrices, colors]] = React.useState(() => {
|
|
6221
6307
|
const mArray = new Float32Array(limit * 16);
|
|
6222
6308
|
for (let i = 0; i < limit; i++) tempMatrix.identity().toArray(mArray, i * 16);
|
|
6223
6309
|
return [mArray, new Float32Array([...new Array(limit * 3)].map(() => 1))];
|
|
6224
6310
|
});
|
|
6225
6311
|
React.useEffect(() => {
|
|
6226
|
-
parentRef.current.instanceMatrix.needsUpdate = true;
|
|
6312
|
+
if (parentRef.current) parentRef.current.instanceMatrix.needsUpdate = true;
|
|
6227
6313
|
});
|
|
6228
6314
|
let iterations = 0;
|
|
6229
6315
|
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
6316
|
useFrame(() => {
|
|
6237
6317
|
if (frames === Infinity || iterations < frames) {
|
|
6318
|
+
if (!parentRef.current) return;
|
|
6238
6319
|
parentRef.current.updateMatrix();
|
|
6239
6320
|
parentRef.current.updateMatrixWorld();
|
|
6240
6321
|
parentMatrix.copy(parentRef.current.matrixWorld).invert();
|
|
@@ -6255,13 +6336,22 @@ const Instances = /* @__PURE__ */ React.forwardRef(({ context, children, range,
|
|
|
6255
6336
|
}
|
|
6256
6337
|
iterations++;
|
|
6257
6338
|
}
|
|
6339
|
+
if (boundsDirty.current && (frames === Infinity || iterations === frames)) {
|
|
6340
|
+
boundsDirty.current = false;
|
|
6341
|
+
if (parentRef.current.boundingBox) parentRef.current.computeBoundingBox();
|
|
6342
|
+
if (parentRef.current.boundingSphere) parentRef.current.computeBoundingSphere();
|
|
6343
|
+
}
|
|
6258
6344
|
});
|
|
6259
6345
|
const api = React.useMemo(
|
|
6260
6346
|
() => ({
|
|
6261
6347
|
getParent: () => parentRef,
|
|
6262
6348
|
subscribe: (ref2) => {
|
|
6263
6349
|
setInstances((instances2) => [...instances2, ref2]);
|
|
6264
|
-
|
|
6350
|
+
boundsDirty.current = true;
|
|
6351
|
+
return () => {
|
|
6352
|
+
setInstances((instances2) => instances2.filter((item) => item.current !== ref2.current));
|
|
6353
|
+
boundsDirty.current = true;
|
|
6354
|
+
};
|
|
6265
6355
|
}
|
|
6266
6356
|
}),
|
|
6267
6357
|
[]
|
|
@@ -6286,10 +6376,23 @@ const Merged = /* @__PURE__ */ React.forwardRef(function Merged2({ meshes, child
|
|
|
6286
6376
|
if (!isArray) {
|
|
6287
6377
|
for (const key of Object.keys(meshes)) if (!meshes[key].isMesh) delete meshes[key];
|
|
6288
6378
|
}
|
|
6289
|
-
const render = (args) =>
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6379
|
+
const render = (args) => {
|
|
6380
|
+
if (isArray) {
|
|
6381
|
+
return children(
|
|
6382
|
+
...args
|
|
6383
|
+
);
|
|
6384
|
+
}
|
|
6385
|
+
const instanceMap = {};
|
|
6386
|
+
const keys = Object.keys(meshes).filter((key) => meshes[key].isMesh);
|
|
6387
|
+
keys.forEach((key, i) => {
|
|
6388
|
+
instanceMap[key] = args[i];
|
|
6389
|
+
});
|
|
6390
|
+
return children(instanceMap);
|
|
6391
|
+
};
|
|
6392
|
+
const components = (isArray ? meshes : Object.values(meshes)).map((mesh) => {
|
|
6393
|
+
const { geometry, material } = mesh;
|
|
6394
|
+
return /* @__PURE__ */ React.createElement(Instances, { key: geometry.uuid, geometry, material, ...props });
|
|
6395
|
+
});
|
|
6293
6396
|
return /* @__PURE__ */ React.createElement("group", { ref }, renderRecursive(render, components));
|
|
6294
6397
|
});
|
|
6295
6398
|
function renderRecursive(render, components, results = []) {
|
|
@@ -7363,12 +7466,13 @@ function Sampler({ children, weight, transform, instances, mesh, count = 16, ...
|
|
|
7363
7466
|
return /* @__PURE__ */ React.createElement("group", { ref: group, ...props }, children);
|
|
7364
7467
|
}
|
|
7365
7468
|
|
|
7469
|
+
const pathStyle = (path) => path.userData?.style;
|
|
7366
7470
|
const Svg = /* @__PURE__ */ forwardRef(
|
|
7367
7471
|
function R3FSvg({ src, skipFill, skipStrokes, fillMaterial, strokeMaterial, fillMeshProps, strokeMeshProps, ...props }, ref) {
|
|
7368
7472
|
const svg = useLoader(SVGLoader, !src.startsWith("<svg") ? src : `data:image/svg+xml;utf8,${src}`);
|
|
7369
7473
|
const strokeGeometries = useMemo(
|
|
7370
7474
|
() => skipStrokes ? [] : svg.paths.map(
|
|
7371
|
-
(path) => path
|
|
7475
|
+
(path) => pathStyle(path)?.stroke === void 0 || pathStyle(path).stroke === "none" ? null : path.subPaths.map((subPath) => SVGLoader.pointsToStroke(subPath.getPoints(), pathStyle(path)))
|
|
7372
7476
|
),
|
|
7373
7477
|
[svg, skipStrokes]
|
|
7374
7478
|
);
|
|
@@ -7376,21 +7480,21 @@ const Svg = /* @__PURE__ */ forwardRef(
|
|
|
7376
7480
|
return () => strokeGeometries.forEach((group) => group && group.map((g) => g.dispose()));
|
|
7377
7481
|
}, [strokeGeometries]);
|
|
7378
7482
|
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
|
|
7483
|
+
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
7484
|
"meshBasicMaterial",
|
|
7381
7485
|
{
|
|
7382
|
-
color: path.
|
|
7383
|
-
opacity: path.
|
|
7486
|
+
color: pathStyle(path).fill,
|
|
7487
|
+
opacity: pathStyle(path).fillOpacity,
|
|
7384
7488
|
transparent: true,
|
|
7385
7489
|
side: DoubleSide,
|
|
7386
7490
|
depthWrite: false,
|
|
7387
7491
|
...fillMaterial
|
|
7388
7492
|
}
|
|
7389
|
-
))), !skipStrokes && path
|
|
7493
|
+
))), !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
7494
|
"meshBasicMaterial",
|
|
7391
7495
|
{
|
|
7392
|
-
color: path.
|
|
7393
|
-
opacity: path.
|
|
7496
|
+
color: pathStyle(path).stroke,
|
|
7497
|
+
opacity: pathStyle(path).strokeOpacity,
|
|
7394
7498
|
transparent: true,
|
|
7395
7499
|
side: DoubleSide,
|
|
7396
7500
|
depthWrite: false,
|
|
@@ -7561,7 +7665,7 @@ function Preload({ all, scene, camera }) {
|
|
|
7561
7665
|
});
|
|
7562
7666
|
}
|
|
7563
7667
|
gl.compile(scene || dScene, camera || dCamera);
|
|
7564
|
-
const cubeRenderTarget = new
|
|
7668
|
+
const cubeRenderTarget = new CubeRenderTarget(128);
|
|
7565
7669
|
const cubeCamera = new CubeCamera$1(0.01, 1e5, cubeRenderTarget);
|
|
7566
7670
|
cubeCamera.update(gl, scene || dScene);
|
|
7567
7671
|
cubeRenderTarget.dispose();
|
|
@@ -7613,8 +7717,8 @@ function useVideoTexture(srcOrSrcObject, {
|
|
|
7613
7717
|
});
|
|
7614
7718
|
if (src && IS_BROWSER && src.endsWith(".m3u8")) {
|
|
7615
7719
|
const hls = hlsRef.current = await getHls(hlsConfig);
|
|
7616
|
-
if (hls) {
|
|
7617
|
-
hls.on(Events.MEDIA_ATTACHED, () => void hls.loadSource(src));
|
|
7720
|
+
if (hls && _HLSModule) {
|
|
7721
|
+
hls.on(_HLSModule.Events.MEDIA_ATTACHED, () => void hls.loadSource(src));
|
|
7618
7722
|
hls.attachMedia(video2);
|
|
7619
7723
|
}
|
|
7620
7724
|
}
|
|
@@ -7834,9 +7938,125 @@ function Fbx({
|
|
|
7834
7938
|
return /* @__PURE__ */ React.createElement(Clone, { ...props, object });
|
|
7835
7939
|
}
|
|
7836
7940
|
|
|
7941
|
+
const SERVICE_KEY = "__drei_ktx2_service__";
|
|
7942
|
+
const DEFAULT_TRANSCODER_PATH = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/basis/";
|
|
7943
|
+
class KTX2LoaderServiceImpl {
|
|
7944
|
+
loader = null;
|
|
7945
|
+
renderer = null;
|
|
7946
|
+
_isReady = false;
|
|
7947
|
+
transcoderPath = DEFAULT_TRANSCODER_PATH;
|
|
7948
|
+
pendingCallbacks = [];
|
|
7949
|
+
/**
|
|
7950
|
+
* Get or create the singleton KTX2Loader instance.
|
|
7951
|
+
* The loader is created lazily on first access.
|
|
7952
|
+
*/
|
|
7953
|
+
getLoader() {
|
|
7954
|
+
if (!this.loader) {
|
|
7955
|
+
this.loader = new KTX2Loader();
|
|
7956
|
+
this.loader.setTranscoderPath(this.transcoderPath);
|
|
7957
|
+
}
|
|
7958
|
+
return this.loader;
|
|
7959
|
+
}
|
|
7960
|
+
/**
|
|
7961
|
+
* Register a renderer and call detectSupport.
|
|
7962
|
+
* Should be called from within React context (useLayoutEffect).
|
|
7963
|
+
* Flushes any queued callbacks.
|
|
7964
|
+
*/
|
|
7965
|
+
registerRenderer(renderer) {
|
|
7966
|
+
if (this._isReady && this.renderer === renderer) {
|
|
7967
|
+
return;
|
|
7968
|
+
}
|
|
7969
|
+
this.renderer = renderer;
|
|
7970
|
+
const loader = this.getLoader();
|
|
7971
|
+
loader.detectSupport(renderer);
|
|
7972
|
+
this._isReady = true;
|
|
7973
|
+
this.flushPendingCallbacks();
|
|
7974
|
+
}
|
|
7975
|
+
/**
|
|
7976
|
+
* Check if the service is ready (has renderer registered).
|
|
7977
|
+
*/
|
|
7978
|
+
isReady() {
|
|
7979
|
+
return this._isReady;
|
|
7980
|
+
}
|
|
7981
|
+
/**
|
|
7982
|
+
* Get the registered renderer, if any.
|
|
7983
|
+
*/
|
|
7984
|
+
getRenderer() {
|
|
7985
|
+
return this.renderer;
|
|
7986
|
+
}
|
|
7987
|
+
/**
|
|
7988
|
+
* Register a callback to run when renderer becomes available.
|
|
7989
|
+
* If renderer is already available, runs immediately.
|
|
7990
|
+
*/
|
|
7991
|
+
onReady(callback) {
|
|
7992
|
+
if (this._isReady) {
|
|
7993
|
+
callback();
|
|
7994
|
+
} else {
|
|
7995
|
+
this.pendingCallbacks.push(callback);
|
|
7996
|
+
}
|
|
7997
|
+
}
|
|
7998
|
+
/**
|
|
7999
|
+
* Process all pending callbacks.
|
|
8000
|
+
*/
|
|
8001
|
+
flushPendingCallbacks() {
|
|
8002
|
+
const callbacks = this.pendingCallbacks;
|
|
8003
|
+
this.pendingCallbacks = [];
|
|
8004
|
+
for (const callback of callbacks) {
|
|
8005
|
+
try {
|
|
8006
|
+
callback();
|
|
8007
|
+
} catch (error) {
|
|
8008
|
+
console.error("KTX2LoaderService: Error in pending callback:", error);
|
|
8009
|
+
}
|
|
8010
|
+
}
|
|
8011
|
+
}
|
|
8012
|
+
/**
|
|
8013
|
+
* Set the transcoder path for basis/ktx2 decoding.
|
|
8014
|
+
*/
|
|
8015
|
+
setTranscoderPath(path) {
|
|
8016
|
+
this.transcoderPath = path;
|
|
8017
|
+
if (this.loader) {
|
|
8018
|
+
this.loader.setTranscoderPath(path);
|
|
8019
|
+
}
|
|
8020
|
+
}
|
|
8021
|
+
/**
|
|
8022
|
+
* Get the current transcoder path.
|
|
8023
|
+
*/
|
|
8024
|
+
getTranscoderPath() {
|
|
8025
|
+
return this.transcoderPath;
|
|
8026
|
+
}
|
|
8027
|
+
/**
|
|
8028
|
+
* Dispose of the loader and reset state.
|
|
8029
|
+
* Useful for testing or cleanup.
|
|
8030
|
+
*/
|
|
8031
|
+
dispose() {
|
|
8032
|
+
if (this.loader) {
|
|
8033
|
+
this.loader.dispose();
|
|
8034
|
+
}
|
|
8035
|
+
const path = this.transcoderPath;
|
|
8036
|
+
this.loader = null;
|
|
8037
|
+
this.renderer = null;
|
|
8038
|
+
this._isReady = false;
|
|
8039
|
+
this.transcoderPath = path;
|
|
8040
|
+
this.pendingCallbacks = [];
|
|
8041
|
+
}
|
|
8042
|
+
}
|
|
8043
|
+
const KTX2LoaderService = globalThis[SERVICE_KEY] || (globalThis[SERVICE_KEY] = new KTX2LoaderServiceImpl());
|
|
8044
|
+
|
|
7837
8045
|
let dracoLoader = null;
|
|
7838
8046
|
let decoderPath = "https://www.gstatic.com/draco/versioned/decoders/1.5.5/";
|
|
7839
|
-
|
|
8047
|
+
let legacyApiWarned = false;
|
|
8048
|
+
function isOptionsObject(arg) {
|
|
8049
|
+
return typeof arg === "object" && arg !== null && !Array.isArray(arg);
|
|
8050
|
+
}
|
|
8051
|
+
function warnLegacyApi() {
|
|
8052
|
+
if (!legacyApiWarned) {
|
|
8053
|
+
legacyApiWarned = true;
|
|
8054
|
+
console.warn(
|
|
8055
|
+
"useGLTF: Boolean arguments are deprecated. Use options object instead:\n useGLTF(path, { draco: true, meshopt: true, ktx2: true })"
|
|
8056
|
+
);
|
|
8057
|
+
}
|
|
8058
|
+
}
|
|
8059
|
+
function extensions(useDraco = true, useMeshopt = true, useKTX2 = false, extendLoader, renderer) {
|
|
7840
8060
|
return (loader) => {
|
|
7841
8061
|
if (extendLoader) {
|
|
7842
8062
|
extendLoader(loader);
|
|
@@ -7852,36 +8072,110 @@ function extensions(useDraco = true, useMeshopt = true, extendLoader) {
|
|
|
7852
8072
|
const decoder = typeof MeshoptDecoder === "function" ? MeshoptDecoder() : MeshoptDecoder;
|
|
7853
8073
|
loader.setMeshoptDecoder(decoder);
|
|
7854
8074
|
}
|
|
8075
|
+
if (useKTX2) {
|
|
8076
|
+
const ktx2Loader = KTX2LoaderService.getLoader();
|
|
8077
|
+
if (typeof useKTX2 === "string") {
|
|
8078
|
+
ktx2Loader.setTranscoderPath(useKTX2);
|
|
8079
|
+
}
|
|
8080
|
+
if (renderer) {
|
|
8081
|
+
ktx2Loader.detectSupport(renderer);
|
|
8082
|
+
}
|
|
8083
|
+
loader.setKTX2Loader(ktx2Loader);
|
|
8084
|
+
}
|
|
7855
8085
|
};
|
|
7856
8086
|
}
|
|
7857
|
-
|
|
7858
|
-
|
|
8087
|
+
function useGLTF(path, optionsOrDraco, useMeshoptArg, useKTX2Arg, extendLoaderArg) {
|
|
8088
|
+
let draco = true;
|
|
8089
|
+
let meshopt = true;
|
|
8090
|
+
let ktx2 = false;
|
|
8091
|
+
let extendLoader;
|
|
8092
|
+
if (isOptionsObject(optionsOrDraco)) {
|
|
8093
|
+
draco = optionsOrDraco.draco ?? true;
|
|
8094
|
+
meshopt = optionsOrDraco.meshopt ?? true;
|
|
8095
|
+
ktx2 = optionsOrDraco.ktx2 ?? false;
|
|
8096
|
+
extendLoader = optionsOrDraco.extendLoader;
|
|
8097
|
+
} else if (optionsOrDraco !== void 0) {
|
|
8098
|
+
warnLegacyApi();
|
|
8099
|
+
draco = optionsOrDraco;
|
|
8100
|
+
meshopt = useMeshoptArg ?? true;
|
|
8101
|
+
ktx2 = useKTX2Arg ?? false;
|
|
8102
|
+
extendLoader = extendLoaderArg;
|
|
8103
|
+
}
|
|
8104
|
+
const renderer = useThree((state) => state.renderer);
|
|
8105
|
+
useLayoutEffect(() => {
|
|
8106
|
+
if (ktx2) {
|
|
8107
|
+
KTX2LoaderService.registerRenderer(renderer);
|
|
8108
|
+
}
|
|
8109
|
+
}, [ktx2, renderer]);
|
|
8110
|
+
return useLoader(GLTFLoader, path, extensions(draco, meshopt, ktx2, extendLoader, ktx2 ? renderer : void 0));
|
|
8111
|
+
}
|
|
8112
|
+
useGLTF.preload = (path, optionsOrDraco, useMeshoptArg, useKTX2Arg, extendLoaderArg) => {
|
|
8113
|
+
let draco = true;
|
|
8114
|
+
let meshopt = true;
|
|
8115
|
+
let ktx2 = false;
|
|
8116
|
+
let extendLoader;
|
|
8117
|
+
if (isOptionsObject(optionsOrDraco)) {
|
|
8118
|
+
draco = optionsOrDraco.draco ?? true;
|
|
8119
|
+
meshopt = optionsOrDraco.meshopt ?? true;
|
|
8120
|
+
ktx2 = optionsOrDraco.ktx2 ?? false;
|
|
8121
|
+
extendLoader = optionsOrDraco.extendLoader;
|
|
8122
|
+
} else if (optionsOrDraco !== void 0) {
|
|
8123
|
+
warnLegacyApi();
|
|
8124
|
+
draco = optionsOrDraco;
|
|
8125
|
+
meshopt = useMeshoptArg ?? true;
|
|
8126
|
+
ktx2 = useKTX2Arg ?? false;
|
|
8127
|
+
extendLoader = extendLoaderArg;
|
|
8128
|
+
}
|
|
8129
|
+
if (ktx2) {
|
|
8130
|
+
KTX2LoaderService.onReady(() => {
|
|
8131
|
+
const renderer = KTX2LoaderService.getRenderer();
|
|
8132
|
+
useLoader.preload(GLTFLoader, path, extensions(draco, meshopt, ktx2, extendLoader, renderer));
|
|
8133
|
+
});
|
|
8134
|
+
} else {
|
|
8135
|
+
useLoader.preload(GLTFLoader, path, extensions(draco, meshopt, false, extendLoader));
|
|
8136
|
+
}
|
|
8137
|
+
};
|
|
7859
8138
|
useGLTF.clear = (path) => useLoader.clear(GLTFLoader, path);
|
|
7860
8139
|
useGLTF.setDecoderPath = (path) => {
|
|
7861
8140
|
decoderPath = path;
|
|
7862
8141
|
};
|
|
8142
|
+
useGLTF.setKTX2TranscoderPath = (path) => {
|
|
8143
|
+
KTX2LoaderService.setTranscoderPath(path);
|
|
8144
|
+
};
|
|
7863
8145
|
const Gltf = /* @__PURE__ */ React.forwardRef(
|
|
7864
|
-
({ src, useDraco, useMeshOpt, extendLoader, ...props }, ref) => {
|
|
7865
|
-
const
|
|
8146
|
+
({ src, useDraco, useMeshOpt, extendLoader, options, ...props }, ref) => {
|
|
8147
|
+
const opts = options ?? {
|
|
8148
|
+
draco: useDraco,
|
|
8149
|
+
meshopt: useMeshOpt,
|
|
8150
|
+
extendLoader
|
|
8151
|
+
};
|
|
8152
|
+
const { scene } = useGLTF(src, opts);
|
|
7866
8153
|
return /* @__PURE__ */ React.createElement(Clone, { ref, ...props, object: scene });
|
|
7867
8154
|
}
|
|
7868
8155
|
);
|
|
7869
8156
|
|
|
7870
|
-
let transcoderPath = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/basis/";
|
|
7871
8157
|
function useKTX2(input, basisPath = true, extendLoader) {
|
|
7872
8158
|
const renderer = useThree((state) => state.renderer);
|
|
8159
|
+
useLayoutEffect(() => {
|
|
8160
|
+
KTX2LoaderService.registerRenderer(renderer);
|
|
8161
|
+
}, [renderer]);
|
|
7873
8162
|
const textures = useLoader(KTX2Loader, IsObject(input) ? Object.values(input) : input, (loader) => {
|
|
7874
8163
|
if (extendLoader) {
|
|
7875
8164
|
extendLoader(loader);
|
|
7876
8165
|
}
|
|
7877
8166
|
if (basisPath) {
|
|
7878
|
-
|
|
8167
|
+
const path = typeof basisPath === "string" ? basisPath : KTX2LoaderService.getTranscoderPath();
|
|
8168
|
+
loader.setTranscoderPath(path);
|
|
7879
8169
|
}
|
|
7880
8170
|
loader.detectSupport(renderer);
|
|
7881
8171
|
});
|
|
7882
8172
|
useEffect(() => {
|
|
7883
8173
|
const array = Array.isArray(textures) ? textures : [textures];
|
|
7884
|
-
array.forEach((texture) =>
|
|
8174
|
+
array.forEach((texture) => {
|
|
8175
|
+
if ("initTexture" in renderer) {
|
|
8176
|
+
renderer.initTexture(texture);
|
|
8177
|
+
}
|
|
8178
|
+
});
|
|
7885
8179
|
}, [renderer, textures]);
|
|
7886
8180
|
if (IsObject(input)) {
|
|
7887
8181
|
const keys = Object.keys(input);
|
|
@@ -7892,17 +8186,26 @@ function useKTX2(input, basisPath = true, extendLoader) {
|
|
|
7892
8186
|
return textures;
|
|
7893
8187
|
}
|
|
7894
8188
|
}
|
|
7895
|
-
useKTX2.preload = (url, basisPath = true, extendLoader) =>
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
8189
|
+
useKTX2.preload = (url, basisPath = true, extendLoader) => {
|
|
8190
|
+
KTX2LoaderService.onReady(() => {
|
|
8191
|
+
const renderer = KTX2LoaderService.getRenderer();
|
|
8192
|
+
useLoader.preload(KTX2Loader, url, (loader) => {
|
|
8193
|
+
if (extendLoader) {
|
|
8194
|
+
extendLoader(loader);
|
|
8195
|
+
}
|
|
8196
|
+
if (basisPath) {
|
|
8197
|
+
const path = typeof basisPath === "string" ? basisPath : KTX2LoaderService.getTranscoderPath();
|
|
8198
|
+
loader.setTranscoderPath(path);
|
|
8199
|
+
}
|
|
8200
|
+
if (renderer) {
|
|
8201
|
+
loader.detectSupport(renderer);
|
|
8202
|
+
}
|
|
8203
|
+
});
|
|
8204
|
+
});
|
|
8205
|
+
};
|
|
7903
8206
|
useKTX2.clear = (input) => useLoader.clear(KTX2Loader, input);
|
|
7904
8207
|
useKTX2.setTranscoderPath = (path) => {
|
|
7905
|
-
|
|
8208
|
+
KTX2LoaderService.setTranscoderPath(path);
|
|
7906
8209
|
};
|
|
7907
8210
|
const Ktx2 = ({ children, input, basisPath, extendLoader }) => {
|
|
7908
8211
|
const texture = useKTX2(input, basisPath, extendLoader);
|
|
@@ -8096,6 +8399,7 @@ function useEffectfulState(fn, deps = [], cb) {
|
|
|
8096
8399
|
}
|
|
8097
8400
|
|
|
8098
8401
|
function Stats({ showPanel = 0, className, parent }) {
|
|
8402
|
+
React.useEffect(() => void console.warn("drei: <Stats /> is deprecated, use <StatsGl /> instead."), []);
|
|
8099
8403
|
const stats = useEffectfulState(() => new StatsImpl(), []);
|
|
8100
8404
|
React.useEffect(() => {
|
|
8101
8405
|
if (stats) {
|
|
@@ -8124,6 +8428,7 @@ const StatsGl = /* @__PURE__ */ React.forwardRef(
|
|
|
8124
8428
|
const stats2 = new Stats$1({
|
|
8125
8429
|
...props
|
|
8126
8430
|
});
|
|
8431
|
+
stats2.init(renderer);
|
|
8127
8432
|
return stats2;
|
|
8128
8433
|
}, [renderer]);
|
|
8129
8434
|
React.useImperativeHandle(fref, () => stats.domElement, [stats]);
|
|
@@ -8141,7 +8446,7 @@ const StatsGl = /* @__PURE__ */ React.forwardRef(
|
|
|
8141
8446
|
return () => {
|
|
8142
8447
|
if (classNames.length) stats.domElement.classList.remove(...classNames);
|
|
8143
8448
|
node?.removeChild(stats.domElement);
|
|
8144
|
-
stats.
|
|
8449
|
+
stats.dispose();
|
|
8145
8450
|
};
|
|
8146
8451
|
}
|
|
8147
8452
|
}, [parent, stats, className, id, clearStatsGlStyle]);
|
|
@@ -8149,7 +8454,7 @@ const StatsGl = /* @__PURE__ */ React.forwardRef(
|
|
|
8149
8454
|
() => {
|
|
8150
8455
|
stats.begin();
|
|
8151
8456
|
},
|
|
8152
|
-
{ before: "
|
|
8457
|
+
{ before: "update" }
|
|
8153
8458
|
);
|
|
8154
8459
|
useFrame(
|
|
8155
8460
|
() => {
|
|
@@ -8314,8 +8619,9 @@ const TUNNEL_KEY = "__drei_view_tunnel__";
|
|
|
8314
8619
|
const tracked = globalThis[TUNNEL_KEY] || (globalThis[TUNNEL_KEY] = tunnel());
|
|
8315
8620
|
function computeContainerPosition(canvasSize, trackRect, forceEven) {
|
|
8316
8621
|
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
8622
|
const canvasBottom = canvasSize.top + canvasSize.height;
|
|
8623
|
+
const canvasRight = canvasSize.left + canvasSize.width;
|
|
8624
|
+
const isOffscreen = trackBottom < canvasSize.top || trackTop > canvasBottom || right < canvasSize.left || trackLeft > canvasRight;
|
|
8319
8625
|
const rawBottom = canvasBottom - trackBottom;
|
|
8320
8626
|
const rawLeft = trackLeft - canvasSize.left;
|
|
8321
8627
|
const rawTop = trackTop - canvasSize.top;
|
|
@@ -8507,7 +8813,7 @@ const HtmlView = /* @__PURE__ */ React.forwardRef(
|
|
|
8507
8813
|
);
|
|
8508
8814
|
const View = /* @__PURE__ */ (() => {
|
|
8509
8815
|
const _View = React.forwardRef((props, fref) => {
|
|
8510
|
-
const store = React.useContext(context$
|
|
8816
|
+
const store = React.useContext(context$b);
|
|
8511
8817
|
if (!store) return /* @__PURE__ */ React.createElement(HtmlView, { ref: fref, ...props });
|
|
8512
8818
|
else return /* @__PURE__ */ React.createElement(CanvasView, { ref: fref, ...props });
|
|
8513
8819
|
});
|
|
@@ -8875,12 +9181,12 @@ useEnvironment.preload = (preloadOptions) => {
|
|
|
8875
9181
|
if (extensions) extensions(loader2);
|
|
8876
9182
|
});
|
|
8877
9183
|
};
|
|
8878
|
-
const
|
|
9184
|
+
const clearDefaultOptions = {
|
|
8879
9185
|
files: defaultFiles,
|
|
8880
9186
|
preset: void 0
|
|
8881
9187
|
};
|
|
8882
9188
|
useEnvironment.clear = (clearOptions) => {
|
|
8883
|
-
const options = { ...
|
|
9189
|
+
const options = { ...clearDefaultOptions, ...clearOptions };
|
|
8884
9190
|
let { files } = options;
|
|
8885
9191
|
const { preset } = options;
|
|
8886
9192
|
if (preset) {
|
|
@@ -9003,7 +9309,7 @@ function EnvironmentPortal({
|
|
|
9003
9309
|
const camera = React.useRef(null);
|
|
9004
9310
|
const [virtualScene] = React.useState(() => new Scene());
|
|
9005
9311
|
const fbo = React.useMemo(() => {
|
|
9006
|
-
const fbo2 = new
|
|
9312
|
+
const fbo2 = new CubeRenderTarget(resolution);
|
|
9007
9313
|
fbo2.texture.type = HalfFloatType;
|
|
9008
9314
|
return fbo2;
|
|
9009
9315
|
}, [resolution]);
|
|
@@ -9574,9 +9880,14 @@ function Select({
|
|
|
9574
9880
|
const oldControlsEnabled = controls?.enabled;
|
|
9575
9881
|
let isDown = false;
|
|
9576
9882
|
function prepareRay(event, vec) {
|
|
9577
|
-
const
|
|
9883
|
+
const canvas = gl.domElement;
|
|
9884
|
+
const rect = canvas.getBoundingClientRect();
|
|
9885
|
+
const x = event.clientX - rect.left;
|
|
9886
|
+
const y = event.clientY - rect.top;
|
|
9578
9887
|
const { width, height } = size;
|
|
9579
|
-
|
|
9888
|
+
const normalizedX = x / width * 2 - 1;
|
|
9889
|
+
const normalizedY = -(y / height) * 2 + 1;
|
|
9890
|
+
vec.set(normalizedX, normalizedY, -1);
|
|
9580
9891
|
}
|
|
9581
9892
|
function onSelectStart(event) {
|
|
9582
9893
|
if (controls) controls.enabled = false;
|
|
@@ -9664,62 +9975,63 @@ const remap = /* @__PURE__ */ Fn((inputs) => {
|
|
|
9664
9975
|
const [value, min1, max1, min2, max2] = inputs;
|
|
9665
9976
|
return min2.add(value.sub(min1).mul(max2.sub(min2)).div(max1.sub(min1)));
|
|
9666
9977
|
});
|
|
9667
|
-
class WireframeMaterialImpl extends MeshBasicNodeMaterial {
|
|
9668
|
-
|
|
9669
|
-
|
|
9670
|
-
|
|
9671
|
-
|
|
9672
|
-
|
|
9673
|
-
|
|
9674
|
-
|
|
9675
|
-
|
|
9676
|
-
|
|
9677
|
-
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9978
|
+
class WireframeMaterialImpl extends withUniforms(MeshBasicNodeMaterial, {
|
|
9979
|
+
/** Stroke (edge) opacity, default: 1 */
|
|
9980
|
+
strokeOpacity: () => uniform(1),
|
|
9981
|
+
/** Fill opacity (background), default: 0.25 */
|
|
9982
|
+
fillOpacity: () => uniform(0.25),
|
|
9983
|
+
/** Mix factor between material color and fill color, default: 0 */
|
|
9984
|
+
fillMix: () => uniform(0),
|
|
9985
|
+
/** Edge thickness 0-1, default: 0.05 */
|
|
9986
|
+
thickness: () => uniform(0.05),
|
|
9987
|
+
/** Use different color for backfaces, default: false */
|
|
9988
|
+
colorBackfaces: () => uniform(false),
|
|
9989
|
+
/** Invert dash pattern, default: true */
|
|
9990
|
+
dashInvert: () => uniform(true),
|
|
9991
|
+
/** Enable dashed lines, default: false */
|
|
9992
|
+
dash: () => uniform(false),
|
|
9993
|
+
/** Number of dash repeats, default: 4 */
|
|
9994
|
+
dashRepeats: () => uniform(4),
|
|
9995
|
+
/** Dash length 0-1, default: 0.5 */
|
|
9996
|
+
dashLength: () => uniform(0.5),
|
|
9997
|
+
/** Squeeze thickness toward line center, default: false */
|
|
9998
|
+
squeeze: () => uniform(false),
|
|
9999
|
+
/** Minimum squeeze factor, default: 0.2 */
|
|
10000
|
+
squeezeMin: () => uniform(0.2),
|
|
10001
|
+
/** Maximum squeeze factor, default: 1 */
|
|
10002
|
+
squeezeMax: () => uniform(1),
|
|
10003
|
+
/** Stroke (edge) color */
|
|
10004
|
+
stroke: () => uniform(new THREE.Color("#ff0000")),
|
|
10005
|
+
/** Backface stroke color */
|
|
10006
|
+
backfaceStroke: () => uniform(new THREE.Color("#0000ff")),
|
|
10007
|
+
/** Fill (background) color */
|
|
10008
|
+
fill: () => uniform(new THREE.Color("#00ff00"))
|
|
10009
|
+
}) {
|
|
9685
10010
|
/** Type flag for identification */
|
|
9686
10011
|
isWireframeMaterial = true;
|
|
9687
10012
|
constructor() {
|
|
9688
10013
|
super();
|
|
9689
|
-
this._strokeOpacity = uniform(1);
|
|
9690
|
-
this._fillOpacity = uniform(0.25);
|
|
9691
|
-
this._fillMix = uniform(0);
|
|
9692
|
-
this._thickness = uniform(0.05);
|
|
9693
|
-
this._colorBackfaces = uniform(0);
|
|
9694
|
-
this._dashInvert = uniform(1);
|
|
9695
|
-
this._dash = uniform(0);
|
|
9696
|
-
this._dashRepeats = uniform(4);
|
|
9697
|
-
this._dashLength = uniform(0.5);
|
|
9698
|
-
this._squeeze = uniform(0);
|
|
9699
|
-
this._squeezeMin = uniform(0.2);
|
|
9700
|
-
this._squeezeMax = uniform(1);
|
|
9701
|
-
this._stroke = uniform(new THREE.Color("#ff0000"));
|
|
9702
|
-
this._backfaceStroke = uniform(new THREE.Color("#0000ff"));
|
|
9703
|
-
this._fill = uniform(new THREE.Color("#00ff00"));
|
|
9704
10014
|
this.transparent = true;
|
|
9705
10015
|
this.side = THREE.DoubleSide;
|
|
9706
10016
|
this._buildWireframeShader();
|
|
9707
10017
|
}
|
|
9708
10018
|
_buildWireframeShader() {
|
|
9709
|
-
const
|
|
9710
|
-
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
|
|
9716
|
-
|
|
9717
|
-
|
|
9718
|
-
|
|
9719
|
-
|
|
9720
|
-
|
|
9721
|
-
|
|
9722
|
-
|
|
10019
|
+
const {
|
|
10020
|
+
strokeOpacity: strokeOpacityUniform,
|
|
10021
|
+
fillOpacity: fillOpacityUniform,
|
|
10022
|
+
thickness: thicknessUniform,
|
|
10023
|
+
colorBackfaces: colorBackfacesUniform,
|
|
10024
|
+
dashInvert: dashInvertUniform,
|
|
10025
|
+
dash: dashUniform,
|
|
10026
|
+
dashRepeats: dashRepeatsUniform,
|
|
10027
|
+
dashLength: dashLengthUniform,
|
|
10028
|
+
squeeze: squeezeUniform,
|
|
10029
|
+
squeezeMin: squeezeMinUniform,
|
|
10030
|
+
squeezeMax: squeezeMaxUniform,
|
|
10031
|
+
stroke: strokeUniform,
|
|
10032
|
+
backfaceStroke: backfaceStrokeUniform,
|
|
10033
|
+
fill: fillUniform
|
|
10034
|
+
} = this.uniforms;
|
|
9723
10035
|
const barycentricAttr = attribute("barycentric", "vec3");
|
|
9724
10036
|
const vBarycentric = varying(barycentricAttr, "v_barycentric");
|
|
9725
10037
|
this.outputNode = Fn(() => {
|
|
@@ -9730,136 +10042,23 @@ class WireframeMaterialImpl extends MeshBasicNodeMaterial {
|
|
|
9730
10042
|
const isYSmallest = barycentric.y.lessThan(barycentric.x).and(barycentric.y.lessThan(barycentric.z));
|
|
9731
10043
|
positionAlong.assign(select(isYSmallest, float(1).sub(maxXY), maxXY));
|
|
9732
10044
|
const computedThickness = remap(thicknessUniform, float(0), float(1), float(0), float(0.34)).toVar();
|
|
9733
|
-
const squeezeEnabled = squeezeUniform.greaterThan(0.5);
|
|
9734
10045
|
const squeezeFactor = mix(squeezeMinUniform, squeezeMaxUniform, float(1).sub(sin(positionAlong.mul(Math.PI))));
|
|
9735
|
-
computedThickness.assign(select(
|
|
9736
|
-
const dashEnabled = dashUniform.greaterThan(0.5);
|
|
9737
|
-
const dashInverted = dashInvertUniform.greaterThan(0.5);
|
|
10046
|
+
computedThickness.assign(select(squeezeUniform, computedThickness.mul(squeezeFactor), computedThickness));
|
|
9738
10047
|
const baseOffset = float(1).div(dashRepeatsUniform).mul(dashLengthUniform).mul(0.5);
|
|
9739
10048
|
const additionalOffset = float(1).div(dashRepeatsUniform).mul(0.5);
|
|
9740
|
-
const dashOffset = select(
|
|
10049
|
+
const dashOffset = select(dashInvertUniform, baseOffset, baseOffset.add(additionalOffset));
|
|
9741
10050
|
const pattern = fract(positionAlong.add(dashOffset).mul(dashRepeatsUniform));
|
|
9742
10051
|
const dashMask = float(1).sub(aastep(dashLengthUniform, pattern));
|
|
9743
|
-
computedThickness.assign(select(
|
|
10052
|
+
computedThickness.assign(select(dashUniform, computedThickness.mul(dashMask), computedThickness));
|
|
9744
10053
|
const edge = float(1).sub(aastep(computedThickness, d));
|
|
9745
|
-
const useBackfaceColor = colorBackfacesUniform.greaterThan(0.5);
|
|
9746
10054
|
const isFrontFace = frontFacing;
|
|
9747
|
-
const currentStroke = select(
|
|
10055
|
+
const currentStroke = select(colorBackfacesUniform.and(isFrontFace.not()), backfaceStrokeUniform, strokeUniform);
|
|
9748
10056
|
const colorStroke = vec4(currentStroke, edge);
|
|
9749
10057
|
const colorFill = vec4(fillUniform, fillOpacityUniform);
|
|
9750
10058
|
const outColor = mix(colorFill, colorStroke, edge.mul(strokeOpacityUniform));
|
|
9751
10059
|
return outColor;
|
|
9752
10060
|
})();
|
|
9753
10061
|
}
|
|
9754
|
-
//* Uniform Accessors ==============================
|
|
9755
|
-
/** Stroke (edge) opacity, default: 1 */
|
|
9756
|
-
get strokeOpacity() {
|
|
9757
|
-
return this._strokeOpacity.value;
|
|
9758
|
-
}
|
|
9759
|
-
set strokeOpacity(v) {
|
|
9760
|
-
this._strokeOpacity.value = v;
|
|
9761
|
-
}
|
|
9762
|
-
/** Fill opacity (background), default: 0.25 */
|
|
9763
|
-
get fillOpacity() {
|
|
9764
|
-
return this._fillOpacity.value;
|
|
9765
|
-
}
|
|
9766
|
-
set fillOpacity(v) {
|
|
9767
|
-
this._fillOpacity.value = v;
|
|
9768
|
-
}
|
|
9769
|
-
/** Mix factor between material color and fill color, default: 0 */
|
|
9770
|
-
get fillMix() {
|
|
9771
|
-
return this._fillMix.value;
|
|
9772
|
-
}
|
|
9773
|
-
set fillMix(v) {
|
|
9774
|
-
this._fillMix.value = v;
|
|
9775
|
-
}
|
|
9776
|
-
/** Edge thickness 0-1, default: 0.05 */
|
|
9777
|
-
get thickness() {
|
|
9778
|
-
return this._thickness.value;
|
|
9779
|
-
}
|
|
9780
|
-
set thickness(v) {
|
|
9781
|
-
this._thickness.value = v;
|
|
9782
|
-
}
|
|
9783
|
-
/** Use different color for backfaces */
|
|
9784
|
-
get colorBackfaces() {
|
|
9785
|
-
return this._colorBackfaces.value > 0.5;
|
|
9786
|
-
}
|
|
9787
|
-
set colorBackfaces(v) {
|
|
9788
|
-
this._colorBackfaces.value = v ? 1 : 0;
|
|
9789
|
-
}
|
|
9790
|
-
/** Invert dash pattern */
|
|
9791
|
-
get dashInvert() {
|
|
9792
|
-
return this._dashInvert.value > 0.5;
|
|
9793
|
-
}
|
|
9794
|
-
set dashInvert(v) {
|
|
9795
|
-
this._dashInvert.value = v ? 1 : 0;
|
|
9796
|
-
}
|
|
9797
|
-
/** Enable dashed lines */
|
|
9798
|
-
get dash() {
|
|
9799
|
-
return this._dash.value > 0.5;
|
|
9800
|
-
}
|
|
9801
|
-
set dash(v) {
|
|
9802
|
-
this._dash.value = v ? 1 : 0;
|
|
9803
|
-
}
|
|
9804
|
-
/** Number of dash repeats, default: 4 */
|
|
9805
|
-
get dashRepeats() {
|
|
9806
|
-
return this._dashRepeats.value;
|
|
9807
|
-
}
|
|
9808
|
-
set dashRepeats(v) {
|
|
9809
|
-
this._dashRepeats.value = v;
|
|
9810
|
-
}
|
|
9811
|
-
/** Dash length 0-1, default: 0.5 */
|
|
9812
|
-
get dashLength() {
|
|
9813
|
-
return this._dashLength.value;
|
|
9814
|
-
}
|
|
9815
|
-
set dashLength(v) {
|
|
9816
|
-
this._dashLength.value = v;
|
|
9817
|
-
}
|
|
9818
|
-
/** Squeeze thickness toward line center */
|
|
9819
|
-
get squeeze() {
|
|
9820
|
-
return this._squeeze.value > 0.5;
|
|
9821
|
-
}
|
|
9822
|
-
set squeeze(v) {
|
|
9823
|
-
this._squeeze.value = v ? 1 : 0;
|
|
9824
|
-
}
|
|
9825
|
-
/** Minimum squeeze factor, default: 0.2 */
|
|
9826
|
-
get squeezeMin() {
|
|
9827
|
-
return this._squeezeMin.value;
|
|
9828
|
-
}
|
|
9829
|
-
set squeezeMin(v) {
|
|
9830
|
-
this._squeezeMin.value = v;
|
|
9831
|
-
}
|
|
9832
|
-
/** Maximum squeeze factor, default: 1 */
|
|
9833
|
-
get squeezeMax() {
|
|
9834
|
-
return this._squeezeMax.value;
|
|
9835
|
-
}
|
|
9836
|
-
set squeezeMax(v) {
|
|
9837
|
-
this._squeezeMax.value = v;
|
|
9838
|
-
}
|
|
9839
|
-
/** Stroke (edge) color */
|
|
9840
|
-
get stroke() {
|
|
9841
|
-
return this._stroke.value;
|
|
9842
|
-
}
|
|
9843
|
-
set stroke(v) {
|
|
9844
|
-
if (v instanceof THREE.Color) this._stroke.value = v;
|
|
9845
|
-
else this._stroke.value = new THREE.Color(v);
|
|
9846
|
-
}
|
|
9847
|
-
/** Backface stroke color */
|
|
9848
|
-
get backfaceStroke() {
|
|
9849
|
-
return this._backfaceStroke.value;
|
|
9850
|
-
}
|
|
9851
|
-
set backfaceStroke(v) {
|
|
9852
|
-
if (v instanceof THREE.Color) this._backfaceStroke.value = v;
|
|
9853
|
-
else this._backfaceStroke.value = new THREE.Color(v);
|
|
9854
|
-
}
|
|
9855
|
-
/** Fill (background) color */
|
|
9856
|
-
get fill() {
|
|
9857
|
-
return this._fill.value;
|
|
9858
|
-
}
|
|
9859
|
-
set fill(v) {
|
|
9860
|
-
if (v instanceof THREE.Color) this._fill.value = v;
|
|
9861
|
-
else this._fill.value = new THREE.Color(v);
|
|
9862
|
-
}
|
|
9863
10062
|
}
|
|
9864
10063
|
function setBarycentricCoordinates(geometry) {
|
|
9865
10064
|
const position = geometry.getAttribute("position");
|
|
@@ -9921,9 +10120,9 @@ const WireframeMaterial = /* @__PURE__ */ React.forwardRef(
|
|
|
9921
10120
|
squeeze,
|
|
9922
10121
|
squeezeMin,
|
|
9923
10122
|
squeezeMax,
|
|
9924
|
-
stroke
|
|
9925
|
-
backfaceStroke
|
|
9926
|
-
fill
|
|
10123
|
+
stroke,
|
|
10124
|
+
backfaceStroke,
|
|
10125
|
+
fill
|
|
9927
10126
|
}
|
|
9928
10127
|
);
|
|
9929
10128
|
}
|
|
@@ -10039,52 +10238,74 @@ function Wireframe({ geometry: customGeometry, ...props }) {
|
|
|
10039
10238
|
return /* @__PURE__ */ React.createElement(WireframeWithoutCustomGeo, { ...props });
|
|
10040
10239
|
}
|
|
10041
10240
|
|
|
10241
|
+
function isShadowCastingLight(object) {
|
|
10242
|
+
const light = object;
|
|
10243
|
+
return light.isLight === true && light.castShadow === true && light.shadow != null;
|
|
10244
|
+
}
|
|
10042
10245
|
function BakeShadows() {
|
|
10043
|
-
const
|
|
10044
|
-
|
|
10045
|
-
|
|
10046
|
-
|
|
10246
|
+
const scene = useThree((state) => state.scene);
|
|
10247
|
+
const priorRef = React.useRef(/* @__PURE__ */ new WeakMap());
|
|
10248
|
+
useFrame(() => {
|
|
10249
|
+
const prior = priorRef.current;
|
|
10250
|
+
scene.traverse((object) => {
|
|
10251
|
+
if (!isShadowCastingLight(object)) return;
|
|
10252
|
+
const shadow = object.shadow;
|
|
10253
|
+
if (prior.has(shadow)) return;
|
|
10254
|
+
prior.set(shadow, { autoUpdate: shadow.autoUpdate, needsUpdate: shadow.needsUpdate });
|
|
10255
|
+
shadow.autoUpdate = false;
|
|
10256
|
+
shadow.needsUpdate = true;
|
|
10257
|
+
});
|
|
10258
|
+
});
|
|
10259
|
+
React.useEffect(() => {
|
|
10260
|
+
const prior = priorRef.current;
|
|
10047
10261
|
return () => {
|
|
10048
|
-
|
|
10262
|
+
scene.traverse((object) => {
|
|
10263
|
+
if (!isShadowCastingLight(object)) return;
|
|
10264
|
+
const previous = prior.get(object.shadow);
|
|
10265
|
+
if (previous === void 0) return;
|
|
10266
|
+
object.shadow.autoUpdate = previous.autoUpdate;
|
|
10267
|
+
object.shadow.needsUpdate = previous.needsUpdate;
|
|
10268
|
+
prior.delete(object.shadow);
|
|
10269
|
+
});
|
|
10049
10270
|
};
|
|
10050
|
-
}, [
|
|
10271
|
+
}, [scene]);
|
|
10051
10272
|
return null;
|
|
10052
10273
|
}
|
|
10053
10274
|
|
|
10054
|
-
class ConvolutionMaterial extends MeshBasicNodeMaterial {
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
10062
|
-
|
|
10063
|
-
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
|
|
10069
|
-
|
|
10275
|
+
class ConvolutionMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
10276
|
+
/** Input color buffer to blur */
|
|
10277
|
+
inputBuffer: () => uniformTexture(new THREE.Texture()),
|
|
10278
|
+
/** Depth buffer for depth-aware blur */
|
|
10279
|
+
depthBuffer: () => uniformTexture(new THREE.Texture()),
|
|
10280
|
+
/** Render resolution */
|
|
10281
|
+
resolution: () => uniform(new THREE.Vector2()),
|
|
10282
|
+
/** Texel size (1/resolution) */
|
|
10283
|
+
texelSize: () => uniform(new THREE.Vector2()),
|
|
10284
|
+
/** Half texel size for offset calculations */
|
|
10285
|
+
halfTexelSize: () => uniform(new THREE.Vector2()),
|
|
10286
|
+
/** Kernel offset multiplier (changes per blur pass) */
|
|
10287
|
+
kernelValue: () => uniform(0),
|
|
10288
|
+
/** Scale factor for blur spread */
|
|
10289
|
+
scale: () => uniform(1),
|
|
10290
|
+
/** Camera near plane for depth calculations */
|
|
10291
|
+
cameraNear: () => uniform(0),
|
|
10292
|
+
/** Camera far plane for depth calculations */
|
|
10293
|
+
cameraFar: () => uniform(1),
|
|
10294
|
+
/** Minimum depth threshold for blur (objects closer than this get less blur) */
|
|
10295
|
+
minDepthThreshold: () => uniform(0),
|
|
10296
|
+
/** Maximum depth threshold for blur (objects farther than this get full blur) */
|
|
10297
|
+
maxDepthThreshold: () => uniform(1),
|
|
10298
|
+
/** Scale factor for depth-based blur adjustment */
|
|
10299
|
+
depthScale: () => uniform(0),
|
|
10300
|
+
/** Bias added to depth-to-blur ratio */
|
|
10301
|
+
depthToBlurRatioBias: () => uniform(0.25),
|
|
10302
|
+
/** Enable depth-based blur */
|
|
10303
|
+
useDepth: () => uniform(false)
|
|
10304
|
+
}) {
|
|
10070
10305
|
/** Kernel weights for multi-pass blur */
|
|
10071
10306
|
kernel;
|
|
10072
10307
|
constructor(texelSize = new THREE.Vector2()) {
|
|
10073
10308
|
super();
|
|
10074
|
-
this._inputBuffer = uniformTexture(new THREE.Texture());
|
|
10075
|
-
this._depthBuffer = uniformTexture(new THREE.Texture());
|
|
10076
|
-
this._resolution = uniform(new THREE.Vector2());
|
|
10077
|
-
this._texelSize = uniform(new THREE.Vector2());
|
|
10078
|
-
this._halfTexelSize = uniform(new THREE.Vector2());
|
|
10079
|
-
this._kernel = uniform(0);
|
|
10080
|
-
this._scale = uniform(1);
|
|
10081
|
-
this._cameraNear = uniform(0);
|
|
10082
|
-
this._cameraFar = uniform(1);
|
|
10083
|
-
this._minDepthThreshold = uniform(0);
|
|
10084
|
-
this._maxDepthThreshold = uniform(1);
|
|
10085
|
-
this._depthScale = uniform(0);
|
|
10086
|
-
this._depthToBlurRatioBias = uniform(0.25);
|
|
10087
|
-
this._useDepth = uniform(0);
|
|
10088
10309
|
this.blending = THREE.NoBlending;
|
|
10089
10310
|
this.depthWrite = false;
|
|
10090
10311
|
this.depthTest = false;
|
|
@@ -10094,16 +10315,19 @@ class ConvolutionMaterial extends MeshBasicNodeMaterial {
|
|
|
10094
10315
|
this._buildShader();
|
|
10095
10316
|
}
|
|
10096
10317
|
_buildShader() {
|
|
10097
|
-
const
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10318
|
+
const {
|
|
10319
|
+
inputBuffer: inputBufferTex,
|
|
10320
|
+
depthBuffer: depthBufferTex,
|
|
10321
|
+
texelSize: texelSizeUniform,
|
|
10322
|
+
halfTexelSize: halfTexelSizeUniform,
|
|
10323
|
+
kernelValue: kernelUniform,
|
|
10324
|
+
scale: scaleUniform,
|
|
10325
|
+
minDepthThreshold: minDepthThresholdUniform,
|
|
10326
|
+
maxDepthThreshold: maxDepthThresholdUniform,
|
|
10327
|
+
depthScale: depthScaleUniform,
|
|
10328
|
+
depthToBlurRatioBias: depthToBlurRatioBiasUniform,
|
|
10329
|
+
useDepth: useDepthUniform
|
|
10330
|
+
} = this.uniforms;
|
|
10107
10331
|
const baseUv = varying(uv(), "vUv");
|
|
10108
10332
|
const dUv = varying(
|
|
10109
10333
|
Fn(() => {
|
|
@@ -10117,17 +10341,16 @@ class ConvolutionMaterial extends MeshBasicNodeMaterial {
|
|
|
10117
10341
|
const vUv3 = varying(Fn(() => vec2$2(baseUv.x.sub(dUv.x), baseUv.y.sub(dUv.y)))(), "vUv3");
|
|
10118
10342
|
this.colorNode = Fn(() => {
|
|
10119
10343
|
const depthFactor = float(0).toVar();
|
|
10120
|
-
const
|
|
10121
|
-
const depthSample = texture(depthBufferTex, baseUv);
|
|
10344
|
+
const depthSample = depthBufferTex.sample(baseUv);
|
|
10122
10345
|
const rawDepth = float(1).sub(depthSample.r.mul(depthSample.a));
|
|
10123
10346
|
const smoothedDepth = smoothstep(minDepthThresholdUniform, maxDepthThresholdUniform, rawDepth);
|
|
10124
10347
|
const scaledDepth = smoothedDepth.mul(depthScaleUniform);
|
|
10125
|
-
const clampedDepth = max(float(0), min(float(1), scaledDepth.add(
|
|
10126
|
-
depthFactor.assign(select(
|
|
10127
|
-
const sample0 =
|
|
10128
|
-
const sample1 =
|
|
10129
|
-
const sample2 =
|
|
10130
|
-
const sample3 =
|
|
10348
|
+
const clampedDepth = max(float(0), min(float(1), scaledDepth.add(depthToBlurRatioBiasUniform)));
|
|
10349
|
+
depthFactor.assign(select(useDepthUniform, clampedDepth, float(0)));
|
|
10350
|
+
const sample0 = inputBufferTex.sample(mix(vUv0, baseUv, depthFactor));
|
|
10351
|
+
const sample1 = inputBufferTex.sample(mix(vUv1, baseUv, depthFactor));
|
|
10352
|
+
const sample2 = inputBufferTex.sample(mix(vUv2, baseUv, depthFactor));
|
|
10353
|
+
const sample3 = inputBufferTex.sample(mix(vUv3, baseUv, depthFactor));
|
|
10131
10354
|
const sum = sample0.add(sample1).add(sample2).add(sample3);
|
|
10132
10355
|
return sum.mul(0.25);
|
|
10133
10356
|
})();
|
|
@@ -10135,111 +10358,12 @@ class ConvolutionMaterial extends MeshBasicNodeMaterial {
|
|
|
10135
10358
|
//* Utility Methods ==============================
|
|
10136
10359
|
/** Set texel size for blur calculations */
|
|
10137
10360
|
setTexelSize(x, y) {
|
|
10138
|
-
this.
|
|
10139
|
-
this.
|
|
10361
|
+
this.uniforms.texelSize.value.set(x, y);
|
|
10362
|
+
this.uniforms.halfTexelSize.value.set(x * 0.5, y * 0.5);
|
|
10140
10363
|
}
|
|
10141
10364
|
/** Set render resolution */
|
|
10142
10365
|
setResolution(resolution) {
|
|
10143
|
-
this.
|
|
10144
|
-
}
|
|
10145
|
-
//* Uniform Accessors ==============================
|
|
10146
|
-
/** Input color buffer to blur */
|
|
10147
|
-
get inputBuffer() {
|
|
10148
|
-
return this._inputBuffer.value;
|
|
10149
|
-
}
|
|
10150
|
-
set inputBuffer(v) {
|
|
10151
|
-
this._inputBuffer.value = v ?? new THREE.Texture();
|
|
10152
|
-
}
|
|
10153
|
-
/** Depth buffer for depth-aware blur */
|
|
10154
|
-
get depthBuffer() {
|
|
10155
|
-
return this._depthBuffer.value;
|
|
10156
|
-
}
|
|
10157
|
-
set depthBuffer(v) {
|
|
10158
|
-
this._depthBuffer.value = v ?? new THREE.Texture();
|
|
10159
|
-
}
|
|
10160
|
-
/** Render resolution */
|
|
10161
|
-
get resolution() {
|
|
10162
|
-
return this._resolution.value;
|
|
10163
|
-
}
|
|
10164
|
-
set resolution(v) {
|
|
10165
|
-
this._resolution.value = v;
|
|
10166
|
-
}
|
|
10167
|
-
/** Texel size (1/resolution) */
|
|
10168
|
-
get texelSize() {
|
|
10169
|
-
return this._texelSize.value;
|
|
10170
|
-
}
|
|
10171
|
-
set texelSize(v) {
|
|
10172
|
-
this._texelSize.value = v;
|
|
10173
|
-
}
|
|
10174
|
-
/** Half texel size for offset calculations */
|
|
10175
|
-
get halfTexelSize() {
|
|
10176
|
-
return this._halfTexelSize.value;
|
|
10177
|
-
}
|
|
10178
|
-
set halfTexelSize(v) {
|
|
10179
|
-
this._halfTexelSize.value = v;
|
|
10180
|
-
}
|
|
10181
|
-
/** Kernel offset multiplier (changes per blur pass) */
|
|
10182
|
-
get kernelValue() {
|
|
10183
|
-
return this._kernel.value;
|
|
10184
|
-
}
|
|
10185
|
-
set kernelValue(v) {
|
|
10186
|
-
this._kernel.value = v;
|
|
10187
|
-
}
|
|
10188
|
-
/** Scale factor for blur spread */
|
|
10189
|
-
get scale() {
|
|
10190
|
-
return this._scale.value;
|
|
10191
|
-
}
|
|
10192
|
-
set scale(v) {
|
|
10193
|
-
this._scale.value = v;
|
|
10194
|
-
}
|
|
10195
|
-
/** Camera near plane for depth calculations */
|
|
10196
|
-
get cameraNear() {
|
|
10197
|
-
return this._cameraNear.value;
|
|
10198
|
-
}
|
|
10199
|
-
set cameraNear(v) {
|
|
10200
|
-
this._cameraNear.value = v;
|
|
10201
|
-
}
|
|
10202
|
-
/** Camera far plane for depth calculations */
|
|
10203
|
-
get cameraFar() {
|
|
10204
|
-
return this._cameraFar.value;
|
|
10205
|
-
}
|
|
10206
|
-
set cameraFar(v) {
|
|
10207
|
-
this._cameraFar.value = v;
|
|
10208
|
-
}
|
|
10209
|
-
/** Minimum depth threshold for blur (objects closer than this get less blur) */
|
|
10210
|
-
get minDepthThreshold() {
|
|
10211
|
-
return this._minDepthThreshold.value;
|
|
10212
|
-
}
|
|
10213
|
-
set minDepthThreshold(v) {
|
|
10214
|
-
this._minDepthThreshold.value = v;
|
|
10215
|
-
}
|
|
10216
|
-
/** Maximum depth threshold for blur (objects farther than this get full blur) */
|
|
10217
|
-
get maxDepthThreshold() {
|
|
10218
|
-
return this._maxDepthThreshold.value;
|
|
10219
|
-
}
|
|
10220
|
-
set maxDepthThreshold(v) {
|
|
10221
|
-
this._maxDepthThreshold.value = v;
|
|
10222
|
-
}
|
|
10223
|
-
/** Scale factor for depth-based blur adjustment */
|
|
10224
|
-
get depthScale() {
|
|
10225
|
-
return this._depthScale.value;
|
|
10226
|
-
}
|
|
10227
|
-
set depthScale(v) {
|
|
10228
|
-
this._depthScale.value = v;
|
|
10229
|
-
}
|
|
10230
|
-
/** Bias added to depth-to-blur ratio */
|
|
10231
|
-
get depthToBlurRatioBias() {
|
|
10232
|
-
return this._depthToBlurRatioBias.value;
|
|
10233
|
-
}
|
|
10234
|
-
set depthToBlurRatioBias(v) {
|
|
10235
|
-
this._depthToBlurRatioBias.value = v;
|
|
10236
|
-
}
|
|
10237
|
-
/** Enable/disable depth-based blur (0 = off, 1 = on) */
|
|
10238
|
-
get useDepth() {
|
|
10239
|
-
return this._useDepth.value > 0.5;
|
|
10240
|
-
}
|
|
10241
|
-
set useDepth(v) {
|
|
10242
|
-
this._useDepth.value = v ? 1 : 0;
|
|
10366
|
+
this.uniforms.resolution.value.copy(resolution);
|
|
10243
10367
|
}
|
|
10244
10368
|
}
|
|
10245
10369
|
|
|
@@ -10428,7 +10552,7 @@ const ImageWithUrl = /* @__PURE__ */ React.forwardRef(
|
|
|
10428
10552
|
return /* @__PURE__ */ React.createElement(ImageBase, { ...props, texture, ref });
|
|
10429
10553
|
}
|
|
10430
10554
|
);
|
|
10431
|
-
const ImageWithTexture = /* @__PURE__ */ React.forwardRef(({
|
|
10555
|
+
const ImageWithTexture = /* @__PURE__ */ React.forwardRef(({ ...props }, ref) => {
|
|
10432
10556
|
return /* @__PURE__ */ React.createElement(ImageBase, { ...props, ref });
|
|
10433
10557
|
});
|
|
10434
10558
|
const Image = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
@@ -10437,28 +10561,26 @@ const Image = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
|
10437
10561
|
else throw new Error("<Image /> requires a url or texture");
|
|
10438
10562
|
});
|
|
10439
10563
|
|
|
10440
|
-
class SpotLightMaterial extends MeshBasicNodeMaterial {
|
|
10441
|
-
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10445
|
-
|
|
10446
|
-
|
|
10447
|
-
|
|
10448
|
-
|
|
10449
|
-
|
|
10450
|
-
|
|
10564
|
+
class SpotLightMaterial extends withUniforms(MeshBasicNodeMaterial, {
|
|
10565
|
+
/** Scene depth (in the R channel) for soft intersection with scene geometry */
|
|
10566
|
+
depth: () => uniformTexture(new THREE.Texture()),
|
|
10567
|
+
/** Distance attenuation factor, default: 5 */
|
|
10568
|
+
attenuation: () => uniform(5),
|
|
10569
|
+
/** Angle falloff power - higher = sharper edges, default: 5 */
|
|
10570
|
+
anglePower: () => uniform(5),
|
|
10571
|
+
/** World position of the cone tip */
|
|
10572
|
+
spotPosition: () => uniform(new THREE.Vector3(0, 0, 0)),
|
|
10573
|
+
/** Light color, default: white */
|
|
10574
|
+
lightColor: () => uniform(new THREE.Color("white")),
|
|
10575
|
+
/** Camera near plane, for depth reconstruction */
|
|
10576
|
+
cameraNear: () => uniform(0.1),
|
|
10577
|
+
/** Camera far plane, for depth reconstruction */
|
|
10578
|
+
cameraFar: () => uniform(100),
|
|
10579
|
+
/** Drawing-buffer size in pixels. Zero disables depth-based soft edges. */
|
|
10580
|
+
resolution: () => uniform(new THREE.Vector2(0, 0))
|
|
10581
|
+
}) {
|
|
10451
10582
|
constructor() {
|
|
10452
10583
|
super();
|
|
10453
|
-
this._depth = uniformTexture(new THREE.Texture());
|
|
10454
|
-
this._opacity = uniform(1);
|
|
10455
|
-
this._attenuation = uniform(5);
|
|
10456
|
-
this._anglePower = uniform(5);
|
|
10457
|
-
this._spotPosition = uniform(new THREE.Vector3(0, 0, 0));
|
|
10458
|
-
this._lightColor = uniform(new THREE.Color("white"));
|
|
10459
|
-
this._cameraNear = uniform(0.1);
|
|
10460
|
-
this._cameraFar = uniform(100);
|
|
10461
|
-
this._resolution = uniform(new THREE.Vector2(0, 0));
|
|
10462
10584
|
this.transparent = true;
|
|
10463
10585
|
this.depthWrite = false;
|
|
10464
10586
|
this.side = THREE.DoubleSide;
|
|
@@ -10466,15 +10588,16 @@ class SpotLightMaterial extends MeshBasicNodeMaterial {
|
|
|
10466
10588
|
}
|
|
10467
10589
|
//* Build TSL Shader ==============================
|
|
10468
10590
|
_buildShader() {
|
|
10469
|
-
const
|
|
10470
|
-
|
|
10471
|
-
|
|
10472
|
-
|
|
10473
|
-
|
|
10474
|
-
|
|
10475
|
-
|
|
10476
|
-
|
|
10477
|
-
|
|
10591
|
+
const {
|
|
10592
|
+
depth: depthTex,
|
|
10593
|
+
attenuation: attenuationUniform,
|
|
10594
|
+
anglePower: anglePowerUniform,
|
|
10595
|
+
spotPosition: spotPositionUniform,
|
|
10596
|
+
lightColor: lightColorUniform,
|
|
10597
|
+
cameraNear: cameraNearUniform,
|
|
10598
|
+
cameraFar: cameraFarUniform,
|
|
10599
|
+
resolution: resolutionUniform
|
|
10600
|
+
} = this.uniforms;
|
|
10478
10601
|
const vNormal = varying(normalize(modelViewMatrix.transformDirection(normalLocal)), "vNormal");
|
|
10479
10602
|
const vIntensity = varying(
|
|
10480
10603
|
saturate(float(1).sub(distance(positionWorld, spotPositionUniform).div(attenuationUniform))),
|
|
@@ -10489,79 +10612,27 @@ class SpotLightMaterial extends MeshBasicNodeMaterial {
|
|
|
10489
10612
|
screenCoordinate.x.div(resolutionUniform.x),
|
|
10490
10613
|
float(1).sub(screenCoordinate.y.div(resolutionUniform.y))
|
|
10491
10614
|
);
|
|
10492
|
-
const sampledDepth =
|
|
10615
|
+
const sampledDepth = depthTex.sample(screenUV).r;
|
|
10493
10616
|
const near = cameraNearUniform;
|
|
10494
10617
|
const far = cameraFarUniform;
|
|
10495
10618
|
const sceneViewZ = near.mul(far).div(far.sub(near).mul(sampledDepth).sub(far));
|
|
10496
10619
|
const depthDiff = vViewZ.sub(sceneViewZ);
|
|
10497
10620
|
const softFactor = smoothstep(float(0), float(1), depthDiff);
|
|
10498
10621
|
intensity.assign(select(hasDepth, intensity.mul(softFactor), intensity));
|
|
10499
|
-
return vec4(lightColorUniform, intensity.mul(
|
|
10622
|
+
return vec4(lightColorUniform, intensity.mul(materialOpacity));
|
|
10500
10623
|
})();
|
|
10501
10624
|
}
|
|
10502
|
-
//* Uniform Accessors ==============================
|
|
10503
|
-
get depth() {
|
|
10504
|
-
return this._depth?.value;
|
|
10505
|
-
}
|
|
10506
|
-
set depth(v) {
|
|
10507
|
-
if (this._depth) this._depth.value = v ?? new THREE.Texture();
|
|
10508
|
-
}
|
|
10509
|
-
get opacity() {
|
|
10510
|
-
return this._opacity?.value;
|
|
10511
|
-
}
|
|
10512
|
-
set opacity(v) {
|
|
10513
|
-
if (this._opacity) this._opacity.value = v;
|
|
10514
|
-
}
|
|
10515
|
-
get attenuation() {
|
|
10516
|
-
return this._attenuation?.value;
|
|
10517
|
-
}
|
|
10518
|
-
set attenuation(v) {
|
|
10519
|
-
if (this._attenuation) this._attenuation.value = v;
|
|
10520
|
-
}
|
|
10521
|
-
get anglePower() {
|
|
10522
|
-
return this._anglePower?.value;
|
|
10523
|
-
}
|
|
10524
|
-
set anglePower(v) {
|
|
10525
|
-
if (this._anglePower) this._anglePower.value = v;
|
|
10526
|
-
}
|
|
10527
|
-
get spotPosition() {
|
|
10528
|
-
return this._spotPosition?.value;
|
|
10529
|
-
}
|
|
10530
|
-
set spotPosition(v) {
|
|
10531
|
-
if (this._spotPosition) this._spotPosition.value = v;
|
|
10532
|
-
}
|
|
10533
|
-
get lightColor() {
|
|
10534
|
-
return this._lightColor?.value;
|
|
10535
|
-
}
|
|
10536
|
-
set lightColor(v) {
|
|
10537
|
-
if (this._lightColor) this._lightColor.value = v;
|
|
10538
|
-
}
|
|
10539
|
-
get cameraNear() {
|
|
10540
|
-
return this._cameraNear?.value;
|
|
10541
|
-
}
|
|
10542
|
-
set cameraNear(v) {
|
|
10543
|
-
if (this._cameraNear) this._cameraNear.value = v;
|
|
10544
|
-
}
|
|
10545
|
-
get cameraFar() {
|
|
10546
|
-
return this._cameraFar?.value;
|
|
10547
|
-
}
|
|
10548
|
-
set cameraFar(v) {
|
|
10549
|
-
if (this._cameraFar) this._cameraFar.value = v;
|
|
10550
|
-
}
|
|
10551
|
-
get resolution() {
|
|
10552
|
-
return this._resolution?.value;
|
|
10553
|
-
}
|
|
10554
|
-
set resolution(v) {
|
|
10555
|
-
if (this._resolution) this._resolution.value = v;
|
|
10556
|
-
}
|
|
10557
10625
|
}
|
|
10558
10626
|
|
|
10559
|
-
class StarfieldMaterial extends SpriteNodeMaterial {
|
|
10560
|
-
|
|
10561
|
-
|
|
10562
|
-
|
|
10627
|
+
class StarfieldMaterial extends withUniforms(SpriteNodeMaterial, {
|
|
10628
|
+
/** Animation time, advanced by the component each frame */
|
|
10629
|
+
time: () => uniform(0),
|
|
10630
|
+
/** 1 = soft circular fade, 0 = hard-edged circle */
|
|
10631
|
+
fade: () => uniform(1)
|
|
10632
|
+
}) {
|
|
10563
10633
|
constructor() {
|
|
10564
10634
|
super();
|
|
10635
|
+
const { time, fade } = this.uniforms;
|
|
10565
10636
|
this.transparent = true;
|
|
10566
10637
|
this.depthWrite = false;
|
|
10567
10638
|
this.blending = AdditiveBlending;
|
|
@@ -10575,7 +10646,7 @@ class StarfieldMaterial extends SpriteNodeMaterial {
|
|
|
10575
10646
|
const worldPos = modelWorldMatrix.mul(vec4(this.positionNode, 1));
|
|
10576
10647
|
const viewPos = cameraViewMatrix.mul(worldPos);
|
|
10577
10648
|
const distanceAttenuation = float(30).div(viewPos.z.negate());
|
|
10578
|
-
const timeScale = float(3.5).add(sin(
|
|
10649
|
+
const timeScale = float(3.5).add(sin(time.add(100)).mul(0.3));
|
|
10579
10650
|
const size = particleSize.mul(distanceAttenuation).mul(timeScale).mul(0.04);
|
|
10580
10651
|
return vec2$2(size);
|
|
10581
10652
|
})();
|
|
@@ -10584,38 +10655,28 @@ class StarfieldMaterial extends SpriteNodeMaterial {
|
|
|
10584
10655
|
const d = length(quadUV.sub(vec2$2(0.5)));
|
|
10585
10656
|
const softFade = float(1).div(float(1).add(exp(float(16).mul(d.sub(0.25)))));
|
|
10586
10657
|
const hardMask = float(1).sub(d.smoothstep(0.3, 0.5));
|
|
10587
|
-
const circularOpacity = select(
|
|
10658
|
+
const circularOpacity = select(fade.equal(1), softFade, hardMask);
|
|
10588
10659
|
const opacity = circularOpacity.mul(0.7);
|
|
10589
10660
|
return vec4(particleColor, opacity);
|
|
10590
10661
|
})();
|
|
10591
10662
|
}
|
|
10592
|
-
//* Uniform Accessors ==============================
|
|
10593
10663
|
setTime(time) {
|
|
10594
|
-
this.
|
|
10664
|
+
this.time = time;
|
|
10595
10665
|
}
|
|
10596
10666
|
setFade(fade) {
|
|
10597
|
-
this.
|
|
10598
|
-
}
|
|
10599
|
-
get time() {
|
|
10600
|
-
return this._time.value;
|
|
10601
|
-
}
|
|
10602
|
-
set time(value) {
|
|
10603
|
-
this._time.value = value;
|
|
10604
|
-
}
|
|
10605
|
-
get fade() {
|
|
10606
|
-
return this._fade.value;
|
|
10607
|
-
}
|
|
10608
|
-
set fade(value) {
|
|
10609
|
-
this._fade.value = value;
|
|
10667
|
+
this.fade = fade;
|
|
10610
10668
|
}
|
|
10611
10669
|
}
|
|
10612
10670
|
|
|
10613
|
-
class SparklesMaterial extends SpriteNodeMaterial {
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10671
|
+
class SparklesMaterial extends withUniforms(SpriteNodeMaterial, {
|
|
10672
|
+
/** Animation time, advanced by the component each frame */
|
|
10673
|
+
time: () => uniform(0),
|
|
10674
|
+
/** Device pixel ratio, scales the point size */
|
|
10675
|
+
pixelRatio: () => uniform(1)
|
|
10676
|
+
}) {
|
|
10617
10677
|
constructor() {
|
|
10618
10678
|
super();
|
|
10679
|
+
const { time, pixelRatio } = this.uniforms;
|
|
10619
10680
|
this.transparent = true;
|
|
10620
10681
|
this.depthWrite = false;
|
|
10621
10682
|
const particlePosition = attribute("particlePosition", "vec3");
|
|
@@ -10626,101 +10687,86 @@ class SparklesMaterial extends SpriteNodeMaterial {
|
|
|
10626
10687
|
const particleColor = attribute("color", "vec3");
|
|
10627
10688
|
this.positionNode = Fn(() => {
|
|
10628
10689
|
const pos = particlePosition.toVar();
|
|
10629
|
-
pos.y.addAssign(sin(
|
|
10630
|
-
pos.z.addAssign(cos(
|
|
10631
|
-
pos.x.addAssign(cos(
|
|
10690
|
+
pos.y.addAssign(sin(time.mul(particleSpeed).add(pos.x.mul(particleNoise.x).mul(100))).mul(0.2));
|
|
10691
|
+
pos.z.addAssign(cos(time.mul(particleSpeed).add(pos.x.mul(particleNoise.y).mul(100))).mul(0.2));
|
|
10692
|
+
pos.x.addAssign(cos(time.mul(particleSpeed).add(pos.x.mul(particleNoise.z).mul(100))).mul(0.2));
|
|
10632
10693
|
return pos;
|
|
10633
10694
|
})();
|
|
10634
10695
|
this.scaleNode = Fn(() => {
|
|
10635
|
-
const
|
|
10636
|
-
const
|
|
10637
|
-
const
|
|
10638
|
-
const size =
|
|
10696
|
+
const pixelSize = particleSize.mul(25).mul(pixelRatio);
|
|
10697
|
+
const projY = cameraProjectionMatrix.element(1).y;
|
|
10698
|
+
const viewportH = screenSize.y;
|
|
10699
|
+
const size = pixelSize.mul(2).div(projY.mul(viewportH));
|
|
10639
10700
|
return vec2$2(size);
|
|
10640
10701
|
})();
|
|
10641
10702
|
this.colorNode = Fn(() => {
|
|
10642
10703
|
const quadUV = uv();
|
|
10643
10704
|
const distanceToCenter = length(quadUV.sub(vec2$2(0.5)));
|
|
10644
|
-
const strength = float(0.05).div(distanceToCenter).sub(0.1);
|
|
10705
|
+
const strength = clamp(float(0.05).div(distanceToCenter).sub(0.1), 0, 1);
|
|
10645
10706
|
return vec4(particleColor, strength.mul(particleOpacity));
|
|
10646
10707
|
})();
|
|
10647
10708
|
}
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10656
|
-
|
|
10657
|
-
|
|
10658
|
-
|
|
10659
|
-
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10673
|
-
|
|
10674
|
-
|
|
10675
|
-
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
_worldCamProjPosition;
|
|
10679
|
-
_worldPlanePosition;
|
|
10709
|
+
}
|
|
10710
|
+
|
|
10711
|
+
class GridMaterialImpl extends withUniforms(MeshBasicNodeMaterial, {
|
|
10712
|
+
/** Cell size, default: 0.5 */
|
|
10713
|
+
cellSize: () => uniform(0.5),
|
|
10714
|
+
/** Section size, default: 1 */
|
|
10715
|
+
sectionSize: () => uniform(1),
|
|
10716
|
+
/** Fade distance, default: 100 */
|
|
10717
|
+
fadeDistance: () => uniform(100),
|
|
10718
|
+
/** Fade strength, default: 1 */
|
|
10719
|
+
fadeStrength: () => uniform(1),
|
|
10720
|
+
/** Fade from camera (1) or origin (0), default: 1 */
|
|
10721
|
+
fadeFrom: () => uniform(1),
|
|
10722
|
+
/** Cell thickness, default: 0.5 */
|
|
10723
|
+
cellThickness: () => uniform(0.5),
|
|
10724
|
+
/** Section thickness, default: 1 */
|
|
10725
|
+
sectionThickness: () => uniform(1),
|
|
10726
|
+
/** Cell color, default: black */
|
|
10727
|
+
cellColor: () => uniform(new THREE.Color("#000000")),
|
|
10728
|
+
/** Section color, default: #2080ff */
|
|
10729
|
+
sectionColor: () => uniform(new THREE.Color("#2080ff")),
|
|
10730
|
+
/** Display the grid infinitely */
|
|
10731
|
+
infiniteGrid: () => uniform(false),
|
|
10732
|
+
/** Follow camera position */
|
|
10733
|
+
followCamera: () => uniform(false),
|
|
10734
|
+
/** Camera projection position on plane (set by component) */
|
|
10735
|
+
worldCamProjPosition: () => uniform(new THREE.Vector3()),
|
|
10736
|
+
/** Plane world position (set by component) */
|
|
10737
|
+
worldPlanePosition: () => uniform(new THREE.Vector3())
|
|
10738
|
+
}) {
|
|
10680
10739
|
/** Type flag for identification */
|
|
10681
10740
|
isGridMaterial = true;
|
|
10682
10741
|
constructor() {
|
|
10683
10742
|
super();
|
|
10684
|
-
this._cellSize = uniform(0.5);
|
|
10685
|
-
this._sectionSize = uniform(1);
|
|
10686
|
-
this._fadeDistance = uniform(100);
|
|
10687
|
-
this._fadeStrength = uniform(1);
|
|
10688
|
-
this._fadeFrom = uniform(1);
|
|
10689
|
-
this._cellThickness = uniform(0.5);
|
|
10690
|
-
this._sectionThickness = uniform(1);
|
|
10691
|
-
this._cellColor = uniform(new THREE.Color("#000000"));
|
|
10692
|
-
this._sectionColor = uniform(new THREE.Color("#2080ff"));
|
|
10693
|
-
this._infiniteGrid = uniform(0);
|
|
10694
|
-
this._followCamera = uniform(0);
|
|
10695
|
-
this._worldCamProjPosition = uniform(new THREE.Vector3());
|
|
10696
|
-
this._worldPlanePosition = uniform(new THREE.Vector3());
|
|
10697
10743
|
this.transparent = true;
|
|
10698
10744
|
this.side = THREE.BackSide;
|
|
10699
10745
|
this._buildGridShader();
|
|
10700
10746
|
}
|
|
10701
10747
|
_buildGridShader() {
|
|
10702
|
-
const
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10748
|
+
const {
|
|
10749
|
+
cellSize: cellSizeUniform,
|
|
10750
|
+
sectionSize: sectionSizeUniform,
|
|
10751
|
+
fadeDistance: fadeDistanceUniform,
|
|
10752
|
+
fadeStrength: fadeStrengthUniform,
|
|
10753
|
+
fadeFrom: fadeFromUniform,
|
|
10754
|
+
cellThickness: cellThicknessUniform,
|
|
10755
|
+
sectionThickness: sectionThicknessUniform,
|
|
10756
|
+
cellColor: cellColorUniform,
|
|
10757
|
+
sectionColor: sectionColorUniform,
|
|
10758
|
+
infiniteGrid: infiniteGridUniform,
|
|
10759
|
+
followCamera: followCameraUniform,
|
|
10760
|
+
worldCamProjPosition: worldCamProjPositionUniform,
|
|
10761
|
+
worldPlanePosition: worldPlanePositionUniform
|
|
10762
|
+
} = this.uniforms;
|
|
10715
10763
|
const computeLocalPosition = Fn(() => {
|
|
10716
10764
|
const pos = positionGeometry;
|
|
10717
10765
|
let localPos = vec3(pos.x, pos.z, pos.y).toVar();
|
|
10718
|
-
const isInfinite = infiniteGridUniform.greaterThan(0.5);
|
|
10719
10766
|
const scaleFactor = float(1).add(fadeDistanceUniform);
|
|
10720
|
-
localPos.assign(select(
|
|
10721
|
-
const isFollowCamera = followCameraUniform.greaterThan(0.5);
|
|
10767
|
+
localPos.assign(select(infiniteGridUniform, localPos.mul(scaleFactor), localPos));
|
|
10722
10768
|
const cameraOffset = worldCamProjPositionUniform.sub(worldPlanePositionUniform);
|
|
10723
|
-
localPos.assign(select(
|
|
10769
|
+
localPos.assign(select(followCameraUniform, localPos.add(cameraOffset), localPos));
|
|
10724
10770
|
return localPos;
|
|
10725
10771
|
});
|
|
10726
10772
|
const vLocalPosition = varying(computeLocalPosition(), "vLocalPosition");
|
|
@@ -10732,12 +10778,10 @@ class GridMaterialImpl extends MeshBasicNodeMaterial {
|
|
|
10732
10778
|
this.positionNode = Fn(() => {
|
|
10733
10779
|
const pos = positionGeometry;
|
|
10734
10780
|
let localPos = vec3(pos.x, pos.z, pos.y).toVar();
|
|
10735
|
-
const isInfinite = infiniteGridUniform.greaterThan(0.5);
|
|
10736
10781
|
const scaleFactor = float(1).add(fadeDistanceUniform);
|
|
10737
|
-
localPos.assign(select(
|
|
10738
|
-
const isFollowCamera = followCameraUniform.greaterThan(0.5);
|
|
10782
|
+
localPos.assign(select(infiniteGridUniform, localPos.mul(scaleFactor), localPos));
|
|
10739
10783
|
const cameraOffset = worldCamProjPositionUniform.sub(worldPlanePositionUniform);
|
|
10740
|
-
localPos.assign(select(
|
|
10784
|
+
localPos.assign(select(followCameraUniform, localPos.add(cameraOffset), localPos));
|
|
10741
10785
|
return localPos;
|
|
10742
10786
|
})();
|
|
10743
10787
|
const getGrid = Fn((inputs) => {
|
|
@@ -10763,100 +10807,6 @@ class GridMaterialImpl extends MeshBasicNodeMaterial {
|
|
|
10763
10807
|
return vec4(gridColor, finalAlpha);
|
|
10764
10808
|
})();
|
|
10765
10809
|
}
|
|
10766
|
-
//* Uniform Accessors ==============================
|
|
10767
|
-
/** Cell size, default: 0.5 */
|
|
10768
|
-
get cellSize() {
|
|
10769
|
-
return this._cellSize.value;
|
|
10770
|
-
}
|
|
10771
|
-
set cellSize(v) {
|
|
10772
|
-
this._cellSize.value = v;
|
|
10773
|
-
}
|
|
10774
|
-
/** Section size, default: 1 */
|
|
10775
|
-
get sectionSize() {
|
|
10776
|
-
return this._sectionSize.value;
|
|
10777
|
-
}
|
|
10778
|
-
set sectionSize(v) {
|
|
10779
|
-
this._sectionSize.value = v;
|
|
10780
|
-
}
|
|
10781
|
-
/** Fade distance, default: 100 */
|
|
10782
|
-
get fadeDistance() {
|
|
10783
|
-
return this._fadeDistance.value;
|
|
10784
|
-
}
|
|
10785
|
-
set fadeDistance(v) {
|
|
10786
|
-
this._fadeDistance.value = v;
|
|
10787
|
-
}
|
|
10788
|
-
/** Fade strength, default: 1 */
|
|
10789
|
-
get fadeStrength() {
|
|
10790
|
-
return this._fadeStrength.value;
|
|
10791
|
-
}
|
|
10792
|
-
set fadeStrength(v) {
|
|
10793
|
-
this._fadeStrength.value = v;
|
|
10794
|
-
}
|
|
10795
|
-
/** Fade from camera (1) or origin (0), default: 1 */
|
|
10796
|
-
get fadeFrom() {
|
|
10797
|
-
return this._fadeFrom.value;
|
|
10798
|
-
}
|
|
10799
|
-
set fadeFrom(v) {
|
|
10800
|
-
this._fadeFrom.value = v;
|
|
10801
|
-
}
|
|
10802
|
-
/** Cell thickness, default: 0.5 */
|
|
10803
|
-
get cellThickness() {
|
|
10804
|
-
return this._cellThickness.value;
|
|
10805
|
-
}
|
|
10806
|
-
set cellThickness(v) {
|
|
10807
|
-
this._cellThickness.value = v;
|
|
10808
|
-
}
|
|
10809
|
-
/** Section thickness, default: 1 */
|
|
10810
|
-
get sectionThickness() {
|
|
10811
|
-
return this._sectionThickness.value;
|
|
10812
|
-
}
|
|
10813
|
-
set sectionThickness(v) {
|
|
10814
|
-
this._sectionThickness.value = v;
|
|
10815
|
-
}
|
|
10816
|
-
/** Cell color */
|
|
10817
|
-
get cellColor() {
|
|
10818
|
-
return this._cellColor.value;
|
|
10819
|
-
}
|
|
10820
|
-
set cellColor(v) {
|
|
10821
|
-
if (v instanceof THREE.Color) this._cellColor.value = v;
|
|
10822
|
-
else this._cellColor.value = new THREE.Color(v);
|
|
10823
|
-
}
|
|
10824
|
-
/** Section color */
|
|
10825
|
-
get sectionColor() {
|
|
10826
|
-
return this._sectionColor.value;
|
|
10827
|
-
}
|
|
10828
|
-
set sectionColor(v) {
|
|
10829
|
-
if (v instanceof THREE.Color) this._sectionColor.value = v;
|
|
10830
|
-
else this._sectionColor.value = new THREE.Color(v);
|
|
10831
|
-
}
|
|
10832
|
-
/** Display the grid infinitely */
|
|
10833
|
-
get infiniteGrid() {
|
|
10834
|
-
return this._infiniteGrid.value > 0.5;
|
|
10835
|
-
}
|
|
10836
|
-
set infiniteGrid(v) {
|
|
10837
|
-
this._infiniteGrid.value = v ? 1 : 0;
|
|
10838
|
-
}
|
|
10839
|
-
/** Follow camera position */
|
|
10840
|
-
get followCamera() {
|
|
10841
|
-
return this._followCamera.value > 0.5;
|
|
10842
|
-
}
|
|
10843
|
-
set followCamera(v) {
|
|
10844
|
-
this._followCamera.value = v ? 1 : 0;
|
|
10845
|
-
}
|
|
10846
|
-
/** Camera projection position on plane (set by component) */
|
|
10847
|
-
get worldCamProjPosition() {
|
|
10848
|
-
return this._worldCamProjPosition.value;
|
|
10849
|
-
}
|
|
10850
|
-
set worldCamProjPosition(v) {
|
|
10851
|
-
this._worldCamProjPosition.value = v;
|
|
10852
|
-
}
|
|
10853
|
-
/** Plane world position (set by component) */
|
|
10854
|
-
get worldPlanePosition() {
|
|
10855
|
-
return this._worldPlanePosition.value;
|
|
10856
|
-
}
|
|
10857
|
-
set worldPlanePosition(v) {
|
|
10858
|
-
this._worldPlanePosition.value = v;
|
|
10859
|
-
}
|
|
10860
10810
|
}
|
|
10861
10811
|
const Grid = /* @__PURE__ */ React.forwardRef(
|
|
10862
10812
|
({
|
|
@@ -10912,17 +10862,95 @@ const Grid = /* @__PURE__ */ React.forwardRef(
|
|
|
10912
10862
|
}
|
|
10913
10863
|
);
|
|
10914
10864
|
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10865
|
+
const createPCSSFilter = (size, samples, focus) => {
|
|
10866
|
+
const sampleCount = Math.min(Math.max(samples, 1), 20);
|
|
10867
|
+
return Fn(({ depthTexture, shadowCoord, shadow, depthLayer }) => {
|
|
10868
|
+
const sampleDepth = (uv2) => {
|
|
10869
|
+
const tex = texture(depthTexture, uv2);
|
|
10870
|
+
const depth = depthTexture.isArrayTexture ? tex.depth(depthLayer) : tex;
|
|
10871
|
+
return depth.r;
|
|
10872
|
+
};
|
|
10873
|
+
const mapSize = reference("mapSize", "vec2", shadow).setGroup(renderGroup);
|
|
10874
|
+
const texelSize = vec2$2(1).div(mapSize);
|
|
10875
|
+
const phi = interleavedGradientNoise(screenCoordinate.xy).mul(6.28318530718);
|
|
10876
|
+
const uv = shadowCoord.xy;
|
|
10877
|
+
const zReceiver = shadowCoord.z.add(1).mul(0.5);
|
|
10878
|
+
const blockerSearchRadius = texelSize.x.mul(size).mul(2);
|
|
10879
|
+
const blockerDepthSum = float(focus).toVar("blockerDepthSum");
|
|
10880
|
+
const blockerCount = float(0).toVar("blockerCount");
|
|
10881
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
10882
|
+
const offset = vogelDiskSample(int(i), int(sampleCount), phi).mul(blockerSearchRadius);
|
|
10883
|
+
const sampleUV = uv.add(offset);
|
|
10884
|
+
const sampleDepthVal = sampleDepth(sampleUV);
|
|
10885
|
+
const isBlocker = step(sampleDepthVal, zReceiver).sub(step(zReceiver, sampleDepthVal)).max(0);
|
|
10886
|
+
blockerDepthSum.addAssign(sampleDepthVal.mul(isBlocker));
|
|
10887
|
+
blockerCount.addAssign(isBlocker);
|
|
10888
|
+
}
|
|
10889
|
+
const avgBlockerDepth = blockerDepthSum.div(blockerCount.max(1));
|
|
10890
|
+
const penumbraRatio = zReceiver.sub(avgBlockerDepth).div(avgBlockerDepth.max(1e-4));
|
|
10891
|
+
const filterRadius = texelSize.x.mul(float(1).add(penumbraRatio.mul(1.25).mul(size)));
|
|
10892
|
+
const shadowSum = float(0).toVar("shadowSum");
|
|
10893
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
10894
|
+
const offset = vogelDiskSample(int(i), int(sampleCount), phi).mul(filterRadius);
|
|
10895
|
+
const sampleUV = uv.add(offset);
|
|
10896
|
+
const sampleDepthVal = sampleDepth(sampleUV);
|
|
10897
|
+
shadowSum.addAssign(step(zReceiver, sampleDepthVal));
|
|
10898
|
+
}
|
|
10899
|
+
const shadowResult = shadowSum.div(sampleCount);
|
|
10900
|
+
const hasBlockers = blockerCount.greaterThan(0.5);
|
|
10901
|
+
return hasBlockers.select(shadowResult, float(1));
|
|
10902
|
+
});
|
|
10903
|
+
};
|
|
10904
|
+
class PCSSShadowNode extends ShadowNode {
|
|
10905
|
+
size;
|
|
10906
|
+
samples;
|
|
10907
|
+
focus;
|
|
10908
|
+
constructor(light, { size = 25, samples = 10, focus = 0 } = {}) {
|
|
10909
|
+
super(light, light.shadow);
|
|
10910
|
+
this.size = size;
|
|
10911
|
+
this.samples = samples;
|
|
10912
|
+
this.focus = focus;
|
|
10913
|
+
}
|
|
10914
|
+
/**
|
|
10915
|
+
* Override to disable hardware depth comparison.
|
|
10916
|
+
* PCSS needs raw depth values for blocker search, so we can't use comparison samplers.
|
|
10917
|
+
*/
|
|
10918
|
+
setupRenderTarget(shadow, builder) {
|
|
10919
|
+
const parentMethod = Object.getPrototypeOf(Object.getPrototypeOf(this)).setupRenderTarget;
|
|
10920
|
+
const result = parentMethod.call(this, shadow, builder);
|
|
10921
|
+
if (result.depthTexture) {
|
|
10922
|
+
result.depthTexture.compareFunction = null;
|
|
10923
|
+
}
|
|
10924
|
+
return result;
|
|
10925
|
+
}
|
|
10926
|
+
/**
|
|
10927
|
+
* Override to use our PCSS filter instead of the default filter.
|
|
10928
|
+
*/
|
|
10929
|
+
getShadowFilterFn(_type) {
|
|
10930
|
+
return createPCSSFilter(this.size, this.samples, this.focus);
|
|
10920
10931
|
}
|
|
10921
10932
|
}
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
)
|
|
10933
|
+
|
|
10934
|
+
function SoftShadows({ size = 25, samples = 10, focus = 0 }) {
|
|
10935
|
+
const scene = useThree((state) => state.scene);
|
|
10936
|
+
React.useLayoutEffect(() => {
|
|
10937
|
+
const originalShadowNodes = /* @__PURE__ */ new Map();
|
|
10938
|
+
scene.traverse((obj) => {
|
|
10939
|
+
const light = obj;
|
|
10940
|
+
if (light.isLight && light.castShadow && light.shadow) {
|
|
10941
|
+
originalShadowNodes.set(light.uuid, light.shadow.shadowNode);
|
|
10942
|
+
light.shadow.shadowNode = new PCSSShadowNode(light, { size, samples, focus });
|
|
10943
|
+
}
|
|
10944
|
+
});
|
|
10945
|
+
return () => {
|
|
10946
|
+
scene.traverse((obj) => {
|
|
10947
|
+
const light = obj;
|
|
10948
|
+
if (originalShadowNodes.has(light.uuid)) {
|
|
10949
|
+
light.shadow.shadowNode = originalShadowNodes.get(light.uuid);
|
|
10950
|
+
}
|
|
10951
|
+
});
|
|
10952
|
+
};
|
|
10953
|
+
}, [scene, size, samples, focus]);
|
|
10926
10954
|
return null;
|
|
10927
10955
|
}
|
|
10928
10956
|
|