使用 WebGL 疊加層檢視打造 3D 地圖體驗

1. 事前準備

本程式碼研究室將教您如何使用 Maps JavaScript API 的 WebGL 功能,以 3D 技術操控向量地圖並呈現這些圖像。

最終 3D 圖釘

必要條件

本程式碼研究室假設您對於 JavaScript 和 Maps JavaScript API 具有中等知識。如要瞭解使用 Maps JS API 的基本知識,不妨試試將地圖加入網站 (JavaScript) 程式碼研究室

課程內容

  • 啟用使用 JavaScript 的向量地圖產生地圖 ID。
  • 透過程式輔助傾斜和旋轉方式來控制地圖。
  • 使用 WebGLOverlayViewThree.js 在地圖上算繪 3D 物件。
  • 使用 moveCamera 為相機動作加入動畫效果。

軟硬體需求

  • 已啟用帳單功能的 Google Cloud Platform 帳戶
  • 已啟用 Maps JavaScript API 的 Google 地圖平台 API 金鑰
  • JavaScript、HTML 和 CSS 的中級知識
  • 您選擇的文字編輯器或 IDE
  • Node.js

2. 做好準備

在下方啟用步驟中,您必須啟用 Maps JavaScript API

設定 Google 地圖平台

如果您還沒有 Google Cloud Platform 帳戶和已啟用計費功能的專案,請參閱開始使用 Google 地圖平台指南,建立帳單帳戶和專案。

  1. Cloud Console 中按一下專案下拉式選單,然後選取您要用於這個程式碼研究室的專案。

  1. Google Cloud Marketplace 中啟用此程式碼研究室所需的 Google 地圖平台 API 和 SDK。詳細步驟請參閱這部影片這份文件
  2. 在 Cloud Console 的「憑證」頁面中產生 API 金鑰。你可以按照這部影片這份說明文件中的步驟進行。傳送至 Google 地圖平台的所有要求都需要 API 金鑰。

Node.js 設定

若您尚未安裝 https://nodejs.org/,請在您的電腦中下載並安裝 Node.js 執行階段。

Node.js 隨附 npm 套件管理員,您必須為這個程式碼研究室安裝依附元件。

下載專案入門範本

開始進行這個程式碼研究室之前,請按照下列步驟下載入門專案範本以及完整的解決方案程式碼:

  1. 前往 https://github.com/googlecodelabs/maps-platform-101-webgl/ 下載或建立此程式碼研究室的 GitHub 存放區。入門專案位於 /starter 目錄中,其中包含完成程式碼研究室所需的基本檔案結構。您所需的一切都位於/starter/src目錄中。
  2. 下載入門專案後,請在 /starter 目錄中執行 npm install。這會安裝 package.json 中列出的所有必要依附元件。
  3. 安裝依附元件後,請在目錄中執行 npm start

設定完成之後,您可以使用 Webpack-dev-server,這個程式會編譯及執行您寫入的程式碼。webpack-dev-server 也會在您變更程式碼時,在瀏覽器中自動重新載入應用程式。

如要查看完整的解決方案程式碼,請在 /solution 目錄中完成上述設定步驟。

新增 API 金鑰

基本應用程式包含使用 JS API 載入器載入地圖所需的所有程式碼,因此您只需要提供 API 金鑰和地圖 ID 即可。JS API 載入器是一個簡單的程式庫,可模擬在 HTML 範本中以 script 標記內嵌載入 Maps JS API 的傳統方法,讓您能夠處理 JavaScript 程式碼中的所有項目。

如要新增 API 金鑰,請在入門專案中執行下列操作:

  1. 開啟 app.js
  2. apiOptions 物件中,將 API 金鑰設為 apiOptions.apiKey 的值。

3. 產生並使用地圖 ID

如要使用 WebGL JavaScript 中的 WebGL 功能,您需要有已啟用向量地圖的地圖 ID。

產生地圖 ID

產生地圖 ID

  1. 在 Google Cloud Console 中,前往「Google 地圖平台」和「地圖管理」。
  2. 按一下 [建立新地圖 ID]
  3. 在 [地圖名稱'] 欄位中,輸入地圖 ID 的名稱。
  4. 在 [地圖類型] 下拉式選單中,選取 [JavaScript]。畫面隨即顯示「JavaScript 選項」。
  5. 在「JavaScript 選項」中,選取「向量」、「圓形按鈕」和「旋轉」等核取方塊。
  6. (選用) 在 [說明] 欄位輸入 API 金鑰的說明。
  7. 按一下 [下一步] 按鈕。畫面上會出現「地圖 ID 詳細資料」頁面。

    地圖詳細資訊頁面
  8. 複製地圖 ID。在下一個步驟中,您將使用此方法載入地圖。

使用地圖 ID

如要載入向量地圖,您必須在對地圖進行執行個體時,在選項中提供地圖 ID 做為屬性。或者,您也可以在載入 Maps JavaScript API 時提供相同的地圖 ID。

如要以地圖 ID 載入地圖,請按照下列步驟操作:

  1. 將您的地圖 ID 設為 mapOptions.mapId 的值。

    提供地圖 ID 時,請提供地圖 ID 讓 Google 地圖平台載入特定執行個體的載入地圖。你可以將同一個地圖 ID 重複用於多個應用程式,或在同一個應用程式中多次檢視。
    const mapOptions = {
      "tilt": 0,
      "heading": 0,
      "zoom": 18,
      "center": { lat: 35.6594945, lng: 139.6999859 },
      "mapId": "YOUR_MAP_ID"
    };
    

檢查瀏覽器上執行的應用程式。啟用傾斜和旋轉的向量地圖會順利載入。如要確認是否已啟用傾斜和旋轉功能,請按住 Shift 鍵,然後用滑鼠拖曳,或使用鍵盤上的方向鍵。

如果地圖無法載入,請確認您已在 apiOptions 中提供有效的 API 金鑰。如果地圖並未傾斜且旋轉,請確認您已在 apiOptionsmapOptions 中提供已啟用傾斜和旋轉的地圖 ID。

傾斜的地圖

您的 app.js 檔案現在應如下所示:

    import { Loader } from '@googlemaps/js-api-loader';

    const apiOptions = {
      "apiKey": 'YOUR_API_KEY',
    };

    const mapOptions = {
      "tilt": 0,
      "heading": 0,
      "zoom": 18,
      "center": { lat: 35.6594945, lng: 139.6999859 },
      "mapId": "YOUR_MAP_ID"
    }

    async function initMap() {
      const mapDiv = document.getElementById("map");
      const apiLoader = new Loader(apiOptions);
      await apiLoader.load();
      return new google.maps.Map(mapDiv, mapOptions);
    }

    function initWebGLOverlayView (map) {
      let scene, renderer, camera, loader;
      // WebGLOverlayView code goes here
    }

    (async () => {
      const map = await initMap();
    })();

4. 實作 WebGLOverlayView

WebGLOverlayView 可讓您直接存取與顯示向量基本地圖相同的 WebGL 轉譯內容。這表示您可以使用 WebGL 以及熱門的 WebGL 圖形程式庫,直接在地圖上算繪 2D 和 3D 物件。

WebGLOverlayView 會呈現五項掛勾,並呈現 WebGL 轉譯功能的生命週期,可供您使用的地圖。以下提供有關每個掛鉤的簡要說明,以及應如何操作:

  • onAdd():在 WebGLOverlayView 執行個體上呼叫 setMap 以將疊加層加入地圖時呼叫。在此之前,您必須執行與 WebGL 相關的任何工作,而不需直接存取 WebGL 內容。
  • onContextRestored():當 WebGL 內容可供使用,但尚未顯示任何內容時,就會呼叫此事件。這裡應初始化物件、繫結狀態,以及執行需要存取 WebGL 內容,但可在 onDraw() 呼叫以外執行的其他任何動作。如此一來,您便可以完成所有設定,而不需為實際顯示的地圖增加過多負荷,因為 GPU 會佔用大量資源。
  • onDraw():當 WebGL 開始轉譯地圖和您要求的任何其他內容時,每頁框呼叫一次。您應該盡量在 onDraw() 中完成所有工作,以免地圖效能造成地圖效能問題。
  • onContextLost():當 WebGL 轉譯內容因任何原因而遺失時,就會呼叫此事件。
  • onRemove():在 WebGLOverlayView 執行個體上呼叫 setMap(null),從疊加層移除地圖時呼叫。

在這個步驟中,您將建立 WebGLOverlayView 的執行個體,並實作三個生命週期生命週期:onAddonContextRestoredonDraw。為了讓程式碼更簡潔易懂,系統會在此程式碼研究室的新手範本中使用 initWebGLOverlayView() 函式處理疊加層的所有程式碼。

  1. 建立 WebGLOverlayView() 執行個體。

    疊加層是由 google.maps.WebGLOverlayView 的 Maps JS API 提供。如要開始使用,請針對 initWebGLOverlayView() 提交要求,藉此建立執行個體:
    const webGLOverlayView = new google.maps.WebGLOverlayView();
    
  2. 實作生命週期掛鉤。

    如要實作生命週期掛鉤,請將以下內容附加至 initWebGLOverlayView()
    webGLOverlayView.onAdd = () => {};
    webGLOverlayView.onContextRestored = ({gl}) => {};
    webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {};
    
  3. 在地圖上新增疊加層例項。

    現在可在疊加層執行個體上呼叫 setMap(),並將以下內容附加至 initWebGLOverlayView(),以傳入地圖:
    webGLOverlayView.setMap(map)
    
  4. 呼叫 initWebGLOverlayView

    最後一步是將 initWebGLOverlayView() 新增到 app.js 底部立即叫用的函式中:
    initWebGLOverlayView(map);
    

您的 initWebGLOverlayView 和立即叫用的函式現在應如下所示:

    async function initWebGLOverlayView (map) {
      let scene, renderer, camera, loader;
      const webGLOverlayView = new google.maps.WebGLOverlayView();

      webGLOverlayView.onAdd = () => {}
      webGLOverlayView.onContextRestored = ({gl}) => {}
      webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {}
      webGLOverlayView.setMap(map);
    }

    (async () => {
      const map = await initMap();
      initWebGLOverlayView(map);
    })();

以上就是執行 WebGLOverlayView 所需的一切資訊。其次,您將使用 Three.js 設定在地圖上繪製 3D 物件所需的一切資訊。

5. 設定 3.js 場景

使用 WebGL 可能十分複雜,因為您必須手動定義每個物件的所有部分,然後才定義。為了簡化這個過程,在本程式碼研究室中,您會使用 Three.js 這個熱門的圖形程式庫,在 WebGL 之上提供簡化的抽象層。Three.js 提供各式各樣的便利功能,從建立 WebGL 轉譯器到繪製常用 2D 與 3D 物件形狀,到控制相機、物件轉換等,各種功能應有盡有。

在 Three.js 中,有三種必須顯示的基本物件類型:

  • 場景:「容器」是指所有物件、光源、紋理等展示與顯示。
  • 相機:代表場景視角的相機。提供多種攝影機類型,也可以在一個場景中加入一或多種攝影機。
  • Renderer:轉譯器能夠處理場景中所有物件的處理和顯示。在 Three.js 中,WebGLRenderer 是最常用的,但還有一些用戶端可用做備用廣告,因為用戶端不支援 WebGL。

在這個步驟中,您將載入 Three.js 所需的所有依附元件,並設定基本場景。

  1. 載入 3.js

    您必須有這個程式碼研究室的兩個依附元件:Three.js 程式庫和 GLTF 載入程式,該類別可讓您以 GL Trasmission Format (gLTF) 載入 3D 物件。Three.js 針對許多不同的 3D 物件格式提供專用載入器,但建議您使用 gLTF。

    在下方程式碼中,系統會匯入整個 Three.js 程式庫。在實際執行應用程式中,您可能只想匯入您需要的課程,但對於這個程式碼研究室,請匯入整個程式庫以簡化作業。另請注意,GLTF 載入器未包含在預設程式庫中,而且必須從依附元件的個別路徑匯入,您可透過此存取 Three.js 提供的所有載入器。

    如要匯入 Three.js 和 GLTF 載入程式,請在 app.js 頂端加入下列指令:
    import * as THREE from 'three';
    import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
    
  2. 建立 3.js 場景。

    要建立場景,請在 onAdd 掛鉤上,將 Three.js Scene 類別執行個體化:
    scene = new THREE.Scene();
    
  3. 在場景中加入相機。

    如先前所述,相機呈現的是場景的視角,並決定 Three.js 如何處理場景中特定物件的視覺呈現。沒有相機,實際上就不是「查看」場景,這表示物件不會被轉譯,因此不會顯示。

    Three.js 提供許多不同的相機,能讓轉譯器在處理角度和深度等方面處理物件。在此情況下,您在 PerspectiveCamera這表示距離相機較遠的物件會小於距離較近的物件,且場景中會出現一個虛線等。

    如要在場景中加入視角相機,請在 onAdd 掛鉤上加入下列標記:
    camera = new THREE.PerspectiveCamera();
    
    使用 PerspectiveCamera 時,您也可以設定構成視角的屬性,包括近距離及遠方的平面、長寬比和視野 (fov)。這些屬性統稱為「檢視區塊」,這是在 3D 工作時共同理解的重要概念,但不在本程式碼研究室的範圍之內。預設的 PerspectiveCamera 設定就夠用了。
  4. 為場景新增光源。

    根據預設,在 Three.js 場景中呈現的物件會以黑色顯示,無論其套用何種材質。這是因為 Three.js 場景會仿照物體在現實中的行為,而色彩的能見度則取決於反射在物體上的光。簡單、輕巧、無色彩

    Three.js 提供不同類型的不同類型的燈光:
  5. AmbientLight:提供擴散的光源,讓光源從拍攝的所有角度平均照射。這會讓場景呈現基準光,確保所有物體的材質都能清楚呈現。
  6. DirectionalLight:提供源自場景中某個方向的光。有別於位置的光源在現實世界中的運作方式,從 DirectionalLight 射出的光線可平行處理,而且不會偏離光源,因此不會超出光源。

    您可以設定每個燈具的顏色和強度,以產生匯總的燈光效果。舉例來說,在下方的程式碼中,環境光度為整個場景提供柔和的白光,而定向光線則提供用於向下移動物件的次要光源。針對方向性光線,角度是使用 position.set(x, y ,z) 設定,其中每個值相對於相對軸。因此,position.set(0,1,0) 會使燈光直射到 Y 軸的正上方。

    如要將光源新增至場景中,請在 onAdd 掛鉤上附加以下項目:
    const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 );
    scene.add(ambientLight);
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
    directionalLight.position.set(0.5, -1, 0.5);
    scene.add(directionalLight);
    

onAdd」掛鉤現在應如下所示:

    webGLOverlayView.onAdd = () => {
      scene = new THREE.Scene();
      camera = new THREE.PerspectiveCamera();
      const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 );
      scene.add(ambientLight);
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
      directionalLight.position.set(0.5, -1, 0.5);
      scene.add(directionalLight);
    }

您的場景已設定完成,可以開始顯示。接著,您必須設定 WebGL 轉譯器並呈現場景。

6. 顯示場景

是時候呈現您的場景了。到目前為止,您使用 Three.js 所建立的所有項目均以程式碼初始化,但基本上不存在,因為尚未轉譯至 WebGL 轉譯內容。WebGL 可透過 canvas API 在瀏覽器中顯示 2D 和 3D 內容。如果您曾使用 Canvas API,表示您可能對 HTML 畫布的 context 很熟悉,也就是 HTML 畫布。您也許不知道,這個介面是透過 WebGLRenderingContext API,在瀏覽器中顯示 OpenGL 圖形轉譯內容。

為方便與 WebGL 轉譯器進行交易,Three.js 提供的 WebGLRenderer 包裝函式可讓您更輕鬆地設定 WebGL 轉譯內容,讓 Three.js 在瀏覽器中顯示場景。不過,如果地圖是地圖,則無法直接在瀏覽器旁顯示 Three.js 場景。Three.js 必須轉譯為地圖完全相同的顯示情境,這樣地圖和 從 Three.js 場景中的任何物件都會顯示為同一個世界空間。如此一來,轉譯器就可以處理地圖物件與場景中物件之間的互動,例如遮蔽,這是一種說服用物體隱藏物體後方的物件。

聽起來很複雜,對吧?幸好,Three.js 再次開始修復。

  1. 設定 WebGL 轉譯器。

    建立新的 Three.js WebGLRenderer 執行個體時,您可以提供所需的 WebGL 轉譯內容,使其能用來轉譯場景。請記住,要傳送至 onContextRestored 掛鉤的 gl 引數?該 gl 物件是地圖的 WebGL 轉譯內容。您只需要將內容、其畫布及其屬性提供給 WebGLRenderer 執行個體,這些執行個體都可以透過 gl 物件取得。在這個程式碼中,轉譯器的 autoClear 屬性也設定為 false,因此轉譯器並不會清除每個頁框的輸出內容。

    如要設定轉譯器,請將以下內容附加至 onContextRestored 掛鉤:
    renderer = new THREE.WebGLRenderer({
      canvas: gl.canvas,
      context: gl,
      ...gl.getContextAttributes(),
    });
    renderer.autoClear = false;
    
  2. 顯示場景。

    轉譯器設定完畢後,請在 WebGLOverlayView 執行個體上呼叫 requestRedraw,指出疊加層會在下一個畫格算繪時需要重新繪製,然後呼叫轉譯器上的 render,並傳送 3.js 場景和相機進行轉譯。最後,清除 WebGL 轉譯內容的狀態。這是避免使用 GL 狀態衝突的重要步驟,因為使用 WebGL 疊加層檢視需要共用 GL 狀態。如果每次繪圖呼叫皆未重設狀態,GL 狀態衝突可能會導致轉譯器失敗。

    方法是將以下內容附加至 onDraw 掛鉤,以便執行每個頁框:
    webGLOverlayView.requestRedraw();
    renderer.render(scene, camera);
    renderer.resetState();
    

onContextRestored」和「onDraw」的掛鉤現在應如下所示:

    webGLOverlayView.onContextRestored = ({gl}) => {
      renderer = new THREE.WebGLRenderer({
        canvas: gl.canvas,
        context: gl,
        ...gl.getContextAttributes(),
      });

      renderer.autoClear = false;
    }

    webGLOverlayView.onDraw = ({gl, transformer}) => {
      webGLOverlayView.requestRedraw();
      renderer.render(scene, camera);
      renderer.resetState();
    }

7. 在地圖上算繪 3D 模型

好,所有事情都完成了。您已設定 WebGl 疊加層檢視並建立了 Three.js 場景,但這有一個問題:還沒有問題。因此,接下來要呈現場景中的 3D 物件。只要利用您之前匯入的 GLTF 載入程式即可。

3D 模型有多種不同格式,但在 Three.js 中,gLTF 格式是其大小和執行階段效能,因此建議使用。在這個程式碼研究室中,您已在 /src/pin.gltf 中提供了可在場景中呈現的模型。

  1. 建立模型載入器執行個體。

    將以下內容附加至 onAdd
    loader = new GLTFLoader();
    
  2. 載入 3D 模型。

    模型載入器為非同步,並在模型完全載入後執行回呼。如要載入 pin.gltf,請將以下內容附加至 onAdd
    const source = "pin.gltf";
    loader.load(
      source,
      gltf => {}
    );
    
  3. 將模型新增至場景。

    現在,您可以將以下內容附加至 loader 回呼,藉此將模型新增至場景。請注意,系統正在新增 gltf.scene,而非 gltf
    scene.add(gltf.scene);
    
  4. 設定相機投影矩陣。

    為了讓模型正確顯示在地圖上,最後的最後一個步驟是設定相機在 Three.js 場景中的投影矩陣。投影矩陣是指定為 Three.js Matrix4 陣列,該陣列定義了在 3D 空間中的點以及轉換 (例如旋轉、剪成、縮放等)。

    WebGLOverlayView 為例,投影矩陣是用來告訴轉譯器相對於相對地圖的繪製 3.js 場景的位置和方式。但這有問題地圖上的位置是經緯度座標的指定,而 Three.js 場景中的位置是 Vector3 座標。如您所知,計算兩個系統之間的轉換並不容易。如要解決這個問題,WebGLOverlayView 會將 coordinateTransformer 物件傳遞至包含 fromLatLngAltitude 函式的 OnDraw 生命週期掛鉤。fromLatLngAltitude 會取得 LatLngAltitudeLatLngAltitudeLiteral 物件,並選擇性定義用來定義場景轉換的引數,並為您將這些物件涵蓋模型檢視投影 (MVP) 矩陣。你只需在地圖上指定 3.js 場景的顯示位置以及轉換方式,剩下的就交給 WebGLOverlayView。接著您就可以將 MVP 矩陣轉換為 Three.js Matrix4 陣列,並且將相機投影矩陣設為該矩陣。

    在下方的程式碼中,第二個引數會指示 WebGl 疊加層檢視將 Three.js 場景的高度設為離地 120 公尺,導致模型看起來像是漂浮。

    如要設定相機投影矩陣,請將以下內容附加至 onDraw 掛鉤:
    const latLngAltitudeLiteral = {
        lat: mapOptions.center.lat,
        lng: mapOptions.center.lng,
        altitude: 120
    }
    const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral);
    camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
    
  5. 轉換模型。

    你會發現圖釘與地圖不相上下。在 3D 圖形中,除了世界上擁有決定 方向的 x、y 和 z 軸,每個物件還擁有自己的物件空間,並具有各自專屬的軸線。

    採用這個模型時,模型並不是以一般的 y 軸表示,因此一般來說不會使用「頂部」的頂部,因此你必須將 rotation.set 轉換成物件,使其與世界空間相對應。請注意,在 Three.js 中,旋轉是以弧度指定,而非度數。一般來說,使用角度比較容易,因此必須使用公式 degrees * Math.PI/180 來進行適當的轉換。

    此外,模型略有小,所以您通過呼叫 scale.set(x, y ,z) 在所有軸上平均分配它。

    如要旋轉及擴充模型,請將 onAddloader 回呼新增至 onAddscene.add(gltf.scene),再將 gLTF 新增至場景:
    gltf.scene.scale.set(25,25,25);
    gltf.scene.rotation.x = 180 * Math.PI/180;
    

現在,圖釘沿著地圖朝上。

直立圖釘

onAdd」和「onDraw」的掛鉤現在應如下所示:

    webGLOverlayView.onAdd = () => {
      scene = new THREE.Scene();
      camera = new THREE.PerspectiveCamera();
      const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 ); // soft white light
      scene.add( ambientLight );
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
      directionalLight.position.set(0.5, -1, 0.5);
      scene.add(directionalLight);

      loader = new GLTFLoader();
      const source = 'pin.gltf';
      loader.load(
        source,
        gltf => {
          gltf.scene.scale.set(25,25,25);
          gltf.scene.rotation.x = 180 * Math.PI/180;
          scene.add(gltf.scene);
        }
      );
    }

    webGLOverlayView.onDraw = ({gl, transformer}) => {
      const latLngAltitudeLiteral = {
        lat: mapOptions.center.lat,
        lng: mapOptions.center.lng,
        altitude: 100
      }

      const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral);
      camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);

      webGLOverlayView.requestRedraw();
      renderer.render(scene, camera);
      renderer.resetState();
    }

接下來是相機動畫!

8. 為相機加入動畫

現在您已經在地圖上繪製了模型,而且可以在 3D 空間上進行所有動作,因此接下來想要進行的動作,就是透過程式輔助方式控制這種動作。moveCamera 函式可讓您同時設定地圖的中心、縮放、傾斜和標題屬性,讓您精細地掌控使用者體驗。此外,moveCamera 還可在動畫迴圈中呼叫,以每秒近 60 個畫格的影格速率建立畫格之間的轉換轉場效果。

  1. 等待模型載入。

    如要打造流暢的使用者體驗,建議你等到 gLTF 模型載入完成後再開始移動相機。如要這麼做,請將載入器的 onLoad 事件處理常式附加至 onContextRestored 掛鉤:
    loader.manager.onLoad = () => {}
    
  2. 建立動畫迴圈。

    您可以透過多種方式建立動畫迴圈,例如使用 setIntervalrequestAnimationFrame。在這種情況下,您會使用 Three.js 轉譯器的 setAnimationLoop 函式;每當 Three.js 轉譯新頁框時,系統將自動呼叫您在回呼中宣告的任何程式碼。如要建立動畫迴圈,請在上一個步驟中加入以下內容至 onLoad 事件處理常式:
    renderer.setAnimationLoop(() => {});
    
  3. 在動畫迴圈中設定相機位置。

    接下來,請呼叫 moveCamera 以更新地圖。這裡用於載入地圖之 mapOptions 物件的屬性會使用定義相機位置的位置:
    map.moveCamera({
      "tilt": mapOptions.tilt,
      "heading": mapOptions.heading,
      "zoom": mapOptions.zoom
    });
    
  4. 每幅更新攝影機。

    最後一步!更新每個畫格的 mapOptions 物件,以設定下一個畫格的相機位置。if完成的動畫播放完畢後,系統會將 null 傳送到 setAnimationLoop 來取消動畫,讓動畫無法永久執行。
    if (mapOptions.tilt < 67.5) {
      mapOptions.tilt += 0.5
    } else if (mapOptions.heading <= 360) {
      mapOptions.heading += 0.2;
    } else {
      renderer.setAnimationLoop(null)
    }
    

onContextRestored」掛鉤現在應如下所示:

    webGLOverlayView.onContextRestored = ({gl}) => {
      renderer = new THREE.WebGLRenderer({
        canvas: gl.canvas,
        context: gl,
        ...gl.getContextAttributes(),
      });

      renderer.autoClear = false;

      loader.manager.onLoad = () => {
        renderer.setAnimationLoop(() => {
           map.moveCamera({
            "tilt": mapOptions.tilt,
            "heading": mapOptions.heading,
            "zoom": mapOptions.zoom
          });

          if (mapOptions.tilt < 67.5) {
            mapOptions.tilt += 0.5
          } else if (mapOptions.heading <= 360) {
            mapOptions.heading += 0.2;
          } else {
            renderer.setAnimationLoop(null)
          }
        });
      }
    }

9. 恭喜

如果一切都按計畫進行,你應該會看到具有大型 3D 圖釘的地圖,如下所示:

最終 3D 圖釘

您學到的內容

在這個程式碼研究室中,您已經學到了很多資訊,重點如下:

  • 實作 WebGLOverlayView 及其生命週期掛鉤。
  • 將 Three.js 整合至地圖。
  • 建立 Three.js 場景的基本概念,包括相機和照明設備。
  • 使用 Three.js 載入並操控 3D 模型。
  • 使用 moveCamera 控制和調整地圖的相機動畫。

後續步驟

整體來說,WebGL 和電腦繪圖都很複雜,因此還有很多需要學習的領域。以下資源可協助您快速上手: