WebGL 叠加视图

查看示例

借助 WebGL 叠加视图,您可以直接使用 WebGL 或使用热门图形库(如 Three.js)向地图添加内容。通过 WebGL 叠加视图,您可以直接访问 Google Maps Platform 用来渲染矢量基本地图的同一 WebGL 渲染上下文。使用共享渲染上下文有诸多好处,例如可利用 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 的句柄。
  • onRemove() 在使用 WebGLOverlayView.setMap(null) 从地图中移除叠加层时调用,您应在其中移除所有的中间对象。

例如,以下是所有生命周期钩子的基本实现:

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
  • rotationArr:欧拉旋转角的 Float32Array(以度数表示)。
  • 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 加速技术的地图体验”Codelab

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);