React/ReactThreeFiber

물리 엔진 추가하기

최 수빈 2025. 3. 14. 15:24

 

물리엔진

 

현실 세계의 물리 법칙들을 3D 공간에서 실현해 주는 엔진

→ React Three Fiber(R3F)에서 Rapier라는 물리엔진을 사용할 수 있게 해주는 React3 Rapier 라이브러리 사용

 

 

@react-three/rapier 패키지 설치

npm install @react-three/rapier

 

 

기본적인 물리 설정

  • Suspense
    비동기로 로딩되는 컴포넌트들이 모두 로딩될 때까지 기다렸다가 렌더링
  • Physics
    물리 법칙이 적용되는 공간을 정의
  • RigidBody
    실제로 물체가 물리적으로 상호작용하도록 설정
import { Suspense } from "react";
import { Physics, RigidBody } from "@react-three/rapier";

<Suspense>
  <Physics>
    <RigidBody>
      <ZooMap />
    </RigidBody>
  </Physics>
</Suspense>

 

 

RigidBody 적용

  • ZooMap(배경 맵)은 움직이지 않도록 Fixed 설정
  • Animal과 Dino는 충돌 감지를 위해 colliders="hull" 적용
  • Animal, Dino Objects 넘어지는 것을 방지 → lockRotations 속성 추가 혹은 enabledRotations속성 값 false로 설정
<Suspense>
  <Physics>
    {/* 맵을 고정된 물체로 설정 */}
    <RigidBody type="fixed" colliders="trimesh">
      <ZooMap />
    </RigidBody>

    {/* 알파카 객체 */}
    <RigidBody lockRotations colliders="hull">
      <Animal name="Alpaca" position={[-15, 20, 0]} />
    </RigidBody>

    {/* 티라노사우르스 객체 */}
    <RigidBody enabledRotations={[false, false, false]} colliders="hull">
      <Dino name="Triceratops" position={[10, 20, 0]} />
    </RigidBody>
  </Physics>
</Suspense>

 

 

물리 엔진 디버깅

<Physics debug>
  ...
</Physics>

물리 법칙 적용 확인용 디버깅 모드 활성화 후 비활성화 (성능이 저하됨)

 

 

Collider 설정

 

Collider

물체와 충돌하는 범위 설정

ball 구형 충돌 감지
cuboid 직육면체 충돌 감지
hull 실제 메쉬의 경계선을 따라 충돌 감지
trimesh 삼각형 메쉬 기반 충돌 감지 (주로 지형에 사용)

배경(Map)에는 trimesh 사용

동물(Animal, Dino)에는 hull 사용

 

 

객체 회전 방지 (lockRotations)

<RigidBody lockRotations colliders="hull">
  <Animal name="Alpaca" position={[-15, 20, 0]} />
</RigidBody>

<RigidBody enabledRotations={[false, false, false]} colliders="hull">
  <Dino name="Triceratops" position={[10, 20, 0]} />
</RigidBody>

lockRotations → 회전을 완전히 고정

enabledRotations → 특정 축에서만 회전 가능하도록 설정 ([false, false, false]는 모든 축에서 회전 금지)

 

 

그리드 헬퍼 추가

객체 위치 조정

<gridHelper rotation={[Math.PI / 2, 0, 0]} args={[500, 50]} />

 

 

최종 참고 코드

import { OrbitControls } from "@react-three/drei";
import { Animal } from "./Animal";
import { ZooMap } from "./ZooMap";
import { Dino } from "./Dino";
import { Suspense } from "react";
import { Physics, RigidBody } from "@react-three/rapier";

const START_Y = 20;

export const Environments = () => {
  return (
    <>
      {/* 그리드 헬퍼 */}
      <gridHelper rotation={[Math.PI / 2, 0, 0]} args={[500, 50]} />
      <ambientLight intensity={4} />
      <directionalLight intensity={4} position={[3, 3, 3]} />
      <OrbitControls />

      <Suspense>
        <Physics>
          {/* 맵을 고정된 물체로 설정 */}
          <RigidBody type="fixed" colliders="trimesh">
            <ZooMap />
          </RigidBody>

          {/* 알파카 객체 */}
          <RigidBody lockRotations colliders="hull">
            <Animal name="Alpaca" position={[-15, START_Y, 0]} />
          </RigidBody>

          {/* 티라노사우르스 객체 */}
          <RigidBody enabledRotations={[false, false, false]} colliders="hull">
            <Dino name="Triceratops" position={[10, START_Y, 0]} />
          </RigidBody>
        </Physics>
      </Suspense>
    </>
  );
};

 

 

물리 엔진 추가