๐น๏ธ TransformControls
ํด๋น ์ปดํฌ๋ํธ๋ mode์ ์์ฑ์ ํตํด ์ค๋ธ์ ํธ์ ํธ์ง ๋ชจ๋๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค.
โ translate: ์ค๋ธ์ ํธ์ ์์น ์ขํ๊ฐ์ ๋ณ๊ฒฝ
โ rotate: ์ค๋ธ์ ํธ์ ํ์ ๊ฐ์ ๋ณ๊ฒฝ
โ scale: ์ค๋ธ์ ํธ์ ๊ท๋ชจ ๋ณ๊ฒฝ
๋ฐ๋ผ์ ๋ฒํผ์ ์์ฑํ๊ณ , ํด๋น ๋ฒํผ์ ๋๋ฅผ ๋ ๋ฒํผ์ ์ ์ฉ๋ ๊ฐ์ผ๋ก ์ํ๊ฐ์ ๋ณ๊ฒฝํ์ฌ ์ปจํธ๋กค๋ฌ์ ํธ์ง ๋ชจ๋๋ฅผ ์ค์ ํด๋ณด๊ฒ ๋ค.
์ด์ ๊ฒ์๊ธ์์ mode๋ผ๋ useState()๋ฅผ ์์ฑํ์ฌ "translate" ๊ฐ์ ๋ฃ์๋ค.
ํด๋น ์ํ๋ฅผ ๋ง๋ค๊ธฐ ์ํด ๋ฒํผ์ ๋ง๋ค์ด๋ณด์
๐ Editor / ๐ TransformControlButtons.tsx
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import styles from "./CSS/TransformControllButtons.module.css";
import translate from "./Assets/translate.svg";
import {
faRotate,
faUpDownLeftRight,
faUpRightAndDownLeftFromCenter,
} from "@fortawesome/free-solid-svg-icons";
import { Dispatch, FC, SetStateAction } from "react";
interface TransformControllButtonsProps {
mode: string;
setMode: Dispatch<SetStateAction<string>>;
}
export const TransformControllButtons: FC<TransformControllButtonsProps> = ({
mode,
setMode,
}) => {
const handlerMode = (type: string) => {
setMode(type);
};
return (
<>
<div className={styles.toolbox}>
<div
className={styles.mode}
style={{
backgroundColor: mode === "translate" ? "#0082ff" : "#101010",
}}
onClick={() => {
handlerMode("translate");
}}
>
<FontAwesomeIcon icon={faUpDownLeftRight} />
</div>
<div
className={styles.mode}
style={{
backgroundColor: mode === "rotate" ? "#0082ff" : "#101010",
}}
onClick={() => {
handlerMode("rotate");
}}
>
<FontAwesomeIcon icon={faRotate} />
</div>
<div
className={styles.mode}
style={{
backgroundColor: mode === "scale" ? "#0082ff" : "#101010",
}}
onClick={() => {
handlerMode("scale");
}}
>
<FontAwesomeIcon icon={faUpRightAndDownLeftFromCenter} />
</div>
</div>
</>
);
};
fontawesome์ ํตํด ๊ฐ ๋ฒํผ์ ์๊ฐ์ ์ผ๋ก ๋ณ๊ฒฝ ๋ชจ๋๋ฅผ ์ค์ ํด์ค๋ค.
๊ทธ๋ฆฌ๊ณ ํด๋น ๋ฒํผ ์ปดํฌ๋ํธ๋ฅผ ์๋ํฐ ์์ ๋์ฐ๊ธฐ ์ํด css. position๊ฐ์ "absolute"๋ก ์ค์ ํด์ฃผ์๋ค.
๐ Editor / ๐ CSS / ๐ TransformControlButtons.module.css
.toolbox {
position: absolute;
top: 2rem;
left: 2rem;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
width: 2.2rem;
height: 6.3rem;
background-color: #101010;
border-radius: 3px;
z-index: 1;
}
.mode {
display: flex;
justify-content: center;
align-items: center;
width: 2rem;
height: 2rem;
border-radius: 3px;
font-size: 1.2rem;
font-weight: 800;
color: white;
}
.mode:hover {
cursor: pointer;
color: white;
background-color: #0082ff;
}
ํด๋น ์ปดํฌ๋ํธ๋ฅผ ์บ๋ฒ์ค ๋ฐ์์ ํธ์ถํ์ฌ ์ค๋ค๋ฉด,
๋ฒํผ์ ๋ณ๊ฒฝํ ๋ ๋ง๋ค mode๊ฐ ๋ณ๊ฒฝ๋๋ฉด์, ํด๋น ์ปจํธ๋กค๋ฌ๊ฐ mode๊ฐ์ ์ ๋ฌ๋ฐ์ ํด๋น ์์ฑ์ ๋ณ๊ฒฝํ ์ ์๋ค.
Scene์ ๋๋ ์ ๋, ์ ํ๋ ๊ฐ์ฒด๋ฅผ ํด์ ํ๊ณ ์ถ๋ค.
๐ Editor / ๐ EditorScene.tsx
import { useState } from "react";
import { Grid } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import styles from "./CSS/EditorScene.module.css";
import { BoxLoader } from "./BoxLoader";
import { Controller } from "./Controller";
import { TransformControllButtons } from "./TransformControllButtons";
export const EditorScene = () => {
const [selectedName, setSelectedName] = useState<string | any>(null);
const [mode, setMode] = useState("translate");
const [gridConfig, setGridConfig] = useState({
cellSize: 0.25,
/** Cell thickness, default: 0.5 */
// cellThickness: "white",
/** Cell color, default: black */
cellColor: "#afafaf",
/** Section size, default: 1 */
sectionSize: 0.5,
/** Section thickness, default: 1 */
// sectionThickness?: number
/** Section color, default: #2080ff */
sectionColor: "#afafaf",
/** Follow camera, default: false */
// followCamera: true,
/** Display the grid infinitely, default: false */
infiniteGrid: true,
/** Fade distance, default: 100 */
fadeDistance: 30,
/** Fade strength, default: 1 */
fadeStrength: 3,
});
const missedObject = () => {
setSelectedName(null);
};
return (
<div className={styles.editorFrame}>
<TransformControllButtons mode={mode} setMode={setMode} />
<Canvas
camera={{
aspect: window.innerWidth / window.innerHeight,
fov: 50,
near: 0.1,
far: 1000,
position: [3, 1, 7],
}}
onPointerMissed={missedObject}
>
<Controller mode={mode} selectedName={selectedName} />
<directionalLight
position={[2.5, 1, 3.5]}
intensity={2}
color={"white"}
/>
<BoxLoader
name={"box1"}
position={[-1, 0, 0]}
color={"red"}
setSelectedName={setSelectedName}
/>
<BoxLoader
name={"box2"}
position={[1, 0, 0]}
color={"skyblue"}
setSelectedName={setSelectedName}
/>
<Grid {...gridConfig} />
</Canvas>
</div>
);
};
onPointerMissed๋ฅผ ์ค์ ํ์ฌ ๋ง์ฐ์ค ํฌ์ธํฐ๋ฅผ ์์์ ๋, ์ ํ๋ ๊ฐ์ด null์ด ๋๋๋ก ํด์ฃผ์๋ค.
'Library > three.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[ three.js ] Scene์ Box ์ค๋ธ์ ํธ๋ฅผ ์ถ๊ฐํ๊ณ ์ปจํธ๋กคํด๋ณด์. (0) | 2024.05.19 |
---|---|
[ three.js ] 3D ๊ณต๊ฐ์ ์์ฑํ๊ณ ์ปจํธ๋กคํด๋ณด์. (0) | 2024.05.19 |
[ three.js ] three.js์ ๋ํด ์์๋ณด์. (2) | 2024.05.19 |