Skip to content

Commit b70a7f4

Browse files
author
takuma-hmng8
committed
ライブラリ公開
1 parent 8ea4701 commit b70a7f4

File tree

31 files changed

+890
-663
lines changed

31 files changed

+890
-663
lines changed

README.md

Lines changed: 82 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
![use-shader-fx](public/app.jpg)
22

3+
`use-shader-fx` is a library designed to easily implement shader effects such as fluid simulations and noise. It relies on [react-three-fiber](https://github.com/pmndrs/react-three-fiber) and has been designed with performance control in mind, especially when combined with [drei](https://github.com/pmndrs/drei).
4+
35
# Usage
46

5-
それぞれの fxHook からは{updateFx,setParams,fxObject}を受け取ります。
7+
From each `fxHooks`, you can receive [`updateFx`, `setParams`, `fxObject`] in array format. The `config` is an object, which varies for each Hook, containing details such as `size` and `dpr`.
68

7-
- updateFx - A function to be called inside `useFrame` that returns a `THREE.Texture`.
8-
- setParams - A function to update the parameters, useful for performance tuning, etc.
9-
- fxObject - An object containing various FX components such as scene, camera, material, and render target.
9+
1. `updateFx` - A function to be invoked inside `useFrame`, returning a `THREE.Texture`.
10+
2. `setParams` - A function to refresh the parameters, beneficial for performance tweaking, etc.
11+
3. `fxObject` - An object that holds various FX components, such as scene, camera, material, and renderTarget.
1012

1113
```js
12-
const { updateFx, setParams, fxObject } = useFruid();
14+
const [updateFx, setParams, fxObject] = useFruid(config);
1315
```
1416

15-
updateFxuseFrame で実行します。第 1 引数には useFrame から受け取る RootState,第 2 引数に HookPrams を受け取ります。
17+
Execute `updateFx` in `useFrame`. The first argument receives the RootState from `useFrame`, and the second one takes `HookPrams`. Each fx has its `HookPrams`, and each type is exported.
1618

1719
```js
1820
useFrame((props) => {
@@ -24,57 +26,96 @@ useFrame((props) => {
2426
});
2527
```
2628

27-
# How to make "custom fx hook"
29+
# Performance
30+
31+
You can control the `dpr` using the `PerformanceMonitor` from [drei](https://github.com/pmndrs/drei). For more details, please refer to the [scaling-performance](https://docs.pmnd.rs/react-three-fiber/advanced/scaling-performance) of r3f.
32+
33+
```js
34+
export const Fx = () => {
35+
const [dpr, setDpr] = useState(1.5);
36+
return (
37+
<Canvas dpr={dpr}>
38+
<PerformanceMonitor
39+
factor={1}
40+
onChange={({ factor }) => {
41+
console.log(`dpr:${dpr}`);
42+
setDpr(Math.round((0.5 + 1.5 * factor) * 10) / 10);
43+
}}>
44+
<Suspense fallback={null}>
45+
<Scene />
46+
</Suspense>
47+
<Perf position={"bottom-right"} minimal={false} />
48+
</PerformanceMonitor>
49+
</Canvas>
50+
);
51+
};
52+
```
53+
54+
By using the `PerformanceMonitor`, you can subscribe to performance changes with `usePerformanceMonitor`. For more details, refer to [drei](https://github.com/pmndrs/drei#performancemonitor).
55+
56+
With `setParams` received from `fxHooks`, it's possible to independently control high-load items such as iteration counts.
57+
58+
```js
59+
usePerformanceMonitor({
60+
onChange({ factor }) {
61+
setParams({
62+
pressure_iterations: Math.round(20 * factor),
63+
});
64+
},
65+
});
66+
```
67+
68+
# How to make "custom fxHooks"
2869

29-
カスタムフック開発に便利な utils をいくつか用意しています
30-
詳細は既存の hook を参照してください
70+
With some functions provided by `use-shader-fx`, creating a custom hook is straightforward (the challenging part is only the shader!). Please refer to existing `fxHooks` for details.
3171

3272
## useDoubleFBO
3373

34-
FBO を生成して、ダブルバッファリングしたバッファーテクスチャーを swap して返してくれます。
35-
第 3 引数には options が入ります。
74+
Generates FBO and returns a double-buffered buffer texture after swapping. The `useFBO` of `drei` by default performs `setSize` for `THREE.WebGLRenderTarget` upon changes in `dpr` and `size`, making it challenging to handle buffer textures during changes like dpr adjustments. Therefore, a non-reactive hook against updates of dpr and size was created. It's possible to make them reactive individually through options. If you want to `setSize` at a custom timing, the `fxObject` that the fxHook receives as the third argument also stores `renderTarget`.
3675

37-
- isDpr: Whether to multiply dpr, default:false
38-
- isSizeUpdate: Whether to resize when resizing occurs. If isDpr is true, set FBO to setSize even if dpr is changed, default:false
76+
```ts
77+
type UseFboProps = {
78+
scene: THREE.Scene;
79+
camera: THREE.Camera;
80+
size: Size;
81+
/** If dpr is set, dpr will be multiplied, default:false */
82+
dpr?: number | false;
83+
/** Whether to resize on resizes. If isDpr is true, set FBO to setSize even if dpr is changed, default:false */
84+
isSizeUpdate?: boolean;
85+
};
3986

40-
drei の useFBO はデフォルトで dpr と size の変更で setSize してしまうため、バッファーテクスチャーが更新されてしまいます。そこで、dpr と size の更新に対して non reactive な hook を作成しました。options でそれぞれ reactive にすることが可能です。
87+
const [velocityFBO, updateVelocityFBO] = useDoubleFBO(UseFboProps);
88+
```
4189

42-
もし resize させたい場合は、fxHook が第 3 引数に受け取る fxObject に renderTarget も格納しています。
90+
When you call the update function, it returns a double-buffered texture. The second argument gets a function called before `gl.render()`, allowing for operations like swapping materials or setting uniforms.
4391

4492
```js
45-
const [velocityFBO, updateVelocityFBO] = useDoubleFBO(scene, camera, {
46-
isDpr: true,
47-
isSizeUpdate: true,
48-
});
49-
50-
// how to render
51-
updateVelocityFBO(gl, ({ read, write }) => {
93+
const texture = updateVelocityFBO(gl, ({ read, write }) => {
5294
// callback before gl.render()
95+
setMeshMaterial(materials.advectionMaterial);
96+
setUniform(materials.advectionMaterial, "uVelocity", read);
5397
});
5498
```
5599

56100
## useSingleFBO
57101

58-
FBO を生成して、焼き付けられた texture を返す、更新関数を生成します。
102+
This is a version without double buffering.
59103

60104
```js
61-
const updateRenderTarget = useSingleFBO(scene, camera, options);
62-
63-
// how to render
64-
updateRenderTarget(gl, ({ read }) => {
65-
// callback before gl.render()
66-
});
105+
const [renderTarget, updateRenderTarget] = useSingleFBO(UseFboProps);
67106
```
68107

69108
## useCamera
70109

110+
Generates and returns a `THREE.OrthographicCamera`.
111+
71112
```js
72-
const camera = useCamera();
113+
const camera = useCamera(size);
73114
```
74115

75116
## usePointer
76117

77-
フレームの pointer の vec2 を渡すと、currentPointer,prevPointer, diffPointer, isVelocityUpdate, velocity を返す更新関数を生成します。
118+
When given the `pointer` vector2 from r3f's `RootState`, it generates an update function that returns {currentPointer, prevPointer, diffPointer, isVelocityUpdate, velocity}.
78119

79120
```js
80121
const updatePointer = usePointer();
@@ -85,25 +126,23 @@ const { currentPointer, prevPointer, diffPointer, isVelocityUpdate, velocity } =
85126

86127
## useResolution
87128

88-
キャンバスのサイズの state のフック
129+
This hook returns `resolution`. If `dpr` isn't set (or set to false), dpr won't be multiplied.
89130

90-
- isDpr: Whether to multiply dpr, default:false
91-
92-
```js
93-
const resolution = useResolution(isDpr);
131+
```ts
132+
const resolution = useResolution(size: Size, dpr: number | false = false);
94133
```
95134

96135
## useAddMesh
97136

98-
メッシュを生成して、scene,geometry,material に add する。mesh を返す。
137+
Creates a mesh and adds it to scene, geometry, and material. Returns the mesh.
99138

100139
```js
101140
useAddMesh(scene, geometry, material);
102141
```
103142

104143
## setUniform
105144

106-
シェーダーマテリアルの uniforms に value をセットする関数
145+
A function to set values in the uniforms of the shader material.
107146

108147
```js
109148
const setUniform = (material, key, value) => {
@@ -113,19 +152,11 @@ const setUniform = (material, key, value) => {
113152

114153
## useParams
115154

116-
params の refObject とその更新用関数を返します。
155+
Returns the refObject of params and its update function.
117156

118157
```ts
119-
const [params, setParams] =
120-
useParams <FruidParams>
121-
{
122-
density_dissipation: 0.0,
123-
velocity_dissipation: 0.0,
124-
velocity_acceleration: 0.0,
125-
pressure_dissipation: 0.0,
126-
pressure_iterations: 20,
127-
curl_strength: 0.0,
128-
splat_radius: 0.001,
129-
fruid_color: new THREE.Vector3(1.0, 1.0, 1.0),
130-
};
158+
const [params, setParams] = useParams<HooksParams>;
159+
{
160+
// HookPrams
161+
}
131162
```

app/favicon.ico

60.7 KB
Binary file not shown.

app/fx/Scene.tsx

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,7 @@ extend({ MainShaderMaterial });
1818

1919
/*===============================================
2020
TODO*
21-
- dprは入れ込んだほうがいいかも?
2221
- 初期値とGUIの整理
23-
- read meの整理
24-
- fx hookは配列で返すようにするか
25-
- 配列とオブジェクトの出ストラクチャリングについてちゃんとstyle bookにまとめよっと
26-
- いや、名前に意味があるし、拡張性的には、オブジェクトか?
27-
- usePointerは確実にオブジェクトで返すいのがいいよな。名前に意味があるし。順不同だから。
28-
- そう考えると、順は確定してるし、今後も増やす必要はないから(むしろそういう設計にしたほうがいい)、配列か
2922
===============================================*/
3023

3124
export const Scene = () => {
@@ -42,19 +35,19 @@ export const Scene = () => {
4235
const dpr = useThree((state) => state.viewport.dpr);
4336

4437
// fx
45-
const { updateFx: updateRipple } = useRipple({ texture: ripple, size });
46-
const { updateFx: updateFruid, setParams: setFruid } = useFruid({
38+
const [updateRipple] = useRipple({ texture: ripple, size });
39+
const [updateFruid, setFruid] = useFruid({
4740
size,
4841
dpr,
4942
});
50-
const { updateFx: updateFlowmap } = useFlowmap({ size });
51-
const { updateFx: updateSimpleFruid } = useSimpleFruid({ size });
52-
const { updateFx: updateBrush } = useBrush({ size });
43+
const [updateFlowmap] = useFlowmap({ size, dpr });
44+
const [updateSimpleFruid] = useSimpleFruid({ size, dpr });
45+
const [updateBrush] = useBrush({ size, dpr });
5346

5447
// post fx
55-
const { updateFx: updateTransitionBg } = useTransitionBg({ size, dpr });
56-
const { updateFx: updateDuoTone } = useDuoTone({ size });
57-
const { updateFx: updateFogProjection } = useFogProjection({ size });
48+
const [updateTransitionBg] = useTransitionBg({ size, dpr });
49+
const [updateDuoTone] = useDuoTone({ size });
50+
const [updateFogProjection] = useFogProjection({ size });
5851

5952
// Monitor performance changes and execute update functions of params
6053
usePerformanceMonitor({
@@ -91,7 +84,7 @@ export const Scene = () => {
9184
break;
9285
case 2:
9386
fx = updateBrush(props, {
94-
texture: ripple,
87+
texture: noise,
9588
radius: CONFIG.brush.radius,
9689
alpha: CONFIG.brush.alpha,
9790
smudge: CONFIG.brush.smudge,

app/fx/gui/useGUI.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,22 @@ export const useGUI = () => {
4747
/*===============================================
4848
fx
4949
===============================================*/
50-
// fruid
51-
const fruid2 = gui.addFolder("fruid(fx)");
52-
fruid2.add(CONFIG.fruid, "density_dissipation", 0, 1, 0.01);
53-
fruid2.add(CONFIG.fruid, "velocity_dissipation", 0, 1, 0.01);
54-
fruid2.add(CONFIG.fruid, "pressure_dissipation", 0, 1, 0.01);
55-
fruid2.add(CONFIG.fruid, "velocity_acceleration", 0, 100, 1);
56-
fruid2.add(CONFIG.fruid, "curl_strength", 0, 100, 1);
57-
fruid2.add(CONFIG.fruid, "splat_radius", 0, 0.1, 0.001);
5850

59-
//brush
51+
const ripple = gui.addFolder("ripple(fx)");
52+
ripple.add(CONFIG.ripple, "frequency", 0, 1, 0.01);
53+
ripple.add(CONFIG.ripple, "rotation", 0, 1, 0.01);
54+
ripple.add(CONFIG.ripple, "fadeout_speed", 0, 1, 0.01);
55+
ripple.add(CONFIG.ripple, "scale", 0, 1, 0.01);
56+
ripple.add(CONFIG.ripple, "alpha", 0, 1, 0.01);
57+
58+
const fruid = gui.addFolder("fruid(fx)");
59+
fruid.add(CONFIG.fruid, "density_dissipation", 0, 1, 0.01);
60+
fruid.add(CONFIG.fruid, "velocity_dissipation", 0, 1, 0.01);
61+
fruid.add(CONFIG.fruid, "pressure_dissipation", 0, 1, 0.01);
62+
fruid.add(CONFIG.fruid, "velocity_acceleration", 0, 100, 1);
63+
fruid.add(CONFIG.fruid, "curl_strength", 0, 100, 1);
64+
fruid.add(CONFIG.fruid, "splat_radius", 0, 0.1, 0.001);
65+
6066
const brush = gui.addFolder("brush(fx)");
6167
brush.add(CONFIG.brush, "radius", 0, 0.5, 0.01);
6268
brush.add(CONFIG.brush, "alpha", 0, 1, 0.01);
@@ -65,7 +71,12 @@ export const useGUI = () => {
6571
brush.add(CONFIG.brush, "magnification", 0, 1, 0.01);
6672
brush.add(CONFIG.brush, "motionBlur", 0, 1, 0.01);
6773

68-
// simple fruid
74+
const flowmap = gui.addFolder("flowmap(fx)");
75+
flowmap.add(CONFIG.flowmap, "radius", 0, 1, 0.01);
76+
flowmap.add(CONFIG.flowmap, "magnification", 0, 1, 0.01);
77+
flowmap.add(CONFIG.flowmap, "alpha", 0, 1, 0.01);
78+
flowmap.add(CONFIG.flowmap, "dissipation", 0, 1, 0.01);
79+
6980
const simpleFruid = gui.addFolder("simpleFruid(fx)");
7081
simpleFruid.add(CONFIG.simpleFruid, "attenuation", 0, 1, 0.01);
7182
simpleFruid.add(CONFIG.simpleFruid, "alpha", 0, 1, 0.01);
@@ -74,12 +85,12 @@ export const useGUI = () => {
7485
simpleFruid.add(CONFIG.simpleFruid, "forceRadius", 0, 100, 0.1);
7586
simpleFruid.add(CONFIG.simpleFruid, "forceCoefficient", 0, 1, 0.1);
7687

77-
//effect selector
7888
gui.add(CONFIG, "selectEffect", {
79-
Ripple: 0,
89+
ripple: 0,
8090
fruid: 1,
8191
brush: 2,
82-
simpleFruid: 3,
92+
flowmap: 3,
93+
simpleFruid: 4,
8394
});
8495
}, [gui]);
8596

0 commit comments

Comments
 (0)