diff --git a/.storybook/stories/UseSimpleBlur.tsx b/.storybook/stories/UseSimpleBlur.tsx new file mode 100644 index 00000000..5459f183 --- /dev/null +++ b/.storybook/stories/UseSimpleBlur.tsx @@ -0,0 +1,59 @@ +import * as React from "react"; +import * as THREE from "three"; +import { useFrame, extend, useThree, useLoader} from "@react-three/fiber"; +import { FxTextureMaterial } from "../../utils/fxTextureMaterial"; +import { FxMaterial, FxMaterialProps } from "../../utils/fxMaterial"; +import GUI from "lil-gui"; +import { useGUI } from "../../utils/useGUI"; +import { CONSTANT } from "../constant"; +import { useSimpleBlur,useTransitionBg} from "../../packages/use-shader-fx/src"; +import { + SimpleBlurParams, + SIMPLEBLUR_PARAMS, +} from "../../packages/use-shader-fx/src/hooks/useSimpleBlur"; + + +extend({ FxMaterial, FxTextureMaterial }); + +const CONFIG: SimpleBlurParams = structuredClone(SIMPLEBLUR_PARAMS); +const setGUI = (gui: GUI) => { + gui.add(CONFIG, "blurSize", 0, 10, 0.01); + gui.add(CONFIG, "blurPower", 0, 10, 1); +}; +const setConfig = () => { + return { + texture: CONFIG.texture, + blurSize: CONFIG.blurSize, + blurPower: CONFIG.blurPower, + } as SimpleBlurParams; +}; + +export const UseSimpleBlur = (args: SimpleBlurParams) => { + const updateGUI = useGUI(setGUI); + const [bg] = useLoader(THREE.TextureLoader, ["thumbnail.jpg"]); + const fxRef = React.useRef(); + const size = useThree((state) => state.size); + const dpr = useThree((state) => state.viewport.dpr); + const [updateTransitionBg] = useTransitionBg({ size, dpr }); + const [updateSimpleBlur] = useSimpleBlur({ size, dpr }); + + useFrame((props) => { + const bgTexture = updateTransitionBg(props, { + imageResolution: CONSTANT.imageResolution, + texture0: bg, + }); + const fx = updateSimpleBlur(props, { + ...setConfig(), + texture: bgTexture + }); + fxRef.current!.u_fx = fx; + updateGUI(); + }); + + return ( + + + + + ); +}; diff --git a/.storybook/stories/useSimpleBlur.stories.tsx b/.storybook/stories/useSimpleBlur.stories.tsx new file mode 100644 index 00000000..9a4261c8 --- /dev/null +++ b/.storybook/stories/useSimpleBlur.stories.tsx @@ -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 { UseSimpleBlur } from "./UseSimpleBlur"; +import { + SIMPLEBLUR_PARAMS, + SimpleBlurParams, +} from "../../packages/use-shader-fx/src/hooks/useSimpleBlur"; + +const meta = { + title: "useSimpleBlur", + component: UseSimpleBlur, + tags: ["autodocs"], + decorators: [(storyFn: any) => {storyFn()}], +} satisfies Meta; +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: SIMPLEBLUR_PARAMS, + argTypes: setArgTypes(SIMPLEBLUR_PARAMS), +}; diff --git a/packages/use-shader-fx/src/hooks/useSimpleBlur/index.ts b/packages/use-shader-fx/src/hooks/useSimpleBlur/index.ts new file mode 100755 index 00000000..b219daae --- /dev/null +++ b/packages/use-shader-fx/src/hooks/useSimpleBlur/index.ts @@ -0,0 +1,95 @@ +import { useCallback, useMemo } from "react"; +import * as THREE from "three"; +import { RootState, Size } from "@react-three/fiber"; +import { useMesh } from "./useMesh"; +import { + useCamera, + useSingleFBO, + useDoubleFBO, + setUniform, + useParams, +} from "@hmng8/use-shader-fx"; +import type { HooksReturn } from "@hmng8/use-shader-fx/types/hooks"; + +export type SimpleBlurParams = { + /** Make this texture blur , Default:new THREE.Texture() */ + texture: THREE.Texture; + /** blurSize, default:3 */ + blurSize: number, + /** blurPower, affects performance default:5 */ + blurPower: number, +}; + +export type SimpleBlurObject = { + scene: THREE.Scene; + material: THREE.Material; + camera: THREE.Camera; + renderTarget: THREE.WebGLRenderTarget +}; + +export const SIMPLEBLUR_PARAMS: SimpleBlurParams = { + texture: new THREE.Texture, + blurSize: 3, + blurPower: 5, +}; + +export const useSimpleBlur = ({ + size, + dpr, +}: { + size: Size; + dpr: number; +}): HooksReturn => { + const scene = useMemo(() => new THREE.Scene(), []); + const material = useMesh(scene); + const camera = useCamera(size); + + const fboProps = useMemo( + () => ({ + scene, + camera, + size, + dpr, + }), + [scene, camera, size, dpr] + ); + const [renderTarget, updateRenderTarget] = useSingleFBO(fboProps); + const [tempTexture, updateTempTexture] = useDoubleFBO(fboProps); + const [params, setParams] = useParams(SIMPLEBLUR_PARAMS); + + const updateFx = useCallback( + (props: RootState, updateParams?: SimpleBlurParams) => { + const {gl} = props; + + updateParams && setParams(updateParams); + + setUniform(material, "uTexture", params.texture) + setUniform(material, "uResolution", [params.texture.source.data.width,params.texture.source.data.height]); + setUniform(material, "uBlurSize", params.blurSize) + + let _tempTexture: THREE.Texture = updateTempTexture(gl); + + const iterations = params.blurPower; + for(let i = 0; i < iterations; i++) { + setUniform(material,"uTexture",_tempTexture); + _tempTexture = updateTempTexture(gl); + } + + const outPutTexture = updateRenderTarget(gl); + + return outPutTexture; + }, + [updateRenderTarget, updateTempTexture, material, setParams, params] + ); + + return [ + updateFx, + setParams, + { + scene: scene, + material: material, + camera: camera, + renderTarget: renderTarget + }, + ]; +}; diff --git a/packages/use-shader-fx/src/hooks/useSimpleBlur/shader/main.frag b/packages/use-shader-fx/src/hooks/useSimpleBlur/shader/main.frag new file mode 100755 index 00000000..59bc64a7 --- /dev/null +++ b/packages/use-shader-fx/src/hooks/useSimpleBlur/shader/main.frag @@ -0,0 +1,26 @@ +precision mediump float; + +varying vec2 vUv; +uniform sampler2D uTexture; +uniform vec2 uResolution; +uniform float uBlurSize; + +void main() { + vec2 uv = vUv; + vec2 perDivSize = uBlurSize / uResolution; + + // calc average color value from adjacent point + vec4 outColor = vec4( + texture2D(uTexture, uv + perDivSize * vec2(-1.0, -1.0)) + + texture2D(uTexture, uv + perDivSize * vec2(0.0, -1.0)) + + texture2D(uTexture, uv + perDivSize * vec2(1.0, -1.0)) + + texture2D(uTexture, uv + perDivSize * vec2(-1.0, 0.0)) + + texture2D(uTexture, uv + perDivSize * vec2(0.0, 0.0)) + + texture2D(uTexture, uv + perDivSize * vec2(1.0, 0.0)) + + texture2D(uTexture, uv + perDivSize * vec2(-1.0, 1.0)) + + texture2D(uTexture, uv + perDivSize * vec2(0.0, 1.0)) + + texture2D(uTexture, uv + perDivSize * vec2(1.0, 1.0)) + ) / 9.0; + + gl_FragColor = outColor; +} \ No newline at end of file diff --git a/packages/use-shader-fx/src/hooks/useSimpleBlur/shader/main.vert b/packages/use-shader-fx/src/hooks/useSimpleBlur/shader/main.vert new file mode 100755 index 00000000..0ed0962a --- /dev/null +++ b/packages/use-shader-fx/src/hooks/useSimpleBlur/shader/main.vert @@ -0,0 +1,8 @@ +precision mediump float; + +varying vec2 vUv; + +void main() { + vUv = uv; + gl_Position = vec4(position, 1.0); +} \ No newline at end of file diff --git a/packages/use-shader-fx/src/hooks/useSimpleBlur/useMesh.ts b/packages/use-shader-fx/src/hooks/useSimpleBlur/useMesh.ts new file mode 100755 index 00000000..1dffa1e4 --- /dev/null +++ b/packages/use-shader-fx/src/hooks/useSimpleBlur/useMesh.ts @@ -0,0 +1,33 @@ +import { useMemo } from "react"; +import * as THREE from "three"; +import vertexShader from "./shader/main.vert"; +import fragmentShader from "./shader/main.frag"; + +import { useAddMesh } from "@hmng8/use-shader-fx"; + +export class SampleMaterial extends THREE.ShaderMaterial { + uniforms!: { + uTexture: { value: THREE.Texture }; + uResolution: { value: THREE.Vector2 }; + uBlurSize: { value: number }; + }; +} + +export const useMesh = (scene: THREE.Scene) => { + const geometry = useMemo(() => new THREE.PlaneGeometry(2, 2), []); + const material = useMemo( + () => + new THREE.ShaderMaterial({ + uniforms: { + uTexture: { value: new THREE.Texture() }, + uResolution: { value: new THREE.Vector2(0,0) }, + uBlurSize: { value: 1, } + }, + vertexShader: vertexShader, + fragmentShader: fragmentShader, + }), + [] + ); + useAddMesh(scene, geometry, material); + return material as SampleMaterial; +}; diff --git a/packages/use-shader-fx/src/index.js b/packages/use-shader-fx/src/index.js index 49d62168..e7cdb034 100644 --- a/packages/use-shader-fx/src/index.js +++ b/packages/use-shader-fx/src/index.js @@ -9,6 +9,7 @@ export { useFruid, FRUID_PARAMS } from "./hooks/useFruid"; export { useRipple, RIPPLE_PARAMS } from "./hooks/useRipple"; export { useTransitionBg, TRANSITIONBG_PARAMS } from "./hooks/useTransitionBg"; export { useNoise, NOISE_PARAMS } from "./hooks/useNoise"; +export { useSimpleBlur, SIMPLEBLUR_PARAMS } from './hooks/useSimpleBlur' // utils export { setUniform } from "./utils/setUniforms"; @@ -19,3 +20,4 @@ export { useParams } from "./utils/useParams"; export { usePointer } from "./utils/usePointer"; export { useResolution } from "./utils/useResolution"; export { useSingleFBO } from "./utils/useSingleFBO"; +