[웹그래픽] - THREE.js로 그래픽 구현하기

TADAIMA TADAIMA·2024년 1월 19일

웹그래픽

목록 보기
2/5
post-thumbnail

Intro

실무에서 진행했던 3D그래픽 프로젝트를 기반으로 설명하고자 합니다.
언어는 자바스크립트이고 주로 사용한 그래픽 라이브러리는 THREE.js이며 애니메이션 구현을 위해 anime.js라이브러리도 사용했습니다.

Step.1 - 렌더러 설정

캔버스에 그래픽을 출력하기 위해서 가장 먼저 그래픽을 '렌더링'할 렌더러가 필요합니다.

<canvas id="webgl-container"></canvas>
<script>
    const divContainerId = "webgl-container"
    const divContainer = document.getElementById(divContainerId)

    // 렌더러 생성
    const renderer = new THREE.WebGLRenderer({ powerPreference: "high-performance", antialias: true, alpha:true, stencil: false, depth: false })
    
    // 렌더러 설정
    renderer.setPixelRatio(window.devicePixelRatio)
    renderer.autoClear = false
    renderer.debug.checkShaderErrors = false
    renderer.toneMappingExposure = 1;
    renderer.toneMapping = THREE.ReinhardToneMapping;
    renderer.setClearColor(0xffffff,0)
    renderer.setSize(divContainer.clientWidth, divContainer.clientHeight)
    renderer.gammaInput = true
    renderer.gammaOutput = true
    renderer.toneMappingExposure = Math.pow( 0.9, 4.0 )
    
    //렌더러를 html에 붙이기
    divContainer.appendChild(renderer.domElement)
</script>

Step.2 - 카메라와 빛 설정

눈이 없으면 물체를 볼 수 없는 것 처럼 카메라가 있어야 각종 물건들(오브젝트)를 화면에 담을 수 있습니다. 그리고 각종 물건들을 담아야할 바구니(scene 씬)도 있어야합니다. 마지막으로 빛이 없으면 물체를 볼 수 없기 때문에 빛 또한 기본 설정을 해줘야합니다.

scene은 모든 렌더링할 객체들, 라이트, 카메라 등 3D 장면을 구성하는 모든 요소들의 부모와 같은 역할을 합니다.
camera는 원근법을 적용한 카메라를 나타냅니다.

<script>
    const scene = new THREE.Scene()
    const camera = new THREE.PerspectiveCamera(60, window.innerWidth/ window.innerHeight, 1, 10000);
    camera.position.set(0, 0, 10);
    const light = new THREE.DirectionalLight(0xffffff, 0.75);
    light.position.setScalar(100);
    scene.add(light);
    scene.add(new THREE.AmbientLight(0xffffff, 2));
</script>

Step.3 - 물체 생성

환경이 설정되었으니 보고자 하는 물체를 씬에 추가합니다. 여기서는 가장 간단한 예제로 정육면체(상자)를 추가하겠습니다.

geometry(기하구조)는 객체의 형태혹은 구조입니다.
BoxGeometry는 박스모양(육면체)의 구조입니다.
material(재질)은 객체의 표면 처리 방식입니다 (빛 반사, 재질, 색상 등).
MeshLambertMaterial은 물체의 표면에 램버트 반사 모델을 사용하여 렌더링하는 재질입니다.
mesh(3D객체)는 기하구조와 재질이 결합한 완전한 3D객체입니다.

<script>
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({ color: 0xffcc00 });
const mesh = new THREE.Mesh(geometry, material);

scene.add(mesh);
</script>

Step.4 - 애니메이션 구현

객체를 움직인다는 개념보다는 객체의 좌표가 변한다는 개념으로 접근하는 게 이해하기 쉽습니다.
자바스크립트 기능 requestAnimationFramer펑션을 통해 Step.3에서 생성한 mesh의 좌표를 움직입니다.
mesh의 좌표가 변화가 생겼고, 이는 곧 mesh를 담고있는 scene에도 변화가 생긴 것입니다.
변화가 생긴 scene과 camera를 한 번 더 '렌더링'합니다.
왜냐하면 renderer.render()함수는 장면을 사진처럼 찍어내는 기능이기 때문입니다.
즉 객체를 x,y축으로 0.01씩 회전시키고 사진으로 찍어서 모니터에 보여주는 기능을 빠르게 반복하는 개념이 THREE.js 웹그래픽의 기본 애니메이션 구현방법입니다.

<script>
function animate() {
  requestAnimationFrame(animate);

  mesh.rotation.x += 0.01;
  mesh.rotation.y += 0.01;

  renderer.render(scene, camera);
}
</script>

Step.5 - 마무리 및 실무에서

이번 예시 설명에서는 THREE.js의 가장 기초적인 기능들을 예시로 소개해보았습니다. 실제로 진행한 프로젝트에서는 더 복잡하고 많은 설계가 들어간 객체와 환경이 조성되어있습니다. 3D모델러가 준 3D파일.glb를 scene에 추가하고, 해당 파일에 담긴 애니메이션 정보를 불러와서 사용자와 상호작용하게끔 설계도 했으며 아래의 내용은 해당 모델을 객체로 불러오는 기능에 대한 내용중 일부입니다.

<script>
    const cn7Url = "../model/effect/model.glb"
    const cn7EffAwait = await loader.loadAsync(cn7Url)
    const cn7Eff = cn7EffAwait.scene
    cn7Eff.position.set(0.02,0,-1)
    cn7Eff.scale.set(40,40,1)
    cn7Eff.traverse( obj => {
        if(obj.isMesh){ obj.material.transparent = true }
    })
    const cn7Mixer = new THREE.AnimationMixer(cn7Eff)
    const cn7Mixer_action = cn7Mixer.clipAction(cn7EffAwait.animations[0])
    cn7Mixer_action.setLoop( THREE.LoopOnce );
    cn7Mixer_action.clampWhenFinished = true
    cn7Mixer_action.setDuration(4.5)
    cn7Mixer_action.play()
    scene.add(starObjs)
    scene.add(cn7Eff)
</script>

cn7Eff 객체의 위치(position.set)설정과 크기(scale.set)설정, 그리고 모델을 이루고있는 mesh들의 속성 설정, 해당 모델파일에 담긴 애니메이션 정보 로드, 설정, 그리고 세팅을 진행하고 다른 곳에서 해당 정보를 토대로 추가개발을 진행했습니다. 자바스크립트에 대한 독학을 어느정도 마치고 THREE.js라는 라이브러리에 대한 공부를 하고있을 무렵에 타이밍이 좋게 맞아떨어져서 이 프로젝트에 투입됐습니다만 역시 실무에서 사용하기 위해서는 더 많은 공부의 필요성을 느꼈습니다. 또한 기존에 알던 데이터의 흐름과는 다른 영역인 컴퓨터그래픽 영역을 사용할 수 있었던 점에서는 매우 재밌던 경험이 됐습니다.

profile
응급병동

0개의 댓글