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
116 changes: 116 additions & 0 deletions .storybook/stories/UseMotionBlur.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import * as THREE from "three";
import * as React from "react";
import { useFrame, extend, useThree, createPortal } from "@react-three/fiber";
import { FxMaterial, FxMaterialProps } from "../../utils/fxMaterial";
import GUI from "lil-gui";
import { useGUI } from "../../utils/useGUI";
import { useMotionBlur, useSingleFBO } from "../../packages/use-shader-fx/src";
import {
MotionBlurParams,
MOTIONBLUR_PARAMS,
} from "../../packages/use-shader-fx/src/fxs/effects/useMotionBlur";
import { OrbitControls } from "@react-three/drei";

extend({ FxMaterial });

const CONFIG: MotionBlurParams = structuredClone(MOTIONBLUR_PARAMS);
const setGUI = (gui: GUI) => {
gui.add(CONFIG, "strength", 0, 0.99, 0.01);
};
const setConfig = () => {
return {
...CONFIG,
} as MotionBlurParams;
};

export const UseMotionBlur = (args: MotionBlurParams) => {
const updateGUI = useGUI(setGUI);

const fxRef = React.useRef<FxMaterialProps>();
const { size, viewport, camera } = useThree();
const [updateMotionBlur, setMotionBlur] = useMotionBlur({
size,
dpr: viewport.dpr,
});

// This scene is rendered offscreen
const offscreenScene = React.useMemo(() => new THREE.Scene(), []);

// create FBO for offscreen rendering
const [boxView, updateRenderTarget] = useSingleFBO({
scene: offscreenScene,
camera,
size,
dpr: viewport.dpr,
samples: 4,
});

setMotionBlur({
texture: boxView.texture,
});

useFrame((props) => {
updateRenderTarget(props.gl);
const fx = updateMotionBlur(props, {
strength: setConfig().strength,
});
fxRef.current!.u_fx = fx;
updateGUI();
});

return (
<>
{createPortal(
<mesh>
<ambientLight intensity={Math.PI} />
<spotLight
position={[10, 10, 10]}
angle={0.15}
penumbra={1}
decay={0}
intensity={Math.PI}
/>
<pointLight
position={[-10, -10, -10]}
decay={0}
intensity={Math.PI}
/>
<Box position={[-1.5, 0, 0]} />
<Box position={[1.5, 0, 0]} />
</mesh>,
offscreenScene
)}
<mesh>
<planeGeometry args={[2, 2]} />
<fxMaterial key={FxMaterial.key} ref={fxRef} />
</mesh>
<OrbitControls />
</>
);
};

function Box(props: any) {
// This reference will give us direct access to the mesh
const meshRef = React.useRef<THREE.Mesh>();
// Set up state for the hovered and active state
const [hovered, setHover] = React.useState(false);
const [active, setActive] = React.useState(false);
// Subscribe this component to the render-loop, rotate the mesh every frame
useFrame((state, delta) => {
meshRef.current!.rotation.x += delta;
meshRef.current!.rotation.y -= delta;
});
// Return view, these are regular three.js elements expressed in JSX
return (
<mesh
{...props}
ref={meshRef}
scale={active ? 2 : 1.5}
onClick={(event) => setActive(!active)}
onPointerOver={(event) => setHover(true)}
onPointerOut={(event) => setHover(false)}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? "hotpink" : "orange"} />
</mesh>
);
}
30 changes: 30 additions & 0 deletions .storybook/stories/useMotionBlur.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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 {
MotionBlurParams,
MOTIONBLUR_PARAMS,
} from "../../packages/use-shader-fx/src/fxs/effects/useMotionBlur";
import { UseMotionBlur } from "./UseMotionBlur";

const meta = {
title: "effects/useMotionBlur",
component: UseMotionBlur,
tags: ["autodocs"],
decorators: [(storyFn: any) => <Setup>{storyFn()}</Setup>],
} satisfies Meta<typeof UseMotionBlur>;

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

const storySetting = {
args: MOTIONBLUR_PARAMS,
argTypes: setArgTypes<MotionBlurParams>(MOTIONBLUR_PARAMS),
};

export const Default: Story = {
render: (args) => <UseMotionBlur {...args} />,
...storySetting,
};
19 changes: 2 additions & 17 deletions app/_home/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as THREE from "three";
import { useMemo, useRef } from "react";
import { useFrame, useThree, extend } from "@react-three/fiber";
import {
useNoise,
useColorStrata,
useMarble,
useHSV,
Expand Down Expand Up @@ -92,10 +91,6 @@ export const Playground = ({
const { size, viewport } = useThree();
const funkun = useVideoTexture("/FT_Ch02-comp.mp4");

const [updateNoise, setNoise, { output: noise }] = useNoise({
size,
dpr: viewport.dpr,
});
const [updateColorStrata, setColorStrata, { output: colorStrata }] =
useColorStrata({ size, dpr: viewport.dpr });
const [updateMarble, setMarble, { output: marble }] = useMarble({
Expand All @@ -108,22 +103,15 @@ export const Playground = ({
});
const [updateBrush, setBrush, { output: brush }] = useBrush({
size,
dpr: viewport.dpr,
dpr: 0.05,
});
const [updateCover, setCover, { output: cover }] = useCoverTexture({
size,
dpr: viewport.dpr,
dpr: 0.1,
});

useMemo(() => {
CONFIG.random();
setNoise({
scale: 1000,
warpOctaves: 1,
noiseOctaves: 1,
fbmOctaves: 1,
timeStrength: 1,
});

setMarble({
...setConfig("marble"),
Expand All @@ -145,7 +133,6 @@ export const Playground = ({
});

setBrush({
map: noise,
texture: cover,
mapIntensity: 0.35,
radius: 0.2,
Expand All @@ -169,7 +156,6 @@ export const Playground = ({
hashMemo.current = hash;
CONFIG.random();
}
updateNoise(props);
updateColorStrata(props, {
...(setConfig("colorStrata") as ColorStrataParams),
});
Expand All @@ -194,7 +180,6 @@ export const Playground = ({
<fxMaterial
key={FxMaterial.key}
u_noise={marble}
u_grain={noise}
u_colorStrata={hsv}
u_brush={brush}
ref={ref}
Expand Down
7 changes: 2 additions & 5 deletions app/_home/main.frag
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,19 @@ varying vec2 vUv;
uniform sampler2D u_noise;
uniform float u_noiseIntensity;
uniform sampler2D u_colorStrata;
uniform sampler2D u_grain;
uniform sampler2D u_brush;

void main() {

vec2 uv = vUv;
vec4 grain = texture2D(u_grain, uv);
vec4 noise = texture2D(u_noise, uv);
vec4 brush = texture2D(u_brush, uv);

uv += grain.rg;

uv += noise.rg * u_noiseIntensity;
vec4 colorStrata = texture2D(u_colorStrata,uv);

vec4 mixColor = mix(colorStrata, brush, brush.a);

gl_FragColor = mixColor;
gl_FragColor.a = 1.0;
}
}
44 changes: 44 additions & 0 deletions app/funtech/FxMaterial.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as THREE from "three";
import { shaderMaterial } from "@react-three/drei";
import frag from "./main.frag";

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

export type FxMaterialProps = {
u_fx: THREE.Texture;
u_time: number;
u_floor: number;
u_contrast: number;
u_brightness: number;
u_saturation: number;
u_noiseStrength: number;
u_floorStrength: THREE.Vector2;
};

export const FxMaterial = shaderMaterial(
{
u_fx: new THREE.Texture(),
u_time: 0,
u_floor: 8,
u_contrast: 1,
u_brightness: 1,
u_saturation: 1,
u_noiseStrength: 0.3,
u_floorStrength: new THREE.Vector2(0.2, 0.8),
},

`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 1.0);
}
`,
frag
);
Loading