Library/three.js

[ three.js ] Scene(3D ๊ณต๊ฐ„)์„ ์ƒ์„ฑํ•˜๊ณ  ์ปจํŠธ๋กคํ•ด๋ณด์ž.

ma.caron_g 2024. 5. 19. 18:29

 

์ž‘์„ฑ์ž๊ฐ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์จ์™€์„œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์— ๋Œ€ํ•ด ๋ฏธ์ˆ™ํ•˜์—ฌ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์— ๋ฏธํกํ•œ ๋ถ€๋ถ„์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“„ fiber / drei

๋ฆฌ์•กํŠธ์—์„œ three.js๋ฅผ ์ข€ ๋” ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž…๋‹ˆ๋‹ค.

 

์ž‘์„ฑ์ž๋Š” ์ด ๋‘๊ฐœ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒŒ์‹œ๊ธ€์„ ์ž‘์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿ™‚

 

https://docs.pmnd.rs/react-three-fiber/getting-started/introduction

 

React Three Fiber Documentation

React-three-fiber is a React renderer for three.js

docs.pmnd.rs

 

https://github.com/pmndrs/drei

 

GitHub - pmndrs/drei: ๐Ÿฅ‰ useful helpers for react-three-fiber

๐Ÿฅ‰ useful helpers for react-three-fiber. Contribute to pmndrs/drei development by creating an account on GitHub.

github.com

 

โฌ‡๏ธ install

๋ฆฌ์•กํŠธ(ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ) ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

$ npx create-react-app <FolderName> --template typescript

 

์ดํ›„, three.js๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

# three.js ์„ค์น˜
$ npm install --save three

# fiber ์„ค์น˜
$ npm install three @types/three @react-three/fiber

# drei ์„ค์น˜
$ npm install @react-three/drei

 

๐ŸŒ Scene ์ƒ์„ฑ

3D ๊ณต๊ฐ„์„ ํŽธ์ง‘ํ•˜๊ธฐ ์œ„ํ•œ Scene์„ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

 

์ž‘์„ฑ์ž๋Š” ํ”„๋กœ์ ํŠธ์— ๐Ÿ“Editor๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํ•ด๋‹น ํด๋” ์•ˆ์— ๐Ÿ“„ EditorScene.tsx๋ฅผ ์ƒ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

๐ŸŒ Scene

๐Ÿ“ Editor/ ๐Ÿ“„ EditorScene.tsx

import { useState } from "react";
import { Canvas } from "@react-three/fiber";
import styles from "./CSS/EditorScene.module.css";

export const EditorScene = () => {

  return (
    <div>
      <Canvas>
      </Canvas>
    </div>
  );
};

 

ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๐Ÿ“„ App.js์— ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

 

$ npm run start

 

๊ทธ๋ฆฌ๊ณ  ํ”„๋กœ์ ํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด

ํ™”๋ฉด์ด ๋‚˜ํƒ€๋‚˜๋Š”๋ฐ ์•„๋ฌด๊ฒƒ๋„ ๋ณด์ด์งˆ ์•Š๋Š”๋‹ค.

 

์ข€ ๋” 3D ๊ณต๊ฐ„์˜ ๋А๋‚Œ์„ ๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์ž.

 

๋ฐฐ๊ฒฝ์ƒ‰์„ ๋ณ€๊ฒฝํ•˜๊ณ  ๊ทธ๋ฆฌ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณด์ž.

์ด๋•Œ, Scene์€ ๋ถ€๋ชจ ์ปจํ…Œ์ด๋„ˆ์˜ ๋„“์ด๋ฅผ ๊ทธ๋Œ€๋กœ ์ƒ์† ๋ฐ›๋Š”๋‹ค.

 

๐Ÿ“ Editor / ๐Ÿ“ CSS / ๐Ÿ“„ EditorScene.module.css

.editorFrame {
  width: 100vw;
  height: 100vh;
  background-color: #2e2e2e;
}

 

โžฐ Grid

๐Ÿ“ 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";

export const EditorScene = () => {

  return (
    <div className={styles.editorFrame}>
      <Canvas>
        <Grid/>
      </Canvas>
    </div>
  );
};

 

๋‹ค์‹œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒˆ๋กœ๊ณ ์นจ ํ•œ๋‹ค๋ฉด,

 

 

๐ŸŽ‰์งœ์ž”~

์•„๋ฌด๊ฒƒ๋„ ์•ˆ ๋ณด์ธ๋‹ค.

 

์‚ฌ์‹ค์€ ์ถ”๊ฐ€๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์ด๋ฉฐ, ํ˜„์žฌ ๊ธฐ๋ณธ ๊ฐ๋„๊ฐ€ ์ •๋ฉด์ด๋ผ์„œ ํ•ด๋‹น ๊ทธ๋ฆฌ๋“œ ๋ผ์ธ์ด ์•ˆ ๋ณด์ด๋Š” ๊ฒƒ์ด๋‹ค.

 

Scene์—์„œ ์นด๋ฉ”๋ผ์˜ ๊ธฐ๋ณธ ์œ„์น˜๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์ฃผ์ž.

 

๐ŸŽฅ Camera

๐Ÿ“ 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";

export const EditorScene = () => {

  return (
    <div className={styles.editorFrame}>
      <Canvas
        camera={{
          aspect: 1280 / 720,
          fov: 50,
          near: 0.1,
          far: 1000,
          position: [2.5, 1.2, 3.5],
        }}
      >
        <Grid />
      </Canvas>
    </div>
  );
};

 

 

๊ทธ๋ฆฌ๋“œ๊ฐ€ ๋‚˜ํƒ€๋‚ฌ์ง€๋งŒ ๋งŽ์ด ์•„์‰ฝ๋‹ค.

 

three-drei์— ๋“ค์–ด๊ฐ€๋ฉด ๊ทธ๋ฆฌ๋“œ์˜ ๊ธฐ๋ณธ ์„ค์ •๊ฐ’์ด ๋‚˜์˜จ๋‹ค.

์„ค์ •ํ•ด์ฃผ์ž.

 

๐Ÿ“ 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";

export const EditorScene = () => {

  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,
  });
  
  return (
    <div className={styles.editorFrame}>
      <Canvas
        camera={{
          aspect: 1280 / 720,
          fov: 50,
          near: 0.1,
          far: 1000,
          position: [2.5, 1.2, 3.5],
        }}
      >
        <Grid {...gridConfig} />
      </Canvas>
    </div>
  );
};

 

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด,

 

 

์ด์ œ ๋ญ”๊ฐ€ 3D ๊ณต๊ฐ„ ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ๐Ÿ‘๐Ÿป๐Ÿ‘๐Ÿป๐Ÿ‘๐Ÿป๐Ÿ‘๐Ÿป๐Ÿ‘๐Ÿป

 

๋งˆ์šฐ์Šค๋ฅผ ๋“œ๋ž˜๊ทธํ•ด๋„ ํ•ด๋‹น ๊ณต๊ฐ„์„ ๋‘˜๋Ÿฌ๋ณผ ์ˆ˜๊ฐ€ ์—†๋‹ค.

Controller๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ณต๊ฐ„์„ ์ปจํŠธ๋กคํ•ด๋ณด์ž.

 

๐Ÿ•น๏ธ OrbitControls

๐Ÿ“ Editor / ๐Ÿ“„ EditorScene.tsx

import { useState } from "react";
import { Grid, OrbitControls } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import styles from "./CSS/EditorScene.module.css";

export const EditorScene = () => {

  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,
  });
  
  return (
    <div className={styles.editorFrame}>
      <Canvas
        camera={{
          aspect: 1280 / 720,
          fov: 50,
          near: 0.1,
          far: 1000,
          position: [2.5, 1, 3.5],
        }}
      >
        <OrbitControls/>
        <Grid {...gridConfig} />
      </Canvas>
    </div>
  );
};

 

๊ทธ๋Ÿผ ์ด์ œ ๊ธฐ๋ณธ ์นด๋ฉ”๋ผ ๊ฐ๋„๋ฅผ ๋งˆ์šฐ์Šค๋กœ ์กฐ์ข…ํ•  ์ˆ˜ ์žˆ๋‹ค.