Skip to content

Commit 7fdf9b1

Browse files
author
takuma-hmng8
committed
v1.1.35
1 parent 15a01fe commit 7fdf9b1

40 files changed

+1838
-1545
lines changed

app/stickers/Background.tsx

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"use client";
2+
3+
import * as THREE from "three";
4+
import { memo } from "react";
5+
import { Environment } from "@react-three/drei";
6+
7+
export const Background = memo(
8+
({
9+
stickerMap,
10+
scene,
11+
}: {
12+
stickerMap: THREE.Texture;
13+
scene: THREE.Scene;
14+
}) => {
15+
return (
16+
<>
17+
<Environment
18+
frames={1}
19+
files={"/env/empty_warehouse_01_1k.hdr"}
20+
environmentIntensity={0.8}
21+
scene={scene}
22+
/>
23+
<mesh scale={100}>
24+
<sphereGeometry args={[3, 32, 32]} />
25+
<meshBasicMaterial
26+
color={new THREE.Color(0x666666)}
27+
map={stickerMap}
28+
side={THREE.BackSide}
29+
/>
30+
</mesh>
31+
</>
32+
);
33+
}
34+
);
35+
Background.displayName = "Background";

app/stickers/CanvasState.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as THREE from "three";
22
import { CLICKED_WOBBLE_STRENGTH } from "./StickerBall";
3-
import { STICKER_TEXTURES_LENGTH } from "./useStickers";
3+
import { STICKER_TEXTURES_LENGTH } from "./StickerBall/useStickers";
44

55
export class CanvasState {
66
private static instance: CanvasState;
@@ -18,7 +18,7 @@ export class CanvasState {
1818
};
1919

2020
public CAMERA_Z = {
21-
zoom: 3.5,
21+
zoom: 3.2,
2222
default: 4,
2323
};
2424

app/stickers/Playground.tsx

+94-45
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,81 @@
11
"use client";
22

33
import * as THREE from "three";
4-
import { memo } from "react";
5-
import { Environment, OrbitControls } from "@react-three/drei";
6-
import { useFrame } from "@react-three/fiber";
7-
import { useStickers } from "./useStickers";
4+
import { useMemo, useRef } from "react";
5+
import { OrbitControls } from "@react-three/drei";
6+
import { useFrame, createPortal, extend, useThree } from "@react-three/fiber";
7+
import { useStickers } from "./StickerBall/useStickers";
88
import { CanvasState } from "./CanvasState";
99
import { StickerBall } from "./StickerBall";
10-
import { Easing, Utils } from "@/packages/use-shader-fx/src";
10+
import {
11+
Easing,
12+
Utils,
13+
useResizeBoundary,
14+
useSingleFBO,
15+
} from "@/packages/use-shader-fx/src";
16+
import { Background } from "./Background";
17+
import { FxMaterial, FxMaterialProps } from "./romanticism/FxMaterial";
18+
import { useRomanticism } from "./romanticism/useRomanticism";
1119

12-
const Background = memo(({ stickerMap }: { stickerMap: THREE.Texture }) => {
13-
return (
14-
<>
15-
<Environment preset="warehouse" environmentIntensity={0.5} />
16-
<mesh scale={100}>
17-
<sphereGeometry args={[3, 32, 32]} />
18-
<meshBasicMaterial
19-
color={new THREE.Color(0x444444)}
20-
map={stickerMap}
21-
side={THREE.BackSide}
22-
/>
23-
</mesh>
24-
</>
25-
);
26-
});
27-
Background.displayName = "Background";
20+
extend({ FxMaterial });
2821

2922
export const Playground = () => {
30-
const { stickerMap, normalMap, isReady, silhouette } = useStickers();
23+
const { camera, size, viewport, gl } = useThree();
3124

3225
const canvasState = CanvasState.getInstance();
3326

34-
useFrame(({ camera, clock }, delta) => {
27+
// 1000以上リサイズした場合のみリサイズする
28+
const resizeBoundary = useResizeBoundary({
29+
gl,
30+
size,
31+
boundFor: "larger",
32+
threshold: 1000,
33+
});
34+
35+
// stickers
36+
const { stickerMap, normalMap, isReady, silhouette } =
37+
useStickers(resizeBoundary);
38+
39+
// offscreen to stickers
40+
const offscreenScene = useMemo(() => new THREE.Scene(), []);
41+
const [portalStickers, updatePortalStickers] = useSingleFBO({
42+
scene: offscreenScene,
43+
camera,
44+
size,
45+
dpr: viewport.dpr,
46+
depthBuffer: true,
47+
isSizeUpdate: resizeBoundary.isUpdate,
48+
});
49+
50+
// romanticism
51+
const romanticism = useRomanticism(portalStickers.texture);
52+
const materialRef = useRef<FxMaterialProps>(null);
53+
54+
useFrame(({ camera, clock, pointer, gl }) => {
3555
if (!isReady) {
3656
return;
3757
}
3858

39-
// control camera state
40-
if (canvasState.cameraState.point.z < canvasState.CAMERA_Z.default) {
41-
canvasState.cameraState.point.z += delta;
59+
// update portalized stickers
60+
updatePortalStickers(gl);
61+
62+
// update romanticism
63+
if (materialRef.current) {
64+
materialRef.current.u_time = clock.getElapsedTime();
4265
}
43-
camera.position.lerp(canvasState.cameraState.point, 0.16);
66+
67+
// control camera state
68+
const _pointer = pointer.clone().multiplyScalar(0.32);
69+
canvasState.cameraState.point.lerp(
70+
{
71+
..._pointer, // uncomment this line to enable camera movement
72+
// x: 0,
73+
// y: 0,
74+
z: canvasState.CAMERA_Z.default,
75+
},
76+
0.12
77+
);
78+
camera.position.lerp(canvasState.cameraState.point, 0.14);
4479
camera.lookAt(0, 0, 0);
4580

4681
// control clock state
@@ -61,23 +96,37 @@ export const Playground = () => {
6196
}
6297
});
6398
return (
64-
<mesh visible={isReady}>
65-
<StickerBall
66-
stickerMap={stickerMap}
67-
normalMap={normalMap}
68-
silhouetteMap={silhouette}
69-
/>
70-
<Background stickerMap={stickerMap} />
71-
<OrbitControls
72-
enabled={true}
73-
enableZoom={false}
74-
enablePan={false}
75-
rotateSpeed={0.12}
76-
minAzimuthAngle={-0.785} // -45
77-
maxAzimuthAngle={0.785} // 45
78-
minPolarAngle={1.134} // 65
79-
maxPolarAngle={1.919} // 110
80-
/>
81-
</mesh>
99+
<>
100+
{createPortal(
101+
<mesh visible={isReady}>
102+
<StickerBall
103+
stickerMap={stickerMap}
104+
normalMap={normalMap}
105+
silhouetteMap={silhouette}
106+
/>
107+
<Background stickerMap={stickerMap} scene={offscreenScene} />
108+
<OrbitControls
109+
enabled={true}
110+
enableZoom={false}
111+
enablePan={false}
112+
rotateSpeed={0.12}
113+
minAzimuthAngle={-0.785} // -45
114+
maxAzimuthAngle={0.785} // 45
115+
minPolarAngle={1.134} // 65
116+
maxPolarAngle={1.919} // 110
117+
/>
118+
</mesh>,
119+
offscreenScene
120+
)}
121+
<mesh visible={isReady}>
122+
<planeGeometry args={[2, 2]} />
123+
<fxMaterial
124+
ref={materialRef}
125+
u_romance={romanticism}
126+
u_original={portalStickers.texture}
127+
key={FxMaterial.key}
128+
/>
129+
</mesh>
130+
</>
82131
);
83132
};

app/stickers/useStickers.ts app/stickers/StickerBall/useStickers.ts

+27-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
import * as THREE from "three";
2-
import {
3-
useMemo,
4-
useCallback,
5-
useReducer,
6-
useRef,
7-
useState,
8-
useEffect,
9-
} from "react";
10-
import { useFrame, useThree, useLoader } from "@react-three/fiber";
11-
import { useBlank, useBrush } from "@/packages/use-shader-fx/src";
12-
import { CanvasState } from "./CanvasState";
2+
import { useMemo, useCallback, useRef, useState } from "react";
3+
import { useFrame, useThree, useLoader, Size } from "@react-three/fiber";
4+
import { ResizeBoundary, Utils, useBlank } from "@/packages/use-shader-fx/src";
5+
import { CanvasState } from "../CanvasState";
136

147
const STICKER_TEXCOORD = `
158
vec2 stamp = uStampPoint;
@@ -61,7 +54,7 @@ const STICKER_TEXTURES = [
6154

6255
export const STICKER_TEXTURES_LENGTH = STICKER_TEXTURES.length;
6356

64-
export const useStickers = () => {
57+
export const useStickers = (resizeBoundary: ResizeBoundary) => {
6558
const canvasState = CanvasState.getInstance();
6659

6760
const textures = useLoader(THREE.TextureLoader, [
@@ -82,7 +75,8 @@ export const useStickers = () => {
8275

8376
const [updateSticker, _, { output: stickerMap }] = useBlank({
8477
size,
85-
dpr: 6,
78+
dpr: Math.min(resizeBoundary.maxDpr, 6),
79+
isSizeUpdate: resizeBoundary.isUpdate,
8680
onBeforeInit: useCallback(
8781
(parameters: any) => {
8882
Object.assign(parameters.uniforms, {
@@ -120,6 +114,11 @@ export const useStickers = () => {
120114
usf_FragColor = finalColor;
121115
`
122116
);
117+
118+
parameters.fragmentShader = parameters.fragmentShader.replace(
119+
"precision highp float;",
120+
"precision lowp float;"
121+
);
123122
},
124123
// eslint-disable-next-line react-hooks/exhaustive-deps
125124
[]
@@ -128,7 +127,8 @@ export const useStickers = () => {
128127

129128
const [updateNormal, __, { output: normalMap }] = useBlank({
130129
size,
131-
dpr: 4,
130+
dpr: Math.min(resizeBoundary.maxDpr, 4),
131+
isSizeUpdate: resizeBoundary.isUpdate,
132132
onBeforeInit: useCallback(
133133
(shader: any) => {
134134
Object.assign(shader.uniforms, {
@@ -201,6 +201,11 @@ export const useStickers = () => {
201201
usf_FragColor = finalColor;
202202
`
203203
);
204+
205+
shader.fragmentShader = shader.fragmentShader.replace(
206+
"precision highp float;",
207+
"precision lowp float;"
208+
);
204209
},
205210
// eslint-disable-next-line react-hooks/exhaustive-deps
206211
[]
@@ -209,6 +214,13 @@ export const useStickers = () => {
209214

210215
const tickCount = useRef(-2);
211216

217+
if (
218+
resizeBoundary.isUpdate &&
219+
tickCount.current === canvasState.stickerState.count
220+
) {
221+
tickCount.current -= 2;
222+
}
223+
212224
const [isReady, setIsReady] = useState(false);
213225

214226
useFrame((state) => {
@@ -218,7 +230,7 @@ export const useStickers = () => {
218230

219231
tickCount.current++;
220232

221-
if (tickCount.current === 0) {
233+
if (tickCount.current === 0 && !isReady) {
222234
setIsReady(true);
223235
}
224236

app/stickers/UI/Cursor/GifPreloader.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { memo } from "react";
22
import Image from "next/image";
3-
import { STICKER_TEXTURES_LENGTH } from "../../useStickers";
3+
import { STICKER_TEXTURES_LENGTH } from "../../StickerBall/useStickers";
44

55
const GIF_IMAGES = [...Array(STICKER_TEXTURES_LENGTH)].map(
66
(_, i) => `/stickers/gif/gif${i}.gif`

app/stickers/UI/Cursor/index.tsx

+7-21
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ import { useCallback, useEffect, useRef, useState } from "react";
77
import gsap from "gsap";
88
import { GifPreloader } from "./GifPreloader";
99
import { Confetti } from "./Confetti";
10-
import { useIsTouchDevice } from "@funtech-inc/spice";
10+
import { useIsTouchDevice, useFrame } from "@funtech-inc/spice";
1111
import s from "./index.module.scss";
1212

1313
const updateTargetPoint = (target: HTMLDivElement, point: THREE.Vector2) => {
14-
const targetRect = target.getBoundingClientRect();
15-
target.style.left = `${point.x - targetRect.width / 2}px`;
16-
target.style.top = `${point.y - targetRect.height / 2}px`;
14+
const width = target.clientWidth;
15+
const height = target.clientHeight;
16+
target.style.left = `${point.x - width / 2}px`;
17+
target.style.top = `${point.y - height / 2}px`;
1718
};
1819

1920
const CURSOR_LERP = 0.8;
@@ -58,7 +59,6 @@ export const CursorUI = () => {
5859
canvasState.stickerState.nextStickerIndex
5960
);
6061

61-
const rafID = useRef<number>(0);
6262
const cursorRef = useRef<HTMLDivElement>(null);
6363
const imageRef = useRef<HTMLImageElement>(null);
6464
const confettiRef = useRef<HTMLDivElement>(null);
@@ -170,7 +170,7 @@ export const CursorUI = () => {
170170
[canvasState]
171171
);
172172

173-
const handleFrame = useCallback(() => {
173+
useFrame(() => {
174174
const isOver = canvasState.cursorState.isOver;
175175

176176
// update sticker index
@@ -194,21 +194,7 @@ export const CursorUI = () => {
194194
updateCursorPoint(false);
195195
}
196196
prevIsOver.current = isOver;
197-
rafID.current = requestAnimationFrame(handleFrame);
198-
}, [
199-
canvasState.stickerState,
200-
stickerIndex,
201-
canvasState.cursorState,
202-
onStickerChange,
203-
onOver,
204-
onOut,
205-
updateCursorPoint,
206-
]);
207-
208-
useEffect(() => {
209-
rafID.current = requestAnimationFrame(handleFrame);
210-
return () => cancelAnimationFrame(rafID.current);
211-
}, [handleFrame]);
197+
});
212198

213199
return (
214200
<div className={s.container}>

0 commit comments

Comments
 (0)