본문 바로가기
공부/etc

Three.js and TypeScript (9)

by Piva 2024. 11. 22.
  • 27. Orbit Controls 부터 28. Lerp 까지.

Orbit Controls

OrbitControl로 카메라를 조작하는 모습

  • 카메라가 타켓 근처 궤도를 돌도록 한다.
  • 별도의 설정을 하지 않았을시, 마우스를 통해 다양한 조작을 할 수 있다.
    • 마우스 왼쪽 클릭 시 카메라를 회전한다.
    • 마우스 휠로 줌 인/줌 아웃을 할 수 있다.
    • 마우스 오른쪽 클릭 시 Panning(pan: ’카메라가 대상을 따라다니며 보여주다, 찍다’ 라는 의미) 한다.
      • Orbit Controls가 설정된 카메라가 바라보는 타겟을 이동시키는 행위인 듯.
  • addons에서 import 하여 사용할 수 있다.
  • 생성자는 2개의 인자를 받는다.
    • object: 컨트롤될 카메라 객체. Scene 이외의 다른 객체의 자식이어선 안 된다.
    • domElement: 이벤트 리스너에 사용될 HTML 요소.
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

new OrbitControls(camera, renderer.domElement);

 

OrbitControls을 사용할 때 주의할 점은, 카메라를 lookAt으로 컨트롤하는 동시에 OrbitControls을 사용하는 것은 제대로 동작하지 않는다는 점이다.

만약 OrbitControls을 사용하는 동시에 카메라가 바라보는 지점을 바꾸고 싶을 경우, camera.lookAt을 사용하는 것을 지양하되 OrbitControls.target.set 메서드를 사용한 후 OrbitControls.update를 호출해야 한다.

 

 

속성

  • autoRotate: 타겟을 중심으로 자동 회전하게끔 하는 속성.
    • 이 속성을 사용하기 위해선 애니메이션 루프에서 꼭 OrbitControls을 업데이트해야 한다(즉, update 함수를 호출해야 한다).
  • autoRotateSpeed: 회전 속도를 나타내는 속성.
  • enableDamping: 물체의 회전에 관성(inertia)을 추가한다. 이것을 활성화하면 관성이 적용되어 타겟을 회전시킬 때 약간의 무게를 느끼게 한다.
  • dampingFactor: 관성이 적용되어있을 시, 관성의 정도를 나타낸다.
    • 위의 두 관성 관련 속성 또한, autoRotate처럼 애니메이션 루프에서 OrbitControls의 업데이트가 이루어져야 한다.
  • listenToKeyEvents: 인자로 넘겨진 DOM 요소에 키보드 이벤트 리스너를 추가한다. 공식적으로 추천되는 인자는 window 이다.
    • 별도로 설정하지 않는다면, 방향키로 움직일 시 타겟이 이동한다.
  • keys: 키보드를 사용해서 조작할 때, 사용할 키를 선택할 수 있다.
    • 아래 코드는 타겟 이동 키로 WASD를 설정한다.
import * as THREE from 'three';

const controls = new OrbitControls(camera, renderer.domElement);
controls.listenToKeyEvents(window);
controls.keys = {
  LEFT: 'KeyA', // default 'ArrowLeft'
  UP: 'KeyW', // default 'ArrowUp'
  RIGHT: 'KeyD', // default 'ArrowRight'
  BOTTOM: 'KeyS' // default 'ArrowDown'
};

 

 

  • mouseButtons: keys와 비슷하게 마우스로 조작할 때 각 마우스 버튼이 어떤 기능을 담당할지 선택할 수 있다.
    • 각 기능에 대한 정보는 Three.js에 Enum으로 정의되어 있다.
import * as THREE from 'three';

const controls = new OrbitControls(camera, renderer.domElement);
controls.mouseButtons = {
  LEFT: THREE.MOUSE.ROTATE, // 타겟 회전
  MIDDLE: THREE.MOUSE.DOLLY, // 카메라 확대/축소
  RIGHT: THREE.MOUSE.PAN // Panning
};

 

  • touches: 스마트폰 등으로 터치했을 때의 조작을 설정한다.
import * as THREE from 'three';

const controls = new OrbitControls(camera, renderer.domElement);
controls.touches = {
  ONE: THREE.TOUCH.ROTATE, // 한 손가락으로 터치했을 때의 동작
  TWO: THREE.TOUCH.DOLLY_PAN // 두 손가락으로 터치했을 때의 동작
};

 

  • screenSpacePanning: Panning 중 카메라의 위치가 어떻게 바뀔지를 결정한다. true일 시 카메라는 Scene 공간 내에서 Panning하며, false면 카메라의 위쪽 방향과 직교하는 평면으로 Panning 한다.
    • 기본값은 true로 설정되어 있으며, false로 설정할 경우 카메라가 앞/뒤로 이동하는 모습을 보인다.
  • minAzimuthAngle / maxAzimuthAngle: 수평적으로 얼마나 회전을 시킬 수 있는지를 결정한다. -2 PI와 2PI 사이 값을 가져야 하며, max - min이 2 PI보다 작아야 한다.
Azimuth: 방위각을 의미한다.
  • minPolarAngle / maxPolarAngle: 수직적으로 얼마나 회전을 시킬 수 있는지 결정한다. 0 ~ PI 사이 값을 가져야 한다.
  • minDistance / maxDistance: 얼마나 확대/축소 할 수 있는지 그 거리를 결정한다.
  • enabled: Orbit Control을 활성화할지, 하지 않을지를 결정한다.
  • enablePan / enableRotate / enableZoom: 각각 Panning, 회전, 확대를 활성화할지, 하지 않을지 결정한다.

 

메서드

  • getPolarAngle(): 현재의 수직 회전각을 반환한다.
  • getAzimuthalAngle(): 현재의 수평 회전각을 반환한다.

위 두 메서드를 사용해 회전각을 받아 띄우는 모습

강의에서는 위 두 메서드를 살폈는데, 이외에도 다양한 메서드들이 존재한다. (문서)

 

 

Lerp

  • 물체를 애니메이팅 하는 방법 중 하나가 Lerp이다.
  • 이 강의를 비롯한 앞으로의 몇 강의들에서는 물체를 애니메이팅 하는 방법들에 대해서 다뤄볼 예정.
    • 이번 강좌에서는 Three.js에서 제공하는 기본 클래스를 확장 구현하는 예제도 다룰 예정.

 

Lerp란?

  • Linear Interpolation(선형 보간법)을 의미하며, 여기서는 이를 이용한 애니메이팅을 뜻한다.
  • Three.js의 다양한 클래스들이 lerp 메서드를 갖고 있으며, 이를 직접 구현하는 것도 가능하다.

 

커스텀 클래스 만들기

  • 강의에서 만드는 클래스는 아래와 같은 구조를 가진다.
class Pickable extends Mesh {
	hovered = false
  clicked = false
  colorTo: Color
  defaultColor: Color
  geometry: BufferGeometry
  material: MeshStandardMaterial
  v = new Vector3()
  
  constructor(geometry: BufferGeometry, material: MeshStandardMaterial, colorTo: Color) {
    // 생성자. 패러미터로 받은 인자들을 속성에 할당한다.
    // geometry와 material은 Mesh 클래스의 기본 인자로, colorTo만 새로이 추가된 인자이다.
    super()
    this.geometry = geometry
    this.material = material
    this.colorTo = colorTo
    this.defaultColor = material.color.clone()
    this.castShadow = true
  }
  
  update(delta: number) {
    // 애니메이션 루프에서 실행될 함수이다.
    // 물체의 현재 상태에 따른 애니메이션을 수행한다.
    
    // 물체가 클릭되었다면 MathUtils.lerp를 사용해 물체를 위/아래로 이동한다
    this.clicked ? (this.position.y = MathUtils.lerp(this.position.y, 1, delta * 5)) : (this.position.y = MathUtils.lerp(this.position.y, 0, delta * 5))
  }
}
  • update 메서드를 살펴보면, MathUtils.lerp 메서드를 사용하는 것을 알 수 있다.
    • MathUtils.lerp는 인자로 들어온 start와 end값을 주어진 보간 계수(delta * 5)로 보간하여 반환한다.
    • 우선은 쉽게 말해, MathUtils.lerp가 호출될 때마다 start값이 end에 점점 더 가까워진다고 이해하면 된다.
      • 단, 가까워질 뿐이지 end 값에 도달한다는 것은 아니다(그저 무한히 가까워지기만 한다).
      • 따라서 구체적으로 특정 값에 도달하는 것을 원한다면, 직접 lerp함수를 구현하여 사용하는 방법이 있다.
const lerp = (from: number, to: number, speed: number) => {
  const amount = (1 - speed) * from + speed * to;
  
  // 어느 정도 목표 값에 가까워지면 목표 값을 반환한다
  return Math.abs(from - to) < 0.001 ? to : amount;
};
 

선형 보간법 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 선형 보간법(線型補間法, linear interpolation)은 끝점의 값이 주어졌을 때 그 사이에 위치한 값을 추정하기 위하여 직선 거리에 따라 선형적으로 계산하는 방법이

ko.wikipedia.org

 

커스텀 클래스 객체 Pickable을 클릭할 때마다 위 아래로 이동하는 모습


  • 점점 수학적 내용이 늘어가는 것 같다. 각오는 했지만 끙끙 앓고 있다...

'공부 > etc' 카테고리의 다른 글

Three.js and TypeScript (11)  (2) 2024.12.03
Three.js and TypeScript (10)  (0) 2024.11.25
Three.js and TypeScript (8)  (1) 2024.11.21
Three.js and TypeScript (7)  (2) 2024.11.20
Three.js and TypeScript (6)  (0) 2024.11.19