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);
例
次の簡単な例では、一般的なオープンソースの WebGL ライブラリである Three.js を使用して、地図に 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);