이번 포스트는 React Three fiber(R3F)로 배우는 인터렉티브 3D 웹 개발을 수강한 뒤 정리하는 포스트입니다.
객체를 렌더하기 위해서는 mesh가 필요하다.
mesh는 geometry와 material이란 property로 이루어져 있다.
geometry는 HTML, material은 CSS로 비유 가능하다.
R3F는 Three.js의 개념을 기본적으로 따르는데, React에서 렌더하는 방식에서 차이가 나다보니 같은 객체를 렌더하더라도 아래와 같이 코드베이스의 차이가 난다.
// Three.js
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
// R3F
export default function ThreeElement() {
return (
<mesh>
<boxGeometry />
<meshStandardMaterial color="white" />
</mesh>
);
}
객체를 공간에 두었다면, 이를 렌더할 frame이 필요하다.
그 frame을 어디서, 얼마만큼 둘 건지 정의하는 추상적인 개념이 바로 camera이다.
ThreeJS에는 총 다섯 가지 카메라가 있는데 이 중에서 보편적으로 쓰이는 것은 아래 두 가지이다.
Renderer는 ThreeJS를 React에 렌더하기 위해 필요한 개념이다.
이는 ThreeJS의 Scene을 Canvas에 그리면서 동시에 React의 상태, hook, prop, event를 이용한다.
대표적으로 쓰는 훅으로 useThree()
, useFrame()
이 있고,
주의할 점은 Canvas 태그 하위에서만 쓸 수 있다.
This hook gives you access to the state model which contains the default renderer, the scene, your camera, and so on. It also gives you the current size of the canvas in screen and viewport coordinates.
.
기본 renderer, scene, camera 등을 포함한 상태 모델에 접근하는 훅이다. 현재 스크린과 viewport 좌표계에서의 canvas 크기도 전달 가능하다.
const { size, gl, scene, camera } = useThree();
This hook allows you to execute code on every rendered frame, like running effects, updating controls, and so on. You receive the state (same as
useThree
) and a clock delta. Your callback function will be invoked just before a frame is rendered. When the component unmounts it is unsubscribed automatically from the render-loop.
.
이 훅은 실행 효과, 제어 업데이트 등 매 렌더 프레임마다 실행된다. useThree와 같은 상태와 시간 delta를 갖는다. 콜백 함수는 프레임이 렌더되기 전에 호출된다.
//...
const boxRef = useRef<THREE.Mesh>(null);
useFrame((state, delta) => {
boxRef.current.rotation.x += delta;
boxRef.current.position.y -= 0.01;
boxRef.current.scale.z += 0.01;
});
return (
<>
<mesh
ref={boxRef}
>
<boxGeometry />
<meshStandardMaterial color={boxColor.color} />
</mesh>
</>
);
//...
@react-three/drei
에 있는 기능으로, scene와 인터렉티브하게 작용하도록 하기 위해 필요한 도구들 중 scene의 기준(축, grid)에 관한 것들이다.OrbitControls
scene의 기준인 축에 의해 움직일 수 있는 범위를 정할 수 있는 control
<OrbitControls
minAzimuthAngle={-Math.PI / 4}
maxAzimuthAngle={Math.PI / 4}
minPolarAngle={Math.PI / 6}
maxPolarAngle={Math.PI - Math.PI / 6}
/>
axesHelper
x, y, z 축 가이드라인을 보여주는 helper
<axesHelper args={[5]} />
args={[축 길이]}
gridHelper
grid인 바닥에 규격에 맞추어 보여주는 helper
<gridHelper args={[20, 20, 0xff0000, 'teal']} />
args={[grid 한 변 길이, grid 한 변 segment 갯수, grid center 색, grid 색]}
threeJS에서 단위는 기본적으로 meter이다!
ex.<gridHelper args={[20, 20, 0xff0000, 'teal']} />
에서 grid 한 변 길이는 20m가 되고, 한 변의 segment 갯수가 20개이니, 한 segment의 한 변 길이는 1m가 된다.
다음과 같이 노란색 테두리로 감싸져 있는 부분이 leva로 생성한 GUI component이다.
해당 스크린샷의 예시 코드는 아래와 같다.
drei, leva와 같은 라이브러리 의존성이 높은 것 같다. drei에서도 React 18이면 사용 시 console error를 뱉을 것이라고도 얘기한다.
아직 불안정한 오픈 소스를 쓰는 게 과연 괜찮을까 싶으면서도 이렇게 한 번 세게 부딪혀보면서 이해도를 높이면 언젠가 직접 컨트리뷰트도 할 수 있지 않을까 싶다.
그나저나 지금은 기본적인 정육면체, 구로 하지만 나중에 직접 렌더하고 싶은 디자인이 있으면 Maya나 3D Max로 직접 그려야 하나 싶다. 궁금해!