Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .storybook/stories/UseMorphParticles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as React from "react";
import * as THREE from "three";
import { useFrame, extend, useThree, useLoader } from "@react-three/fiber";
import { FxMaterial, FxMaterialProps } from "../../utils/fxMaterial";
import GUI from "lil-gui";
import { useGUI } from "../../utils/useGUI";
import { useCreateMorphParticles } from "../../packages/use-shader-fx/src";
import {
MORPHPARTICLES_PARAMS,
MorphParticlesParams,
} from "../../packages/use-shader-fx/src/fxs/3D/useMorphParticles";
import { Environment, OrbitControls } from "@react-three/drei";

extend({ FxMaterial });

const CONFIG: MorphParticlesParams = structuredClone(MORPHPARTICLES_PARAMS);
const setGUI = (gui: GUI) => {
gui.add(CONFIG, "blurAlpha", 0, 1, 0.01);
gui.add(CONFIG, "blurRadius", 0, 2, 0.01);
gui.add(CONFIG, "pointSize", 0.01, 2, 0.01);
gui.addColor(CONFIG, "color0");
gui.addColor(CONFIG, "color1");
gui.addColor(CONFIG, "color2");
gui.addColor(CONFIG, "color3");
gui.add(CONFIG, "wobbleStrength", 0, 10, 0.01);
gui.add(CONFIG, "wobblePositionFrequency", 0, 10, 0.01);
gui.add(CONFIG, "wobbleTimeFrequency", 0, 10, 0.01);
gui.add(CONFIG, "warpStrength", 0, 10, 0.01);
gui.add(CONFIG, "warpPositionFrequency", 0, 10, 0.01);
gui.add(CONFIG, "warpTimeFrequency", 0, 10, 0.01);
gui.add(CONFIG, "displacementIntensity", 0, 10, 0.01);
gui.add(CONFIG, "displacementColorIntensity", 0, 40, 0.01);
gui.add(CONFIG, "morphProgress", 0, 1, 0.01);
};
const setConfig = () => {
return {
...CONFIG,
} as MorphParticlesParams;
};

const morphList = [
new THREE.PlaneGeometry(5, 5, 100, 100).attributes.position
.array as Float32Array,
new THREE.TorusGeometry(2.5, 1, 50, 30).attributes.position
.array as Float32Array,
];
const uvList = [
new THREE.PlaneGeometry(5, 5, 100, 100).attributes.uv.array as Float32Array,
new THREE.TorusGeometry(2.5, 1, 50, 30).attributes.uv.array as Float32Array,
];

export const UseMorphParticles = (args: MorphParticlesParams) => {
const updateGUI = useGUI(setGUI);

const { viewport, size } = useThree();

const [updateMorph, morph] = useCreateMorphParticles({
scene: false,
size,
dpr: viewport.dpr,
geometry: React.useMemo(() => new THREE.IcosahedronGeometry(2.5, 50), []),
positions: morphList,
uvs: uvList,
});

useFrame((props) => {
updateMorph(props, {
...setConfig(),
});
updateGUI();
});
return (
<mesh>
<OrbitControls />
<primitive object={morph.points} />
</mesh>
);
};
74 changes: 74 additions & 0 deletions .storybook/stories/UseWobble3D.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import * as React from "react";
import * as THREE from "three";
import { useFrame, extend, useThree, useLoader } from "@react-three/fiber";
import { FxMaterial, FxMaterialProps } from "../../utils/fxMaterial";
import GUI from "lil-gui";
import { useGUI } from "../../utils/useGUI";
import {
useWobble3D,
useCreateWobble3D,
} from "../../packages/use-shader-fx/src";
import {
WOBBLE3D_PARAMS,
Wobble3DParams,
} from "../../packages/use-shader-fx/src/fxs/3D/useWobble3D";
import { Environment, OrbitControls } from "@react-three/drei";

extend({ FxMaterial });

const CONFIG: Wobble3DParams = structuredClone(WOBBLE3D_PARAMS);
const setGUI = (gui: GUI) => {
gui.addColor(CONFIG, "color0");
gui.addColor(CONFIG, "color1");
gui.addColor(CONFIG, "color2");
gui.addColor(CONFIG, "color3");
gui.add(CONFIG, "wobbleStrength", 0, 10, 0.01);
gui.add(CONFIG, "wobblePositionFrequency", 0, 10, 0.01);
gui.add(CONFIG, "wobbleTimeFrequency", 0, 10, 0.01);
gui.add(CONFIG, "warpStrength", 0, 10, 0.01);
gui.add(CONFIG, "warpPositionFrequency", 0, 10, 0.01);
gui.add(CONFIG, "warpTimeFrequency", 0, 10, 0.01);
gui.add(CONFIG, "wobbleShine", 0, 5, 0.01);
gui.add(CONFIG, "samples", 0, 10, 1);
gui.add(CONFIG, "colorMix", 0, 1, 0.01);
gui.add(CONFIG, "chromaticAberration", 0, 10, 0.01);
gui.add(CONFIG, "anisotropicBlur", 0, 10, 0.01);
gui.add(CONFIG, "distortion", 0, 10, 0.01);
gui.add(CONFIG, "distortionScale", 0, 10, 0.01);
gui.add(CONFIG, "temporalDistortion", 0, 10, 0.01);
};
const setConfig = () => {
return {
...CONFIG,
} as Wobble3DParams;
};

export const UseWobble3D = (args: Wobble3DParams) => {
const updateGUI = useGUI(setGUI);

const [updateWobble, wobble] = useCreateWobble3D({
baseMaterial: THREE.MeshPhysicalMaterial,
materialParameters: {
iridescence: 1,
metalness: 0.0,
roughness: 0.0,
transmission: 2,
thickness: 1,
transparent: true,
},
});

useFrame((props) => {
updateWobble(props, {
...setConfig(),
});
updateGUI();
});
return (
<mesh>
<Environment preset="warehouse" background />
<OrbitControls />
<primitive object={wobble.mesh} />
</mesh>
);
};
29 changes: 29 additions & 0 deletions .storybook/stories/useMorphParticles.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from "react";
import type { StoryObj } from "@storybook/react";
import { setArgTypes } from "../utils/setArgTypes";
import { Setup } from "../utils/Setup";
import type { Meta } from "@storybook/react";
import {
MORPHPARTICLES_PARAMS,
MorphParticlesParams,
} from "../../packages/use-shader-fx/src/fxs/3D/useMorphParticles";
import { UseMorphParticles } from "./UseMorphParticles";

const meta = {
title: "3D/useMorphParticles",
component: UseMorphParticles,
tags: ["autodocs"],
decorators: [(storyFn: any) => <Setup>{storyFn()}</Setup>],
} satisfies Meta<typeof UseMorphParticles>;

export default meta;
type Story = StoryObj<typeof meta>;

const storySetting = {
args: MORPHPARTICLES_PARAMS,
argTypes: setArgTypes<MorphParticlesParams>(MORPHPARTICLES_PARAMS),
};
export const MorphParticles: Story = {
render: (args) => <UseMorphParticles {...args} />,
...storySetting,
};
29 changes: 29 additions & 0 deletions .storybook/stories/useWobble3D.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from "react";
import type { StoryObj } from "@storybook/react";
import { setArgTypes } from "../utils/setArgTypes";
import { Setup } from "../utils/Setup";
import type { Meta } from "@storybook/react";
import {
WOBBLE3D_PARAMS,
Wobble3DParams,
} from "../../packages/use-shader-fx/src/fxs/3D/useWobble3D";
import { UseWobble3D } from "./UseWobble3D";

const meta = {
title: "3D/useWobble3D",
component: UseWobble3D,
tags: ["autodocs"],
decorators: [(storyFn: any) => <Setup>{storyFn()}</Setup>],
} satisfies Meta<typeof UseWobble3D>;

export default meta;
type Story = StoryObj<typeof meta>;

const storySetting = {
args: WOBBLE3D_PARAMS,
argTypes: setArgTypes<Wobble3DParams>(WOBBLE3D_PARAMS),
};
export const Wobble3D: Story = {
render: (args) => <UseWobble3D {...args} />,
...storySetting,
};
146 changes: 39 additions & 107 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ npm install @funtech-inc/use-shader-fx
<td><a href="https://use-shader-fx-stories.vercel.app/?path=/docs/utils-usealphablending--docs">useAlphaBlending</a>, <a href="https://use-shader-fx-stories.vercel.app/?path=/docs/utils-useblending--docs">useBlending</a>, <a href="https://use-shader-fx-stories.vercel.app/?path=/docs/utils-usebrightnesspicker--docs">useBrightnessPicker</a>, <a href="https://use-shader-fx-stories.vercel.app/?path=/docs/utils-usecovertexture--docs">useCoverTexture</a>, <a href="https://use-shader-fx-stories.vercel.app/?path=/docs/utils-useduotone--docs">useDuoTone</a>, <a href="https://use-shader-fx-stories.vercel.app/?path=/docs/utils-usefxblending--docs">useFxBlending</a>, <a href="https://use-shader-fx-stories.vercel.app/?path=/docs/utils-usefxtexture--docs">useFxTexture</a>, <a href="https://use-shader-fx-stories.vercel.app/?path=/docs/utils-usehsv--docs">useHSV</a></td>
</tr>

<tr>
<th><strong><a href="#3D">3D</a></strong></th>
<td><a href="https://use-shader-fx-stories.vercel.app/?path=/docs/3d-usemorphparticles--docs">useMorphParticles</a>, <a href="https://use-shader-fx-stories.vercel.app/?path=/docs/3d-usewobble3d--docs">useWobble3D</a></td>
</tr>

</table>
※ The hook with `~~Texutre` calculates the texture resolution and canvas resolution and covers the texture.

Expand Down Expand Up @@ -283,113 +288,6 @@ usePerformanceMonitor({
});
```

# How to make "custom fxHooks"

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.

In addition, we have prepared a template in the repository below that is useful for creating custom hooks, so please clone and use it in the location where you created your custom hook.

```bash
git clone https://github.com/takuma-hmng8/CreateShaderFx
```

If you can create a cool FX, please contribute!
👉 [CONTRIBUTING](CONTRIBUTING.md)! 👈

## useDoubleFBO

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`.

```ts
type UseFboProps = {
scene: THREE.Scene;
camera: THREE.Camera;
size: Size;
/** If dpr is set, dpr will be multiplied, default:false */
dpr?: number | false;
/** Whether to resize when resizing occurs. If isDpr is true, set FBO to setSize even if dpr is changed, default:false */
isSizeUpdate?: boolean;
/** Defines the count of MSAA samples. Can only be used with WebGL 2. Default is 0. */
samples?: number;
/** Renders to the depth buffer. Unlike the three.js, Default is false. */
depthBuffer?: boolean;
/** If set, the scene depth will be rendered to this texture. Default is false. */
depthTexture?: boolean;
};

const [velocityFBO, updateVelocityFBO] = useDoubleFBO(UseFboProps);
```

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.

```js
const texture = updateVelocityFBO(gl, ({ read, write }) => {
// callback before gl.render()
setMeshMaterial(materials.advectionMaterial);
setUniform(materials.advectionMaterial, "uVelocity", read);
});
```

## useSingleFBO

This is a version without double buffering.

```js
const [renderTarget, updateRenderTarget] = useSingleFBO(UseFboProps);
```

## useCamera

Generates and returns a `THREE.OrthographicCamera`.

```js
const camera = useCamera(size);
```

## useResolution

This hook returns `resolution`. If `dpr` isn't set (or set to false), dpr won't be multiplied.

```ts
const resolution = useResolution(size: Size, dpr: number | false = false);
```

## useAddMesh

Creates a mesh and adds it to scene, geometry, and material. Returns the mesh.

```js
useAddMesh(scene, geometry, material);
```

## setUniform

A function to set values in the uniforms of the shader material.

```js
setUniform(material, "key", someValue);
```

## useParams

Returns the refObject of params and its update function.

```ts
const [params, setParams] = useParams<HooksParams>;
{
// HookPrams
}
```

## useCopyTexture

Generate an FBO array to copy the texture.

```tsx
const [renderTargets, copyTexture] = useCopyTexture(UseFboProps, length);
copyTexture(gl, index); // return texture
```

# Misc

## useDomSyncer
Expand Down Expand Up @@ -548,3 +446,37 @@ useFrame((props) => {
}
});
```

## useCopyTexture

Generate an FBO array to copy the texture.

```tsx
const [renderTargets, copyTexture] = useCopyTexture(UseFboProps, length);
copyTexture(gl, index); // return texture
```

# 3D

The `3D` series has a set of exported hooks, each with `Create`, like `useCreateWobble3D`, which can be used as a texture, but also to add `object3D` as a `primitive` to an r3f scene. It is also possible to add `object3D` as a `primitive` to an r3f scene.

```tsx
const [updateWobble, wobble] = useCreateWobble3D({
baseMaterial: THREE.MeshPhysicalMaterial,
materialParameters: {
roughness: 0.0,
transmission: 1,
thickness: 1,
},
});
useFrame((props) => updateWobble(props));
return (
<mesh>
<Environment preset="warehouse" background />
<primitive object={wobble.mesh} />
</mesh>
);
```

👉 [wobble3D demo](https://use-shader-fx.vercel.app/useWobble3D) 👈
👉 [morphParticles demo](https://use-shader-fx.vercel.app/useMorphParticles) 👈
5 changes: 4 additions & 1 deletion app/ShaderFx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ export const ShaderFx = ({
}) => {
const [dpr, setDpr] = useState(1.5);
return (
<Canvas dpr={dpr} gl={{ preserveDrawingBuffer: preserveDrawingBuffer }}>
<Canvas
dpr={dpr}
gl={{ preserveDrawingBuffer: preserveDrawingBuffer }}
shadows>
<PerformanceMonitor
factor={1}
onChange={({ factor }) => {
Expand Down
Loading