[Three.js journey 강의노트] 08

9rganizedChaos·2022년 9월 24일
1
post-thumbnail

🙌🏻 해당 글은 Three.js Journey의 강의 노트입니다.

08 Fullscreen and resizing

현재 우리는 정해진 크기의 캔버스에 WebGL를 맞춰 활용하고 있다. 그러나 때로는 immersive experience를 선사하기 위해 우리는 Full Screen을 활용해고 싶을 수 있다. 그러나 Full Screen에서 ThreeJS를 활용한다면, 물론이지 반응형에도 잘 대응해야 한다. 이번 레슨에서는 이 부분에 대해서 다뤄볼 것이다.

Fit in the viewport

window.innerWidthwindow.innerHeight를 이용하면, 캔버스가 뷰포트에 딱 들어맞게끔 조정할 수 있다. (기본으로 생성되어있는 마진, 패딩은 style.css를 통해 제거해준다.)

const sizes = {
    width: window.innerWidth,
    height: window.innerHeight
}
// styles.css
* {
    margin: 0;
    padding: 0;
}
html,
body
{
    overflow: hidden;
}
.webgl {
    position: fixed;
    top: 0;
    left: 0;
    outline: none;
    // ThreeJS에서 renderer.setSize를 사용해주고 있기 때문에, 
    // 따로 정확한 width와 height 속성을 입력해주지 않아도 된다.
}

이제 Full screen에서 ThreeJS를 경험할 수 있게 되었다. 그러나 여전히 리사이즈에는 대응이 불가능하다.

Handle resize

윈도우 리사이즈에 대응하기 위해서 우선 이벤트 리스너를 통해 리사이즈를 감지할 수 있도록 해준다. 그리고, 윈도우 사이즈가 변화함게 따라, sizes, camera.aspect을 수정해준다.

camera.aspect는 카메라 절두체의 종횡비인데, 이 때 절두체란 사각뿔의 윗부분을 밑면에 평행하게 잘라낸 입체 형상을 가리킨다. 아래와 같은 형태! 일반적으로 캔버스 너비를 캔버스의 높이로 나눈 값이다.

추가로, camera.aspect를 업데이트 해줄 때는 camera.updateProjectionMatrix() 메서드를 활용해서 프로젝션의 매트릭스를 같이 업데이트 해줘야 되는데, 이 부분에 대해서는 추후에 다루도록 한다.

그리고 마지막으로, renderer 까지 업데이트 해주면 리사이즈가 되는 모습을 살펴볼 수 있다!

window.addEventListener('resize', () => {
  sizes.width = window.innerWidth
  sizes.height = window.innerHeight
  
  camera.aspect = sizes.width / sizes.height
  camera.updateProjectionMatrix()
  
  renderer.setSize(sizes.width, sizes.height)
})

Handle pixel ratio

모두가 그러한 것은 아니지만 우리들 중 일부는 오브젝트의 가장자리에 계단모양의 흐릿한 모습을 살펴볼 수 있을 것이다.

이는 픽셀 비율이 1보다 큰 화면에서 테스트를 하고 있기 때문에 그런 것이다. 픽셀 비율(Pixel Ratio)이란 소프트웨어의 한 픽셀 유닛에 대해 당신이 실제 스크린 위에 몇 개의 픽셀을 갖고 있는가를 말한다.

Pixel Ratio의 역사...!

몇 년 전만 해도, 모든 스크린들을 pixel ratio 1의 스크린을 갖고 있었다. 스크린에 정말 가까이 다가가면 그 픽셀들을 살펴볼 수가 있었고, 그것이 곧 얼마나 이미지를 정확히 표현할 수 있는지, 그리고 폰트가 얼마나 가늘어질 수 있는지를 의미했다. 애플이 retina 디스플레이를 발표하면서, pixel ratio 2의 디스플레이가 등장하기 시작했다.

더 나은 이미지 퀄리티를 위해 개발된 이 retina 디스플레이는 결국 네 배 더 많은 픽셀을 렌더링 할 수 있게 되었다. pixel ratio가 3인 경우는 결과적으로 9배 더 많은 픽셀을 렌더링할 수 있는 것. 현재는 가장 작은 디바이스인 모바일의 경우에 가장 높은 pixel ratio를 도입하고 있다.

그래서 어떻게 핸들링할 것인가

우리는 window.devicePixelRatio를 통해서 스크린의 pixel ratio를 알 수 있고, pixel ratio를 세팅해주기 위해서는 renderer.setPixelRatio(...)를 활용하면 된다. pixel ratio가 2인 경우도, 3인 경우도 있는데, 보통 2를 초과하는 값의 경우 사람의 눈으로 차이를 분간하기 어렵고, 실상은 마케팅이라 봐도 무방하다. 우리는 Math.min()을 활용해 값을 제한해줄 것이다.

window.addEventListener('resize', () => {
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight

    camera.aspect = sizes.width / sizes.height

    renderer.setSize(sizes.width, sizes.height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})

(현재 내가 사용중인 디바이스들은 모두 pixel ratio가 2이기 때문에 위 코드를 활성화했을 때와 아닐 때의 차이를 분간하기 어렵다.)

✨ Pixel Ratio에 대해서 다시 공부하기!

Handle fullscreen

이번에는 fullscreen과 그렇지 않은 모드를 유저가 직접 선택할 수 있도록 지원해보려고 한다. 다양한 트리거를 활용할 수 있지만 이 레슨에서는 더블클릭을 통해 실습해보자. 더블클릭을 통해 전체화면 모드를 토글할 수 있도록 하는 것이다.

우리는 document.fullscreenElement 속성과 requestFullscreen(), exitFullscreen() 메서드를 활용할 것이다.

window.addEventListener('dblclick', () => {
    if(!document.fullscreenElement) {
        canvas.requestFullscreen()
    } else {
        document.exitFullscreen()
    }
})

아쉽게도 사파리에서는 위 코드가 유효하지 않다.
그래서 우리는 아래와 같이 코드를 수정해줄 것이다.

window.addEventListener('dblclick', () => {
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement

    if(!fullscreenElement) {
        if(canvas.requestFullscreen) {
            canvas.requestFullscreen()
        } else if(canvas.webkitRequestFullscreen) {
            canvas.webkitRequestFullscreen()
        }
    } else {
        if(document.exitFullscreen) {
            document.exitFullscreen()
        } else if(document.webkitExitFullscreen) {
            document.webkitExitFullscreen()
        }
    }
})

profile
부정확한 정보나 잘못된 정보는 댓글로 알려주시면 빠르게 수정토록 하겠습니다, 감사합니다!

0개의 댓글