본문 바로가기

3D Project/3D 인터랙티브 웹

[3D 인터랙티브 웹] 3D 공간 떠다니기

키보드 입력을 통해 카메라 이동을 이용하여 공간 떠다니기 - eventListener와 연동하여 움직임 주기

eventListener 적용해서 키보드 입력(W, S) 적용하기

import { THREE, GLTFLoader, GenerateCanvas } from "./study/settings";

const canvas = GenerateCanvas();

let camera, scene, renderer, mesh;
let originPosition;

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

    camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        0.1,
        3000
    );
    camera.position.set(0, 0, 0);

    // gamma
    renderer.gammaFactor = 2.2;

    scene = new THREE.Scene();
    scene.background = new THREE.Color(0x000000);

    // add new group
    const group = new THREE.Group();
    group.position.copy(camera.position);
    group.rotation.copy(camera.rotation);
    scene.add(group);

    group.add(camera);

    // add gltf model
    const loader = new GLTFLoader();

    loader.load("/gltf/move.glb", function (gltf) {
        mesh = gltf.scene;
        mesh.position.set(0, 0, 0);

        const ratio = 0.1;
        mesh.scale.set(ratio, ratio, ratio);
        scene.add(mesh);

        // set default camera position to gltf camera
        const cam = gltf.cameras[0];
        // multiply by ratio
        camera.position.set(
            cam.position.x * ratio,
            cam.position.y * ratio,
            cam.position.z * ratio
        );
        camera.rotation.set(cam.rotation.x, cam.rotation.y, cam.rotation.z);
        originPosition = camera.position.clone();

        // change child material
        mesh.traverse((child) => {
            if (child.isMesh) {
                if (child.name == "light") {
                    child.material = new THREE.MeshBasicMaterial({
                        color: 0xffffff,
                    });
                    // double sided
                    child.material.side = THREE.DoubleSide;
                } else {
                    child.material = new THREE.MeshStandardMaterial({
                        color: 0xffffff,
                        roughness: 0.5,
                    });
                }
            }
        });

        render();
    });

    // add point light
    const pointLight = new THREE.PointLight(0xffffff, 1);
    pointLight.position.set(0, 0, 0);
    scene.add(pointLight);

    // hemi light
    const hemiLight = new THREE.HemisphereLight(0x000000, 0xffffff, 0.3);
    hemiLight.position.set(1, 0, 1);
    scene.add(hemiLight);
}

function render() {
    animate();
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

// window resize event
window.addEventListener("resize", onWindowResize);
function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

// ** type below

// 01. make variables
//키가 눌려 있는지 체크하기 위한 Object type 변수 - 기본값은 false
const keyPressed = {
    forward: false,
    backward: false,
}

// 02. add events
//키보드에 관련된 이벤트를 설정할 때는 keydown(처음 눌렀을 때)과 keyup(누르고 키를 뗐을 때)에 대해서 둘 다 설정해야함
window.addEventListener("keydown", event => {
    if(event.code == "KeyW") keyPressed.forward = true;
    if(event.code == "KeyS") keyPressed.backward = true;
   
})
window.addEventListener("keyup", event => {
    if(event.code == "KeyW") keyPressed.forward = false;
    if(event.code == "KeyS") keyPressed.backward = false;
})

// 03. make movement
function animate() {
    // a. checking key pressed
    if(keyPressed.forward == true){
        camera.position.z -= 5;
    }
    if(keyPressed.backward == true){
        camera.position.z += 2;
    }
    console.log(camera.position.z) //z가 -45지점에 흰 네모에 도달 -> 카메라의 처음 위치(z값이 1934)로 되돌아가기
    // 움직임의 범위 제한하기
    if(camera.position.z < -45) {
        camera.position.z = 1934;
    }
    if(camera.position.z > 1934){
        camera.position.z = 1934;
    }
}

// ** end
init();

 

애니메이션 결과