diff --git a/.storybook/stories/UseFluid.tsx b/.storybook/stories/UseFluid.tsx index f1e61aa2..f777c5c3 100644 --- a/.storybook/stories/UseFluid.tsx +++ b/.storybook/stories/UseFluid.tsx @@ -4,7 +4,11 @@ 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 { useFluid, useFxTexture } from "../../packages/use-shader-fx/src"; +import { + useFPSLimiter, + useFluid, + useFxTexture, +} from "../../packages/use-shader-fx/src"; import { FLUID_PARAMS, FluidParams, @@ -38,7 +42,7 @@ export const UseFluid = (args: FluidParams) => { const [updateFluid] = useFluid({ size, dpr, - fluidOnBeforeCompile: { + customFluidProps: { curl: { onBeforeCompile: React.useCallback((shader: THREE.Shader) => { console.log(shader.fragmentShader); diff --git a/.storybook/stories/UseRipple.tsx b/.storybook/stories/UseRipple.tsx index 0614395d..9790f1c9 100644 --- a/.storybook/stories/UseRipple.tsx +++ b/.storybook/stories/UseRipple.tsx @@ -31,11 +31,11 @@ export const UseRipple = (args: RippleParams) => { const updateGUI = useGUI(setGUI); const fxRef = React.useRef(); const { size, viewport } = useThree(); - const [updateRipple] = useRipple({ + const [updateRipple, setRipple] = useRipple({ size, texture: ripple, dpr: viewport.dpr, - max: 20, + max: 80, uniforms: React.useMemo( () => ({ testtest: { value: 0 }, @@ -60,6 +60,7 @@ export const UseRipple = (args: RippleParams) => { ); }, []), }); + useFrame((props) => { const fx = updateRipple(props, setConfig(), { testtest: props.clock.getElapsedTime(), diff --git a/.storybook/utils/Setup.tsx b/.storybook/utils/Setup.tsx index 908ac7c9..5fa185f0 100644 --- a/.storybook/utils/Setup.tsx +++ b/.storybook/utils/Setup.tsx @@ -6,18 +6,11 @@ import { Perf } from "r3f-perf"; import { PerformanceMonitor } from "@react-three/drei"; export const Setup = ({ children }: { children: React.ReactNode }) => { - const [dpr, setDpr] = useState(1.5); + // const [dpr, setDpr] = useState(1.5);s return ( - - { - console.log(`dpr:${dpr}`); - setDpr(Math.round((0.5 + 1.0 * factor) * 10) / 10); - }}> - {children} - - + + {children} + ); }; diff --git a/README.md b/README.md index a2b12233..3d65aaee 100644 --- a/README.md +++ b/README.md @@ -81,24 +81,20 @@ npm install @funtech-inc/use-shader-fx 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). +1. `updateFx` - Functions to update parameters and render. +2. `updateParams` - Function to update parameters only. +3. `fxObject` - An object that holds various FX components, such as scene, camera, mesh, renderTarget, and `output`(final rendered texture). 4. `HooksProps` - `size`,`dpr`,`samples`,`isSizeUpdate`,`uniforms`,`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(HooksProps); +const [updateFx, updateParams, 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. +Call `updateFx` on `useFrame`. The first argument is the RootState of `useFrame` and the second argument is `HookParams`. The third argument can be `CustomParams` customised by the user. Each FX has `HookParams` and each type is exported. ```js useFrame((props) => { - const texture = updateFx(props, HookPrams, customParams); - const main = mainShaderRef.current; - if (main) { - main.u_bufferTexture = texture; - } + const texture = updateFx(props, HookParams, CustomParams); }); ``` @@ -119,37 +115,13 @@ import { useFrame, useThree } from "@react-three/fiber"; import { useFluid } from "@funtech-inc/use-shader-fx"; export const Home = () => { - const ref = useRef(null); - const { size, viewport } = useThree(); - const [updateFluid, , { output }] = useFluid({ size, dpr: viewport.dpr }); + const { size } = useThree(); + const [updateFluid, , { output }] = useFluid({ size, dpr: 1 }); useFrame((props) => updateFluid(props)); - return ( - - + + ); }; diff --git a/app/_home/FxMaterial.tsx b/app/_home/FxMaterial.tsx deleted file mode 100644 index f0d195e5..00000000 --- a/app/_home/FxMaterial.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import * as THREE from "three"; -import { shaderMaterial } from "@react-three/drei"; -import fragment from "./main.frag"; - -declare global { - namespace JSX { - interface IntrinsicElements { - fxMaterial: any; - } - } -} - -export type FxMaterialProps = { - u_noise: THREE.Texture; - u_colorStrata: THREE.Texture; - u_brush: THREE.Texture; - u_grain: THREE.Texture; - u_noiseIntensity: number; - u_funkun: THREE.Texture; - u_time: number; -}; - -export const FxMaterial = shaderMaterial( - { - u_noise: new THREE.Texture(), - u_colorStrata: new THREE.Texture(), - u_brush: new THREE.Texture(), - u_grain: new THREE.Texture(), - u_funkun: new THREE.Texture(), - u_noiseIntensity: 1, - u_time: 0, - }, - - ` - varying vec2 vUv; - void main() { - vUv = uv; - gl_Position = vec4(position, 1.0); - } - `, - fragment -); diff --git a/app/_home/Playground.tsx b/app/_home/Playground.tsx index 65d79357..997930ce 100644 --- a/app/_home/Playground.tsx +++ b/app/_home/Playground.tsx @@ -1,24 +1,20 @@ import * as THREE from "three"; -import { useMemo, useRef } from "react"; -import { useFrame, useThree, extend } from "@react-three/fiber"; +import { useCallback, useMemo, useRef } from "react"; +import { useFrame, useThree } from "@react-three/fiber"; import { useColorStrata, useMarble, useHSV, useBeat, - useCoverTexture, useFPSLimiter, EasingTypes, ColorStrataParams, HSVParams, MarbleParams, - useFluid, + useBlank, } from "@/packages/use-shader-fx/src"; -import { FxMaterial, FxMaterialProps } from "./FxMaterial"; -import { useVideoTexture } from "@react-three/drei"; - -extend({ FxMaterial }); +import { Environment, OrbitControls } from "@react-three/drei"; export const CONFIG = { marble: { @@ -86,19 +82,9 @@ export const Playground = ({ bpm: number; easing: EasingTypes; }) => { - const ref = useRef(); const { size, viewport } = useThree(); - const funkun = useVideoTexture("/FT_Ch02-comp.mp4", { - width: 1280, - height: 780, - }); - const [updateCover, setCover, { output: cover }] = useCoverTexture({ - size, - dpr: viewport.dpr, - }); - setCover({ texture: funkun }); - + // init fxs const [updateColorStrata, setColorStrata, { output: colorStrata }] = useColorStrata({ size, dpr: viewport.dpr }); const [updateMarble, setMarble, { output: marble }] = useMarble({ @@ -109,47 +95,78 @@ export const Playground = ({ size, dpr: viewport.dpr, }); - const [updateFluid, setFluid, { output: brush }] = useFluid({ + const [updateBlank, _, { output: blank }] = useBlank({ size, - dpr: 0.06, + dpr: viewport.dpr, + uniforms: useMemo( + () => ({ + u_noise: { + value: marble, + }, + u_noiseIntensity: { + value: CONFIG.noiseIntensity, + }, + u_colorStrata: { + value: hsv, + }, + }), + [hsv, marble] + ), + onBeforeCompile: useCallback((shader: THREE.Shader) => { + shader.fragmentShader = shader.fragmentShader.replace( + "#usf uniforms", + ` + uniform sampler2D u_noise; + uniform float u_noiseIntensity; + uniform sampler2D u_colorStrata; + float rand(vec2 n) { + return fract(sin(dot(n ,vec2(12.9898,78.233))) * 43758.5453); + } + ` + ); + shader.fragmentShader = shader.fragmentShader.replace( + "#usf main", + ` + vec2 uv = vUv; + float grain=rand(uv+sin(uTime))*.4; + grain=grain*.5+.5; + vec4 noise = texture2D(u_noise, uv); + uv += noise.rg * u_noiseIntensity; + vec4 colorStrata = texture2D(u_colorStrata,uv); + usf_FragColor = colorStrata*grain; + ` + ); + }, []), + }); + + // set fxs + setMarble({ + ...setConfig("marble"), + timeStrength: 0.5, + }); + setColorStrata({ + ...setConfig("colorStrata"), + timeStrength: new THREE.Vector2(0, 0), + }); + setHSV({ + ...setConfig("hsv"), + texture: colorStrata, }); useMemo(() => { CONFIG.random(); - - setMarble({ - ...setConfig("marble"), - timeStrength: 0.5, - }); - - setColorStrata({ - ...setConfig("colorStrata"), - timeStrength: new THREE.Vector2(0, 0), - }); - - setHSV({ - ...setConfig("hsv"), - texture: colorStrata, - }); - - setFluid({ - density_dissipation: 0.96, - velocity_dissipation: 0.96, - splat_radius: 0.001, - pressure_iterations: 2, - }); - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const beting = useBeat(bpm, easing); const limiter = useFPSLimiter(40); const hashMemo = useRef(0); + const meshRef = useRef(null); useFrame((props) => { if (!limiter(props.clock)) { return; } - const { beat, hash } = beting(props.clock); + const { beat, hash, fract } = beting(props.clock); if (hash !== hashMemo.current) { hashMemo.current = hash; CONFIG.random(); @@ -164,23 +181,31 @@ export const Playground = ({ ...(setConfig("marble") as MarbleParams), beat: beat, }); - updateFluid(props); - updateCover(props); - ref.current!.u_noiseIntensity = CONFIG.noiseIntensity; - ref.current!.u_time = props.clock.getElapsedTime(); + updateBlank( + props, + {}, + { + u_noiseIntensity: CONFIG.noiseIntensity, + } + ); + meshRef.current!.rotation.x += 0.03 * fract; + meshRef.current!.rotation.y += 0.04 * fract; + meshRef.current!.rotation.z += 0.05 * fract; + meshRef.current!.position.z = Math.sin(fract) * 0.08; }); return ( - - + + + + + + ); }; diff --git a/app/_home/index.tsx b/app/_home/index.tsx index ff03f265..6d992328 100644 --- a/app/_home/index.tsx +++ b/app/_home/index.tsx @@ -29,7 +29,7 @@ export default function Page() { null ) as React.MutableRefObject; const [bpm, setBpm] = useState(120); - const [easing, setEasing] = useState("easeOutQuad"); + const [easing, setEasing] = useState("easeInOutBack"); const easingTypes: EasingTypes[] = [ "easeInSine", @@ -67,7 +67,7 @@ export default function Page() { return ( <>
- +
diff --git a/app/_home/main.frag b/app/_home/main.frag deleted file mode 100644 index 204df6c7..00000000 --- a/app/_home/main.frag +++ /dev/null @@ -1,37 +0,0 @@ -precision highp float; -varying vec2 vUv; -uniform sampler2D u_noise; -uniform float u_noiseIntensity; -uniform sampler2D u_colorStrata; -uniform sampler2D u_brush; -uniform sampler2D u_funkun; -uniform float u_time; - -float rand(vec2 n) { - return fract(sin(dot(n ,vec2(12.9898,78.233))) * 43758.5453); -} - -void main() { - - vec2 uv = vUv; - vec3 funkun = texture2D(u_funkun,uv).rgb; - - float grain = rand(uv + sin(u_time)) * .4; - grain=grain*.5+.5; // .5 ~ 1. - - vec4 noise = texture2D(u_noise, uv); - vec4 brush = texture2D(u_brush, uv); - - uv += brush.rg; - float brushAlpha = min(brush.r + brush.g + brush.b,1.0); - - uv += noise.rg * u_noiseIntensity; - vec4 colorStrata = texture2D(u_colorStrata,uv); - - vec3 mixedBrush = mix(brush.rgb , funkun, brushAlpha); - - vec3 mixColor = mix(colorStrata.rgb, mixedBrush, brushAlpha); - - gl_FragColor.rgb = mixColor * grain; - gl_FragColor.a = 1.0; -} diff --git a/app/_ui/index.module.scss b/app/_ui/index.module.scss index 0de47a5e..52876e3d 100644 --- a/app/_ui/index.module.scss +++ b/app/_ui/index.module.scss @@ -17,12 +17,6 @@ nav top: 16px; left: 16px; color: white; - display: flex; - align-items: baseline; - gap: 12px; - p { - line-height: 1; - } select { border-radius: 100vh; background-color: rgba(255, 255, 255, 0.24); @@ -35,6 +29,7 @@ nav text-align: left; padding: 0 16px; width: 120px; + font-size: 14px; } } } diff --git a/app/_ui/index.tsx b/app/_ui/index.tsx index 177a7626..551f42c7 100644 --- a/app/_ui/index.tsx +++ b/app/_ui/index.tsx @@ -14,11 +14,11 @@ const Menu = () => { "/useWobble3D", "/useBlank", "/expo2025", + "/shoasakawa-0", ]; const pathname = usePathname(); return (