foundry-component-library 0.2.9 → 0.2.10
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/lib/components/ServiceHubsTeaserEffects/TileBalls.tsx +35 -0
- package/lib/components/ServiceHubsTeaserEffects/TileFluid.tsx +29 -0
- package/lib/components/ServiceHubsTeaserEffects/TileGlass.tsx +23 -0
- package/lib/components/ServiceHubsTeaserEffects/TileRays.tsx +94 -0
- package/lib/components/ServiceHubsTeaserEffects/bubbles/Bubble.tsx +35 -0
- package/lib/components/ServiceHubsTeaserEffects/bubbles/Bubbles.tsx +44 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/Fluid.tsx +192 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/constant.ts +23 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/effect/Fluid.tsx +22 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/effect/FluidEffect.tsx +58 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/advection.frag +16 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/base.vert +26 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/clear.frag +7 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/composite.frag +41 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/curl.frag +22 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/divergence.frag +41 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/gradientSubstract.frag +26 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/pressure.frag +28 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/splat.frag +19 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl/vorticity.frag +36 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/glsl.d.ts +14 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/hooks/useDoubleFBO.tsx +37 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/hooks/useFBOs.tsx +71 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/hooks/useMaterials.tsx +242 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/hooks/usePointer.tsx +54 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/index.ts +5 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/types.ts +27 -0
- package/lib/components/ServiceHubsTeaserEffects/fluid/utils.ts +12 -0
- package/lib/components/ServiceHubsTeaserEffects/glass/Lens.tsx +66 -0
- package/lib/components/ServiceHubsTeaserEffects/index.tsx +67 -0
- package/lib/components/ServiceHubsTeaserEffects/rays/LightSource.tsx +64 -0
- package/lib/components/ServiceHubsTeaserEffects/rays/noise.js +97 -0
- package/lib/components/ServiceHubsTeaserEffects/styles.module.scss +135 -0
- package/lib/index.ts +2 -0
- package/package.json +6 -2
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
precision highp float;
|
|
2
|
+
|
|
3
|
+
varying highp vec2 vUv;
|
|
4
|
+
varying highp vec2 vL;
|
|
5
|
+
varying highp vec2 vR;
|
|
6
|
+
varying highp vec2 vT;
|
|
7
|
+
varying highp vec2 vB;
|
|
8
|
+
|
|
9
|
+
uniform sampler2D uVelocity;
|
|
10
|
+
|
|
11
|
+
void main() {
|
|
12
|
+
float L = texture2D(uVelocity, vL).x;
|
|
13
|
+
|
|
14
|
+
float R = texture2D(uVelocity, vR).x;
|
|
15
|
+
|
|
16
|
+
float T = texture2D(uVelocity, vT).y;
|
|
17
|
+
|
|
18
|
+
float B = texture2D(uVelocity, vB).y;
|
|
19
|
+
|
|
20
|
+
vec2 C = texture2D(uVelocity, vUv).xy;
|
|
21
|
+
|
|
22
|
+
if(vL.x < 0.0) {
|
|
23
|
+
L = -C.x;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if(vR.x > 1.0) {
|
|
27
|
+
R = -C.x;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if(vT.y > 1.0) {
|
|
31
|
+
T = -C.y;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if(vB.y < 0.0) {
|
|
35
|
+
B = -C.y;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
float div = 0.5 * (R - L + T - B);
|
|
39
|
+
|
|
40
|
+
gl_FragColor = vec4(div, 0.0, 0.0, 1.0);
|
|
41
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
precision highp float;
|
|
2
|
+
|
|
3
|
+
varying highp vec2 vUv;
|
|
4
|
+
varying highp vec2 vL;
|
|
5
|
+
varying highp vec2 vR;
|
|
6
|
+
varying highp vec2 vT;
|
|
7
|
+
varying highp vec2 vB;
|
|
8
|
+
|
|
9
|
+
uniform sampler2D uPressure;
|
|
10
|
+
uniform sampler2D uVelocity;
|
|
11
|
+
|
|
12
|
+
void main() {
|
|
13
|
+
float L = texture2D(uPressure, vL).x;
|
|
14
|
+
|
|
15
|
+
float R = texture2D(uPressure, vR).x;
|
|
16
|
+
|
|
17
|
+
float T = texture2D(uPressure, vT).x;
|
|
18
|
+
|
|
19
|
+
float B = texture2D(uPressure, vB).x;
|
|
20
|
+
|
|
21
|
+
vec2 velocity = texture2D(uVelocity, vUv).xy;
|
|
22
|
+
|
|
23
|
+
velocity.xy -= vec2(R - L, T - B);
|
|
24
|
+
|
|
25
|
+
gl_FragColor = vec4(velocity, 0.0, 1.0);
|
|
26
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
precision highp float;
|
|
2
|
+
|
|
3
|
+
varying highp vec2 vUv;
|
|
4
|
+
varying highp vec2 vL;
|
|
5
|
+
varying highp vec2 vR;
|
|
6
|
+
varying highp vec2 vT;
|
|
7
|
+
varying highp vec2 vB;
|
|
8
|
+
|
|
9
|
+
uniform sampler2D uPressure;
|
|
10
|
+
uniform sampler2D uDivergence;
|
|
11
|
+
|
|
12
|
+
void main() {
|
|
13
|
+
float L = texture2D(uPressure, vL).x;
|
|
14
|
+
|
|
15
|
+
float R = texture2D(uPressure, vR).x;
|
|
16
|
+
|
|
17
|
+
float T = texture2D(uPressure, vT).x;
|
|
18
|
+
|
|
19
|
+
float B = texture2D(uPressure, vB).x;
|
|
20
|
+
|
|
21
|
+
float C = texture2D(uPressure, vUv).x;
|
|
22
|
+
|
|
23
|
+
float divergence = texture2D(uDivergence, vUv).x;
|
|
24
|
+
|
|
25
|
+
float pressure = (L + R + B + T - divergence) * 0.25;
|
|
26
|
+
|
|
27
|
+
gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0);
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
varying vec2 vUv;
|
|
2
|
+
|
|
3
|
+
uniform sampler2D uTarget;
|
|
4
|
+
uniform float aspectRatio;
|
|
5
|
+
uniform vec3 uColor;
|
|
6
|
+
uniform vec2 uPointer;
|
|
7
|
+
uniform float uRadius;
|
|
8
|
+
|
|
9
|
+
void main() {
|
|
10
|
+
vec2 p = vUv - uPointer.xy;
|
|
11
|
+
|
|
12
|
+
p.x *= aspectRatio;
|
|
13
|
+
|
|
14
|
+
vec3 splat = exp(-dot(p, p) / uRadius) * uColor;
|
|
15
|
+
|
|
16
|
+
vec3 base = texture2D(uTarget, vUv).xyz;
|
|
17
|
+
|
|
18
|
+
gl_FragColor = vec4(base + splat, 1.0);
|
|
19
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
precision highp float;
|
|
2
|
+
|
|
3
|
+
varying vec2 vUv;
|
|
4
|
+
varying vec2 vL;
|
|
5
|
+
varying vec2 vR;
|
|
6
|
+
varying vec2 vT;
|
|
7
|
+
varying vec2 vB;
|
|
8
|
+
|
|
9
|
+
uniform sampler2D uVelocity;
|
|
10
|
+
uniform sampler2D uCurl;
|
|
11
|
+
uniform float uCurlValue;
|
|
12
|
+
uniform float dt;
|
|
13
|
+
|
|
14
|
+
void main() {
|
|
15
|
+
float L = texture2D(uCurl, vL).x;
|
|
16
|
+
|
|
17
|
+
float R = texture2D(uCurl, vR).x;
|
|
18
|
+
|
|
19
|
+
float T = texture2D(uCurl, vT).x;
|
|
20
|
+
|
|
21
|
+
float B = texture2D(uCurl, vB).x;
|
|
22
|
+
|
|
23
|
+
float C = texture2D(uCurl, vUv).x;
|
|
24
|
+
|
|
25
|
+
vec2 force = vec2(abs(T) - abs(B), abs(R) - abs(L)) * 0.5;
|
|
26
|
+
|
|
27
|
+
force /= length(force) + 1.;
|
|
28
|
+
|
|
29
|
+
force *= uCurlValue * C;
|
|
30
|
+
|
|
31
|
+
force.y *= -1.;
|
|
32
|
+
|
|
33
|
+
vec2 vel = texture2D(uVelocity, vUv).xy;
|
|
34
|
+
|
|
35
|
+
gl_FragColor = vec4(vel + force * dt, 0.0, 1.0);
|
|
36
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { useFBO, type FboProps } from '@react-three/drei';
|
|
3
|
+
import { useRef } from 'react';
|
|
4
|
+
|
|
5
|
+
type FBO = {
|
|
6
|
+
read: THREE.WebGLRenderTarget;
|
|
7
|
+
write: THREE.WebGLRenderTarget;
|
|
8
|
+
swap: () => void;
|
|
9
|
+
dispose: () => void;
|
|
10
|
+
setGenerateMipmaps: (value: boolean) => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const useDoubleFBO = (width: number, height: number, options: FboProps) => {
|
|
14
|
+
const read = useFBO(width, height, options);
|
|
15
|
+
|
|
16
|
+
const write = useFBO(width, height, options);
|
|
17
|
+
|
|
18
|
+
const fbo = useRef<FBO>({
|
|
19
|
+
read,
|
|
20
|
+
write,
|
|
21
|
+
swap: () => {
|
|
22
|
+
const temp = fbo.read;
|
|
23
|
+
fbo.read = fbo.write;
|
|
24
|
+
fbo.write = temp;
|
|
25
|
+
},
|
|
26
|
+
dispose: () => {
|
|
27
|
+
read.dispose();
|
|
28
|
+
write.dispose();
|
|
29
|
+
},
|
|
30
|
+
setGenerateMipmaps: (value: boolean) => {
|
|
31
|
+
read.texture.generateMipmaps = value;
|
|
32
|
+
write.texture.generateMipmaps = value;
|
|
33
|
+
},
|
|
34
|
+
}).current;
|
|
35
|
+
|
|
36
|
+
return fbo;
|
|
37
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
import { useFBO } from '@react-three/drei';
|
|
4
|
+
import { useEffect, useMemo } from 'react';
|
|
5
|
+
import { useDoubleFBO } from '../hooks/useDoubleFBO';
|
|
6
|
+
import { DEFAULT_CONFIG } from '../constant';
|
|
7
|
+
|
|
8
|
+
export const useFBOs = () => {
|
|
9
|
+
const density = useDoubleFBO(DEFAULT_CONFIG.dyeRes, DEFAULT_CONFIG.dyeRes, {
|
|
10
|
+
type: THREE.HalfFloatType,
|
|
11
|
+
format: THREE.RGBAFormat,
|
|
12
|
+
minFilter: THREE.LinearFilter,
|
|
13
|
+
depthBuffer: false,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const velocity = useDoubleFBO(DEFAULT_CONFIG.simRes, DEFAULT_CONFIG.simRes, {
|
|
17
|
+
type: THREE.HalfFloatType,
|
|
18
|
+
format: THREE.RGFormat,
|
|
19
|
+
minFilter: THREE.LinearFilter,
|
|
20
|
+
depthBuffer: false,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const pressure = useDoubleFBO(DEFAULT_CONFIG.simRes, DEFAULT_CONFIG.simRes, {
|
|
24
|
+
type: THREE.HalfFloatType,
|
|
25
|
+
format: THREE.RedFormat,
|
|
26
|
+
minFilter: THREE.NearestFilter,
|
|
27
|
+
depthBuffer: false,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const divergence = useFBO(DEFAULT_CONFIG.simRes, DEFAULT_CONFIG.simRes, {
|
|
31
|
+
type: THREE.HalfFloatType,
|
|
32
|
+
format: THREE.RedFormat,
|
|
33
|
+
minFilter: THREE.NearestFilter,
|
|
34
|
+
depthBuffer: false,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const curl = useFBO(DEFAULT_CONFIG.simRes, DEFAULT_CONFIG.simRes, {
|
|
38
|
+
type: THREE.HalfFloatType,
|
|
39
|
+
format: THREE.RedFormat,
|
|
40
|
+
minFilter: THREE.NearestFilter,
|
|
41
|
+
depthBuffer: false,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const FBOs = useMemo(() => {
|
|
45
|
+
return {
|
|
46
|
+
density,
|
|
47
|
+
velocity,
|
|
48
|
+
pressure,
|
|
49
|
+
divergence,
|
|
50
|
+
curl,
|
|
51
|
+
};
|
|
52
|
+
}, [curl, density, divergence, pressure, velocity]);
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
for (const FBO of Object.values(FBOs)) {
|
|
56
|
+
if ('write' in FBO) {
|
|
57
|
+
FBO.setGenerateMipmaps(false);
|
|
58
|
+
} else {
|
|
59
|
+
FBO.texture.generateMipmaps = false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return () => {
|
|
64
|
+
for (const FBO of Object.values(FBOs)) {
|
|
65
|
+
FBO.dispose();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}, [FBOs]);
|
|
69
|
+
|
|
70
|
+
return FBOs;
|
|
71
|
+
};
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { ShaderMaterial, Texture, Vector2, Vector3 } from 'three';
|
|
2
|
+
import { useEffect, useMemo } from 'react';
|
|
3
|
+
import { useThree } from '@react-three/fiber';
|
|
4
|
+
import { DEFAULT_CONFIG, REFRESH_RATE } from '../constant';
|
|
5
|
+
|
|
6
|
+
import baseVertex from '../glsl/base.vert';
|
|
7
|
+
import clearFrag from '../glsl/clear.frag';
|
|
8
|
+
import curlFrag from '../glsl/curl.frag';
|
|
9
|
+
import divergenceFrag from '../glsl/divergence.frag';
|
|
10
|
+
import gradientSubstractFrag from '../glsl/gradientSubstract.frag';
|
|
11
|
+
import pressureFrag from '../glsl/pressure.frag';
|
|
12
|
+
import splatFrag from '../glsl/splat.frag';
|
|
13
|
+
import advectionFrag from '../glsl/advection.frag';
|
|
14
|
+
import vorticityFrag from '../glsl/vorticity.frag';
|
|
15
|
+
|
|
16
|
+
export const useMaterials = (): { [key: string]: ShaderMaterial } => {
|
|
17
|
+
const size = useThree((s) => s.size);
|
|
18
|
+
|
|
19
|
+
const shaderMaterials = useMemo(() => {
|
|
20
|
+
const advection = new ShaderMaterial({
|
|
21
|
+
name: 'Fluid/Advection',
|
|
22
|
+
uniforms: {
|
|
23
|
+
uVelocity: {
|
|
24
|
+
value: new Texture(),
|
|
25
|
+
},
|
|
26
|
+
uSource: {
|
|
27
|
+
value: new Texture(),
|
|
28
|
+
},
|
|
29
|
+
dt: {
|
|
30
|
+
value: 1 / REFRESH_RATE,
|
|
31
|
+
},
|
|
32
|
+
uDissipation: {
|
|
33
|
+
value: 1.0,
|
|
34
|
+
},
|
|
35
|
+
texelSize: { value: new Vector2() },
|
|
36
|
+
},
|
|
37
|
+
fragmentShader: advectionFrag,
|
|
38
|
+
vertexShader: baseVertex,
|
|
39
|
+
defines: {
|
|
40
|
+
USE_V_UV: '',
|
|
41
|
+
},
|
|
42
|
+
depthTest: false,
|
|
43
|
+
depthWrite: false,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const clear = new ShaderMaterial({
|
|
47
|
+
name: 'Fluid/Clear',
|
|
48
|
+
uniforms: {
|
|
49
|
+
uTexture: {
|
|
50
|
+
value: new Texture(),
|
|
51
|
+
},
|
|
52
|
+
uClearValue: {
|
|
53
|
+
value: DEFAULT_CONFIG.pressure,
|
|
54
|
+
},
|
|
55
|
+
texelSize: {
|
|
56
|
+
value: new Vector2(),
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
fragmentShader: clearFrag,
|
|
60
|
+
vertexShader: baseVertex,
|
|
61
|
+
defines: {
|
|
62
|
+
USE_V_UV: '',
|
|
63
|
+
},
|
|
64
|
+
depthTest: false,
|
|
65
|
+
depthWrite: false,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const curl = new ShaderMaterial({
|
|
69
|
+
name: 'Fluid/Curl',
|
|
70
|
+
uniforms: {
|
|
71
|
+
uVelocity: {
|
|
72
|
+
value: new Texture(),
|
|
73
|
+
},
|
|
74
|
+
texelSize: {
|
|
75
|
+
value: new Vector2(),
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
fragmentShader: curlFrag,
|
|
79
|
+
vertexShader: baseVertex,
|
|
80
|
+
defines: {
|
|
81
|
+
USE_OFFSETS: '',
|
|
82
|
+
},
|
|
83
|
+
depthTest: false,
|
|
84
|
+
depthWrite: false,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const divergence = new ShaderMaterial({
|
|
88
|
+
name: 'Fluid/Divergence',
|
|
89
|
+
uniforms: {
|
|
90
|
+
uVelocity: {
|
|
91
|
+
value: new Texture(),
|
|
92
|
+
},
|
|
93
|
+
texelSize: {
|
|
94
|
+
value: new Vector2(),
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
fragmentShader: divergenceFrag,
|
|
98
|
+
vertexShader: baseVertex,
|
|
99
|
+
defines: {
|
|
100
|
+
USE_V_UV: '',
|
|
101
|
+
USE_OFFSETS: '',
|
|
102
|
+
},
|
|
103
|
+
depthTest: false,
|
|
104
|
+
depthWrite: false,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const gradientSubstract = new ShaderMaterial({
|
|
108
|
+
name: 'Fluid/GradientSubtract',
|
|
109
|
+
uniforms: {
|
|
110
|
+
uPressure: {
|
|
111
|
+
value: new Texture(),
|
|
112
|
+
},
|
|
113
|
+
uVelocity: {
|
|
114
|
+
value: new Texture(),
|
|
115
|
+
},
|
|
116
|
+
texelSize: {
|
|
117
|
+
value: new Vector2(),
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
fragmentShader: gradientSubstractFrag,
|
|
121
|
+
vertexShader: baseVertex,
|
|
122
|
+
defines: {
|
|
123
|
+
USE_V_UV: '',
|
|
124
|
+
USE_OFFSETS: '',
|
|
125
|
+
},
|
|
126
|
+
depthTest: false,
|
|
127
|
+
depthWrite: false,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const pressure = new ShaderMaterial({
|
|
131
|
+
name: 'Fluid/Pressure',
|
|
132
|
+
uniforms: {
|
|
133
|
+
uPressure: {
|
|
134
|
+
value: new Texture(),
|
|
135
|
+
},
|
|
136
|
+
uDivergence: {
|
|
137
|
+
value: new Texture(),
|
|
138
|
+
},
|
|
139
|
+
texelSize: {
|
|
140
|
+
value: new Vector2(),
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
fragmentShader: pressureFrag,
|
|
144
|
+
vertexShader: baseVertex,
|
|
145
|
+
defines: {
|
|
146
|
+
USE_V_UV: '',
|
|
147
|
+
USE_OFFSETS: '',
|
|
148
|
+
},
|
|
149
|
+
depthTest: false,
|
|
150
|
+
depthWrite: false,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const splat = new ShaderMaterial({
|
|
154
|
+
name: 'Fluid/Splat',
|
|
155
|
+
uniforms: {
|
|
156
|
+
uTarget: {
|
|
157
|
+
value: new Texture(),
|
|
158
|
+
},
|
|
159
|
+
aspectRatio: {
|
|
160
|
+
value: size.width / size.height,
|
|
161
|
+
},
|
|
162
|
+
uColor: {
|
|
163
|
+
value: new Vector3(),
|
|
164
|
+
},
|
|
165
|
+
uPointer: {
|
|
166
|
+
value: new Vector2(),
|
|
167
|
+
},
|
|
168
|
+
uRadius: {
|
|
169
|
+
value: DEFAULT_CONFIG.radius / 100.0,
|
|
170
|
+
},
|
|
171
|
+
texelSize: {
|
|
172
|
+
value: new Vector2(),
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
fragmentShader: splatFrag,
|
|
176
|
+
vertexShader: baseVertex,
|
|
177
|
+
defines: {
|
|
178
|
+
USE_V_UV: '',
|
|
179
|
+
},
|
|
180
|
+
depthTest: false,
|
|
181
|
+
depthWrite: false,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const vorticity = new ShaderMaterial({
|
|
185
|
+
name: 'Fluid/Vorticity',
|
|
186
|
+
uniforms: {
|
|
187
|
+
uVelocity: {
|
|
188
|
+
value: new Texture(),
|
|
189
|
+
},
|
|
190
|
+
uCurl: {
|
|
191
|
+
value: new Texture(),
|
|
192
|
+
},
|
|
193
|
+
uCurlValue: {
|
|
194
|
+
value: DEFAULT_CONFIG.curl,
|
|
195
|
+
},
|
|
196
|
+
dt: {
|
|
197
|
+
value: 1 / REFRESH_RATE,
|
|
198
|
+
},
|
|
199
|
+
texelSize: {
|
|
200
|
+
value: new Vector2(),
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
fragmentShader: vorticityFrag,
|
|
204
|
+
vertexShader: baseVertex,
|
|
205
|
+
defines: {
|
|
206
|
+
USE_V_UV: '',
|
|
207
|
+
USE_OFFSETS: '',
|
|
208
|
+
},
|
|
209
|
+
depthTest: false,
|
|
210
|
+
depthWrite: false,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
splat,
|
|
215
|
+
curl,
|
|
216
|
+
clear,
|
|
217
|
+
divergence,
|
|
218
|
+
pressure,
|
|
219
|
+
gradientSubstract,
|
|
220
|
+
advection,
|
|
221
|
+
vorticity,
|
|
222
|
+
};
|
|
223
|
+
}, [size]);
|
|
224
|
+
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
for (const material of Object.values(shaderMaterials)) {
|
|
227
|
+
const aspectRatio = size.width / (size.height + 400);
|
|
228
|
+
material.uniforms.texelSize.value.set(
|
|
229
|
+
1 / (DEFAULT_CONFIG.simRes * aspectRatio),
|
|
230
|
+
1 / DEFAULT_CONFIG.simRes,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return () => {
|
|
235
|
+
for (const material of Object.values(shaderMaterials)) {
|
|
236
|
+
material.dispose();
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}, [shaderMaterials, size]);
|
|
240
|
+
|
|
241
|
+
return shaderMaterials;
|
|
242
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useThree } from '@react-three/fiber';
|
|
2
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
3
|
+
import { Vector2 } from 'three';
|
|
4
|
+
|
|
5
|
+
type SplatStack = {
|
|
6
|
+
mouseX: number;
|
|
7
|
+
mouseY: number;
|
|
8
|
+
velocityX: number;
|
|
9
|
+
velocityY: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const usePointer = ({ force }: { force: number }) => {
|
|
13
|
+
const { size, gl } = useThree();
|
|
14
|
+
|
|
15
|
+
const splatStack = useRef<SplatStack[]>([]).current;
|
|
16
|
+
const lastMouse = useRef(new Vector2());
|
|
17
|
+
const hasMoved = useRef(false);
|
|
18
|
+
|
|
19
|
+
const onPointerMove = useCallback(
|
|
20
|
+
(event: PointerEvent) => {
|
|
21
|
+
const rect = gl.domElement.getBoundingClientRect();
|
|
22
|
+
|
|
23
|
+
const x = event.clientX - rect.left;
|
|
24
|
+
const y = event.clientY - rect.top;
|
|
25
|
+
|
|
26
|
+
const deltaX = x - lastMouse.current.x;
|
|
27
|
+
const deltaY = y - lastMouse.current.y;
|
|
28
|
+
|
|
29
|
+
if (!hasMoved.current) {
|
|
30
|
+
hasMoved.current = true;
|
|
31
|
+
lastMouse.current.set(x, y);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
lastMouse.current.set(x, y);
|
|
36
|
+
|
|
37
|
+
splatStack.push({
|
|
38
|
+
mouseX: x / size.width,
|
|
39
|
+
mouseY: 1 - y / size.height,
|
|
40
|
+
velocityX: deltaX * force,
|
|
41
|
+
velocityY: -deltaY * force,
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
[force, size.width, size.height, gl, splatStack],
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const el = gl.domElement;
|
|
49
|
+
el.addEventListener('pointermove', onPointerMove);
|
|
50
|
+
return () => el.removeEventListener('pointermove', onPointerMove);
|
|
51
|
+
}, [onPointerMove, gl]);
|
|
52
|
+
|
|
53
|
+
return splatStack;
|
|
54
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BlendFunction } from 'postprocessing';
|
|
2
|
+
import { Texture } from 'three';
|
|
3
|
+
|
|
4
|
+
export type SharedProps = {
|
|
5
|
+
blend?: number;
|
|
6
|
+
intensity?: number;
|
|
7
|
+
distortion?: number;
|
|
8
|
+
rainbow?: boolean;
|
|
9
|
+
fluidColor?: string;
|
|
10
|
+
backgroundColor?: string;
|
|
11
|
+
showBackground?: boolean;
|
|
12
|
+
blendFunction?: BlendFunction;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type FluidProps = SharedProps & {
|
|
16
|
+
densityDissipation?: number;
|
|
17
|
+
pressure?: number;
|
|
18
|
+
velocityDissipation?: number;
|
|
19
|
+
force?: number;
|
|
20
|
+
radius?: number;
|
|
21
|
+
curl?: number;
|
|
22
|
+
swirl?: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type EffectProps = Required<SharedProps> & {
|
|
26
|
+
tFluid: Texture;
|
|
27
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Color, Vector3 } from 'three';
|
|
2
|
+
import { REFRESH_RATE } from './constant';
|
|
3
|
+
|
|
4
|
+
export const hexToRgb = (hex: string) => {
|
|
5
|
+
const color = new Color(hex);
|
|
6
|
+
|
|
7
|
+
return new Vector3(color.r, color.g, color.b);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const normalizeScreenHz = (value: number, dt: number) => {
|
|
11
|
+
return Math.pow(value, dt * REFRESH_RATE);
|
|
12
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { useRef, useState } from "react";
|
|
3
|
+
import { createPortal, useFrame, useThree } from "@react-three/fiber";
|
|
4
|
+
import { useFBO, useGLTF, MeshTransmissionMaterial } from "@react-three/drei";
|
|
5
|
+
import { easing } from "maath";
|
|
6
|
+
|
|
7
|
+
const Lens = ({ children, damping = 0.2, ...props }) => {
|
|
8
|
+
const ref = useRef(null);
|
|
9
|
+
const { nodes } = useGLTF("/lens-transformed.glb");
|
|
10
|
+
const buffer = useFBO();
|
|
11
|
+
const viewport = useThree((state) => state.viewport);
|
|
12
|
+
const [scene] = useState(() => new THREE.Scene());
|
|
13
|
+
useFrame((state, delta) => {
|
|
14
|
+
// Tie lens to the pointer
|
|
15
|
+
// getCurrentViewport gives us the width & height that would fill the screen in threejs units
|
|
16
|
+
// By giving it a target coordinate we can offset these bounds, for instance width/height for a plane that
|
|
17
|
+
// sits 15 units from 0/0/0 towards the camera (which is where the lens is)
|
|
18
|
+
const viewport = state.viewport.getCurrentViewport(
|
|
19
|
+
state.camera,
|
|
20
|
+
[0, 0, 15]
|
|
21
|
+
);
|
|
22
|
+
easing.damp3(
|
|
23
|
+
ref.current!.position,
|
|
24
|
+
[
|
|
25
|
+
(state.pointer.x * viewport.width) / 2,
|
|
26
|
+
(state.pointer.y * viewport.height) / 2,
|
|
27
|
+
15,
|
|
28
|
+
],
|
|
29
|
+
damping,
|
|
30
|
+
delta
|
|
31
|
+
);
|
|
32
|
+
// This is entirely optional but spares us one extra render of the scene
|
|
33
|
+
// The createPortal below will mount the children of <Lens> into the new THREE.Scene above
|
|
34
|
+
// The following code will render that scene into a buffer, whose texture will then be fed into
|
|
35
|
+
// a plane spanning the full screen and the lens transmission material
|
|
36
|
+
state.gl.setRenderTarget(buffer);
|
|
37
|
+
state.gl.setClearColor("#f197f4");
|
|
38
|
+
state.gl.render(scene, state.camera);
|
|
39
|
+
state.gl.setRenderTarget(null);
|
|
40
|
+
});
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
{createPortal(children, scene)}
|
|
44
|
+
<mesh scale={[viewport.width, viewport.height, 1]}>
|
|
45
|
+
<planeGeometry />
|
|
46
|
+
<meshBasicMaterial map={buffer.texture} />
|
|
47
|
+
</mesh>
|
|
48
|
+
<mesh
|
|
49
|
+
scale={0.25}
|
|
50
|
+
ref={ref}
|
|
51
|
+
rotation-x={Math.PI / 2}
|
|
52
|
+
geometry={nodes.Cylinder.geometry}
|
|
53
|
+
{...props}>
|
|
54
|
+
<MeshTransmissionMaterial
|
|
55
|
+
buffer={buffer.texture}
|
|
56
|
+
ior={1.2}
|
|
57
|
+
thickness={1.5}
|
|
58
|
+
anisotropy={0.1}
|
|
59
|
+
chromaticAberration={0.02}
|
|
60
|
+
/>
|
|
61
|
+
</mesh>
|
|
62
|
+
</>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default Lens;
|