React/ReactThreeFiber

Obj 3D & Transform

최 수빈 2025. 3. 6. 12:46

 

Obj 3D + Transform

 

Object 3D

 

모든 3D 객체의 부모 클래스

 

  • Scene, Mesh, Group, Camera 등 모든 주요 요소가 Object3D를 상속받음
    → 자동으로 생성되는 Scene도 Object3D의 인스턴스
  • position, rotation, scale 등의 변형(Tranform) 속성을 기본적으로 가짐
  • Object3D를 상속받은 모든 객체는 Transform(변환)기능 사용 가능
    → useThree 훅을 사용하면 scene을 가져와서 조작 가능

Object3

 

three.js docs

 

threejs.org

 

 

 

useThree 훅을 이용한 Scene 접근

import { Canvas, useThree } from "@react-three/fiber";

const Element = () => {
  const { scene } = useThree(); // Scene 객체 가져오기

  return <></>;
};

function App() {
  return (
    <Canvas>
      <Element />
    </Canvas>
  );
}
  • useThree 훅을 사용하여 scene, camera 등 Three.js의 주요 객체에 접근 가능
  • useThree는 Canvas 내부에서만 호출 (Canvas 외부에서 호출하면 에러 발생)

 

 

CardComponent: 카드 객체 생성

import { useLoader } from "@react-three/fiber";
import * as THREE from "three";

const CardComponent = ({ position, rotationY, rotationZ, imageUrl }) => {
  const texture = useLoader(THREE.TextureLoader, imageUrl);
  texture.colorSpace = THREE.DisplayP3ColorSpace; // P3 색공간 설정

  const materials = [
    new THREE.MeshStandardMaterial(), // 오른쪽
    new THREE.MeshStandardMaterial(), // 왼쪽
    new THREE.MeshStandardMaterial(), // 윗면
    new THREE.MeshStandardMaterial(), // 바닥면
    new THREE.MeshStandardMaterial({ map: texture }), // 앞면 (이미지 적용)
    new THREE.MeshStandardMaterial({ map: texture }), // 뒷면 (이미지 적용)
  ];

  return (
    <mesh
      position={position}
      rotation-y={THREE.MathUtils.degToRad(rotationY)}
      rotation-z={THREE.MathUtils.degToRad(rotationZ)}
      material={materials}
    >
      <boxGeometry args={[1, 1.6, 0.01]} />
    </mesh>
  );
};
  • useLoader(THREE.TextureLoader, imageUrl) : 이미지 텍스처 로딩
  • THREE.DisplayP3ColorSpace : 더 넓은 색공간 적용 (THREE.SRGBColorSpace 사용)
  • ratation-y, rotation-z : degToRad를 사용해 각도를 라디안 값으로 변환

 

cardData 배열: 카드 정보 저장

const cardData = [
  { imageUrl: "/tarrot_1.png", position: [0, -1, 0], rotationY: -10, rotationZ: 0 },
  { imageUrl: "/tarrot_2.png", position: [0.5, -1.05, -0.1], rotationY: -10, rotationZ: -10 },
  { imageUrl: "/tarrot_3.png", position: [-0.5, -1.05, 0.1], rotationY: -10, rotationZ: 10 },
  { imageUrl: "/tarrot_4.png", position: [-1, -1.15, 0.2], rotationY: -10, rotationZ: 20 },
  { imageUrl: "/tarrot_5.png", position: [1, -1.15, -0.1], rotationY: -10, rotationZ: -20 },
];

// 카드 컴포넌트 렌더링
{cardData.map((props) => (
  <CardComponent key={props.imageUrl} {...props} />
))}
  • 여러 개의 카드를 관리하기 위한 cardData 선언
  • map 함수를 사용, CardComponent를 동적으로 생성
  • key 속성으로 imageUrl을 사용, 같은 이미지를 쓰는 경우에는 id를 추가하는 게 좋음

 

카드 배치 변경

const cardData = [
  { imageUrl: "/card_1.png", position: [0, -1, 0], rotationY: -5, rotationZ: 0 },
  { imageUrl: "/card_2.png", position: [0.5, -1.05, -0.1], rotationY: -5, rotationZ: -10 },
  { imageUrl: "/card_3.png", position: [-0.5, -1.05, 0.1], rotationY: -5, rotationZ: 10 },
  { imageUrl: "/card_4.png", position: [-1, -1.15, 0.2], rotationY: -5, rotationZ: 20 },
  { imageUrl: "/card_5.png", position: [1, -1.15, -0.1], rotationY: -5, rotationZ: -20 },
];

// 컴포넌트에서 반복 렌더링
{cardData.map((props) => (
  <CardComponent key={props.imageUrl} {...props} />
))}
  • rotationY : Y축 회전 (카드가 좌우로 회전)
  • rotationZ : Z축 회전 (카드가 앞뒤로 기울어짐)

 

AxesHelper로 방향 확인

 

AxesHelper를 추가해서 좌표축을 시각적으로 확인

<axesHelper args={[5]} />
  • args[5] : 축 길이 설정 값을 키우면 더 명확하게 보임)
  • CardComponent : 내부에 추가하면 개별 카드의 회전 방향 확인 가능

 

import './App.css'
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from '@react-three/drei';

import { useLoader, useThree } from "@react-three/fiber";
import * as THREE from "three";

const CardData = [
  {
    imageUrl: "/card_1.jpg",
    position: [-1.1, -1.15, 0.4],
    rotationY: 10,
    rotationZ: 30,
  },
  {
    imageUrl: "/card_2.jpg",
    position: [-0.7, -1.05, 0.2],
    rotationY: 10,
    rotationZ: 10,
  },
  {
    imageUrl: "/card_3.jpg",
    position: [0, -1.05, 0],
    rotationY: 0,
    rotationZ: 0,
  },
  {
    imageUrl: "/card_4.jpg",
    position: [0.7, -1.15, -0.2],
    rotationY: -10,
    rotationZ: -10,
  },
  {
    imageUrl: "/card_5.jpg",
    position: [1.3, -1.30, -0.4],
    rotationY: -10,
    rotationZ: -30,
  },
]

const CardComponent = ({ position, rotationY, rotationZ, imageUrl }) => {
  const { scene } = useThree();
  const texture = useLoader(THREE.TextureLoader, imageUrl)
  texture.colorSpace = THREE.SRGBColorSpace;

  scene.rotation.set(0, 20, 0);

  const materials = [
    new THREE.MeshStandardMaterial(), // 오른쪽
    new THREE.MeshStandardMaterial(), // 왼쪽
    new THREE.MeshStandardMaterial(), // 윗면
    new THREE.MeshStandardMaterial(), // 바닥면
    new THREE.MeshStandardMaterial({ map: texture }), // 앞면 (이미지 적용)
    new THREE.MeshStandardMaterial({ map: texture }), // 뒷면 (이미지 적용)
  ];

  return (
    <mesh
      position={position}
      rotation-y={THREE.MathUtils.degToRad(rotationY)}
      rotation-z={THREE.MathUtils.degToRad(rotationZ)}
      material={materials}
    >
      <axesHelper />
      <boxGeometry args={[1, 1.6, 0.02]} />
    </mesh>
  )
}

function App() {
  return (
    <Canvas>
      <OrbitControls />
      <ambientLight intensity={1} /> {/* ambientLight : 환경광 (모든 방향에서 균일하게 씌워지는 빛)-모든 오브젝트가 동일한 강도로 조명을 받는 빛 */}
      <directionalLight intensity={3} position={[3, 2, 5]} />
      {
        CardData.map((props) => {
          return <CardComponent key={props.imageUrl} {...props} />

        })
      }
    </Canvas>
  );
}

export default App;
  • position, rotation 조절하여 카드 배치 변경 (scale도 조절 가능)
  • 카드 여러 개를 추가하여 호(arc) 형태로 배치

 

CardComponent

 

 

 

 

'React > ReactThreeFiber' 카테고리의 다른 글

Light & Shadow  (0) 2025.03.07
Material & Texture  (1) 2025.03.05
Geometry  (0) 2025.03.04
GUI Controller  (2) 2025.03.03
3D 개발을 도와주는 도구들 - OrbitControls, AxesHelper, GridHelper  (0) 2025.03.02