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,35 @@
|
|
|
1
|
+
import { Canvas } from "@react-three/fiber";
|
|
2
|
+
import { Environment, Text } from "@react-three/drei";
|
|
3
|
+
import { EffectComposer, N8AO, TiltShift2 } from "@react-three/postprocessing";
|
|
4
|
+
import Bubbles from "./bubbles/Bubbles";
|
|
5
|
+
|
|
6
|
+
const TileBalls = () => {
|
|
7
|
+
return (
|
|
8
|
+
<Canvas
|
|
9
|
+
shadows
|
|
10
|
+
dpr={[1, 2]}
|
|
11
|
+
gl={{ antialias: false }}
|
|
12
|
+
camera={{ fov: 15, position: [0, 0, 20] }}>
|
|
13
|
+
<color attach="background" args={["#380de8"]} />
|
|
14
|
+
<fog attach="fog" args={["red", 20, -5]} />
|
|
15
|
+
<ambientLight intensity={1.5} />
|
|
16
|
+
<pointLight position={[10, 10, 10]} intensity={1} castShadow />
|
|
17
|
+
<Bubbles />
|
|
18
|
+
<EffectComposer>
|
|
19
|
+
<N8AO aoRadius={6} intensity={2} color="red" />
|
|
20
|
+
<TiltShift2 blur={0.1} />
|
|
21
|
+
</EffectComposer>
|
|
22
|
+
<Environment preset="city" />
|
|
23
|
+
<Text
|
|
24
|
+
position={[0, 0, 0]}
|
|
25
|
+
fontSize={0.4}
|
|
26
|
+
textAlign="center"
|
|
27
|
+
fontWeight={600}
|
|
28
|
+
color="#fff">
|
|
29
|
+
Content and{"\n"}Campaigning
|
|
30
|
+
</Text>
|
|
31
|
+
</Canvas>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default TileBalls;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Text } from "@react-three/drei";
|
|
2
|
+
import { Canvas } from "@react-three/fiber";
|
|
3
|
+
import { EffectComposer } from "@react-three/postprocessing";
|
|
4
|
+
import { Fluid } from "./fluid/Fluid";
|
|
5
|
+
|
|
6
|
+
const TileFluid = () => {
|
|
7
|
+
return (
|
|
8
|
+
<Canvas
|
|
9
|
+
style={{
|
|
10
|
+
height: "100%",
|
|
11
|
+
width: "100%",
|
|
12
|
+
}}
|
|
13
|
+
camera={{ position: [0, 0, 20], fov: 15 }}>
|
|
14
|
+
<Text
|
|
15
|
+
position={[0, 0, 0]}
|
|
16
|
+
fontSize={0.4}
|
|
17
|
+
textAlign="center"
|
|
18
|
+
fontWeight={600}
|
|
19
|
+
color="#380de8">
|
|
20
|
+
Branding &{"\n"}Corporate ID
|
|
21
|
+
</Text>
|
|
22
|
+
<EffectComposer>
|
|
23
|
+
<Fluid backgroundColor="#fbff00" fluidColor="#380de8" rainbow={true} />
|
|
24
|
+
</EffectComposer>
|
|
25
|
+
</Canvas>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default TileFluid;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Canvas } from "@react-three/fiber";
|
|
2
|
+
import { Text } from "@react-three/drei";
|
|
3
|
+
import Lens from "./glass/Lens";
|
|
4
|
+
|
|
5
|
+
const TileGlass = () => {
|
|
6
|
+
return (
|
|
7
|
+
<Canvas camera={{ position: [0, 0, 20], fov: 15 }}>
|
|
8
|
+
<Lens>
|
|
9
|
+
<Text
|
|
10
|
+
position={[0, 0, 0]}
|
|
11
|
+
fontSize={0.4}
|
|
12
|
+
textAlign="center"
|
|
13
|
+
fontWeight={600}
|
|
14
|
+
color="#491b11">
|
|
15
|
+
Strategy &{"\n"}
|
|
16
|
+
Positioning
|
|
17
|
+
</Text>
|
|
18
|
+
</Lens>
|
|
19
|
+
</Canvas>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default TileGlass;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { useRef } from "react";
|
|
4
|
+
import { Canvas, useFrame, useThree } from "@react-three/fiber";
|
|
5
|
+
import { OrbitControls, useGLTF } from "@react-three/drei";
|
|
6
|
+
import { Vector2, MeshBasicMaterial, DoubleSide } from "three";
|
|
7
|
+
import { LightSource } from "./rays/LightSource";
|
|
8
|
+
import {
|
|
9
|
+
EffectComposer,
|
|
10
|
+
EffectPass,
|
|
11
|
+
GodRaysEffect,
|
|
12
|
+
RenderPass,
|
|
13
|
+
} from "postprocessing";
|
|
14
|
+
|
|
15
|
+
function Slab({ url }) {
|
|
16
|
+
const gltf = useGLTF(url);
|
|
17
|
+
const slabRef = useRef();
|
|
18
|
+
const { camera, scene, gl } = useThree();
|
|
19
|
+
|
|
20
|
+
// GodRays light
|
|
21
|
+
const lightRef = useRef();
|
|
22
|
+
useFrame(({ pointer }) => {
|
|
23
|
+
if (lightRef.current) {
|
|
24
|
+
const LIGHT_RANGE = 5;
|
|
25
|
+
lightRef.current.position.x = pointer.x * LIGHT_RANGE;
|
|
26
|
+
lightRef.current.position.y = pointer.y * LIGHT_RANGE;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
React.useEffect(() => {
|
|
31
|
+
if (!gltf) return;
|
|
32
|
+
|
|
33
|
+
const slab = gltf.scene;
|
|
34
|
+
slab.rotation.x = Math.PI / 2;
|
|
35
|
+
|
|
36
|
+
slab.traverse((obj) => {
|
|
37
|
+
if (obj.isMesh) {
|
|
38
|
+
obj.material = new MeshBasicMaterial({
|
|
39
|
+
color: 0x491b11,
|
|
40
|
+
side: DoubleSide,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
slabRef.current.add(slab);
|
|
46
|
+
|
|
47
|
+
// Setup postprocessing
|
|
48
|
+
const composer = new EffectComposer(gl);
|
|
49
|
+
composer.addPass(new RenderPass(scene, camera));
|
|
50
|
+
|
|
51
|
+
const gre = new GodRaysEffect(camera, lightRef.current, {
|
|
52
|
+
height: 480,
|
|
53
|
+
kernelSize: 2,
|
|
54
|
+
density: 1,
|
|
55
|
+
decay: 0.8,
|
|
56
|
+
weight: 0.5,
|
|
57
|
+
exposure: 0.3,
|
|
58
|
+
samples: 20,
|
|
59
|
+
clampMax: 0.95,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
composer.addPass(new EffectPass(camera, gre));
|
|
63
|
+
|
|
64
|
+
// Render loop override
|
|
65
|
+
const originalSetAnimationLoop = gl.setAnimationLoop;
|
|
66
|
+
gl.setAnimationLoop(() => composer.render());
|
|
67
|
+
|
|
68
|
+
return () => {
|
|
69
|
+
// Cleanup
|
|
70
|
+
gl.setAnimationLoop(originalSetAnimationLoop);
|
|
71
|
+
composer.dispose();
|
|
72
|
+
};
|
|
73
|
+
}, [gltf, gl, scene, camera]);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<>
|
|
77
|
+
{/* <mesh ref={lightRef} position={[0, 0, -10]} /> */}
|
|
78
|
+
<group ref={slabRef} />
|
|
79
|
+
<LightSource ref={lightRef} position={[0, 0, -20]} />
|
|
80
|
+
</>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export default function SlabScene() {
|
|
85
|
+
return (
|
|
86
|
+
<Canvas
|
|
87
|
+
camera={{ fov: 60, position: [0, 0, 10], near: 1, far: 100 }}
|
|
88
|
+
gl={{ antialias: true, powerPreference: "high-performance" }}>
|
|
89
|
+
{/* <ambientLight intensity={0.2} /> */}
|
|
90
|
+
{/* <OrbitControls /> */}
|
|
91
|
+
<Slab url="/slab-with-text.glb" />
|
|
92
|
+
</Canvas>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import { useFrame } from "@react-three/fiber";
|
|
3
|
+
import { Instance } from "@react-three/drei";
|
|
4
|
+
|
|
5
|
+
const Bubble = ({ factor, speed, xFactor, yFactor, zFactor }) => {
|
|
6
|
+
const ref = useRef();
|
|
7
|
+
|
|
8
|
+
useFrame((state) => {
|
|
9
|
+
const t = factor + state.clock.elapsedTime * (speed / 2);
|
|
10
|
+
|
|
11
|
+
ref.current!.scale.setScalar(Math.max(1.5, Math.cos(t) * 5));
|
|
12
|
+
|
|
13
|
+
ref.current!.position.set(
|
|
14
|
+
Math.cos(t) +
|
|
15
|
+
Math.sin(t * 1) / 10 +
|
|
16
|
+
xFactor +
|
|
17
|
+
Math.cos((t / 10) * factor) +
|
|
18
|
+
(Math.sin(t * 1) * factor) / 10,
|
|
19
|
+
Math.sin(t) +
|
|
20
|
+
Math.cos(t * 2) / 10 +
|
|
21
|
+
yFactor +
|
|
22
|
+
Math.sin((t / 10) * factor) +
|
|
23
|
+
(Math.cos(t * 2) * factor) / 10,
|
|
24
|
+
Math.sin(t) +
|
|
25
|
+
Math.cos(t * 2) / 10 +
|
|
26
|
+
zFactor +
|
|
27
|
+
Math.cos((t / 10) * factor) +
|
|
28
|
+
(Math.sin(t * 3) * factor) / 4
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return <Instance ref={ref} />;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default Bubble;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { MathUtils } from "three";
|
|
2
|
+
import { useRef } from "react";
|
|
3
|
+
import { useFrame } from "@react-three/fiber";
|
|
4
|
+
import { Instances } from "@react-three/drei";
|
|
5
|
+
import Bubble from "./Bubble";
|
|
6
|
+
|
|
7
|
+
const particles = Array.from({ length: 20 }, () => ({
|
|
8
|
+
factor: MathUtils.randInt(20, 100),
|
|
9
|
+
speed: MathUtils.randFloat(0.01, 0.75),
|
|
10
|
+
xFactor: MathUtils.randFloatSpread(3),
|
|
11
|
+
yFactor: MathUtils.randFloatSpread(3),
|
|
12
|
+
zFactor: MathUtils.randFloatSpread(5),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
const Bubbles = () => {
|
|
16
|
+
const ref = useRef(null);
|
|
17
|
+
|
|
18
|
+
useFrame(
|
|
19
|
+
(state, delta) =>
|
|
20
|
+
void (ref.current.rotation.y = MathUtils.damp(
|
|
21
|
+
ref.current.rotation.y,
|
|
22
|
+
(-state.pointer.x * Math.PI) / 6,
|
|
23
|
+
2.75,
|
|
24
|
+
delta
|
|
25
|
+
))
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Instances
|
|
30
|
+
limit={particles.length}
|
|
31
|
+
ref={ref}
|
|
32
|
+
castShadow
|
|
33
|
+
receiveShadow
|
|
34
|
+
position={[0, 2.5, 0]}>
|
|
35
|
+
<sphereGeometry args={[0.45, 64, 64]} />
|
|
36
|
+
<meshStandardMaterial roughness={1} color="#f0f0f0" />
|
|
37
|
+
{particles.map((data, i) => (
|
|
38
|
+
<Bubble key={i} {...data} />
|
|
39
|
+
))}
|
|
40
|
+
</Instances>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default Bubbles;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { createPortal, useFrame, useThree } from '@react-three/fiber';
|
|
2
|
+
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { Camera, Color, Mesh, Scene, Texture, Vector2, Vector3 } from 'three';
|
|
4
|
+
import { ShaderPass } from 'three/examples/jsm/Addons.js';
|
|
5
|
+
import { Effect as FluidEffect } from './effect/Fluid';
|
|
6
|
+
import { useFBOs } from './hooks/useFBOs';
|
|
7
|
+
import { useMaterials } from './hooks/useMaterials';
|
|
8
|
+
import { type FluidProps } from './types';
|
|
9
|
+
import { DEFAULT_CONFIG } from './constant';
|
|
10
|
+
import { usePointer } from './hooks/usePointer';
|
|
11
|
+
import { normalizeScreenHz } from './utils';
|
|
12
|
+
|
|
13
|
+
type MaterialName = keyof ReturnType<typeof useMaterials>;
|
|
14
|
+
type FBONames = keyof ReturnType<typeof useFBOs>;
|
|
15
|
+
|
|
16
|
+
type Uniforms = {
|
|
17
|
+
uColor: Vector3 | Color;
|
|
18
|
+
uPointer: Vector2;
|
|
19
|
+
uTarget: Texture | null;
|
|
20
|
+
uVelocity: Texture;
|
|
21
|
+
uCurl: Texture;
|
|
22
|
+
uTexture: Texture;
|
|
23
|
+
uPressure: Texture;
|
|
24
|
+
uDivergence: Texture;
|
|
25
|
+
uSource: Texture;
|
|
26
|
+
uRadius: number;
|
|
27
|
+
uClearValue: number;
|
|
28
|
+
uCurlValue: number;
|
|
29
|
+
uDissipation: number;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const Fluid = ({
|
|
33
|
+
blend = DEFAULT_CONFIG.blend,
|
|
34
|
+
force = DEFAULT_CONFIG.force,
|
|
35
|
+
radius = DEFAULT_CONFIG.radius,
|
|
36
|
+
curl = DEFAULT_CONFIG.curl,
|
|
37
|
+
swirl = DEFAULT_CONFIG.swirl,
|
|
38
|
+
intensity = DEFAULT_CONFIG.intensity,
|
|
39
|
+
distortion = DEFAULT_CONFIG.distortion,
|
|
40
|
+
fluidColor = DEFAULT_CONFIG.fluidColor,
|
|
41
|
+
backgroundColor = DEFAULT_CONFIG.backgroundColor,
|
|
42
|
+
showBackground = DEFAULT_CONFIG.showBackground,
|
|
43
|
+
rainbow = DEFAULT_CONFIG.rainbow,
|
|
44
|
+
pressure = DEFAULT_CONFIG.pressure,
|
|
45
|
+
densityDissipation = DEFAULT_CONFIG.densityDissipation,
|
|
46
|
+
velocityDissipation = DEFAULT_CONFIG.velocityDissipation,
|
|
47
|
+
blendFunction = DEFAULT_CONFIG.blendFunction,
|
|
48
|
+
}: FluidProps) => {
|
|
49
|
+
const size = useThree((three) => three.size);
|
|
50
|
+
const gl = useThree((three) => three.gl);
|
|
51
|
+
|
|
52
|
+
const [bufferScene] = useState(() => new Scene());
|
|
53
|
+
const bufferCamera = useMemo(() => new Camera(), []);
|
|
54
|
+
|
|
55
|
+
const meshRef = useRef<Mesh>(null);
|
|
56
|
+
const postRef = useRef<ShaderPass>(null);
|
|
57
|
+
const pointerRef = useRef(new Vector2());
|
|
58
|
+
const colorRef = useRef(new Vector3());
|
|
59
|
+
|
|
60
|
+
const FBOs = useFBOs();
|
|
61
|
+
const materials = useMaterials();
|
|
62
|
+
const splatStack = usePointer({ force });
|
|
63
|
+
|
|
64
|
+
const setShaderMaterial = useCallback(
|
|
65
|
+
(name: MaterialName) => {
|
|
66
|
+
if (!meshRef.current) return;
|
|
67
|
+
|
|
68
|
+
meshRef.current.material = materials[name];
|
|
69
|
+
meshRef.current.material.needsUpdate = true;
|
|
70
|
+
},
|
|
71
|
+
[materials],
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const setRenderTarget = useCallback(
|
|
75
|
+
(name: FBONames) => {
|
|
76
|
+
const target = FBOs[name];
|
|
77
|
+
|
|
78
|
+
if ('write' in target) {
|
|
79
|
+
gl.setRenderTarget(target.write);
|
|
80
|
+
gl.clear();
|
|
81
|
+
gl.render(bufferScene, bufferCamera);
|
|
82
|
+
target.swap();
|
|
83
|
+
} else {
|
|
84
|
+
gl.setRenderTarget(target);
|
|
85
|
+
gl.clear();
|
|
86
|
+
gl.render(bufferScene, bufferCamera);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
[bufferCamera, bufferScene, FBOs, gl],
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const setUniforms = useCallback(
|
|
93
|
+
<K extends keyof Uniforms>(material: MaterialName, uniform: K, value: Uniforms[K]) => {
|
|
94
|
+
const mat = materials[material];
|
|
95
|
+
|
|
96
|
+
if (mat && mat.uniforms[uniform]) {
|
|
97
|
+
mat.uniforms[uniform].value = value;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
[materials],
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
useFrame((_, delta) => {
|
|
104
|
+
if (!meshRef.current || !postRef.current) return;
|
|
105
|
+
|
|
106
|
+
for (let i = splatStack.length - 1; i >= 0; i--) {
|
|
107
|
+
const { mouseX, mouseY, velocityX, velocityY } = splatStack[i];
|
|
108
|
+
|
|
109
|
+
pointerRef.current.set(mouseX, mouseY);
|
|
110
|
+
colorRef.current.set(velocityX, velocityY, 10.0);
|
|
111
|
+
|
|
112
|
+
setShaderMaterial('splat');
|
|
113
|
+
setUniforms('splat', 'uTarget', FBOs.velocity.read.texture);
|
|
114
|
+
setUniforms('splat', 'uPointer', pointerRef.current);
|
|
115
|
+
setUniforms('splat', 'uColor', colorRef.current);
|
|
116
|
+
setUniforms('splat', 'uRadius', radius / 100.0);
|
|
117
|
+
setRenderTarget('velocity');
|
|
118
|
+
setUniforms('splat', 'uTarget', FBOs.density.read.texture);
|
|
119
|
+
setRenderTarget('density');
|
|
120
|
+
|
|
121
|
+
splatStack.pop();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
setShaderMaterial('curl');
|
|
125
|
+
setUniforms('curl', 'uVelocity', FBOs.velocity.read.texture);
|
|
126
|
+
setRenderTarget('curl');
|
|
127
|
+
|
|
128
|
+
setShaderMaterial('vorticity');
|
|
129
|
+
setUniforms('vorticity', 'uVelocity', FBOs.velocity.read.texture);
|
|
130
|
+
setUniforms('vorticity', 'uCurl', FBOs.curl.texture);
|
|
131
|
+
setUniforms('vorticity', 'uCurlValue', curl);
|
|
132
|
+
setRenderTarget('velocity');
|
|
133
|
+
|
|
134
|
+
setShaderMaterial('divergence');
|
|
135
|
+
setUniforms('divergence', 'uVelocity', FBOs.velocity.read.texture);
|
|
136
|
+
setRenderTarget('divergence');
|
|
137
|
+
|
|
138
|
+
setShaderMaterial('clear');
|
|
139
|
+
setUniforms('clear', 'uTexture', FBOs.pressure.read.texture);
|
|
140
|
+
setUniforms('clear', 'uClearValue', normalizeScreenHz(pressure, delta));
|
|
141
|
+
setRenderTarget('pressure');
|
|
142
|
+
|
|
143
|
+
setShaderMaterial('pressure');
|
|
144
|
+
setUniforms('pressure', 'uDivergence', FBOs.divergence.texture);
|
|
145
|
+
|
|
146
|
+
for (let i = 0; i < swirl; i++) {
|
|
147
|
+
setUniforms('pressure', 'uPressure', FBOs.pressure.read.texture);
|
|
148
|
+
setRenderTarget('pressure');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
setShaderMaterial('gradientSubstract');
|
|
152
|
+
setUniforms('gradientSubstract', 'uPressure', FBOs.pressure.read.texture);
|
|
153
|
+
setUniforms('gradientSubstract', 'uVelocity', FBOs.velocity.read.texture);
|
|
154
|
+
setRenderTarget('velocity');
|
|
155
|
+
|
|
156
|
+
setShaderMaterial('advection');
|
|
157
|
+
setUniforms('advection', 'uVelocity', FBOs.velocity.read.texture);
|
|
158
|
+
setUniforms('advection', 'uSource', FBOs.velocity.read.texture);
|
|
159
|
+
setUniforms('advection', 'uDissipation', normalizeScreenHz(velocityDissipation, delta));
|
|
160
|
+
|
|
161
|
+
setRenderTarget('velocity');
|
|
162
|
+
setUniforms('advection', 'uVelocity', FBOs.velocity.read.texture);
|
|
163
|
+
setUniforms('advection', 'uSource', FBOs.density.read.texture);
|
|
164
|
+
setUniforms('advection', 'uDissipation', normalizeScreenHz(densityDissipation, delta));
|
|
165
|
+
|
|
166
|
+
setRenderTarget('density');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<>
|
|
171
|
+
{createPortal(
|
|
172
|
+
<mesh ref={meshRef} scale={[size.width, size.height, 1]}>
|
|
173
|
+
<planeGeometry args={[2, 2]} />
|
|
174
|
+
</mesh>,
|
|
175
|
+
bufferScene,
|
|
176
|
+
)}
|
|
177
|
+
|
|
178
|
+
<FluidEffect
|
|
179
|
+
blendFunction={blendFunction}
|
|
180
|
+
intensity={intensity}
|
|
181
|
+
rainbow={rainbow}
|
|
182
|
+
distortion={distortion}
|
|
183
|
+
backgroundColor={backgroundColor}
|
|
184
|
+
blend={blend}
|
|
185
|
+
fluidColor={fluidColor}
|
|
186
|
+
showBackground={showBackground}
|
|
187
|
+
ref={postRef}
|
|
188
|
+
tFluid={FBOs.density.read.texture}
|
|
189
|
+
/>
|
|
190
|
+
</>
|
|
191
|
+
);
|
|
192
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BlendFunction } from 'postprocessing';
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_CONFIG = {
|
|
4
|
+
blend: 5,
|
|
5
|
+
intensity: 2,
|
|
6
|
+
force: 1.1,
|
|
7
|
+
distortion: 0.4,
|
|
8
|
+
curl: 1.9,
|
|
9
|
+
radius: 0.3,
|
|
10
|
+
swirl: 4,
|
|
11
|
+
pressure: 0.8,
|
|
12
|
+
densityDissipation: 0.96,
|
|
13
|
+
velocityDissipation: 1.0,
|
|
14
|
+
fluidColor: '#3300ff',
|
|
15
|
+
backgroundColor: '#070410',
|
|
16
|
+
showBackground: true,
|
|
17
|
+
rainbow: false,
|
|
18
|
+
dyeRes: 512,
|
|
19
|
+
simRes: 128,
|
|
20
|
+
blendFunction: BlendFunction.SET,
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
export const REFRESH_RATE = 60;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { forwardRef, useEffect, useMemo } from 'react';
|
|
2
|
+
import { EffectProps } from '../types';
|
|
3
|
+
import { FluidEffect } from './FluidEffect';
|
|
4
|
+
|
|
5
|
+
export const Effect = forwardRef(function Fluid(props: EffectProps, ref) {
|
|
6
|
+
// prevent re-creating the effect on every render
|
|
7
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
8
|
+
const effect = useMemo(() => new FluidEffect(props), []);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
effect.state = { ...props };
|
|
12
|
+
effect.update();
|
|
13
|
+
}, [effect, props]);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
return () => {
|
|
17
|
+
effect.dispose?.();
|
|
18
|
+
};
|
|
19
|
+
}, [effect]);
|
|
20
|
+
|
|
21
|
+
return <primitive ref={ref} object={effect} dispose={null} />;
|
|
22
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Effect, EffectAttribute } from 'postprocessing';
|
|
2
|
+
import { Texture, Uniform, Vector3 } from 'three';
|
|
3
|
+
import compositeFrag from '../glsl/composite.frag';
|
|
4
|
+
import { type EffectProps } from '../types';
|
|
5
|
+
import { hexToRgb } from '../utils';
|
|
6
|
+
|
|
7
|
+
type Uniforms = {
|
|
8
|
+
tFluid: Texture;
|
|
9
|
+
uColor: Vector3;
|
|
10
|
+
uBackgroundColor: Vector3;
|
|
11
|
+
uRainbow: boolean;
|
|
12
|
+
uShowBackground: boolean;
|
|
13
|
+
uDistort: number;
|
|
14
|
+
uBlend: number;
|
|
15
|
+
uIntensity: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export class FluidEffect extends Effect {
|
|
19
|
+
state: EffectProps;
|
|
20
|
+
|
|
21
|
+
constructor(props: EffectProps) {
|
|
22
|
+
const uniforms: Record<keyof Uniforms, Uniform> = {
|
|
23
|
+
tFluid: new Uniform(props.tFluid),
|
|
24
|
+
uDistort: new Uniform(props.distortion),
|
|
25
|
+
uRainbow: new Uniform(props.rainbow),
|
|
26
|
+
uIntensity: new Uniform(props.intensity),
|
|
27
|
+
uBlend: new Uniform(props.blend),
|
|
28
|
+
uShowBackground: new Uniform(props.showBackground),
|
|
29
|
+
uColor: new Uniform(hexToRgb(props.fluidColor!)),
|
|
30
|
+
uBackgroundColor: new Uniform(hexToRgb(props.backgroundColor!)),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
super('FluidEffect', compositeFrag, {
|
|
34
|
+
blendFunction: props.blendFunction,
|
|
35
|
+
attributes: EffectAttribute.CONVOLUTION,
|
|
36
|
+
uniforms: new Map(Object.entries(uniforms)),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
this.state = props;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private updateUniform<K extends keyof Uniforms>(key: K, value: Uniforms[K]) {
|
|
43
|
+
const uniform = this.uniforms.get(key);
|
|
44
|
+
if (uniform) {
|
|
45
|
+
uniform.value = value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
update() {
|
|
50
|
+
this.updateUniform('uIntensity', this.state.intensity);
|
|
51
|
+
this.updateUniform('uDistort', this.state.distortion);
|
|
52
|
+
this.updateUniform('uRainbow', this.state.rainbow);
|
|
53
|
+
this.updateUniform('uBlend', this.state.blend);
|
|
54
|
+
this.updateUniform('uShowBackground', this.state.showBackground);
|
|
55
|
+
this.updateUniform('uColor', hexToRgb(this.state.fluidColor));
|
|
56
|
+
this.updateUniform('uBackgroundColor', hexToRgb(this.state.backgroundColor));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
precision highp float;
|
|
2
|
+
|
|
3
|
+
varying vec2 vUv;
|
|
4
|
+
uniform sampler2D uVelocity;
|
|
5
|
+
uniform sampler2D uSource;
|
|
6
|
+
uniform vec2 texelSize;
|
|
7
|
+
uniform float dt;
|
|
8
|
+
uniform float uDissipation;
|
|
9
|
+
|
|
10
|
+
void main() {
|
|
11
|
+
vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize;
|
|
12
|
+
|
|
13
|
+
gl_FragColor = uDissipation * texture2D(uSource, coord);
|
|
14
|
+
|
|
15
|
+
gl_FragColor.a = 1.0;
|
|
16
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#ifdef USE_V_UV
|
|
2
|
+
varying vec2 vUv;
|
|
3
|
+
#endif
|
|
4
|
+
|
|
5
|
+
#ifdef USE_OFFSETS
|
|
6
|
+
varying vec2 vL;
|
|
7
|
+
varying vec2 vR;
|
|
8
|
+
varying vec2 vT;
|
|
9
|
+
varying vec2 vB;
|
|
10
|
+
uniform vec2 texelSize;
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
void main() {
|
|
14
|
+
#ifdef USE_V_UV
|
|
15
|
+
vUv = uv;
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
#ifdef USE_OFFSETS
|
|
19
|
+
vL = uv - vec2(texelSize.x, 0.0);
|
|
20
|
+
vR = uv + vec2(texelSize.x, 0.0);
|
|
21
|
+
vT = uv + vec2(0.0, texelSize.y);
|
|
22
|
+
vB = uv - vec2(0.0, texelSize.y);
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
gl_Position = vec4(position, 1.0);
|
|
26
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
uniform sampler2D tFluid;
|
|
2
|
+
|
|
3
|
+
uniform vec3 uColor;
|
|
4
|
+
uniform vec3 uBackgroundColor;
|
|
5
|
+
|
|
6
|
+
uniform float uDistort;
|
|
7
|
+
uniform float uIntensity;
|
|
8
|
+
uniform float uRainbow;
|
|
9
|
+
uniform float uBlend;
|
|
10
|
+
uniform float uShowBackground;
|
|
11
|
+
|
|
12
|
+
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
|
|
13
|
+
|
|
14
|
+
vec3 fluidColor = texture2D(tFluid, uv).rgb;
|
|
15
|
+
|
|
16
|
+
vec2 distortedUv = uv - fluidColor.rg * uDistort * 0.001;
|
|
17
|
+
|
|
18
|
+
vec4 texture = texture2D(inputBuffer, distortedUv);
|
|
19
|
+
|
|
20
|
+
float intensity = length(fluidColor) * uIntensity * 0.0001;
|
|
21
|
+
|
|
22
|
+
vec3 selectedColor = uColor * length(fluidColor);
|
|
23
|
+
|
|
24
|
+
vec4 colorForFluidEffect = vec4(uRainbow == 1.0 ? fluidColor : selectedColor, 1.0);
|
|
25
|
+
|
|
26
|
+
vec4 computedBgColor = uShowBackground != 0.0 ? vec4(uBackgroundColor, 1.0) : vec4(0.0, 0.0, 0.0, 0.0);
|
|
27
|
+
|
|
28
|
+
outputColor = mix(texture, colorForFluidEffect, intensity);
|
|
29
|
+
|
|
30
|
+
vec4 computedFluidColor = mix(texture, colorForFluidEffect, uBlend * 0.01);
|
|
31
|
+
|
|
32
|
+
vec4 finalColor;
|
|
33
|
+
|
|
34
|
+
if(texture.a < 0.1) {
|
|
35
|
+
finalColor = mix(computedBgColor, colorForFluidEffect, intensity);
|
|
36
|
+
} else {
|
|
37
|
+
finalColor = mix(computedFluidColor, computedBgColor, 1.0 - texture.a);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
outputColor = finalColor;
|
|
41
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
precision highp float;
|
|
2
|
+
|
|
3
|
+
varying vec2 vL;
|
|
4
|
+
varying vec2 vR;
|
|
5
|
+
varying vec2 vT;
|
|
6
|
+
varying vec2 vB;
|
|
7
|
+
|
|
8
|
+
uniform sampler2D uVelocity;
|
|
9
|
+
|
|
10
|
+
void main() {
|
|
11
|
+
float L = texture2D(uVelocity, vL).y;
|
|
12
|
+
|
|
13
|
+
float R = texture2D(uVelocity, vR).y;
|
|
14
|
+
|
|
15
|
+
float T = texture2D(uVelocity, vT).x;
|
|
16
|
+
|
|
17
|
+
float B = texture2D(uVelocity, vB).x;
|
|
18
|
+
|
|
19
|
+
float vorticity = R - L - T + B;
|
|
20
|
+
|
|
21
|
+
gl_FragColor = vec4(vorticity, 0.0, 0.0, 1.0);
|
|
22
|
+
}
|