개발/js

[JS] model-viewer 사용법 2 - model animation 추가하기 (with. modal 닫기)

waterpole-dev 2022. 9. 13. 16:59
반응형

이전 글 보기 (더보기 클릭)

 

저번 포스팅에 이어서

이번에는 3D model에 animation이 존재하는 경우 animation을 추가해보겠습니다.


로드 시 애니메이션 체크

저번 포스팅에서 progress 이벤트를 통해 로드가 완료되었을 때 카메라 궤도 재설정을 했었습니다.

이번에는 load 이벤트를 활용해서 src가 변경 될 때마다 animation을 가지고 있는지 체크해도 되지만

저는 처음부터 애니메이션을 작동시킬게 아니여서(ex. 버튼 토글을 통해 문을 열고 닫음) progress 이벤트에서 체크하도록 하겠습니다.

 

처음부터 animation이 작동해야한다면 load를 사용해서 체크하는 것도 방법입니다. 아니면 progress 0 때 체크하거나..?

 

이번에도 js만 수정됩니다.

const MV_MODAL_BOX = document.querySelector('.mv-modal-box');
const MODAL_VIEWER = document.querySelector('#model-ex');
const modelOpenBtn = document.querySelector('.open-model-btn');

let animationArr = [];

MODEL_VIEWER.addEventListener('progress', (e) => {
    if (e.detail.totalProgress === 1) {
        MODEL_VIEWER.cameraOrbit = '0deg 75deg 105%';
        animationArr = MODEL_VIEWER.availableAnimations;
    }
});

modelOpenBtn.addEventListener('click', (e) => {
    const target = e.currentTarget;
    const productName = target.getAttribute('data-product-name');
    
    MV_MODAL_BOX.style.display = 'block';
    loadModel(productName)
});

function loadModel(name) {
    const modelSrc = `./assets/model/${name}.glb`;
    MODEL_VIEWER.setAttribute('src', modelSrc);
}

공식 문서에 animation > properties에 보시면 availableAnimations라는 프로퍼티가 있습니다.

이 프로퍼티는 로드된 모델의 animation-name으로 선택할 수 있는 animation의 문자열 배열을 가져옵니다.

예를 들어서 로드된 car.glb에 사용가능한 animation이 open, close가 있다면 ['open', 'close']

 

가져온 배열을 변수에 담아줍니다.


애니메이션 설정하기

animation 체크 후 animation-name 속성을 통해 설정해줍니다.

const MV_MODAL_BOX = document.querySelector('.mv-modal-box');
const MODAL_VIEWER = document.querySelector('#model-ex');
const modelOpenBtn = document.querySelector('.open-model-btn');

let animationArr = [];

MODEL_VIEWER.addEventListener('progress', (e) => {
    if (e.detail.totalProgress === 1) {
        MODEL_VIEWER.cameraOrbit = '0deg 75deg 105%';
        animationArr = MODEL_VIEWER.availableAnimations;
    }
});

modelOpenBtn.addEventListener('click', (e) => {
    const target = e.currentTarget;
    const productName = target.getAttribute('data-product-name');
    
    MV_MODAL_BOX.style.display = 'block';
    loadModel(productName)
});

function loadModel(name) {
    const modelSrc = `./assets/model/${name}.glb`;
    MODEL_VIEWER.setAttribute('src', modelSrc);
}

function setAnimation() {
    if (animationArr.length > 0) {
        MODEL_VIEWER.setAttribute('animation-name', animationArr[0]);
    } else {
        console.log("사용 가능한 애니메이션이 없습니다.")
    }
}

위 progress 이벤트에서 빈배열인지 아닌지 체크를 안 해주고 할당한 해줬기 때문에 setAnimation함수에서 animationArr에 담아놓은 애니메이션 배열이 존재하는지 체크를 해주고 배열이 존재할 경우에만 animation-name 속성을 추가해줍니다.

 

animationArr[0]을 한 이유는 제가 사용한 모든 model 파일은 사용 가능한 animation이 2개로 고정이기에 0 혹은 1이라 저렇게 설정했고, 이 부분은 개인 프로젝트에 맞게 커스텀 하시면 될 거 같습니다.

 

만약 animation이 자동재생 되길 원하면 if문안에

MODEL_VIEWER.setAttribute('autoplay', "true");

를 추가해주시면 됩니다. 저는 자동재생이 필요 없어서 추가하지 않았습니다.

 

자 이제 애니메이션을 사용 할 준비는 됐습니다. (autoplay의 경우 그냥 끝난 거나 다름없음)

우선 준비까지만 해놓고 저번 포스팅에서 얘기했던

2. zoom in/out, animation toggle, full screen 기능 추가하기

포스팅에서 toggle로 작동시키도록 하겠습니다.

 

하지만 그전에 열어놓은 modal을 닫기 위해선 매번 새로고침을 할 수 없으니 닫기 버튼을 추가해주고 이번 포스팅을 끝내도록 하겠습니다.


모달 닫기 버튼 추가

<button class="open-model-btn" data-product-name="robot">3D - 01</button>
<button class="open-model-btn" data-product-name="phone">3D - 02</button>
<button class="open-model-btn" data-product-name="car">3D - 03</button>

<div class="mv-modal-box">
    <button class="close-modal-btn">X</button>
    <model-viewer id="model-ex" camera-controls></model-viewer>
</div>
const MV_MODAL_BOX = document.querySelector('.mv-modal-box');
const MODAL_VIEWER = document.querySelector('#model-ex');
const modelOpenBtn = document.querySelector('.open-model-btn');
const modalCloseBtn = document.querySelector('.close-modal-btn');

let animationArr = [];

MODEL_VIEWER.addEventListener('progress', (e) => {
    if (e.detail.totalProgress === 1) {
        MODEL_VIEWER.cameraOrbit = '0deg 75deg 105%';
        animationArr = MODEL_VIEWER.availableAnimations;
    }
});

modelOpenBtn.addEventListener('click', (e) => {
    const target = e.currentTarget;
    const productName = target.getAttribute('data-product-name');
    
    MV_MODAL_BOX.style.display = 'block';
    loadModel(productName)
});

modalCloseBtn.addEventListener('click', () => {
    MODEL_VIEWER.removeAttribute('src');
    MODEL_VIEWER.removeAttribute('animation-name');
    animationArr = [];
    MV_MODAL_BOX.style.display = 'none';
});

function loadModel(name) {
    const modelSrc = `./assets/model/${name}.glb`;
    MODEL_VIEWER.setAttribute('src', modelSrc);
}

function setAnimation() {
    if (animationArr.length > 0) {
        MODEL_VIEWER.setAttribute('animation-name', animationArr[0]);
    } else {
        console.log("사용 가능한 애니메이션이 없습니다.")
    }
}

간단합니다.

닫기 버튼을 modal에 추가해주시고, 스크립트에서 닫기 버튼에 이벤트 리스터를 통해서 설정했던 src, animation-name, animationArr을 날려버리고 다시 display: none 해버리면 됩니다.

 

사실 굳이 날려버리진 않아도 괜찮은데 개인적으로 active 되어 있지도 않은 model 정보들이 남아있는 게 마음에 안 들어서 다 날려버렸습니다.


이번 포스팅에선 간단하게 model 파일이 사용 가능한 애니메이션이 있는지 체크하고, 결과에 따라 animation-name 속성을 추가해줘서 애니메이션을 사용할 준비를 해봤습니다.

 

다음은

2. zoom in/out, animation toggle, full screen 기능 추가하기
 

[JS] model-viewer 사용법 3 - model control 하기 (zoom in/out, animation toggle, full screen)

이전 글 보기 (더보기 클릭) 더보기 2022.09.13 - [개발/js] - [JS] model-viewer 사용법 1 - web에 3D 모델을 띄우자! JS - web에 3D 모델을 띄우자! with. AR (model-viewer 사용법 1) 구글에서 제공하는 라이브..

waterpole.tistory.com

에 관해 포스팅하겠습니다.


util, ui등 평소 개발 스타일대로 포스팅 소스의 파일을 나눠서 export/import해서 진행하는 것은 포스팅 가독성을 떨어뜨린다고 판단해서 해당 포스팅은 별도의 리팩토링 없이 한 파일에 진행됩니다.

 

피드백, 질문, 댓글 언제나 환영입니다!

감사합니다 :)

반응형