Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use enum && add types && FSD architecture #37

Merged
merged 12 commits into from
Sep 28, 2024
4 changes: 2 additions & 2 deletions app/(landing)/_components/IntroButtonSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from '@/components/ui/drawer';
import { Button } from '@/components/ui/button';
} from '@/shared/components/ui/drawer';
import { Button } from '@/shared/components/ui/button';
import useModal from '@/shared/hooks/useModal';

const IntroButtonSection = () => {
Expand Down
4 changes: 2 additions & 2 deletions components.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"prefix": ""
},
"aliases": {
"components": "@/components",
"components": "@/shared/components",
"utils": "@/lib/utils"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { BASE } from '@/shared/constants/3dModel';
import { useGLTF } from '@react-three/drei';

const Base = () => {
const base = useGLTF('/assets/bases/base1.glb').scene.clone();
const base = useGLTF(BASE.ONE).scene.clone();

base.scale.set(1, 1, 1);
base.position.set(0, 0, 0);
Expand Down
5 changes: 3 additions & 2 deletions shared/components/3dModels/Bottom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { Mesh, MeshStandardMaterial, CanvasTexture } from 'three';
import { useGLTF } from '@react-three/drei';
import { BOTTOM } from '@/shared/constants/3dModel';

const makeCanvasTexture = ({
width,
Expand Down Expand Up @@ -48,7 +49,7 @@ const makeCanvasTexture = ({
};

const Bottom = () => {
const bottom = useGLTF('/assets/bottoms/bottom1.glb').scene.clone();
const bottom = useGLTF(BOTTOM.ONE).scene.clone();

const nameTag = bottom.getObjectByName('nameTag') as Mesh | undefined;

Expand All @@ -58,7 +59,7 @@ const Bottom = () => {
width: 1024,
height: 1024,
positionY: 1024 / 8,
font: 'Bold 6.25rem KingSejongInstitute, sans-serit',
font: 'bold 100px Arial',
fontColor: 'black',
bgColor: 'white',
});
Expand Down
72 changes: 72 additions & 0 deletions shared/components/3dModels/Decoration.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Group, Mesh, Object3DEventMap, Vector3 } from 'three';

import { useGLTF } from '@react-three/drei';

import { makeColorChangedMaterial } from '@/shared/components/3dModels/utils/model';
import { DECO } from '@/shared/constants/3dModel';
import { MSG_COLOR } from '@/shared/constants/modal';

interface DecoProps {
id: number;
scale: number;
position: Vector3;
message: string;
color: string;
sender: string;
letterID: number;
isOpened: boolean;
messageID: number;
sendAt: string;
}

const DecoSet = (deco: Group<Object3DEventMap>) => {
const newModel = useGLTF('/assets/etcs/new.glb').scene.clone().children[0];
newModel.position.set(0, 1.2, 0);
newModel.scale.set(0.1, 0.1, 0.1);
deco.add(newModel);
};

const Decoration = ({
scale,
position,
message,
id,
color,
sender,
letterID,
isOpened,
messageID,
sendAt,
}: DecoProps) => {
const decorations = Object.values(DECO);

const deco = useGLTF(decorations[id - 1].fileName).scene.clone();
const target = { x: 8, z: 0 };
const focus = Math.atan2(position.z - target.z, position.x - target.x);

deco.name = decorations[id].name;
deco.scale.set(scale, scale, scale);
deco.position.set(position.x, position.y, position.z);
if (!isOpened) {
DecoSet(deco);
}

deco.children.forEach((child) => {
if (child instanceof Mesh) {
child.userData.message = message;
child.userData.sender = sender;
child.userData.letterColor = MSG_COLOR[letterID].color;
child.userData.messageID = messageID;
child.userData.sendAt = sendAt;
child.castShadow = false;
if (child.name === 'Main') {
child.material = makeColorChangedMaterial(child, color);
}
}
});
deco.rotateY(Math.PI - focus);

return <primitive object={deco} />;
};

export default Decoration;
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ import { useGLTF } from '@react-three/drei';
import { useFrame } from '@react-three/fiber';
import { Group, Mesh, Vector3 } from 'three';

import { Sentiment, SENTIMENT } from '@/shared/constants/3dModel';
import {
rotateAnimate,
visibleInRange,
} from '@/shared/components/3dModels/utils/model';

interface SnowProps {
centerPosition: Vector3;
rangeRadius: number;
sentiment: 'positive' | 'neutral' | 'negative';
sentiment: Sentiment;
confidence: number;
}

Expand Down Expand Up @@ -39,50 +45,20 @@ const fallingAnimate = (
target.position.y -= speed;
};

const rotateAnimate = (target: Mesh, speed: number) => {
target.rotation.y += speed;
};

const visibleInRange = (
target: Mesh,
centerPosition: Vector3,
radius: number
) => {
target.visible =
target.position.distanceTo(centerPosition) > radius ? false : true;
};

export const SENTIMENT_MODEL = [
{ name: '선물상자', fileName: '/assets/models/ribbonBox.glb' },
{
name: '긍정',
fileName: '/assets/flakes/heart.glb',
},
{
name: '보통',
fileName: '/assets/flakes/star.glb',
},
{
name: '부정',
fileName: '/assets/flakes/water.glb',
},
];

const Emoji = ({
centerPosition,
rangeRadius,
sentiment,
confidence,
}: SnowProps) => {
const snowRef = useRef<Mesh>(null);
const index = sentiment === 'positive' ? 1 : sentiment === 'neutral' ? 2 : 3;
const snow = useGLTF(SENTIMENT_MODEL[index].fileName).scene.clone();
const flake = useGLTF(SENTIMENT[sentiment]).scene.clone();
const scale = 0.3 + confidence / 200; // min 0.3 max 0.8

randomizePosition(snow, centerPosition, rangeRadius);
randomizePosition(flake, centerPosition, rangeRadius);

snow.scale.set(scale, scale, scale);
snow.rotation.y = Math.random();
flake.scale.set(scale, scale, scale);
flake.rotation.y = Math.random();

useFrame((_, delta) => {
const snow = snowRef.current;
Expand All @@ -94,7 +70,7 @@ const Emoji = ({
}
});

return <primitive object={snow} ref={snowRef} />;
return <primitive object={flake} ref={snowRef} />;
};

export default Emoji;
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Sphere } from '@react-three/drei';
import { Color, Vector3 } from 'three';

import { RADIUS } from '@/shared/constants/canvas';

const Glass = () => {
const color = new Color('white');
const radius = 7;
const position = new Vector3(0, radius / 2, 0);
const position = new Vector3(0, RADIUS / 2, 0);

return (
<Sphere
args={[radius, 36, 32]}
args={[RADIUS, 36, 32]}
position={position}
castShadow={true}
receiveShadow={true}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useGLTF } from '@react-three/drei';
import { GROUND } from '@/shared/constants/3dModel';

const Ground = () => {
const ground = useGLTF('/assets/grounds/winter.glb').scene.clone();
const ground = useGLTF(GROUND.WINTER).scene.clone();

ground.scale.set(20, 20, 20);
ground.position.set(0, -5, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,10 @@
import { MutableRefObject, useEffect, useRef } from 'react';
import { useGLTF } from '@react-three/drei';
import { useFrame } from '@react-three/fiber';
import {
Mesh,
Group,
Vector3,
Material,
MeshBasicMaterial,
MeshStandardMaterial,
} from 'three';
import { Mesh, Group, Vector3 } from 'three';

const makeColorChangedMaterial = (mesh: Mesh, color: string) => {
const newMaterial = (mesh.material as Material).clone() as Material;

if (
newMaterial instanceof MeshBasicMaterial ||
newMaterial instanceof MeshStandardMaterial
) {
newMaterial.color.set(color);
}

return newMaterial;
};
import { makeColorChangedMaterial } from '@/shared/components/3dModels/utils/model';
import { MAIN_DECORATION } from '@/shared/constants/3dModel';

const fallingModel = (
modelRef: Group,
Expand All @@ -50,7 +33,7 @@ const fallingModel = (
};

const MainDecoration = () => {
const deco = useGLTF('/assets/sprites/bcduck.glb').scene.clone() as Group;
const deco = useGLTF(MAIN_DECORATION.DUCK).scene.clone() as Group;
const speedRef = useRef<Vector3>(new Vector3(0, 0, 0));
const isStoppedRef = useRef<boolean>(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,14 @@ import { useGLTF } from '@react-three/drei';
import { useFrame } from '@react-three/fiber';
import { Mesh, Vector3 } from 'three';

import { Material, MeshBasicMaterial, MeshStandardMaterial } from 'three';
import { RADIUS } from '@/shared/constants/canvas';

const makeColorChangedMaterial = (mesh: Mesh, color: string) => {
const newMaterial = (mesh.material as Material).clone() as Material;

if (
newMaterial instanceof MeshBasicMaterial ||
newMaterial instanceof MeshStandardMaterial
) {
newMaterial.color.set(color);
}

return newMaterial;
};
import {
makeColorChangedMaterial,
rotateAnimate,
visibleInRange,
} from '@/shared/components/3dModels/utils/model';
import { SNOW_FLAKE } from '@/shared/constants/3dModel';

const randomizePosition = (
target: Mesh,
Expand Down Expand Up @@ -44,40 +38,25 @@ const fallingAnimate = (
target.position.y -= speed;
};

const rotateAnimate = (target: Mesh, speed: number) => {
target.rotation.y += speed;
};

const visibleInRange = (
target: Mesh,
centerPosition: Vector3,
radius: number
) => {
target.visible =
target.position.distanceTo(centerPosition) > radius ? false : true;
};

const snowcolor = ['#99c9fd', '#a5bbd3', '#f1faff'];

const Snowflake = () => {
const snowRef = useRef<Mesh>(null);
const rangeRadius = 7;
const center = new Vector3(0, rangeRadius / 2, 0);
const radius = 0.2 + Math.random() * 0.5;
const center = new Vector3(0, RADIUS / 2, 0);
const scale = 0.2 + Math.random() * 0.5;
const modelIndex = Math.floor(Math.random() * 3);
const snowflakes = Object.values(SNOW_FLAKE);

const position = new Vector3(
center.x - rangeRadius + Math.random() * rangeRadius * 2,
center.y + rangeRadius + Math.random() * rangeRadius * 2,
center.z - rangeRadius + Math.random() * rangeRadius * 2
center.x - RADIUS + Math.random() * RADIUS * 2,
center.y + RADIUS + Math.random() * RADIUS * 2,
center.z - RADIUS + Math.random() * RADIUS * 2
);

const snow = useGLTF(
`/assets/flakes/snowFlake0${modelIndex + 1}.glb`
).scene.clone();
const snow = useGLTF(snowflakes[modelIndex]).scene.clone();

snow.position.set(position.x, position.y, position.z);
snow.scale.set(radius, radius, radius);
snow.scale.set(scale, scale, scale);
snow.rotation.y = Math.random();
snow.traverse((obj) => {
if (obj instanceof Mesh) {
Expand All @@ -92,9 +71,9 @@ const Snowflake = () => {
const snow = snowRef.current;
const speed = 1 * delta;
if (snow) {
fallingAnimate(snow, speed, center, rangeRadius);
fallingAnimate(snow, speed, center, RADIUS);
rotateAnimate(snow, speed);
visibleInRange(snow, center, rangeRadius - 1);
visibleInRange(snow, center, RADIUS - 1);
}
});

Expand Down
28 changes: 28 additions & 0 deletions shared/components/3dModels/utils/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Vector3 } from 'three';
import { Mesh, Material, MeshBasicMaterial, MeshStandardMaterial } from 'three';

export const makeColorChangedMaterial = (mesh: Mesh, color: string) => {
const newMaterial = (mesh.material as Material).clone() as Material;

if (
newMaterial instanceof MeshBasicMaterial ||
newMaterial instanceof MeshStandardMaterial
) {
newMaterial.color.set(color);
}

return newMaterial;
};

export const rotateAnimate = (target: Mesh, speed: number) => {
target.rotation.y += speed;
};

export const visibleInRange = (
target: Mesh,
centerPosition: Vector3,
radius: number
) => {
target.visible =
target.position.distanceTo(centerPosition) > radius ? false : true;
};
Loading