Режим наложения в WebGL

Посмотреть пример

С помощью наложений WebGL вы можете добавлять объекты на карты напрямую через WebGL или с помощью популярных графических библиотек, таких как Three.js. Такие наложения обеспечивают прямой доступ к контексту визуализации WebGL, который платформа Google Карт использует для отрисовки векторной базовой карты. Общий контекст визуализации позволяет отрисовывать перекрывающиеся в глубине трехмерные здания и синхронизировать показ 2D/3D-контента с отрисовкой базовой карты. Объекты в наложениях WebGL также можно привязать к географическим координатам, чтобы они перемещались, когда пользователь перетаскивает, масштабирует, панорамирует карту или меняет ее наклон.

Требования

Для работы с режимом просмотра WebGL необходимо загрузить векторную карту с присвоенным ей идентификатором. Мы настоятельно рекомендуем включить функции наклона и ориентации при создании идентификатора карты, чтобы обеспечить полноценное управление 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 c двумя полями:
    • gl – дескриптор WebGLRenderingContext в базовой карте.
    • transformer – вспомогательные функции для преобразования координат карты через матрицу "модель-вид-проекция" в объекты пространства мира, камеры или экрана.
  • onContextLost() – вызывается, когда контекст визуализации потерян по какой бы то ни было причине. При его вызове необходимо очистить все предыдущие состояния графической библиотеки, поскольку они больше не потребуются.
  • onStateUpdate({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);

Как сбросить состояние графической библиотеки

Наложение WebGL предоставляет контекст WebGL для визуализации базовой карты. Поэтому по окончании отрисовки объектов состояние графической библиотеки важно вернуть к исходному. В противном случае это может вызвать конфликт состояний графической библиотеки, и ни карта, ни добавленные вами объекты отрисованы не будут.

Сброс состояния графической библиотеки обычно обрабатывается хуком onDraw(). Например, в Three.js предусмотрена вспомогательная функция, которая сбрасывает все изменения в состоянии библиотеки:

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

Если ваша карта или объекты на ней не отображаются, весьма вероятно, что состояние графической библиотеки не было сброшено.

Как преобразовывать координаты

Положение объекта на векторной карте определяется комбинацией координат широты, долготы и высоты. В то же время положение объектов 3D-графики задается в пространстве мира, камеры или экрана. Чтобы упростить преобразование координат карты в координаты этих пространств, в наложении WebGL предусмотрена вспомогательная функция coordinateTransformer.fromLatLngAltitude(latLngAltitude, rotationArr, scalarArr) в хуке onDraw(). Она принимает следующие объекты и возвращает в ответ массив 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.

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