웹개발 자료실/three.js 프론트개발 Code

「three.js」클릭으로 3D오브젝트 만들기

Recstasy 2023. 1. 13. 12:46

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()함수를 이용해 랜덤으로 생성한다.