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
10 changes: 8 additions & 2 deletions .storybook/stories/UseAlphaBlending.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@ export const UseAlphaBlending = (args: AlphaBlendingParams) => {
return { size: state.size, dpr: state.viewport.dpr };
});

const [updateBrush, setBrush, { output: brush }] = useBrush({ size, dpr });
const [update, set, { output }] = useAlphaBlending({ size, dpr });
const [updateBrush, setBrush, { output: brush }] = useBrush({
size,
dpr,
});
const [update, set, { output }] = useAlphaBlending({
size,
dpr,
});
const [updateMarble, setMarble, { output: marble }] = useMarble({
size,
dpr,
Expand Down
24 changes: 24 additions & 0 deletions .storybook/stories/UseBlank.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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 { UseBlank } from "./UseBlank";
import {
BLANK_PARAMS,
BlankParams,
} from "../../packages/use-shader-fx/src/fxs/misc/useBlank";

const meta = {
title: "misc/useBlank",
component: UseBlank,
tags: ["autodocs"],
decorators: [(storyFn: any) => <Setup>{storyFn()}</Setup>],
} satisfies Meta<typeof UseBlank>;
export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: BLANK_PARAMS,
argTypes: setArgTypes<BlankParams>(BLANK_PARAMS),
};
46 changes: 46 additions & 0 deletions .storybook/stories/UseBlank.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from "react";
import * as THREE from "three";
import { useFrame, extend, useThree } from "@react-three/fiber";
import { FxMaterial } from "../../utils/fxMaterial";

import { useBlank } from "../../packages/use-shader-fx/src";
import { BlankParams } from "../../packages/use-shader-fx/src/fxs/misc/useBlank";

extend({ FxMaterial });

/**
* By default, it is a blank canvas with nothing drawn on it. You can customise the shaders using `onBeforeCompile`.
* Fragment shaders have `uTexture`,`uBackbuffer`,`uTime`,`uPointer` and `uResolution` as default uniforms.
*
* ※ `usf_FragColor` overrides `gl_FragColor`
*
* ※ `usf_Position` overrides `gl_Position`
* @link https://github.com/FunTechInc/use-shader-fx?tab=readme-ov-file#usage
*/
export const UseBlank = (args: BlankParams) => {
const { size, dpr } = useThree((state) => {
return { size: state.size, dpr: state.viewport.dpr };
});

const [updateBlank, _, { output: blank }] = useBlank({
size,
dpr: dpr,
onBeforeCompile: React.useCallback((shader: THREE.Shader) => {
shader.fragmentShader = shader.fragmentShader.replace(
"//#usf main",
`float t=uTime,c;vec2 z,n=vec2(cos(t),sin(t));z=vUv*2.-1.;for(int i=0;i<12;i++){if(dot(z,z)>8.)discard;z=vec2(z.x*z.x-z.y*z.y,z.x*z.y)+n;}c=cos(length(z)+log(length(z)));usf_FragColor=vec4(vec3(c),1.);`
);
}, []),
});

useFrame((props) => {
updateBlank(props);
});

return (
<mesh>
<planeGeometry args={[2, 2]} />
<fxMaterial key={FxMaterial.key} u_fx={blank} u_alpha={0.0} />
</mesh>
);
};
5 changes: 4 additions & 1 deletion .storybook/stories/UseBlending.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ export const UseBlending = (args: BlendingParams) => {
return { size: state.size, dpr: state.viewport.dpr };
});
const [updateCover] = useCoverTexture({ size, dpr });
const [updateFluid, setFluid, { output: fluid }] = useFluid({ size, dpr });
const [updateFluid, setFluid, { output: fluid }] = useFluid({
size,
dpr,
});
const [updateBlending, setBlending] = useBlending({ size, dpr });
const [updateBrightnessPicker] = useBrightnessPicker({ size, dpr });

Expand Down
1 change: 0 additions & 1 deletion .storybook/stories/UseBrightnessPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from "react";
import * as THREE from "three";
import { useFrame, extend, useThree } from "@react-three/fiber";
import { FxMaterial, FxMaterialProps } from "../../utils/fxMaterial";
import GUI from "lil-gui";
Expand Down
1 change: 0 additions & 1 deletion .storybook/stories/UseColorStrata.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from "react";
import * as THREE from "three";
import { useFrame, extend, useThree } from "@react-three/fiber";
import { FxMaterial, FxMaterialProps } from "../../utils/fxMaterial";
import GUI from "lil-gui";
Expand Down
52 changes: 40 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ npm install @funtech-inc/use-shader-fx

<tr>
<th><strong>misc</strong></th>
<td><a href="https://use-shader-fx-stories.vercel.app/?path=/docs/misc-usechromakey--docs">useChromaKey</a></td>
<td><a href="https://use-shader-fx-stories.vercel.app/?path=/docs/misc-usechromakey--docs">useChromaKey</a>, <a href="https://use-shader-fx-stories.vercel.app/?path=/docs/misc-useblank--docs">useBlank</a></td>
</tr>

<tr>
Expand Down Expand Up @@ -79,21 +79,22 @@ npm install @funtech-inc/use-shader-fx

# Usage

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`,`dpr` and `samples`.
From each `fxHooks`, you can receive [`updateFx`, `setParams`, `fxObject`] in array format. `HooksProps` are objects that are different for each hook and contain values such as `size`, `dpr` ... etc.

1. `updateFx` - A function to be invoked inside `useFrame`, returning a `THREE.Texture`.
2. `setParams` - A function to refresh the parameters, beneficial for performance tweaking, etc.
3. `fxObject` - An object that holds various FX components, such as scene, camera, material,renderTarget, and `output`(final rendered texture).
4. `HooksProps` - `size`,`dpr`,`samples`,`isSizeUpdate`,`onBeforeCompile`but may also be hook specific. ※ `isSizeUpdate` : Whether to `setSize` the FBO when updating size or dpr(default : `false`).

```js
const [updateFx, setParams, fxObject] = useSomeFx(config);
const [updateFx, setParams, fxObject] = useSomeFx(HooksProps);
```

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

```js
useFrame((props) => {
const texture = updateFx(props, params);
const texture = updateFx(props, HookPrams);
const main = mainShaderRef.current;
if (main) {
main.u_bufferTexture = texture;
Expand Down Expand Up @@ -327,14 +328,10 @@ Also, you can make more detailed adjustments by passing an object to `dpr` inste
type Dpr =
| number
| {
dpr: number;
/** you can set whether `dpr` affects `shader` and `fbo`. default is `true` for both */
effect?: {
/** default : `true` */
shader?: boolean;
/** default : `true` */
fbo?: boolean;
};
/** you can set whether `dpr` affects `shader`. default : `false` */
shader?: false | number;
/** you can set whether `dpr` affects `fbo`. default : `false` */
fbo?: false | number;
};
```

Expand Down Expand Up @@ -531,3 +528,34 @@ return (
👉 [wobble3D demo](https://use-shader-fx.vercel.app/useWobble3D) 👈

👉 [morphParticles demo](https://use-shader-fx.vercel.app/useMorphParticles) 👈

# useBlank

By default, it is a blank canvas with nothing drawn on it. You can customise the shaders using `onBeforeCompile`.

Fragment shaders have `uTexture`,`uBackbuffer`,`uTime`,`uPointer` and `uResolution` as default uniforms.

```tsx
const [updateBlank, _, { output: blank, material }] = useBlank({
size,
dpr: viewport.dpr,
uniforms: {
hoge: { value: 0 },
},
onBeforeCompile: useCallback((shader: THREE.Shader) => {
shader.fragmentShader = shader.fragmentShader.replace(
"//#usf uniforms",
"uniform float hoge;"
);
shader.fragmentShader = shader.fragmentShader.replace(
"//#usf main",
`usf_FragColor=vec4(vec3(1.,hoge,1.),1.);`
);
console.log(shader.vertexShader);
console.log(shader.fragmentShader);
}, []),
});
```

※ `usf_FragColor` overrides `gl_FragColor`
※ `usf_Position` overrides `gl_Position`
2 changes: 1 addition & 1 deletion app/_home/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export const Playground = ({
});
const [updateFluid, setFluid, { output: brush }] = useFluid({
size,
dpr: 0.03,
dpr: 0.06,
});

useMemo(() => {
Expand Down
1 change: 1 addition & 0 deletions app/_ui/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const Menu = () => {
"/obscurus",
"/useMorphParticles",
"/useWobble3D",
"/useBlank",
];
const pathname = usePathname();
return (
Expand Down
6 changes: 2 additions & 4 deletions app/cream/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ export const Playground = () => {
const [updateFluid, setFluid, { output: fluid }] = useFluid({
size,
dpr: {
dpr: 0.08,
effect: {
fbo: false,
},
shader: 0.08,
fbo: 0.2,
},
});

Expand Down
9 changes: 8 additions & 1 deletion app/playground/Playground.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
useFrame,
useThree,
Expand Down Expand Up @@ -46,6 +46,13 @@ export const Playground = () => {
useMotionBlur({
size,
dpr: 0.1,
onBeforeCompile: useCallback((shader: THREE.Shader) => {
// shader.fragmentShader = shader.fragmentShader.replace(
// "gl_FragColor = mixed;",
// "gl_FragColor = vec4(0.2,1.,0.2,1.);"
// );
console.log(shader.fragmentShader);
}, []),
});
setMotionBlur({
texture: cover,
Expand Down
38 changes: 38 additions & 0 deletions app/useBlank/FxMaterial.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as THREE from "three";
import { shaderMaterial } from "@react-three/drei";

declare global {
namespace JSX {
interface IntrinsicElements {
fxMaterial: any;
}
}
}

export type FxMaterialProps = {
u_fx: THREE.Texture;
};

export const FxMaterial = shaderMaterial(
{
u_fx: new THREE.Texture(),
},

`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 1.0);
}
`,
`
precision highp float;
varying vec2 vUv;
uniform sampler2D u_fx;
void main() {
vec2 uv = vUv;
vec4 color = texture2D(u_fx, uv);
gl_FragColor = color;
}
`
);
64 changes: 64 additions & 0 deletions app/useBlank/Playground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"use client";

import * as THREE from "three";
import { useCallback } from "react";
import { useFrame, useThree, extend } from "@react-three/fiber";
import { useBlank, useCoverTexture } from "@/packages/use-shader-fx/src";
import { FxMaterial } from "./FxMaterial";
import { useVideoTexture } from "@react-three/drei";

extend({ FxMaterial });

export const Playground = () => {
const { size, viewport } = useThree();
const funkun_mov = useVideoTexture("/FT_Ch02-comp.mp4", {
width: 1280,
height: 720,
});
const [updateCover, setCover, { output: cover }] = useCoverTexture({
size,
dpr: 1,
});
setCover({
texture: funkun_mov,
});
const [updateBlank, setBlank, { output: blank, material }] = useBlank({
size,
dpr: viewport.dpr,
uniforms: {
hoge: { value: 0 },
},
onBeforeCompile: useCallback((shader: THREE.Shader) => {
shader.fragmentShader = shader.fragmentShader.replace(
"//#usf uniforms",
"uniform float hoge;"
);
shader.fragmentShader = shader.fragmentShader.replace(
"//#usf main",
`float t=uTime,c;vec2 z,u,n=vec2(cos(t),sin(t));z=vUv*2.-1.;for(int i=0;i<12;i++){if(dot(z,z)>8.)discard;z=vec2(z.x*z.x-z.y*z.y,z.x*z.y)+n;}c=cos(length(z)+log(length(z)));u=vUv;u+=z*hoge;usf_FragColor=vec4(mix(vec3(c),texture2D(uTexture,u).rgb,1.-hoge),1.);`
);
console.log(shader.vertexShader);
console.log(shader.fragmentShader);
}, []),
});
setBlank({
texture: cover,
});

const mat = material as any;

useFrame((props) => {
mat.uniforms.hoge.value = Math.sin(props.clock.getElapsedTime());
updateBlank(props);
updateCover(props);
});

return (
<>
<mesh>
<planeGeometry args={[2, 2]} />
<fxMaterial u_fx={blank} key={FxMaterial.key} />
</mesh>
</>
);
};
18 changes: 18 additions & 0 deletions app/useBlank/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ShaderFx } from "../ShaderFx";
import { Playground } from "./Playground";

export default function Page() {
return (
<div
style={{
position: "fixed",
width: "100%",
height: "100svh",
pointerEvents: "none",
}}>
<ShaderFx isDprUpdate={false}>
<Playground />
</ShaderFx>
</div>
);
}
7 changes: 7 additions & 0 deletions app/useMorphParticles/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ export const Playground = () => {
positions: morphList,
uvs: uvList,
// geometry: new THREE.PlaneGeometry(5, 5, 100, 100),
// onBeforeCompile: useCallback((shader: THREE.Shader) => {
// // shader.vertexShader = shader.vertexShader.replace(
// // "gl_Position = projectedPosition += wobble;",
// // "gl_Position = projectedPosition += wobble + 2.;"
// // );
// console.log(shader);
// }, []),
});

const beat = useBeat(140, "easeOutCubic");
Expand Down
Loading