구글 Street View + Three.js 관로 구현(2)

김유현·2024년 11월 24일

실무 개선 기록

목록 보기
9/10
post-thumbnail

이번 글에서는 Street View 와 Three.js 카메라를 동기화하는 작업을 설명합니다.

지난 글에서는 GIS 데이터를 로드해서 Three.js에서 사용 가능한 좌표계로 변환하고,
Mesh를 만들었습니다.

이제 만들어놓은 Mesh들을 구글 스트리트 뷰에서 동기화 하는 작업에 대해서 설명하겠습니다.


Google Street View와 Three.js 동기화하기

엔진이 배를 움직이는 것이 아니다. 배는 그 자리에 가만이 있으나 엔진이 이 세상을 회전해 움직이는 것이다.
출처: OpenGL Tutorial

const streetView = map.getStreetView();
streetView.addListener('position_changed', () => { // (1)
  const position = streetView.getPosition();
  if (position === null) return;

  const meters = this.latLngToMeters(position.lng(), position.lat()); // (2)
  this.camera?.position.set(meters.x, 3, -meters.y);

  this.updateCameraFov(); // (3)
  this.updatePipeVisibility(); // (5)
  this.updateMarkerVisibility(); // (6) 
  this.camera.updateMatrixWorld(); // (7)
});

streetView.addListener('pov_changed', () => { // (4)
  const pov = streetView.getPov();
  const deg2rad = (degrees: number) => degrees * (Math.PI / 180);
  this.camera.rotation.set(deg2rad(pov.pitch), deg2rad(-pov.heading), 0, 'YXZ');

  // 카메라의 월드 매트릭스를 업데이트하여 정확한 위치를 확보
  this.camera.updateMatrixWorld();
  this.updateCameraFov();
});
  1. position_changed 이벤트 리스너

    • Google Street View에서 사용자의 위치가 변경될 때마다 실행됩니다.
    • 새 위치를 가져와 Three.js 카메라와 관련 데이터를 업데이트합니다.
  2. 스트리트 뷰의 좌표를 미터 단위로 반환해서 Threes.js 카메라 위치 업데이트

    • 여기서 카메라의 y축(높이)는 3m로 설정하였습니다.
    • 스트리트 뷰의 카메라는 차량 위에서 촬영되기 때문
  3. Three.js 카메라 시야각(FOV) 업데이트 함수 호출

    // 카메라 FOV 업데이트 함수
    updateCameraFov() {
      const zoom = this.panorama?.getZoom(); // Google Street View의 현재 zoom 레벨
      if(zoom === undefined) return;
      const fov = this.zoomLevelToFov(zoom); // Zoom 레벨에 따른 FOV 계산
      this.camera.fov = fov; // THREE.js 카메라의 FOV 설정
      this.camera.updateProjectionMatrix(); // 카메라의 프로젝션 매트릭스 업데이트
    }
    
    // Zoom 레벨에 따른 FOV 계산 함수 (근사값 사용)
    zoomLevelToFov(zoom: number) {
      // Zoom 레벨 1에서의 FOV를 90도로 가정
      // Zoom 레벨이 증가함에 따라 FOV 감소
      return 55 / Math.pow(2, zoom - 1);
    }
    • 여기서 zoom은 Google Street View의 줌 레벨을 의미합니다.
    • zoom 레벨이 높아져 지도가 확대되어 보일수록 FOV가 작아져야합니다.
  4. pov_changed 이벤트 리스너

  • Google Street View의 POV(Point of View, 시점) 값이 변경될 때, Three.js 카메라의 회전 상태를 업데이트하여 Street View와 동기화합니다.
    - Street View의 POV(Point of View)가 변경될 때마다 실행됩니다.
    - POV는 사용자가 Street View에서 시점을 이동하거나 회전시킬 때 변경되며, heading(수평 회전)과 pitch(수직 회전) 값을 포함합니다.
    • POV 구성 요소
      - heading: 시점의 수평 각도(0~360도, 동쪽 기준).
      - pitch: 시점의 수직 각도(-90~90도, 아래에서 위로).
    • const deg2rad = (degrees: number) => degrees * (Math.PI / 180);
      • Three.js에서 회전 값은 라디안 단위로 설정해야 합니다.
        - 이 함수는 각도(degrees)를 라디안(radians)으로 변환합니다.
        - deg2rad(pov.pitch): 수직 회전 각도(pitch)를 라디안으로 변환해 X축 회전에 적용합니다.
        - deg2rad(-pov.heading): 수평 회전 각도(heading)를 라디안으로 변환해 Y축 회전에 적용합니다. 음수(-)를 적용해 Three.js 좌표계와 Street View의 방향 차이를 보정합니다.
        - YXZ: 회전 순서를 지정합니다.
        - YXZ는 Y축 → X축 → Z축 순서로 회전을 적용하는 것을 의미하며, 이는 카메라 회전에서 흔히 사용하는 순서입니다.
  1. 관로 렌더링 여부 업데이트
    • 현재 카메라 위치에서 반경(this.radius) 이내에 있는 관로만 렌더링합니다.
    • 카메라와 관로 경로의 각 점 사이의 거리를 계산해 가시 여부를 판단합니다.
    • 반경 이내에 있는 관로는 구글 Street View + Three.js 관로 구현(1)에서 구현했던 addPipeLine 함수를 통해 Three.js 렌더러에 Mesh를 그려줍니다.
  2. 마커 렌더링 여부 업데이트
    • 카메라 반경(this.radius) 내에 있는 마커만 가시화합니다.
    • 구글 스트리트 뷰에서 마커 표시 기능은 지원하므로 빌보드 만 추가해줍니다.
  3. updateMatrixWorld
    • 카메라의 월드 매트릭스를 업데이트하여 정확한 위치를 확보합니다.

결론

이 작업을 통해 Google Street View와 Three.js의 카메라가 동기화되며, 3D 관로와 마커가 자연스럽게 표시됩니다.

profile
FRONTEND DEVELOPER

0개의 댓글