본문 바로가기
코딩과 알고리즘

3차원 웹, 마우스로 움직이다, 캔버스와 함께하는 자바스크립트, 16번째 시간

3차원 웹 기술, 캔버스와 자바스크립트 "마우스로 움직이다" 시간입니다 :)

오늘은 우선 예제 영상을 보도록 하실까요?

https://youtu.be/2ECIpZvg7Og

허공에 3개의 정육면체가 있으며, 마우스로 클릭하여 드래그하니 3개의 정육면체가 동시에 돌아갑니다.

마우스 휠을 위로 돌리면, 확대되고 아래로 돌리면 축소하며,

마우스 우클릭하여 드래그할 경우 화면이 상하 좌우로 그대로 이동합니다.

마우스 우클릭이 추가됨으로서 마치 가상공간을 마음껏 들여다 보는 느낌인데요.

꽤 복잡해 보일듯 하지만, 사실 이 부분은 이미 만들어져 있는 멋진 기능이 마련되어 있기 때문에 그냥 가져다가 사용하면 됩니다.

이를 위해서 먼저 스크립트 라이브러리를 추가해 주어야 하는데요.

지난 소스의 여기 아래 부분에

<script src="https://threejs.org/build/three.min.js"></script>
       :

이 부분을 추가해 주시면 됩니다.

<script src="http://fenixrepo.fao.org/cdn/js/threejs/4.4/OrbitControls.js"></script>

그리고 마우스로 클릭하면 상자가 돌아가는 부분은 과감히 삭제합니다.

이 부분 말이지요 :)

function onDocumentMouseDown(event)
{
	event.preventDefault();
	var mouse = new THREE.Vector2(
		( event.clientX / window.innerWidth ) * 2 - 1,
		- ( event.clientY / window.innerHeight ) * 2 + 1
	);
	var raycaster = new THREE.Raycaster();
	raycaster.setFromCamera( mouse, camera );
	var intersects = raycaster.intersectObjects( scene.children );
	if(intersects.length>0)
	{
		if(intersects[0].object.name=='Box1')
		{
			speed+=0.05;
		}
	}
}

document.addEventListener('mousedown', onDocumentMouseDown, false);

아울러 회전속도에 따라 작동하는 부분 또한 삭제합니다.

var speed=0;
if(speed>0){
	mesh.rotation.y +=speed;
	speed-=0.001;
}

마지막으로 마우스와 카메라 제어를 연결하는 2줄의 코드를 추가해주면 되는데요.

아래 소스로 된 부분 아랫 쪽에,

camera.rotation.y = 35 * ( Math.PI / 180 );
          :

다음과 같은 소스를 추가합니다.

var controls = new THREE.OrbitControls (camera, renderer.domElement);
controls.update();

이렇게 완성된 소스는 아래와 같습니다.

<html>
	<head>
		<title>3차원 캔바스 예제 1</title>
		<style>
			body { margin: 0; }
			canvas { width: 100%; height: 100% }
		</style>
	</head>
	<body>
		<script src="https://threejs.org/build/three.min.js"></script>
		<script src="http://fenixrepo.fao.org/cdn/js/threejs/4.4/OrbitControls.js"></script>
		<script>

			// ==========================
			// 초기화 부분 시작 ( 이 부분은 문서에서 한번만 수행되면 됩니다 )
			// ==========================
			// 3차원 세계
			var scene = new THREE.Scene();

			// 카메라 ( 카메라 수직 시야 각도, 가로세로 종횡비율, 시야거리 시작지점, 시야거리 끝지점
			var camera = new THREE.PerspectiveCamera( 45, window.innerWidth/window.innerHeight, 0.1, 1000 );

			// 렌더러 정의 및 크기 지정, 문서에 추가하기
			var renderer = new THREE.WebGLRenderer( { antialias: true, preserveDrawingBuffer: true } );
			renderer.setSize( window.innerWidth, window.innerHeight );
			
			document.body.appendChild( renderer.domElement );

			// 빛을 생성해서
			var light1 = new THREE.PointLight( 0xffffff, 1, 100 );
			// 위치를 적당한 지점에 놓고
			light1.position.set( 5, 5, 5 );
			// 장면에 추가합니다.
			scene.add( light1 );

			// 빛을 또한 생성해서
			var light2 = new THREE.PointLight( 0xffFFFF, 1, 100 );
			// 위치를 적당한 지점에 놓고
			light2.position.set( 7, -5, 6 );
			// 장면에 추가합니다.
			scene.add( light2 );

			// 빛을 또한 생성해서
			var light3 = new THREE.PointLight( 0xffffff, 1, 100 );
			// 위치를 적당한 지점에 놓고
			light3.position.set( -7, 3, 3 );
			// 장면에 추가합니다.
			scene.add( light3 );
			
			var loader = new THREE.TextureLoader();

			// 큐브1
			var mesh;
			loader.load(
				'http://dreamplan7.cafe24.com/SL/img/%EC%B9%B4%EB%93%9C_%EC%97%B0%EB%82%A0%EB%A6%AC%EA%B8%B0.jpg', 
				function ( texture ) {
					mesh = new THREE.Mesh(
						new THREE.BoxGeometry(3, 3, 3), 
						new THREE.MeshStandardMaterial({map: texture})
					);
					scene.add(mesh);
				}
			);

			// 카메라의 Z좌표를 물체에서 7 정도 떨어진 지점에 위치합니다.
			camera.position.z = 7;

			camera.position.y = 5;			
			camera.rotation.x = -35 * ( Math.PI / 180 );

			camera.position.x = 5;
			camera.rotation.y = 35 * ( Math.PI / 180 );
	
			// 카메라 컨트롤러 추가
			var controls = new THREE.OrbitControls (camera, renderer.domElement);
			controls.update();

			// ==========================
			// 초기화 부분 끝
			// ========================== 

			var framesPerSecond=60;

			// 에니메이션 효과를 자동으로 주기 위한 보조 기능입니다.
			var animate = function () {
				// 프레임 처리
				setTimeout(function() {
					 requestAnimationFrame(animate); 
				}, 1000 / framesPerSecond);

				// 랜더링을 수행합니다.
				renderer.render( scene, camera );
			};

			// animate()함수를 최초에 한번은 수행해주어야 합니다.
			animate();
			
		</script>
	</body>
</html>

이 소스를 작동하고 마우스로 움직이면 상자가 회전하지요.

다만, 혼동할 수 있는 부분이 있습니다.

이 컨트롤 기능은 정확히 말하면 상자가 회전하는게 아닙니다.

"그럼요?"

카메라가 회전하는 것이지요 :)

아래 녹색 물체가 카메라라고 치면,

마우스로 클릭 드래그 할때,

상자는 가만히 있고 카메라가 빙그르르 회전하는 것입니다.

마우스 휠을 당길때에도,

카메라가 앞으로 스스륵 다가오는 것이고,

마우스 우클릭하여 드래그할 때에도,

카메라가 옆으로 스르륵 이동하는 것이지요.

그 카메라 안에 비치는 영상을 보여주는 것인데요.

정말 그러한지 한번 상자 2개를 더 추가해보도록 하겠습니다.

소스에서 이 아랫 부분에

var mesh;
loader.load(
	'http://dreamplan7.cafe24.com/SL/img/%EC%B9%B4%EB%93%9C_%EC%97%B0%EB%82%A0%EB%A6%AC%EA%B8%B0.jpg', 
	function ( texture ) {
		mesh = new THREE.Mesh(
			new THREE.BoxGeometry(3, 3, 3), 
			new THREE.MeshStandardMaterial({map: texture})
		);
		scene.add(mesh);
	}
);
     :

상자 2개를 추가하는 소스를 넣어볼까요?

상자 표면에 들어갈 이미지는 크레이가 준비했으나 여러분 임의의 앨범그림을 넣으셔도 좋습니다 :)

			// 큐브2
			var mesh2;
			loader.load(
				'http://dreamplan7.cafe24.com/SL/img/%EC%B9%B4%EB%93%9C_%EA%B1%B4%EB%B0%98%ED%9A%A8%EA%B3%BC.jpg', 
				function ( texture ) {
					mesh2 = new THREE.Mesh(
						new THREE.BoxGeometry(3, 3, 3), 
						new THREE.MeshStandardMaterial({map: texture})
					);
					scene.add(mesh2);
					mesh2.position.set(5, 0, 0);
				}
			);

			// 큐브3
			var mesh3;
			loader.load(
				'http://dreamplan7.cafe24.com/SL/img/%EC%B9%B4%EB%93%9C_%EB%AC%B4%ED%95%9C%EC%BB%A4%ED%94%BC.jpg', 
				function ( texture ) {
					mesh3 = new THREE.Mesh(
						new THREE.BoxGeometry(3, 3, 3), 
						new THREE.MeshStandardMaterial({map: texture})
					);
					scene.add(mesh3);
					mesh3.position.set(-5, 0, 0);
				}
			);

참고로 각 상자의 위치를 조종하는 부분은 이 부분입니다.

mesh3.position.set(-5, 0, 0);

이 상태에서 마우스 클릭하고 돌려보면,

와우! 뭔가 좀 분위기가 있습니다.

 

이 것으로 상자가 회전하는 것이 아니라 카메라가 회전하는 것을 알수가 있습니다.

그런데, 마우스를 더 돌려보면,

이럴수가! 상자 뒤가 시커먼 것을 볼 수가 있습니다!

사람의 마음은 그 속을 알 수 없다고 했는데,

상자의 뒷면이 이렇게 시커먼지는 미처 몰랐지요 ? :)

사실 이 이유는 포인트 라이트라는 조명이 물체의 부분만을 비춰주기 때문입니다.

물체를 비춰주지 않는 표면 부분은 전혀 빛의 영향을 주지 않는데요.

이를 위한 전체조명이라는게 있습니다.

다음 시간에 전체조명에 대해 알아보도록 하겠습니다.

여기까지 읽어주신 분들께 감사드립니다. 수고하셨습니다 :)

 

※ 아울러 본 예제는 아래 url 에서 실제 작동확인해보실수 있습니다.

http://dreamplan7.cafe24.com/canvas/three004.php

 

3차원 캔바스 예제 1

 

dreamplan7.cafe24.com