diff --git a/gallery.html b/gallery.html index d9d651d..b87d8a4 100644 --- a/gallery.html +++ b/gallery.html @@ -40,8 +40,8 @@ - - + + @@ -171,8 +171,6 @@ - - \ No newline at end of file diff --git a/js/gallery.js b/js/gallery.js index 89d75a9..3a1b63e 100644 --- a/js/gallery.js +++ b/js/gallery.js @@ -6,7 +6,7 @@ document.addEventListener('DOMContentLoaded', function() { initGallery(); initLightbox(); initGalleryAnimations(); - initPhotoSphereViewers(); + initAFrame360Viewers(); }); // 갤러리 초기화 @@ -267,20 +267,22 @@ function handleSwipe() { } // ======================================== -// Photo Sphere Viewer - 진짜 360도 VR 뷰어 +// A-Frame 기반 360도 VR 뷰어 - 안정적이고 강력한 VR 체험 // ======================================== -let currentPhotoSphereViewer = null; +let currentAFrameScene = null; +let autoRotationInterval = null; +let isAutoRotating = false; -function initPhotoSphereViewers() { +function initAFrame360Viewers() { // 모달 생성 - createPhotoSphereModal(); + createAFrameModal(); // 미리보기 설정 - initPhotoSpherePreviews(); + initAFramePreviews(); } -function initPhotoSpherePreviews() { +function initAFramePreviews() { const containers = document.querySelectorAll('.panorama-clickable'); containers.forEach(container => { @@ -289,7 +291,7 @@ function initPhotoSpherePreviews() { // 클릭 이벤트 container.addEventListener('click', () => { - openPhotoSphereModal(imageSrc, title); + openAFrameModal(imageSrc, title); }); // 도움말 자동 숨김 @@ -303,39 +305,41 @@ function initPhotoSpherePreviews() { }); } -function createPhotoSphereModal() { +function createAFrameModal() { const modalHTML = ` -
+
-
+
+ +
-
+
- - - -
- -
+

360° VR 조작법

🖱️ 드래그: 전방향 회전

📱 터치: 터치 후 드래그

🖱️ 휠: 줌 인/아웃

📱 핀치: 줌 인/아웃

-

⌨️ 화살표: 방향 이동

-

⌨️ +/-: 줌 조절

+

⌨️ WASD: 이동

+

📱 VR모드: VR 헤드셋 지원

⌨️ ESC: 닫기

@@ -343,67 +347,65 @@ function createPhotoSphereModal() { `; document.body.insertAdjacentHTML('beforeend', modalHTML); - setupPhotoSphereModalListeners(); + setupAFrameModalListeners(); } -function setupPhotoSphereModalListeners() { - const modal = document.getElementById('photosphere-modal'); - const closeBtn = document.getElementById('photosphere-modal-close'); - const resetBtn = document.getElementById('photosphere-reset-btn'); - const autoBtn = document.getElementById('photosphere-auto-btn'); - const fullscreenBtn = document.getElementById('photosphere-fullscreen-btn'); - const helpBtn = document.getElementById('photosphere-help-btn'); - const helpText = document.getElementById('photosphere-help-text'); +function setupAFrameModalListeners() { + const modal = document.getElementById('aframe-modal'); + const closeBtn = document.getElementById('aframe-modal-close'); + const resetBtn = document.getElementById('aframe-reset-btn'); + const autoBtn = document.getElementById('aframe-auto-btn'); + const vrBtn = document.getElementById('aframe-vr-btn'); + const helpBtn = document.getElementById('aframe-help-btn'); + const helpText = document.getElementById('aframe-help-text'); - let isAutoRotating = false; let helpVisible = false; // 모달 닫기 - closeBtn.addEventListener('click', closePhotoSphereModal); + closeBtn.addEventListener('click', closeAFrameModal); modal.addEventListener('click', (e) => { - if (e.target === modal) closePhotoSphereModal(); + if (e.target === modal) closeAFrameModal(); }); // ESC 키 document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && modal.classList.contains('active')) { - closePhotoSphereModal(); + closeAFrameModal(); } }); // 리셋 버튼 resetBtn.addEventListener('click', () => { - if (currentPhotoSphereViewer) { - currentPhotoSphereViewer.animate({ - yaw: 0, - pitch: 0, - zoom: 50, - speed: '2rpm' - }); + if (currentAFrameScene) { + const camera = currentAFrameScene.querySelector('[camera]'); + if (camera) { + camera.setAttribute('rotation', '0 0 0'); + camera.setAttribute('position', '0 0 0'); + } } }); // 자동 회전 버튼 autoBtn.addEventListener('click', () => { - if (currentPhotoSphereViewer) { - if (isAutoRotating) { - currentPhotoSphereViewer.stopAutorotate(); - autoBtn.innerHTML = ' 자동회전'; - autoBtn.classList.remove('active'); - isAutoRotating = false; - } else { - currentPhotoSphereViewer.startAutorotate(); - autoBtn.innerHTML = ' 정지'; - autoBtn.classList.add('active'); - isAutoRotating = true; - } + if (isAutoRotating) { + stopAutoRotation(); + autoBtn.innerHTML = ' 자동회전'; + autoBtn.classList.remove('active'); + } else { + startAutoRotation(); + autoBtn.innerHTML = ' 정지'; + autoBtn.classList.add('active'); } }); - // 전체화면 버튼 - fullscreenBtn.addEventListener('click', () => { - if (currentPhotoSphereViewer) { - currentPhotoSphereViewer.enterFullscreen(); + // VR 버튼 + vrBtn.addEventListener('click', () => { + if (currentAFrameScene) { + const vrButton = currentAFrameScene.querySelector('[vr-mode-ui]'); + if (vrButton) { + // VR 모드 진입 + currentAFrameScene.enterVR(); + } } }); @@ -420,84 +422,113 @@ function setupPhotoSphereModalListeners() { }, 6000); } -function openPhotoSphereModal(imageSrc, title) { - const modal = document.getElementById('photosphere-modal'); - const modalTitle = document.getElementById('photosphere-modal-title'); - const viewerContainer = document.getElementById('photosphere-viewer'); +function openAFrameModal(imageSrc, title) { + const modal = document.getElementById('aframe-modal'); + const modalTitle = document.getElementById('aframe-modal-title'); + const viewerContainer = document.getElementById('aframe-viewer'); modalTitle.textContent = title; modal.classList.add('active'); document.body.style.overflow = 'hidden'; - // Photo Sphere Viewer 생성 - try { - currentPhotoSphereViewer = new PhotoSphereViewer.Viewer({ - container: viewerContainer, - panorama: imageSrc, - caption: title, - loadingImg: imageSrc, // 로딩 중 미리보기 - touchmoveTwoFingers: true, - mousewheelCtrlKey: false, - defaultYaw: 0, - defaultPitch: 0, - defaultZoomLvl: 50, - minFov: 30, - maxFov: 90, - autorotateDelay: null, - autorotateIdle: false, - autorotateSpeed: '2rpm', - fisheye: false, - navbar: [ - 'zoom', - 'move', - 'fullscreen', - { - title: '자동회전', - content: '🔄', - onClick: () => { - const autoBtn = document.getElementById('photosphere-auto-btn'); - autoBtn.click(); - } - } - ] - }); - - // 이벤트 리스너 - currentPhotoSphereViewer.addEventListener('ready', () => { - console.log('Photo Sphere Viewer 준비 완료'); - }); - - currentPhotoSphereViewer.addEventListener('autorotate', () => { - console.log('자동 회전 시작'); - }); - - currentPhotoSphereViewer.addEventListener('autorotate-stop', () => { - console.log('자동 회전 정지'); - }); - - } catch (error) { - console.error('Photo Sphere Viewer 초기화 실패:', error); - alert('360도 뷰어를 로드할 수 없습니다. 페이지를 새로고침해주세요.'); + // A-Frame Scene 생성 + const sceneHTML = ` + + + + + + + + + + + + + + + + + + + `; + + viewerContainer.innerHTML = sceneHTML; + currentAFrameScene = document.getElementById('aframe-scene'); + + // A-Frame 로딩 완료 대기 + currentAFrameScene.addEventListener('loaded', () => { + console.log('A-Frame 360도 뷰어 로드 완료:', title); + }); +} + +function startAutoRotation() { + if (!currentAFrameScene) return; + + isAutoRotating = true; + const camera = currentAFrameScene.querySelector('#panorama-camera'); + let currentRotationY = 0; + + autoRotationInterval = setInterval(() => { + if (camera && isAutoRotating) { + currentRotationY += 0.5; // 초당 0.5도 회전 + if (currentRotationY >= 360) currentRotationY = 0; + + const currentRotation = camera.getAttribute('rotation'); + camera.setAttribute('rotation', `${currentRotation.x} ${currentRotationY} ${currentRotation.z}`); + } + }, 50); // 20fps +} + +function stopAutoRotation() { + isAutoRotating = false; + if (autoRotationInterval) { + clearInterval(autoRotationInterval); + autoRotationInterval = null; } } -function closePhotoSphereModal() { - const modal = document.getElementById('photosphere-modal'); - const autoBtn = document.getElementById('photosphere-auto-btn'); +function closeAFrameModal() { + const modal = document.getElementById('aframe-modal'); + const autoBtn = document.getElementById('aframe-auto-btn'); - // 뷰어 정리 - if (currentPhotoSphereViewer) { - currentPhotoSphereViewer.destroy(); - currentPhotoSphereViewer = null; - } + // 자동 회전 정지 + stopAutoRotation(); // 버튼 초기화 autoBtn.innerHTML = ' 자동회전'; autoBtn.classList.remove('active'); + // A-Frame Scene 정리 + if (currentAFrameScene) { + currentAFrameScene.destroy(); + currentAFrameScene = null; + } + modal.classList.remove('active'); document.body.style.overflow = ''; // 컨테이너 정리 - document.getElementById('photosphere-viewer').innerHTML = ''; + document.getElementById('aframe-viewer').innerHTML = ''; } \ No newline at end of file