「three.js」클릭으로 3D오브젝트 만들기
raycaster, 마우스 이벤트를 3D소스와 결합하는 것만으로도 재미있는 효과를 만들 수 있다. 가장 간단한 3D웹앱은 아래와 같은 경우다.
| 기획
1) 사용자가 3D 뷰어 화면을 클릭한다.
2) sphere가 화면에 생성된다.
3) 생성된 sphere와 카메라의 거리 = 50
| 기본구조
3D앱 기본 구조는 scene, camera, light, renderer, 재귀loop이다. 이번 포스팅에서는 grid가 필요하므로 그리드만 추가해준다.
let scene, sphere, camera, renderer, light, rayCast, controls, clock, mouse;
let ele = document.getElementById('wd-mouseClick');
let init = function () {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
camera = new THREE.PerspectiveCamera(75, ele.clientWidth / ele.clientHeight, 1, 1000);
camera.position.set( 0, 30, 55 );
light = new THREE.DirectionalLight(0xffffff, 1);
scene.add( light );
let grid = new THREE.GridHelper(100, 20);
scene.add( grid );
renderer = new THREE.WebGLRenderer();
renderer.setSize( ele.clientWidth, ele.clientHeight );
ele.appendChild( renderer.domElement );
renderer.domElement.addEventListener('click', onMouseClick, false);
controls = new OrbitControls( camera, renderer.domElement );
controls.update();
}
let mainLoop = function () {
requestAnimationFrame(mainLoop);
renderer.render(scene, camera);
}
init()
mainLoop();
| 마우스 클릭 이벤트 | Raycaster().ray
init함수의 끝부분에 추가한 onMouseClick은 Raycaster()를 이용한 값들이 필요하다. 사용자가 클릭한 위치에 sphere가 나타나야 한다. 이를 위해서는 사용자의 마우스 좌표를 3차원으로 변경해주는 Raycaster().ray.at() 메서드를 이용해야 한다.
let onMouseClick = function (e) {
let gapX = e.clientX - e.offsetX;
let gapY = e.clientY - e.offsetY;
mouse.x = ((e.clientX - gapX) / (ele.clientWidth)) * 2 - 1;
mouse.y = -((e.clientY - gapY) / (ele.clientHeight)) * 2 + 1;
rayCast.setFromCamera( mouse, camera );
let objectVec3 = new THREE.Vector3();
console.log( rayCast.ray.at( 50, objectVec3 ));
/*
* rayCast.ray는 'origin', 'direction' 2가지 key값을 갖고 있음
* rayCast.ray.origin = 카메라 포지션
* rayCast.ray.at() = 카메라 포지션과 타겟 오브젝트와의 distance 3차원 벡터값 반환
*/
createSphere( rayCast.ray.at( 50, objectVec3) )
}
위의 코드에서 중요한 부분은 Raycaster()의 속성 '.ray'다. Raycaster().ray는 '.origin'과 '.direction'객체를 반환한다. 자바스크립트 콘솔에서 Raycaster().ray는 아래와 같은 결과값을 보여주며, 22개의 메서드를 볼 수 있다.
ray의 메서드 중에서 .at()은 2개의 파라미터 값을 받는다. 첫번째 파라미터, 't'는 카메라 원점으로부터의 거리를 의미하며, 두 번째 파라미터 'target'은 3차원 벡터값이다. 가령, "ray.at( 30, new THREE.Vector3() )"는 "카메라 원점으로부터 30 떨어진 위치의 x, y, z 3차원 벡터값 반환'을 의미한다.
마우스 클릭 이벤트는 카메라로부터 50 떨어진 위치 값을 3차원 벡터로 전환한 후 createSphere( pos )함수의 인자값으로 넘겨준다. 위의 코드에서는 Raycaster.ray.at( 50, [3차원 벡터])으로 지정했기에 카메라에서 50 떨어진 위치의 3차원 벡터값이 반환되고 있다.
| createSphere() 함수
let createSphere = function ( pos ) {
let geometry = new THREE.SphereGeometry( 4, 30, 30 );
let material = new THREE.MeshPhongMaterial({
color: 0xffffff * Math.random(),
shininess: 100
});
sphere = new THREE.Mesh( geometry, material );
sphere.position.set( pos.x, pos.y, pos.z );
scene.add( sphere );
}
createSphere()함수에 전달된 pos는 rayCast.ray.at(50, [3차원 벡터])의 반환값(벡터값)이다. 해당 값을 이용해 sphere의 위치를 지정할 수 있으며, 색상값은 Math.random()함수를 이용해 랜덤으로 생성한다.