借助 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
:纬度/经度/海拔高度坐标,格式为LatLngAltitude
或LatLngAltitudeLiteral
。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);