구글에서 제공하는 라이브러리인 model-viewer를 사용해서 web에 3D 모델을 띄우고, AR까지 적용시켜봅시다!
문서가 많이 없더라고요..
조금은 간결하게 다룰 예정이라
더 자세한 내용은 공식문서 보시면 됩니다. 쉽게 적혀있어요
설치
glitch 같은 방법도 있지만 npm 혹은 cdn을 이용해서 설치를 진행하겠습니다.
// npm
npm install @google/model-viewer
// cdn
<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
모델 띄우기
지원되는 3D 모델은 glTF/GLB 파일입니다.
<model-viewer id="model-ex" src="sample.glb" alt="model sample" camera-controls></model-viewer>
- src
- 3D 모델 glTF/GLB 파일
- camera-controls
- 마우스/터치로 제어가 가능해집니다. 사실상 필수 기본값입니다.
저는 우선 위 3가지만 설정해주도록 하겠습니다.
모달로 띄우기
자 우선 여기까지만 해도 web에 3D 모델이 보이기 시작합니다.
그대로 둬도 괜찮지만, 저는 감춰놨다가 리스트에서 '3D' 버튼을 클릭하면 modal로 띄워주겠습니다.
<button class="open-model-btn">3D</button>
<div class="mv-modal-box">
<model-viewer id="model-ex" src="sample.glb" alt="model sample" camera-controls></model-viewer>
</div>
.mv-modal-box {
display: none;
}
const MV_MODAL_BOX = document.querySelector('.mv-modal-box');
const modelOpenBtn = document.querySelector('.open-model-btn');
modelOpenBtn.addEventListener('click', () => {
MV_MODAL_BOX.style.display = 'block';
})
이제 버튼을 누르면 display: none 되어있던 'mv-modal-box'가 노출됩니다.
하지만 이렇게 되면 src가 고정적이라 확장성이 떨어지게 됩니다.
버튼을 몇 개 더 추가해서 각 버튼을 누를 때마다 버튼에 맞는 3D 모델을 노출하도록 수정을 해주겠습니다.
확장하기
<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">
<model-viewer id="model-ex" camera-controls></model-viewer>
</div>
버튼에 'data-product-name'을 추가했습니다.
클릭한 버튼에서 attr 속성을 가져와 해당 속성과 일치하는 모델을 로드시켜주기 위함입니다.
model-viewer의 src와 alt 속성은 제거하였습니다.
사용자가 처음에 어떤 모델을 누를지 모르는 상황에서 굳이 하나를 로드시키는 건 자원낭비라고 생각했기 때문입니다.
const MV_MODAL_BOX = document.querySelector('.mv-modal-box');
const MODAL_VIEWER = document.querySelector('#model-ex');
const modelOpenBtn = document.querySelector('.open-model-btn');
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);
}
이제 각 버튼을 클릭할 때마다 robot.glb, phone.glb, car.glb로 src가 변경될 것입니다.
src가 변경되면 자동으로 model-viewer는 리로드 됩니다. (로드되었던 모델은 캐싱되어 남아있음)
근데 이상합니다.
모델을 변경할 때마다 모델을 이리저리 돌려놓은 카메라 궤도가 그대로 유지되고, 모델만 변경되고 있습니다.
이를 해결해봅시다.
모델 로드 시 카메라 궤도 초기화
맨 위에 링크 걸었던 공식 문서에 loading > event로 가보시면 load라는 이벤트가 있습니다.
load이벤트는 src 속성이 변경될 때마다 실행됩니다. (model-visibility와는 다름)
load 외에 모델이 로드되는 과정을 0 ~ 1로 제공해주는 progress라는 이벤트도 있습니다.
저는 둘 중에 확실하게 로드가 끝난 후에 카메라 궤도를 재설정해주기 위해 progress를 사용하겠습니다.
(html, css는 그대로 js만 수정합니다)
const MV_MODAL_BOX = document.querySelector('.mv-modal-box');
const MODAL_VIEWER = document.querySelector('#model-ex');
const modelOpenBtn = document.querySelector('.open-model-btn');
MODEL_VIEWER.addEventListener('progress', (e) => {
if (e.detail.totalProgress === 1) {
MODEL_VIEWER.cameraOrbit = '0deg 75deg 105%';
}
});
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);
}
progress 이벤트 내에서 e.detail.totalProgress를 콘솔로 찍어보면 0 ~ 1까지 여러 번 찍히는 것을 알 수 있는데 진행률이 1이 되었을 때(완료) 카메라 궤도를 재설정해줬습니다.
camera-orbit이라는 속성입니다. 기본값은 위에 설정한 대로 '0 deg 75 deg 105%'이며 각각 theta phi radius를 나타내고 기본값 외에 다른 값 설정이 가능합니다.
이제 모델을 변경해보면 로드 후에 카메라 궤도가 재설정되어 처음으로 돌아가는 것을 확인할 수 있습니다.
1. 애니메이션 추가하기 및 모달 닫기
2. zoom in/out, animation toggle, full screen 기능 추가하기
3. ar 활성화
util, ui등 평소 개발 스타일대로 포스팅 소스의 파일을 나눠서 export/import해서 진행하는 것은 포스팅 가독성을 떨어뜨린다고 판단해서 해당 포스팅은 별도의 리팩토링 없이 한 파일에 진행됩니다.
피드백, 질문, 댓글 언제나 환영입니다!
감사합니다 :)
'개발 > js' 카테고리의 다른 글
[JS] model-viewer 사용법 4 - model AR 활성화 및 커스텀 하기 (0) | 2022.09.15 |
---|---|
[JS] model-viewer 사용법 3 - model control 하기 (zoom in/out, animation toggle, full screen) (2) | 2022.09.14 |
[JS] model-viewer 사용법 2 - model animation 추가하기 (with. modal 닫기) (0) | 2022.09.13 |
JS - 실시간 시계 만들기 (requestAnimationFrame) (0) | 2022.09.06 |
JS - try/catch문 404 Error 핸들링하기 (0) | 2022.09.01 |