Front-end/Threejs

React Three.js 컨트롤러, 빛, 그림자, 스탯 추가

아지송아지 2022. 3. 22. 14:55

안녕하세요!

오늘은 threejs를 다뤄보겠습니다.

포폴과 가볍게 취미 생활용으로 만들 예정이라 다른 글들에 비해 가볍습니다!

three.js 관련 글을 쓸 때가 부담 없고 가장 재밌는것 같습니다 :)

 

 

이전 글에서 씬과 오브젝트를 만들었는데요.

아마 이 상태일겁니다.

이제 빛, 컨트롤러, 그림자를 추가해보겠습니다.

 

Light


빛이 있어야 도형의 색을 볼 수 있고 그림자도 볼 수 있습니다.

저는 Canvas 안에 LightController라는 컴포넌트를 추가 후 light 관련 코드들을 다 넣었습니다.

<Canvas>
    <LightController />
    .
    .
    .
    <PlaneModel />
    <ReactModel />
</Canvas>
// lightController.jsx
import React from 'react';

const LightController = (props) => (
    <>
        <directionalLight 
            castShadow
            position={[0, 10, 0]}
            intensity={4}
            shadow-mapSize-width={1024}
            shadow-mapSize-height={1024}
            shadow-camera-far={50}
            shadow-camera-left={-100}
            shadow-camera-right={100}
            shadow-camera-top={100}
            shadow-camera-bottom={-100}
        />
        <ambientLight intensity={0.4}/>
        <pointLight position={[-10, 0, -20]} intensity={0.5} />
        <pointLight position={[0, -10, 0]} intensity={1.5} />        
    </>
);

export default LightController;

light의 종류들은 공식 문서에서 확인하시면 됩니다.

공식 문서입니다.

 

제가 사용한 빛들을 소개해 드리겠습니다.

1. directionalLight

태양광이라고 생각하시면 편합니다.

그림자를 넣을 예정이기 때문에 shadow 속성들을 주었습니다.

 

2. ambientLight

모든 개체들에게 전체적으로 빛을 줍니다.

빛의 방향이 없기 때문에 그림자가 없습니다. 저는 톤 보정을 할 때도 이 빛을 활용합니다.

 

3. pointLight

동그란 광원이 있다고 생각하시면 됩니다.

 

position은 x, y, z 값이며, intensity는 빛의 세기입니다.

유니티나 3D 프로그램을 해보셨으면 아마 쉽게 이해가 가실 겁니다.

 

 

 

Controls


 

<Canvas>
    <LightController />
    <OrbitControls />

    <PlaneModel />
    <ReactModel />
</Canvas>

저는 OrbitControls 를 자주 사용했습니다.

마우스를 통해 줌인, 줌아웃, 위치 이동 모든게 가능합니다. 자율성이 좋기 때문에 개발을 할때 편리합니다.

이외에도 공식 문서에 여러 컨트롤러가 나와있습니다.

공식 문서입니다.

 

 

 

Shadow


그림자입니다.

저는 아래와 같은 버전을 사용하고 있으며 버전마다 그림자를 추가하는 방식이 조금씩 다를 수도 있습니다.

"three": "^0.138.3",
"@react-three/drei": "^8.16.7",
"@react-three/fiber": "^7.0.26",

 

1. Canvas

우선 <Canvas>에 shadows 속성을 주어야합니다. 다른 버전은 shadowMap을 사용합니다.

<Canvas
    shadows
    colorManagement
    camera={{position:[0, 0, 40], fov:80 }}
>
	...
</Canvas>

 

2. castShadow

그림자를 주고자 하는 light와 mesh에 castShadow 속성을 줍니다.

<mesh position={[0, 0, 0]} castShadow>
    <torusKnotBufferGeometry
        attach='geometry'
        args={[10, 1, 300, 20, 6, 10]}
    />
    <meshPhysicalMaterial
        attach='material'
        color={"#61DBFB"}
    />
</mesh>
<directionalLight 
    castShadow
    position={[0, 10, 0]}
    intensity={4}
    ... />

 

3. receiveShadow

그림자를 받는 곳(바닥)에는 receiveShadow 속성을 줍니다.

<mesh
    rotation={[-Math.PI / 2, 0, 0]}
    position={[0, -20, 0]}
    receiveShadow>
    <planeBufferGeometry attach='geometry' args={[100, 100]} />
    <shadowMaterial attach='material' opacity={0.3} />
</mesh>

 

이제 빛이 생겼을겁니다.

쫌 더 부드러운 그림자를 원하시면 @react-three/drie의 softShadows를 사용하시면 됩니다.

 

...
import { OrbitControls, softShadows } from '@react-three/drei';
...

softShadows();

const Main = ({}) =>
    return(
        <Container>
            <Canvas
            ...

좌측이 softShadows 사용 전

우측이 softShadows 사용 후입니다. 

 

스탯


스탯은 현재 상태를 보여줍니다.

<Canvas
    shadows
    colorManagement
    camera={{position:[0, 0, 40], fov:80 }}
>
    <LightController />
    <OrbitControls />
    <Stats />

    <PlaneModel />
    <ReactModel />
</Canvas>

Canvas안에 <Stats />를 추가해 주시면 화면 좌측 상단에 현재 상태가 나옵니다.

클릭하면 다른 상태도 볼 수 있습니다.

 

 

최종 화면


최종 화면입니다.

다음번에는 애니메이션과 obj파일을 추가해보겠습니다!