[three.js journey] 7강 복습: canvas 전체 화면 만들기 및 resize 관리
캔버스를 더 이상 800x600가 아닌 브라우저 뷰포트에 꽉 차도록 하고 싶다면 window 인터페이스와 css를 활용하면 된다.
브라우저가 리사이즈될 때 캔버스도 이와 동기화하고 싶다면 resize 이벤트를 사용하면 된다.
7강에서는 위와 같은 내용을 배우며, 그 외에 pixel ratio와 fullscreen에 대해서 더 알아볼 것이다.
1. 브라우저 viewport에 캔버스 맞추기
window의 innerWidth, innerHeight 속성을 사용해 canvas의 크기를 정해줄 것이다.
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
CSS는 아래와 같이 하면 뷰포트 전체를 차지하게 된다.
*
{
margin: 0;
padding: 0;
}
.webgl
{
position: fixed;
top: 0;
left: 0;
outline: none;
}
스크롤바까지 없애고 싶다면 overflow: hidden;을 추가하면 된다.
html,
body
{
overflow: hidden;
}
2. 브라우저 resize 시 캔버스도 함께 리사이즈하기
resize 이벤트가 발생할 때마다 sizes를 갱신하고, 갱신된 sizes에 따라 카메라와 렌더러를 업데이트한다.
카메라 업데이트의 경우 카메라가 보는 화면의 가로, 세로 비율(종횡비, aspect ratio) 계산하고 updateProjectionMatrix()를 호출한다. updateProjectMatrix()를 호출해야 변경된 가로, 세로 비율에 맞게 카메라의 projection matrix가 업데이트가 되고 3D 장면이 왜곡되어 보이지 않는다. 그렇지 않으면 렌더링된 장면이 찌그러져 보일 수 있다.
렌더러 업데이트의 경우 업데이트 된 창 크기에 맞게 렌더러 출력 크기를 조정해야 한다.
이 과정이 없으면 3D 장면이 캔버스 창 크기와 맞지 않게 렌더링되어 일부가 잘리거나 빈 공간이 생길 수 있고 렌더링된 이미지가 늘어나거나 줄어들어 보일 수 있다. 또한 클릭이나 드래그 위치가 실제와 다르게 인식되어 마우스 이벤트의 좌표 계산이 부정확해질 수 있다.
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(sizes.width, sizes.height)
})
3. pixel ratio
렌더러의 경우 픽셀이 흐릿하게 보일 수 있는데 이는 캔버스의 실제 해상도와 표시되는 해상도가 다를 때 발생한다.
특히 가장자리에 계단 같은 모양의 앨리어싱이 나타난다면 pixel ratio가 1보다 큰 화면이기 때문이다.
pixel ratio 소프트웨어 픽셀 단위 당 화면에 표시되는 물리적 픽셀 수를 나타낸다.
pixel ratio의 역사를 보면 몇 년 전까지 모든 화면의 pixel ratio는 1이었지만 애플이 이미지 품질을 위해 레티나 디스플레이라고 불리는 pixel ratio 2의 화면을 구성하기 시작했다. 다만 pixel ratio가 2배가 되며 렌더링할 픽셀은 4배가 되었다.
화면의 pixel ratio를 얻으려면 window.devicePixelRatio를 사용하고,
렌더러의 픽셀 비율을 업데이트 하려면 renderer.setPixelRatio(n)를 호출하면 된다.
pixel ratio가 2일 때와 3일 때 차이는 거의 없는 대신 성능 문제가 발생하고 배터리가 빨리 소모되기 때문에 2로 제한하여 사용하는 것을 추천한다. 이 때 Math.min()을 사용하면 된다.
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
해당 코드를 resize 이벤트 안에서 호출하는 이유는 브라우저의 확대/축소 또는 모니터 변경이 일어날 때 해당 이벤트가 발생하기 때문이다.
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
4. fullscreen
더블 클릭 이벤트를 통해 브라우저의 전체 화면 모드를 켜고 끄는 방법은 아래와 같다.
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()
}
}
})