WebGL 疊加層檢視

查看範例

您可以透過 WebGL 疊加層檢視,直接使用 WebGL 或常用圖形程式庫 (例如 Three.js) 在地圖上新增內容。運用 WebGL 疊加層檢視,即可直接存取 Google 地圖平台算繪向量基本地圖的環境。共用算繪環境有許多好處,包括運用 3D 建築物幾何圖形進行深度遮蔽,及同步處理 2D/3D 內容與基本地圖算繪。透過 WebGL 疊加層檢視算繪的物件也可以與經緯度座標建立關聯,因此當您拖曳、縮放、平移或傾斜地圖時,這些物件會隨之移動。

需求條件

如要使用 WebGL 疊加層檢視,請透過已啟用向量地圖的地圖 ID 載入地圖。強烈建議您在建立地圖 ID 時啟用傾斜和旋轉,即可使用完整的 3D 攝影機控制功能。詳情請參閱總覽

新增 WebGL 疊加層檢視

如要將疊加層加入地圖,請導入 google.maps.WebGLOverlayView,然後使用 setMap 傳遞至地圖執行個體:

// Create a map instance.
const map = new google.maps.Map(mapDiv, mapOptions);

// Create a WebGL Overlay View instance.
const webglOverlayView = new google.maps.WebGLOverlayView();

// Add the overlay to the map.
webglOverlayView.setMap(map);

生命週期掛鉤

WebGL 疊加層檢視提供一組掛鉤,可在向量基本地圖 WebGL 算繪環境生命週期中的不同時間點呼叫。在這些生命週期掛鉤中,您可以設定、繪製及拆解要在疊加層中算繪的任何內容。

  • 建立疊加層後,系統會呼叫 onAdd()。在繪製疊加層前,請使用此方法擷取或建立中繼資料結構,不需要立即存取 WebGL 算繪環境。
  • 算繪環境可供使用時,系統會呼叫 onContextRestored({gl})。可用來初始化或繫結任何 WebGL 狀態,例如著色器、GL 緩衝區物件等。onContextRestored() 會採用 WebGLStateOptions 執行個體,其中包含單一欄位:
    • gl 是基本地圖使用的 WebGLRenderingContext 控制代碼。
  • onDraw({gl, transformer}) 會在基本地圖上算繪場景。onDraw() 的參數是 WebGLDrawOptions 物件,其中包含兩個欄位:
    • gl 是基本地圖使用的 WebGLRenderingContext 控制代碼。
    • transformer 提供輔助函式,能把地圖座標轉換為模型檢視投影矩陣。您可以使用此函式將地圖座標轉譯為世界空間、攝影機空間和螢幕空間。
  • 如有任何因素造成算繪環境遺失,系統會呼叫 onContextLost(),其中任何既有的 GL 狀態都不再需要使用,請加以清除。
  • onStateUpdate({gl}) 會更新算繪迴圈外的 GL 狀態,並在呼叫 requestStateUpdate 時加以叫用。這會採用 WebGLStateOptions 執行個體,其中包含單一欄位:
    • gl 是基本地圖使用的 WebGLRenderingContext 控制代碼。
  • 使用 WebGLOverlayView.setMap(null) 從地圖中移除疊加層時,系統會呼叫 onRemove(),請務必移除其中的所有中繼物件。

舉例來說,以下是所有生命週期掛鉤的基本實作方式:

const webglOverlayView = new google.maps.WebGLOverlayView();

webglOverlayView.onAdd = () => {
  // Do setup that does not require access to rendering context.
}

webglOverlayView.onContextRestored = ({gl}) => {
  // Do setup that requires access to rendering context before onDraw call.
}

webglOverlayView.onStateUpdate = ({gl}) => {
  // Do GL state setup or updates outside of the render loop.
}

webglOverlayView.onDraw = ({gl, transformer}) => {
  // Render objects.
}

webglOverlayView.onContextLost = () => {
  // Clean up pre-existing GL state.
}

webglOverlayView.onRemove = () => {
  // Remove all intermediate objects.
}

webglOverlayView.setMap(map);

重設 GL 狀態

WebGL 疊加層檢視可顯示基本地圖的 WebGL 算繪環境。因此,完成算繪物件時,請務必將 GL 狀態重設為原始狀態。如未能重設 GL 狀態,可能會導致 GL 狀態衝突,造成地圖和您指定的任何物件算繪失敗。

GL 狀態重設通常會在 onDraw() 掛鉤中處理。例如,Three.js 提供的輔助函式會清除 GL 狀態的任何變更:

webglOverlayView.onDraw = ({gl, transformer}) => {
  // Specify an object to render.
  renderer.render(scene, camera);
  renderer.resetState();
}

如果地圖或物件無法算繪,很可能表示 GL 狀態尚未重設。

座標轉換

提供經緯度座標的組合以及海拔高度,即可指定物件在向量地圖上的位置。不過,3D 圖形是在世界空間、攝影機空間或螢幕空間中指定。為方便將地圖座標轉換為更常用的空間,WebGL 疊加層檢視會在 onDraw() 掛鉤中提供 coordinateTransformer.fromLatLngAltitude(latLngAltitude, rotationArr, scalarArr) 輔助函式,該掛鉤會使用下列項目並傳回 Float64Array

  • latLngAltitude:緯度/經度/海拔高度座標,格式為 LatLngAltitudeLatLngAltitudeLiteral
  • rotationArrFloat32Array 的歐拉旋轉角度 (以度為單位)。
  • scalarArr:要套用至基軸的純量 Float32Array

例如,以下程式碼使用 fromLatLngAltitude() 在 Three.js 中建立攝影機投影矩陣:

const camera = new THREE.PerspectiveCamera();
const matrix = coordinateTransformer.fromLatLngAltitude({
    lat: mapOptions.center.lat,
    lng: mapOptions.center.lng,
    altitude: 120,
});
camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);

範例

以下簡單示範如何使用 Three.js (常用開放原始碼 WebGL 程式庫) 在地圖上放置 3D 物件。若想瞭解如何使用 WebGL 疊加層檢視建立本頁上方的範例,請到程式碼研究室:打造採用 WebGL 加速技術的地圖體驗,查看完整逐步操作說明。

const webglOverlayView = new google.maps.WebGLOverlayView();
let scene, renderer, camera, loader;

webglOverlayView.onAdd = () => {
  // Set up the Three.js scene.
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera();
  const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 ); // Soft white light.
  scene.add(ambientLight);

  // Load the 3D model with GLTF Loader from Three.js.
  loader = new GLTFLoader();
  loader.load("pin.gltf");
}

webglOverlayView.onContextRestored = ({gl}) => {
  // Create the Three.js renderer, using the
  // maps's WebGL rendering context.
  renderer = new THREE.WebGLRenderer({
    canvas: gl.canvas,
    context: gl,
    ...gl.getContextAttributes(),
  });
  renderer.autoClear = false;
}

webglOverlayView.onDraw = ({gl, transformer}) => {
  // Update camera matrix to ensure the model is georeferenced correctly on the map.
  const matrix = transformer.fromLatLngAltitude({
      lat: mapOptions.center.lat,
      lng: mapOptions.center.lng,
      altitude: 120,
  });
camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);

  // Request a redraw and render the scene.
  webglOverlayView.requestRedraw();
  renderer.render(scene, camera);

  // Always reset the GL state.
  renderer.resetState();
}

// Add the overlay to the map.
webglOverlayView.setMap(map);