JavaScript/Three.js

Three.js 란?

밤토리세상 2020. 10. 9. 22:16

Three.js 는 웹페이지에서 3D객체를 쉽게 렌더링 할수있게 도와주는 라이브러리입니다.

 

WebGL을 사용하여 3D를 구현하는데 자세한 구조설명등은 생략하고 실질적으로 사용하는 내용으로만 

작성하여 나가겠습니다.

좀더 자세한 내용을 원하시면

threejs.org/

 

three.js – JavaScript 3D library

 

threejs.org

위 공식 사이트에서 찾아보실수 있습니다

 

현재 라이브러리는 모듈로 불러와서 사용하는게 대부분인듯 합니다

하지만 IE에서도 동작을 해야한다면 모듈을 사용할수 없겠죠

 

그래서 모듈이 아닌 라이브러리를 사용하겠습니다

 

우선 Three.js 를 불러옵니다

 

<script src="js/three.js-master/build/three.js"></script>

 

그리고 HTML에 캔버스를 만들 Container 를 만들겠습니다

 

<body>
    <div id="container"></div>
</body>

 

이제 Script를 작성하여 Canvas 를 Container에 추가해보겠습니다.

const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);

var container = document.getElementById('container');
var canvas = renderer.domElement;
container.appendChild(renderer.domElement);

const renderer = new THREE.WebGLRenderer({antialias:true});

 

renderer를 생성합니다. new THREE.WebGLRenderer(); 만 호출하여도 되지만 

안티 에일리어싱 을 사용할 것이기 때문에 옵션값을 추가했습니다.

 

setPixelRatio , setSize 로 픽셀비율과 사이즈를 정하는데 저는 전체화면에 띄우기위해

윈도우의 사이즈와 픽셀비율을 불러와 set 하였습니다.

 

그리고 container 를 불러와 renderer 에서 뽑은 Canvas를 caonrainer의 자식으로 추가합니다.

 

 

3D객체를 그릴 판을 만들었으니 이제 그 판을 볼 카메라를 추가해 줍니다.

const fov = 75;
const aspect =  window.innerWidth / window.innerHeight;
const near = 0.1;
const far = 500;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

fov 는 카메라 화각, aspect 는 화면비율, near 는 카메라 시작점, far 는 카메라 끝 점 입니다.

 

기본으로 생성된 카메라의 위치는 0,0,0 이므로 생성한 객체를 보기위해 살짝 이동시켜보겠습니다.

camera.position.z = 2;

 

이제 정육면체를 만들어서 넣어보겠습니다.

캔버스에 객체를 넣기위해 Scene에 추가해야합니다. 먼저 씬을 만들겠습니다.

그리고 정육면체를 만들어서 해당 씬에 추가를 해보겠습니다.

const scene = new THREE.Scene();

const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

const material = new THREE.MeshBasicMaterial({color: 0x44aa88});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

renderer.render(scene, camera);

new THREE.Scene(); 

씬을 생성하고 박스의 크기를 설정하는 

new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

사이즈는 1 , 1 , 1 로 정육면체의 정보입니다.

 

그리고 정육면체의 재질 정보를 넣어줍니다.

new THREE.MeshBasicMaterial({color: 0x44aa88});

컬러값은 CSS의 RGB의 코드와 동일하게 사용할수있습니다.

 

이제 크기와 재질의 정보를 만들었으니 실질적인 상자를 생성합니다.

new THREE.Mesh(geometry, material);

자 이제 생성된 상자를 씬에 추가하고 renderer.render(scene, camera); 로 랜더링을 해줍니다

 

캔버스에 해당 씬을 해당 카메라로 랜더링 하는것입니다.

 

위 소스까지만 적용하면 3D인지 확인이 안되니 애니메이션을 통하여 돌아가도록 해보겠습니다.

function render(time) {
    time *= 0.001;  // convert time to seconds

    cube.rotation.x = time;
    cube.rotation.y = time;

    renderer.render(scene, camera);

    requestAnimationFrame(render);
}
requestAnimationFrame(render);

 

애니메이션을 만들기위해 requestAnimationFrame 함수를 통하여 루프 안에서 랜더링을 해줍니다.

 

하지만 광원이 없기때문에 음영이 보이질 않아서 3D같지가 않습니다

이제 광원도 추가하고 재질도 반사가 가능한것으로 바꾸어서 추가해보겠습니다

MeshBasicMaterial 을 MeshPhongMaterial 으로 바꾸어 주고 직사광 하나를 추가하겠습니다.

 

{
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);
}

광원의 색은 흰색 쌔기는 1 로

new THREE.DirectionalLight() 를 호출하여 생성하고 광원의 위치를 왼쪽으로 1 높이 2 위로 4 올린것입니다.

X, Y, Z 순인데 좌우, 위아래, 앞뒤 가 적용됩니다.

 

이제 광원과 재질의 빛 반사,음영이 생겨서 3D로 보이게 되었습니다.

 

아래는 전체 소스입니다.

function main3D(){
    const renderer = new THREE.WebGLRenderer({antialias:true});
	renderer.setSize(200, 200);

	var container = document.getElementById('container3d');
	var canvas = renderer.domElement;
	container.appendChild(renderer.domElement);
  	
  	const fov = 75;
	const aspect =  1;
	const near = 0.1;
	const far = 5;
	const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  	camera.position.z = 2;
  
  	const scene = new THREE.Scene();

	const boxWidth = 1;
	const boxHeight = 1;
	const boxDepth = 1;
	const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

	const material = new THREE.MeshPhongMaterial({color: 0x44aa88});
	const cube = new THREE.Mesh(geometry, material);
	scene.add(cube);
    
    {
        const color = 0xFFFFFF;
        const intensity = 1;
        const light = new THREE.DirectionalLight(color, intensity);
        light.position.set(-1, 2, 4);
        scene.add(light);
    }
  
  	function render(time) {
      time *= 0.001;  // convert time to seconds

      cube.rotation.x = time;
      cube.rotation.y = time;

      renderer.render(scene, camera);
      requestAnimationFrame(render);
    }
    requestAnimationFrame(render);
}
  
  main3D();

아래 보여지는 사이즈를 맞추기위해 좌우 200px 로 맞추고 컨테이너의 id 도 바꾸었습니다.

캔버스의 비율은 1:1 이므로 카메라의 aspect를 1로 변경하였습니다.