Vista de superposición de WebGL

Ver muestra

Con la vista de superposición de WebGL, puedes agregar contenido a tus mapas directamente con WebGL o con las bibliotecas de gráficos populares, como Three.js. La vista de superposición de WebGL brinda acceso directo al mismo contexto de renderización de WebGL que usa Google Maps Platform para renderizar el mapa base de vectores. Este uso de un contexto de renderización compartido proporciona beneficios, como la oclusión de profundidad con la geometría de edificios 3D y la capacidad de sincronizar el contenido 2D y 3D con la renderización del mapa base. Los objetos renderizados con la vista de superposición de WebGL también pueden vincularse a coordenadas de latitud y longitud, por lo que se mueven cuando arrastras, desplazas lateralmente o inclinas el mapa, o cuando haces zoom.

Requisitos

Para usar la vista de superposición de WebGL, debes cargar el mapa mediante un ID de mapa que tenga el mapa de vectores habilitado. Te recomendamos que habilites la inclinación y la rotación cuando crees el ID de mapa para permitir el control total de la cámara 3D. Consulta la descripción general para obtener más información.

Cómo agregar la vista de superposición de WebGL

Para agregar la superposición a tu mapa, implementa google.maps.WebGLOverlayView y, luego, pasa la vista a tu instancia de mapa mediante 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);

Hooks de ciclo de vida

La vista de superposición de WebGL proporciona un conjunto de hooks a los que se llama varias veces durante el ciclo de vida del contexto de renderización de WebGL del mapa base de vectores. En estos hooks de ciclo de vida, puedes configurar, dibujar y quitar todo lo que deseas renderizar en la superposición.

  • Se llama a onAdd() cuando se crea la superposición. Úsalo para recuperar o crear estructuras intermedias de datos antes de que se dibuje la superposición que no requieran acceso inmediato al contexto de renderización de WebGL.
  • Se llama a onContextRestored({gl}) una vez que el contexto de renderización está disponible. Úsalo para inicializar o vincular cualquier estado de WebGL, como sombreadores, objetos de búfer de GL, etc. onContextRestored() toma una instancia de WebGLStateOptions, que tiene un solo campo:
    • gl es un controlador del WebGLRenderingContext que usa el mapa base.
  • onDraw({gl, transformer}) renderiza la escena en el mapa base. Los parámetros de onDraw() son un objeto WebGLDrawOptions, que tiene dos campos:
    • gl es un controlador del WebGLRenderingContext que usa el mapa base.
    • transformer proporciona funciones auxiliares para transformar las coordenadas del mapa en una matriz de proyección de vista de modelo, que se puede usar para traducir las coordenadas del mapa al espacio del mundo, el espacio de la cámara y el espacio de la pantalla.
  • Se llama a onContextLost() cuando se pierde el contexto de renderización por algún motivo, y es allí donde debes borrar todos los estados de GL preexistentes, porque ya no son necesarios.
  • onStateUpdate({gl}) actualiza el estado de GL fuera del bucle de renderización y se invoca cuando se llama a requestStateUpdate. Toma una instancia de WebGLStateOptions, que tiene un solo campo:
    • gl es un controlador del WebGLRenderingContext que usa el mapa base.
  • Se llama a onRemove() cuando se quita la superposición del mapa con WebGLOverlayView.setMap(null) y es el lugar de donde debes quitar todos los objetos intermedios.

Por ejemplo, la siguiente es una implementación básica de todos los hooks de ciclo de vida:

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

Cómo restablecer el estado de GL

La vista de superposición de WebGL expone el contexto de renderización de WebGL del mapa base. Por lo tanto, es muy importante que restablezcas el estado original de GL cuando termines de renderizar los objetos. Si no se restablece el estado de GL, es probable que se generen conflictos, lo que hará que falle la renderización del mapa y de los objetos que especifiques.

El restablecimiento del estado de GL normalmente se controla en el hook onDraw(). Por ejemplo, Three.js proporciona una función auxiliar que borra cualquier cambio en el estado de GL:

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

Si el mapa o los objetos no se renderizan, es muy probable que no se haya restablecido el estado de GL.

Cómo coordinar las transformaciones

La posición de un objeto en el mapa de vectores se especifica proporcionando una combinación de coordenadas de latitud, longitud y altitud. Sin embargo, los gráficos 3D se especifican en el espacio del mundo, el espacio de la cámara o el espacio de la pantalla. Para facilitar la transformación de las coordenadas del mapa en estos espacios de uso general, la vista de superposición de WebGL proporciona la función auxiliar coordinateTransformer.fromLatLngAltitude(latLngAltitude, rotationArr, scalarArr) en el hook onDraw(), que toma lo siguiente y muestra un Float64Array:

  • latLngAltitude: Coordenadas de latitud, longitud y altitud como LatLngAltitude o LatLngAltitudeLiteral
  • rotationArr: Float32Array de ángulos de rotación de Euler especificados en grados
  • scalarArr: Float32Array de escalares para aplicar al eje cardinal

En el siguiente ejemplo, se usa fromLatLngAltitude() para crear una matriz de proyección de cámara en 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);

Ejemplo

El siguiente es un ejemplo simple del uso de Three.js, una biblioteca de WebGL popular de código abierto, para colocar un objeto 3D en el mapa. Si deseas obtener una explicación completa sobre cómo usar la vista de superposición de WebGL para compilar el ejemplo que se ejecuta en la parte superior de esta página, prueba el codelab Compila experiencias de mapas acelerados con 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);