[three.js journey] 6강 복습(2): Controls 알아보기
이전 글: https://be-at-peace.tistory.com/18
Controls는 카메라의 움직임을 제어할 수 있도록 해준다.
카메라맨이 카메라 위치, 각도, 바라보는 대상을 제어하는 것과 같다고 느꼈다.
마우스에 따라 카메라를 위치를 바꾸는 custom controls를 만들어보자.
PerspectiveCamera를 제어해볼 것이며 이후 three.js journey 강의에서도 PerspectiveCamera만 사용한다.
1. Custom Controls
커서 위치에 따라 카메라 position 변화하게 만들기
위와 같이 마우스 커서로 상호작용하려면 어떻게 해야할까?
우선 웹 api인 mousemove 이벤트를 활용한다.
canvas.addEventListener("mousemove", (e) => {
console.log(`마우스 좌표: X:${e.clientX} Y:${e.clientY}`);
})
맨 왼쪽 위의 (X,Y) 좌표는 (0,0)이고, 맨 오른쪽 아래 브라우저의 뷰포트 크기에 따라 결정된다.
예를 들어 가로, 세로가 1920px, 1080px이면 맨 오른쪽 아래 좌표는 (1920, 1080)가 될 것이다.
캔버스 중앙의 메시를 기준으로 제어할 것이므로, 캔버스 크기를 기준으로 중앙을 (0,0), 맨 위 왼쪽을 (-0.5, -0.5) 맨 오른쪽 아래를 (0.5, 0.5)로 만들어주면 된다.
참고로 y 축의 경우 three.js와 웹 api 방향이 반대기 때문에 -를 붙인다.
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
const cursor = {
x: 0,
y: 0
}
canvas.addEventListener("mousemove", (e) => {
cursor.x = e.clientX/sizes.width - 0.5;
cursor.y = -(e.clientY/sizes.height - 0.5);
camera.position.x = cursor.x;
camera.position.y = cursor.y;
})
마우스 커서에 따라 카메라 회전하게 만들기
애니메이션 함수 내부에 camera.lookAt(model.position); 을 추가하면 된다.
주의할 점은 애니메이션 함수 외부에 한 번만 호출하면 마우스에 따라 이동만 하고 회전은 하지 않는다.
그 이유는 camera.lookAt의 경우 호출될 때 model.position을 바라보도록 카메라의 rotation을 설정하는 일회성 기능이기 때문이다.
새로운 위치에서 카메라의 여전히 그 모델을 바라보게 하고 싶다면 lookAt을 다시 호출해주어야 한다.
이에 반해 built-in controls에서 배울 controls.target의 경우 내부적으로 lookAt을 계속 업데이트해주기 때문에 한번 호출하면 계속해서 정해준 위치를 바라본다.
마우스 커서로 정확한 한 바퀴 회전하게 만들기
원점에 있는 model을 기준으로 카메라가 xz 평면에서 원운동하게 만들면 된다.
커서의 범위가 -0.5 ~ 0.5이므로 2*pi를 곱해주면 -pi ~ pi 만큼 회전한다.
// 애니메이션 함수
camera.position.x = Math.sin(cursor.x * Math.PI * 2) * 2
camera.position.z = Math.cos(cursor.x * Math.PI * 2) * 2
camera.position.y = cursor.y * 3
camera.lookAt(mesh.position)
y축에 대해서도 원운동을 적용해 상하좌우 전부 한바퀴 씩 돌 수 있게 할 수 있지 않을까 의문이 들 수 있다.
그렇게 하지 않은 이유는 이미 x축과 z 축에 대해서 rotation이 일어나는데 y축에도 이를 적용하면 짐벌락 현상이 발생할 수 있기 때문이다.
2. Built-in Controls
ArcballControls
DragControls
FirstPersonControls
FlyControls
MapControls
OrbitControls
PointerLockControls
TrackballControls
TransformControls
Three.js는 대표적으로 9종류의 컨트롤을 지원하며 OrbitControls가 가장 많이 사용된다.
내장된 controls를 사용하면 카메라의 회전, 위치, 목표를 자동으로 제어할 수 있어 편리하다.
위에서 배웠던 mousemove에 대해 카메라 position이나 rotation을 변경해주는 코드를 사용할 필요가 없어진다.
주의할 점은 패키지에서 바로 사용 가능한 클래스가 아니며 아래 경로에서 임포트해야 사용할 수 있다.
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
OrbitControls에 대해서 주로 알아보자.
초기화 방법
const controls = new OrbitControls(camera, canvas)
Target
기본적으로 카메라는 원점을 바라보고 있고, 이를 변경해주려면 target을 설정하면 된다.
target은 Vector3 객체로 카메라가 항상 바라보는 지점이며 카메라 궤도 운동의 중심점을 정의한다.
주의할 점은 update 메서드를 호출해 OrbitControls에 target을 업데이트하라고 알려줘야 한다. 그렇지 않으면 동작하지 않는다.
controls.target.y = 2
controls.update()
Damping
Damping은 가속도나 마찰 관련 공식을 추가하여 애니메이션을 자연스럽게 만들어준다.
동작하게 하려면 enableDamping 값을 true로 해주고 애니메이션 함수 내부에서 update를 호출해야 한다.
Damping을 위해선 이전 움직임의 속도를 기반으로 새로운 위치와 회전을 계산해야 하는데, update를 매 프레임마다 호출하여 이러한 계산을 수행하는 것이다.
따라서 Damping을 사용할 필요가 없다면 controls를 매번 애니메이션 함수 내부에서 업데이트 할 필요는 없다.
// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true
// ...
const tick = () =>
{
// ...
// Update controls
controls.update()
// ...
}
참고 자료
Controls.target vs Camera.lookAt : https://discourse.threejs.org/t/controls-target-vs-camera-lookat/5086
three.js journey 6강