Skip to content

Commit 03089f4

Browse files
author
takuma-hmng8
committed
3.5
1 parent b09fd41 commit 03089f4

File tree

30 files changed

+3205
-124
lines changed

30 files changed

+3205
-124
lines changed

README.md

Lines changed: 9 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -283,113 +283,6 @@ usePerformanceMonitor({
283283
});
284284
```
285285

286-
# How to make "custom fxHooks"
287-
288-
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.
289-
290-
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.
291-
292-
```bash
293-
git clone https://github.com/takuma-hmng8/CreateShaderFx
294-
```
295-
296-
If you can create a cool FX, please contribute!
297-
👉 [CONTRIBUTING](CONTRIBUTING.md)! 👈
298-
299-
## useDoubleFBO
300-
301-
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`.
302-
303-
```ts
304-
type UseFboProps = {
305-
scene: THREE.Scene;
306-
camera: THREE.Camera;
307-
size: Size;
308-
/** If dpr is set, dpr will be multiplied, default:false */
309-
dpr?: number | false;
310-
/** Whether to resize when resizing occurs. If isDpr is true, set FBO to setSize even if dpr is changed, default:false */
311-
isSizeUpdate?: boolean;
312-
/** Defines the count of MSAA samples. Can only be used with WebGL 2. Default is 0. */
313-
samples?: number;
314-
/** Renders to the depth buffer. Unlike the three.js, Default is false. */
315-
depthBuffer?: boolean;
316-
/** If set, the scene depth will be rendered to this texture. Default is false. */
317-
depthTexture?: boolean;
318-
};
319-
320-
const [velocityFBO, updateVelocityFBO] = useDoubleFBO(UseFboProps);
321-
```
322-
323-
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.
324-
325-
```js
326-
const texture = updateVelocityFBO(gl, ({ read, write }) => {
327-
// callback before gl.render()
328-
setMeshMaterial(materials.advectionMaterial);
329-
setUniform(materials.advectionMaterial, "uVelocity", read);
330-
});
331-
```
332-
333-
## useSingleFBO
334-
335-
This is a version without double buffering.
336-
337-
```js
338-
const [renderTarget, updateRenderTarget] = useSingleFBO(UseFboProps);
339-
```
340-
341-
## useCamera
342-
343-
Generates and returns a `THREE.OrthographicCamera`.
344-
345-
```js
346-
const camera = useCamera(size);
347-
```
348-
349-
## useResolution
350-
351-
This hook returns `resolution`. If `dpr` isn't set (or set to false), dpr won't be multiplied.
352-
353-
```ts
354-
const resolution = useResolution(size: Size, dpr: number | false = false);
355-
```
356-
357-
## useAddMesh
358-
359-
Creates a mesh and adds it to scene, geometry, and material. Returns the mesh.
360-
361-
```js
362-
useAddMesh(scene, geometry, material);
363-
```
364-
365-
## setUniform
366-
367-
A function to set values in the uniforms of the shader material.
368-
369-
```js
370-
setUniform(material, "key", someValue);
371-
```
372-
373-
## useParams
374-
375-
Returns the refObject of params and its update function.
376-
377-
```ts
378-
const [params, setParams] = useParams<HooksParams>;
379-
{
380-
// HookPrams
381-
}
382-
```
383-
384-
## useCopyTexture
385-
386-
Generate an FBO array to copy the texture.
387-
388-
```tsx
389-
const [renderTargets, copyTexture] = useCopyTexture(UseFboProps, length);
390-
copyTexture(gl, index); // return texture
391-
```
392-
393286
# Misc
394287

395288
## useDomSyncer
@@ -548,3 +441,12 @@ useFrame((props) => {
548441
}
549442
});
550443
```
444+
445+
## useCopyTexture
446+
447+
Generate an FBO array to copy the texture.
448+
449+
```tsx
450+
const [renderTargets, copyTexture] = useCopyTexture(UseFboProps, length);
451+
copyTexture(gl, index); // return texture
452+
```

app/ShaderFx.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const ShaderFx = ({
2222
return;
2323
}
2424
console.log(`dpr:${dpr}`);
25-
setDpr(Math.round((1.0 + 1.0 * factor) * 10) / 10);
25+
// setDpr(Math.round((1.0 + 1.0 * factor) * 10) / 10);
2626
}}>
2727
<Suspense fallback={null}>{children}</Suspense>
2828
{/* <Perf position={"bottom-left"} minimal={false} /> */}

app/useMorph3D/FxMaterial.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as THREE from "three";
2+
import { shaderMaterial } from "@react-three/drei";
3+
// import fragment from "./main.frag";
4+
5+
declare global {
6+
namespace JSX {
7+
interface IntrinsicElements {
8+
fxMaterial: any;
9+
}
10+
}
11+
}
12+
13+
export type FxMaterialProps = {
14+
u_fx: THREE.Texture;
15+
};
16+
17+
export const FxMaterial = shaderMaterial(
18+
{
19+
u_fx: new THREE.Texture(),
20+
},
21+
22+
`
23+
varying vec2 vUv;
24+
void main() {
25+
vUv = uv;
26+
gl_Position = vec4(position, 1.0);
27+
}
28+
`,
29+
`
30+
precision highp float;
31+
varying vec2 vUv;
32+
uniform sampler2D u_fx;
33+
34+
void main() {
35+
gl_FragColor = texture2D(u_fx,vUv);
36+
}
37+
`
38+
);

app/useMorph3D/Playground.tsx

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"use client";
2+
3+
import * as THREE from "three";
4+
import { useCallback, useEffect, useMemo, useRef } from "react";
5+
import {
6+
useFrame,
7+
useThree,
8+
extend,
9+
useLoader,
10+
Size,
11+
} from "@react-three/fiber";
12+
import { useBeat, useFluid, usePointer } from "@/packages/use-shader-fx/src";
13+
import { FxMaterial, FxMaterialProps } from "./FxMaterial";
14+
import GUI from "lil-gui";
15+
import { useGUI } from "@/utils/useGUI";
16+
import { CONFIG as HomeConfig } from "../_home/Playground";
17+
import { OrbitControls, useGLTF } from "@react-three/drei";
18+
import CustomShaderMaterial from "three-custom-shader-material/vanilla";
19+
import wobbleVertexShader from "./vert.glsl";
20+
import wobbleFragmentShader from "./frag.glsl";
21+
import { mergeVertices } from "three-stdlib";
22+
23+
extend({ FxMaterial });
24+
25+
const uniforms = {
26+
uTime: new THREE.Uniform(0),
27+
uPositionFrequency: new THREE.Uniform(0.5),
28+
uTimeFrequency: new THREE.Uniform(0.2),
29+
uStrength: new THREE.Uniform(0.9),
30+
uWarpPositionFrequency: new THREE.Uniform(0.2),
31+
uWarpTimeFrequency: new THREE.Uniform(0.2),
32+
uWarpStrength: new THREE.Uniform(0.2),
33+
uColorA: new THREE.Uniform(new THREE.Color("white")),
34+
uColorB: new THREE.Uniform(new THREE.Color("black")),
35+
uBaloon: new THREE.Uniform(0),
36+
uFx: new THREE.Uniform(new THREE.Texture()),
37+
};
38+
39+
export const Playground = () => {
40+
const { size, viewport, scene: rootScene, camera } = useThree();
41+
42+
// camera.position.set(0, 0, 2);
43+
44+
// const { scene } = useGLTF(
45+
// "https://vazxmixjsiawhamofees.supabase.co/storage/v1/object/public/models/suzanne-high-poly/model.gltf"
46+
// );
47+
48+
const [updateFluid, setFluid, fluid] = useFluid({ size, dpr: viewport.dpr });
49+
50+
const mesh = useMemo(() => {
51+
const material = new CustomShaderMaterial({
52+
// CSM
53+
baseMaterial: THREE.MeshPhysicalMaterial,
54+
vertexShader: wobbleVertexShader,
55+
fragmentShader: wobbleFragmentShader,
56+
uniforms: uniforms,
57+
silent: true,
58+
59+
// MeshPhysicalMaterial
60+
metalness: 0.9,
61+
roughness: 0.5,
62+
color: "#ffffff",
63+
transmission: 0,
64+
ior: 1.5,
65+
thickness: 1.5,
66+
transparent: true,
67+
wireframe: false,
68+
});
69+
const depthMaterial = new CustomShaderMaterial({
70+
// CSM
71+
baseMaterial: THREE.MeshDepthMaterial,
72+
vertexShader: wobbleVertexShader,
73+
uniforms: uniforms,
74+
silent: true,
75+
76+
// MeshDepthMaterial
77+
depthPacking: THREE.RGBADepthPacking,
78+
});
79+
let geometry = new THREE.IcosahedronGeometry(
80+
2.5,
81+
50
82+
) as THREE.BufferGeometry;
83+
// let geometry = scene.children[0].geometry as THREE.BufferGeometry;
84+
85+
geometry = mergeVertices(geometry);
86+
geometry.computeTangents();
87+
88+
const wobble = new THREE.Mesh(geometry, material);
89+
wobble.customDepthMaterial = depthMaterial;
90+
wobble.receiveShadow = true;
91+
wobble.castShadow = true;
92+
return wobble;
93+
}, []);
94+
95+
const beat = useBeat(140);
96+
const updatePointer = usePointer();
97+
98+
const raycaster = useMemo(() => new THREE.Raycaster(), []);
99+
const rayCursor = useRef<THREE.Vector2 | null>(null);
100+
101+
useFrame((props) => {
102+
const b = beat(props.clock);
103+
updateFluid(props);
104+
mesh.material.uniforms.uTime.value = b.beat;
105+
106+
raycaster.setFromCamera(props.pointer, camera);
107+
const intersects = raycaster.intersectObject(mesh);
108+
if (intersects.length > 0) {
109+
const uv = intersects[0]?.uv as THREE.Vector2;
110+
if (!uv) return;
111+
rayCursor.current = uv.multiplyScalar(2).subScalar(1);
112+
}
113+
if (rayCursor.current) {
114+
mesh.material.uniforms.uFx.value = updateFluid(props, {
115+
pointerValues: updatePointer(rayCursor.current),
116+
});
117+
}
118+
});
119+
120+
return (
121+
<mesh>
122+
<ambientLight />
123+
<directionalLight />
124+
<OrbitControls />
125+
<primitive object={mesh} position={[0, 0, 0]} />
126+
</mesh>
127+
);
128+
};

app/useMorph3D/frag.glsl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
uniform vec3 uColorA;
2+
uniform vec3 uColorB;
3+
4+
varying float vWobble;
5+
varying vec3 vFxColor;
6+
7+
void main()
8+
{
9+
float colorMix = smoothstep(- 1.0, 1.0, vWobble);
10+
csm_DiffuseColor.rgb = mix(vFxColor, uColorB, colorMix);
11+
12+
// // Mirror step
13+
// csm_Metalness = step(0.25, vWobble);
14+
// csm_Roughness = 1.0 - csm_Metalness;
15+
16+
// Shinny tip
17+
csm_Roughness = 1.0 - colorMix;
18+
}

app/useMorph3D/page.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ShaderFx } from "../ShaderFx";
2+
import { Playground } from "./Playground";
3+
4+
export default function Page() {
5+
return (
6+
<div
7+
style={{
8+
position: "fixed",
9+
width: "100%",
10+
height: "100svh",
11+
pointerEvents: "none",
12+
}}>
13+
<ShaderFx>
14+
<Playground />
15+
</ShaderFx>
16+
</div>
17+
);
18+
}

0 commit comments

Comments
 (0)