1. Прежде чем начать
В этой лабораторной работе вы узнаете, как использовать функции Maps JavaScript API на основе WebGL для управления и визуализации векторной карты в трех измерениях.
Предпосылки
В этой лабораторной работе предполагается, что у вас есть промежуточные знания JavaScript и Maps JavaScript API. Чтобы изучить основы использования Maps JS API, попробуйте лабораторную работу Добавить карту на свой веб-сайт (JavaScript) .
Что вы узнаете
- Создание идентификатора карты с включенной векторной картой для JavaScript.
- Управление картой с программным наклоном и вращением.
- Отрисовка 3D-объектов на карте с помощью
WebGLOverlayView
и Three.js . - Анимация движения камеры с помощью
moveCamera
.
Что вам понадобится
- Аккаунт Google Cloud Platform с включенным выставлением счетов.
- Ключ API платформы Google Карт с включенным API JavaScript Карт.
- Среднее знание JavaScript, HTML и CSS
- Текстовый редактор или IDE на ваш выбор
- Node.js
2. Настройте
Для этапа включения, описанного ниже, вам потребуется включить Maps JavaScript API .
Настройте платформу Google Карт
Если у вас еще нет учетной записи Google Cloud Platform и проекта с включенным выставлением счетов, ознакомьтесь с руководством по началу работы с платформой Google Maps , чтобы создать платежную учетную запись и проект.
- В Cloud Console щелкните раскрывающееся меню проекта и выберите проект, который вы хотите использовать для этой лаборатории кода.
- Включите API и SDK платформы Google Maps, необходимые для этой лаборатории кода, в Google Cloud Marketplace . Для этого выполните действия, описанные в этом видео или в этой документации .
- Создайте ключ API на странице учетных данных Cloud Console. Вы можете выполнить действия, описанные в этом видео или в этой документации . Для всех запросов к платформе Google Maps требуется ключ API.
Настройка Node.js
Если у вас его еще нет, перейдите на https://nodejs.org/ , чтобы загрузить и установить среду выполнения Node.js на свой компьютер.
Node.js поставляется с менеджером пакетов npm, который необходим для установки зависимостей для этой лаборатории кода.
Скачать стартовый шаблон проекта
Прежде чем приступить к работе с этой лабораторией кода, выполните следующие действия, чтобы загрузить шаблон начального проекта, а также полный код решения:
- Загрузите или разветвите репозиторий GitHub для этой кодовой лаборатории по адресу https://github.com/googlecodelabs/maps-platform-101-webgl/ . Стартовый проект находится в каталоге
/starter
и включает в себя базовую файловую структуру, необходимую для завершения лаборатории кода. Все, с чем вам нужно работать, находится в каталоге/starter/src
. - Как только вы загрузите начальный проект, запустите
npm install
в каталоге/starter
. Это установит все необходимые зависимости, перечисленные вpackage.json
. - Как только ваши зависимости будут установлены, запустите
npm start
в каталоге.
Стартовый проект был настроен для использования вами webpack-dev-server, который компилирует и запускает код, который вы пишете локально. webpack-dev-server также автоматически перезагружает ваше приложение в браузере каждый раз, когда вы вносите изменения в код.
Если вы хотите увидеть работающий полный код решения, вы можете выполнить описанные выше действия по настройке в каталоге /solution
.
Добавьте свой ключ API
Стартовое приложение включает в себя весь код, необходимый для загрузки карты с помощью JS API Loader , так что все, что вам нужно сделать, это предоставить ключ API и идентификатор карты. JS API Loader — это простая библиотека, которая абстрагирует традиционный метод загрузки JS API Карт, встроенный в HTML-шаблон с помощью тега script
, что позволяет обрабатывать все в коде JavaScript.
Чтобы добавить ключ API, выполните следующие действия в стартовом проекте:
- Откройте
app.js
- В объекте
apiOptions
задайте ключ API как значениеapiOptions.apiKey
.
3. Создайте и используйте идентификатор карты
Чтобы использовать функции Maps JavaScript API на основе WebGL, вам нужен идентификатор карты с включенной векторной картой.
Создание идентификатора карты
- В консоли Google Cloud выберите «Платформа Google Maps» > «Управление картами».
- Нажмите «СОЗДАТЬ НОВЫЙ ID КАРТЫ».
- В поле «Название карты» введите имя для идентификатора вашей карты.
- В раскрывающемся списке «Тип карты» выберите «JavaScript». Появятся «Параметры JavaScript».
- В разделе «Параметры JavaScript» установите переключатель «Вектор», установите флажок «Наклон» и флажок «Поворот».
- Опционально . В поле «Описание» введите описание вашего ключа API.
- Нажмите кнопку «Далее». Появится страница «Подробности идентификатора карты».
- Скопируйте идентификатор карты. Вы будете использовать это на следующем шаге для загрузки карты.
Использование идентификатора карты
Чтобы загрузить векторную карту, вы должны указать идентификатор карты в качестве свойства в параметрах при создании экземпляра карты. При желании вы также можете указать тот же идентификатор карты при загрузке Maps JavaScript API.
Чтобы загрузить карту с идентификатором карты, выполните следующие действия:
- Установите идентификатор карты в качестве значения
mapOptions.mapId
.
Предоставление идентификатора карты при создании экземпляра карты сообщает платформе Google Maps, какие из ваших карт следует загружать для конкретного экземпляра. Вы можете повторно использовать один и тот же идентификатор карты в нескольких приложениях или в нескольких представлениях в одном приложении.const mapOptions = { "tilt": 0, "heading": 0, "zoom": 18, "center": { lat: 35.6594945, lng: 139.6999859 }, "mapId": "YOUR_MAP_ID" };
Проверьте приложение, работающее в вашем браузере. Векторная карта с включенными наклоном и вращением должна успешно загрузиться. Чтобы проверить, включены ли наклон и вращение, удерживайте клавишу Shift и перетащите мышью или используйте клавиши со стрелками на клавиатуре.
Если карта не загружается, убедитесь, что вы указали действительный ключ API в apiOptions
. Если карта не наклоняется и не поворачивается, убедитесь, что вы предоставили идентификатор карты с включенным наклоном и поворотом в apiOptions
и mapOptions
.
Ваш файл app.js
теперь должен выглядеть так:
import { Loader } from '@googlemaps/js-api-loader';
const apiOptions = {
"apiKey": 'YOUR_API_KEY',
};
const mapOptions = {
"tilt": 0,
"heading": 0,
"zoom": 18,
"center": { lat: 35.6594945, lng: 139.6999859 },
"mapId": "YOUR_MAP_ID"
}
async function initMap() {
const mapDiv = document.getElementById("map");
const apiLoader = new Loader(apiOptions);
await apiLoader.load();
return new google.maps.Map(mapDiv, mapOptions);
}
function initWebGLOverlayView (map) {
let scene, renderer, camera, loader;
// WebGLOverlayView code goes here
}
(async () => {
const map = await initMap();
})();
4. Реализовать WebGLOverlayView
WebGLOverlayView
дает вам прямой доступ к тому же контексту рендеринга WebGL, который используется для рендеринга векторной базовой карты. Это означает, что вы можете визуализировать 2D- и 3D-объекты непосредственно на карте с помощью WebGL, а также популярных графических библиотек на основе WebGL.
WebGLOverlayView
предоставляет пять хуков в жизненном цикле контекста рендеринга WebGL карты, которые вы можете использовать. Вот краткое описание каждого хука и того, для чего они нужны:
-
onAdd()
: вызывается, когда наложение добавляется на карту путем вызоваsetMap
для экземпляраWebGLOverlayView
. Здесь вы должны выполнять любую работу, связанную с WebGL, которая не требует прямого доступа к контексту WebGL. -
onContextRestored()
: вызывается, когда контекст WebGL становится доступным, но до того, как что-либо будет отрисовано. Здесь вы должны инициализировать объекты, привязывать состояние и делать все, что требует доступа к контексту WebGL, но может быть выполнено внеonDraw()
. Это позволяет вам настроить все, что вам нужно, не добавляя лишних ресурсов к фактическому рендерингу карты, который и без того интенсивно использует GPU. -
onDraw()
: вызывается один раз за кадр, как только WebGL начинает рендеринг карты и всего, что вы запросили. Вы должны делать как можно меньше работы вonDraw()
, чтобы избежать проблем с производительностью при рендеринге карты. -
onContextLost()
: вызывается, когда по какой-либо причине теряется контекст рендеринга WebGL. -
onRemove()
: вызывается, когда наложение удаляется с карты путем вызоваsetMap(null)
в экземпляреWebGLOverlayView
.
На этом шаге вы создадите экземпляр WebGLOverlayView
и реализуете три его обработчика жизненного цикла: onAdd
, onContextRestored
и onDraw
. Чтобы все было чисто и было проще для понимания, весь код для оверлея будет обрабатываться в функции initWebGLOverlayView()
, представленной в начальном шаблоне для этой лаборатории кода.
- Создайте
WebGLOverlayView()
.
Наложение предоставляется Maps JS API вgoogle.maps.WebGLOverlayView
. Для начала создайте экземпляр, добавив кinitWebGLOverlayView()
следующее:const webGLOverlayView = new google.maps.WebGLOverlayView();
- Реализуйте хуки жизненного цикла.
Чтобы реализовать хуки жизненного цикла, добавьте кinitWebGLOverlayView()
следующее:webGLOverlayView.onAdd = () => {}; webGLOverlayView.onContextRestored = ({gl}) => {}; webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {};
- Добавьте экземпляр наложения на карту.
Теперь вызовитеsetMap()
для экземпляра оверлея и передайте карту, добавив кinitWebGLOverlayView()
следующее:webGLOverlayView.setMap(map)
- Вызовите
initWebGLOverlayView
.
Последним шагом является выполнениеinitWebGLOverlayView()
путем добавления следующего к немедленно вызванной функции в нижней частиapp.js
:initWebGLOverlayView(map);
Теперь ваш initWebGLOverlayView
и немедленно вызванная функция должны выглядеть так:
async function initWebGLOverlayView (map) {
let scene, renderer, camera, loader;
const webGLOverlayView = new google.maps.WebGLOverlayView();
webGLOverlayView.onAdd = () => {}
webGLOverlayView.onContextRestored = ({gl}) => {}
webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {}
webGLOverlayView.setMap(map);
}
(async () => {
const map = await initMap();
initWebGLOverlayView(map);
})();
Это все, что вам нужно для реализации WebGLOverlayView
. Далее вы настроите все необходимое для рендеринга 3D-объекта на карте с помощью Three.js.
5. Настройте сцену three.js
Использование WebGL может быть очень сложным, поскольку требует от вас определения всех аспектов каждого объекта вручную, а затем и некоторых других. Чтобы упростить задачу, для этой кодовой лаборатории вы будете использовать Three.js, популярную графическую библиотеку, которая предоставляет упрощенный уровень абстракции поверх WebGL. Three.js поставляется с широким спектром удобных функций, которые делают все: от создания средства визуализации WebGL до рисования общих форм 2D- и 3D-объектов, управления камерами, преобразования объектов и многого другого.
В Three.js есть три основных типа объектов, которые необходимы для отображения чего-либо:
- Сцена: «контейнер», в котором визуализируются и отображаются все объекты, источники света, текстуры и т. д.
- Камера: камера, представляющая точку обзора сцены. Доступно несколько типов камер, и к одной сцене можно добавить одну или несколько камер.
- Рендерер: визуализатор, который занимается обработкой и отображением всех объектов в сцене. В Three.js чаще всего используется
WebGLRenderer
, но несколько других доступны в качестве запасных вариантов на случай, если клиент не поддерживает WebGL.
На этом шаге вы загрузите все зависимости, необходимые для Three.js, и настроите базовую сцену.
- Загрузите файл three.js
Для этой лаборатории кода вам понадобятся две зависимости: библиотека Three.js и загрузчик GLTF, класс, который позволяет загружать 3D-объекты в формате передачи GL (gLTF) . Three.js предлагает специализированные загрузчики для многих различных форматов 3D-объектов, но рекомендуется использовать gLTF.
В приведенном ниже коде импортируется вся библиотека Three.js. В рабочем приложении вы, вероятно, захотите импортировать только те классы, которые вам нужны, но для этой лаборатории кода импортируйте всю библиотеку, чтобы не усложнять задачу. Также обратите внимание, что загрузчик GLTF не включен в библиотеку по умолчанию и должен быть импортирован из отдельного пути в зависимости — это путь, по которому вы можете получить доступ ко всем загрузчикам, предоставляемым Three.js.
Чтобы импортировать Three.js и загрузчик GLTF, добавьте следующее в началоapp.js
:
.import * as THREE from 'three'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
- Создайте сцену three.js.
Чтобы создать сцену, создайте экземпляр класса Three.jsScene
, добавив кonAdd
:scene = new THREE.Scene();
- Добавьте камеру к сцене.
Как упоминалось ранее, камера представляет перспективу просмотра сцены и определяет, как Three.js обрабатывает визуальную визуализацию объектов в сцене. Без камеры сцена фактически не «видна», а это означает, что объекты не будут отображаться, потому что они не будут визуализированы.
Three.js предлагает множество различных камер, которые влияют на то, как средство визуализации обрабатывает объекты в отношении таких вещей, как перспектива и глубина. В этой сцене вы будете использоватьPerspectiveCamera
, наиболее часто используемый тип камеры в Three.js, который предназначен для имитации восприятия сцены человеческим глазом. Это означает, что объекты, находящиеся дальше от камеры, будут казаться меньше, чем объекты, расположенные ближе, сцена будет иметь точку схода и многое другое.
Чтобы добавитьPerspectiveCamera
камеру в сцену, добавьте кonAdd
: зрение (fov). В совокупности эти атрибуты составляют то, что известно как усеченная пирамида просмотра, важное понятие, которое необходимо понимать при работе в 3D, но оно выходит за рамки этой лаборатории кода. Конфигурацииcamera = new THREE.PerspectiveCamera();
PerspectiveCamera
по умолчанию будет вполне достаточно. - Добавьте в сцену источники света.
По умолчанию объекты, отображаемые в сцене Three.js, будут отображаться черными, независимо от примененных к ним текстур. Это связано с тем, что сцена Three.js имитирует поведение объектов в реальном мире, где видимость цвета зависит от света, отражающегося от объекта. Короче говоря, ни света, ни цвета.
Three.js предоставляет множество различных типов источников света, из которых вы будете использовать два: -
AmbientLight
: обеспечивает рассеянный источник света, который равномерно освещает все объекты в кадре со всех сторон. Это даст сцене базовое количество света, чтобы текстуры на всех объектах были видны. -
DirectionalLight
: обеспечивает свет, исходящий из направления в сцене. В отличие от того, как позиционированный источник света будет работать в реальном мире, все световые лучи, исходящие отDirectionalLight
, параллельны и не распространяются и не рассеиваются по мере удаления от источника света.
Вы можете настроить цвет и интенсивность каждого источника света для создания совокупных световых эффектов. Например, в приведенном ниже коде окружающий свет обеспечивает мягкий белый свет для всей сцены, а направленный свет обеспечивает вторичный свет, падающий на объекты под углом вниз. В случае направленного света угол устанавливается с помощьюposition.set(x, y ,z)
, где каждое значение относится к соответствующей оси. Так, например,position.set(0,1,0)
света прямо над сценой по оси Y, направленной прямо вниз.
Чтобы добавить источники света в сцену, добавьте кonAdd
:const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 ); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25); directionalLight.position.set(0.5, -1, 0.5); scene.add(directionalLight);
Теперь ваш хук onAdd
должен выглядеть так:
webGLOverlayView.onAdd = () => {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera();
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 );
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
directionalLight.position.set(0.5, -1, 0.5);
scene.add(directionalLight);
}
Теперь ваша сцена настроена и готова к рендерингу. Далее вы настроите средство визуализации WebGL и выполните визуализацию сцены.
6. Визуализировать сцену
Время отрендерить вашу сцену. До этого момента все, что вы создавали с помощью Three.js, инициализировалось в коде, но, по сути, не существовало, поскольку оно еще не было отрисовано в контексте рендеринга WebGL. WebGL визуализирует 2D- и 3D-контент в браузере с помощью API холста . Если вы уже использовали Canvas API, вы, вероятно, знакомы с context
HTML-холста, где все отображается. Возможно, вы не знаете, что это интерфейс, который предоставляет контекст рендеринга графики OpenGL через API WebGLRenderingContext
в браузере.
Чтобы упростить работу с модулем рендеринга WebGL, Three.js предоставляет WebGLRenderer
, оболочку, которая упрощает настройку контекста рендеринга WebGL, чтобы Three.js мог отображать сцены в браузере. Однако в случае с картой недостаточно просто отобразить сцену Three.js в браузере вместе с картой. Three.js должен отображаться в том же самом контексте рендеринга, что и карта, чтобы и карта, и любые объекты из сцены Three.js отображались в одном и том же мировом пространстве. Это позволяет рендереру обрабатывать взаимодействия между объектами на карте и объектами в сцене, такие как окклюзия, которая является причудливым способом сказать, что объект будет скрывать объекты за собой из поля зрения.
Звучит довольно сложно, правда? К счастью, Three.js снова приходит на помощь.
- Настройте визуализатор WebGL.
Когда вы создаете новый экземпляр Three.jsWebGLRenderer
, вы можете предоставить ему конкретный контекст рендеринга WebGL, в котором вы хотите, чтобы он отображал вашу сцену. Помните аргументgl
, который передается в хукonContextRestored
? Этот объектgl
является контекстом рендеринга карты WebGL. Все, что вам нужно сделать, это предоставить контекст, его холст и его атрибуты экземпляруWebGLRenderer
, все из которых доступны через объектgl
. В этом коде свойствоautoClear
средства визуализации также имеет значениеfalse
, чтобы средство визуализации не очищало свой вывод в каждом кадре.
Чтобы настроить визуализатор, добавьте кonContextRestored
:renderer = new THREE.WebGLRenderer({ canvas: gl.canvas, context: gl, ...gl.getContextAttributes(), }); renderer.autoClear = false;
- Рендеринг сцены.
После того, как средство визуализации настроено, вызовитеrequestRedraw
в экземпляреWebGLOverlayView
, чтобы сообщить оверлею, что требуется перерисовка при отображении следующего кадра, затем вызовитеrender
в средстве визуализации и передайте ему сцену Three.js и камеру для визуализации. Наконец, очистите состояние контекста рендеринга WebGL. Это важный шаг, позволяющий избежать конфликтов состояния GL, поскольку использование представления WebGL Overlay View зависит от общего состояния GL. Если состояние не сбрасывается в конце каждого вызова отрисовки, конфликты состояния GL могут привести к сбою средства визуализации.
Для этого добавьте кonDraw
следующее, чтобы он выполнялся в каждом кадре:webGLOverlayView.requestRedraw(); renderer.render(scene, camera); renderer.resetState();
Теперь ваши хуки onContextRestored
и onDraw
должны выглядеть так:
webGLOverlayView.onContextRestored = ({gl}) => {
renderer = new THREE.WebGLRenderer({
canvas: gl.canvas,
context: gl,
...gl.getContextAttributes(),
});
renderer.autoClear = false;
}
webGLOverlayView.onDraw = ({gl, transformer}) => {
webGLOverlayView.requestRedraw();
renderer.render(scene, camera);
renderer.resetState();
}
7. Отрисовка 3D-модели на карте
Хорошо, у вас есть все части на месте. Вы настроили WebGl Overlay View и создали сцену Three.js, но есть одна проблема: в ней ничего нет. Итак, пришло время визуализировать 3D-объект в сцене. Для этого вы будете использовать импортированный ранее загрузчик GLTF.
3D-модели бывают разных форматов, но для Three.js формат gLTF является предпочтительным из-за его размера и производительности во время выполнения. В этой кодовой лаборатории модель для рендеринга в сцене уже предоставлена вам в /src/pin.gltf
.
- Создайте экземпляр загрузчика модели.
Добавьте кonAdd
следующее:loader = new GLTFLoader();
- Загрузите 3D-модель.
Загрузчики моделей являются асинхронными и выполняют обратный вызов после полной загрузки модели. Чтобы загрузитьpin.gltf
, добавьте кonAdd
следующее:const source = "pin.gltf"; loader.load( source, gltf => {} );
- Добавьте модель на сцену.
Теперь вы можете добавить модель на сцену, добавив следующее к обратному вызовуloader
. Обратите внимание, что добавляетсяgltf.scene
, а неgltf
:scene.add(gltf.scene);
- Настройте матрицу проекции камеры.
Последнее, что вам нужно, чтобы правильно отобразить модель на карте, — это установить матрицу проекции камеры в сцене Three.js. Матрица проекции указывается в виде массива Three.jsMatrix4
, который определяет точку в трехмерном пространстве вместе с преобразованиями, такими как повороты, сдвиг, масштаб и т. д.
В случаеWebGLOverlayView
матрица проекции используется, чтобы указать средству визуализации, где и как отображать сцену Three.js относительно базовой карты. Но есть проблема. Местоположения на карте задаются парами координат широты и долготы, тогда как местоположения в сцене Three.js представляют собой координатыVector3
. Как вы могли догадаться, вычисление преобразования между двумя системами не является тривиальным. Чтобы решить эту проблему,WebGLOverlayView
передает объектcoordinateTransformer
Transformer в обработчик жизненного циклаOnDraw
, который содержит функцию, вызываемуюfromLatLngAltitude
.fromLatLngAltitude
принимает объектLatLngAltitude
илиLatLngAltitudeLiteral
и, при необходимости, набор аргументов, определяющих преобразование сцены, а затем преобразует их в матрицу проекции представления модели (MVP) для вас. Все, что вам нужно сделать, это указать, где на карте вы хотите отобразить сцену Three.js, а также как вы хотите ее преобразовать, аWebGLOverlayView
сделает все остальное. Затем вы можете преобразовать матрицу MVP в массив Three.jsMatrix4
и установить для нее матрицу проекции камеры.
В приведенном ниже коде второй аргумент указывает WebGl Overlay View установить высоту сцены Three.js на 120 метров над землей, что сделает модель плавающей.
Чтобы установить матрицу проекции камеры, добавьте кonDraw
:const latLngAltitudeLiteral = { lat: mapOptions.center.lat, lng: mapOptions.center.lng, altitude: 120 } const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral); camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
- Преобразуйте модель.
Вы заметите, что булавка не расположена перпендикулярно карте. В 3D-графике, в дополнение к тому, что мировое пространство имеет собственные оси x, y и z, определяющие ориентацию, каждый объект также имеет свое собственное пространство объектов с независимым набором осей.
В случае этой модели она не была создана с тем, что мы обычно считаем «верхней частью» булавки, направленной вверх по оси Y, поэтому вам необходимо преобразовать объект, чтобы сориентировать его в нужном направлении относительно мирового пространства с помощью вызывая на немrotation.set
. Обратите внимание, что в Three.js вращение указывается в радианах, а не в градусах. Как правило, проще думать в градусах, поэтому необходимо выполнить соответствующее преобразование, используя формулуdegrees * Math.PI/180
.
Кроме того, модель немного мала, поэтому вы также равномерно масштабируете ее по всем осям, вызываяscale.set(x, y ,z)
.
Чтобы повернуть и масштабировать модель, добавьте следующее в обратный вызовloader
onAdd
передscene.add(gltf.scene)
, который добавляет gLTF в сцену:gltf.scene.scale.set(25,25,25); gltf.scene.rotation.x = 180 * Math.PI/180;
Теперь булавка стоит вертикально относительно карты.
Теперь ваши хуки onAdd
и onDraw
должны выглядеть так:
webGLOverlayView.onAdd = () => {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera();
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 ); // soft white light
scene.add( ambientLight );
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
directionalLight.position.set(0.5, -1, 0.5);
scene.add(directionalLight);
loader = new GLTFLoader();
const source = 'pin.gltf';
loader.load(
source,
gltf => {
gltf.scene.scale.set(25,25,25);
gltf.scene.rotation.x = 180 * Math.PI/180;
scene.add(gltf.scene);
}
);
}
webGLOverlayView.onDraw = ({gl, transformer}) => {
const latLngAltitudeLiteral = {
lat: mapOptions.center.lat,
lng: mapOptions.center.lng,
altitude: 100
}
const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral);
camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
webGLOverlayView.requestRedraw();
renderer.render(scene, camera);
renderer.resetState();
}
Далее идет анимация камеры!
8. Анимируйте камеру
Теперь, когда вы визуализировали модель на карте и можете перемещать все в трехмерном пространстве, следующее, что вы, вероятно, захотите сделать, это программно управлять этим движением. Функция moveCamera
позволяет одновременно задавать свойства центра, масштабирования, наклона и направления карты, обеспечивая точный контроль над взаимодействием с пользователем. Кроме того, moveCamera
можно вызывать в цикле анимации для создания плавных переходов между кадрами с частотой кадров около 60 кадров в секунду.
- Дождитесь загрузки модели.
Чтобы создать беспрепятственный пользовательский интерфейс, вам нужно подождать, чтобы начать перемещение камеры, пока не будет загружена модель gLTF. Для этого добавьте обработчик событияonContextRestored
onLoad
loader.manager.onLoad = () => {}
- Создайте цикл анимации.
Существует несколько способов создания цикла анимации, например, с помощьюsetInterval
илиrequestAnimationFrame
. В этом случае вы будете использовать функциюsetAnimationLoop
средства визуализации Three.js, которая будет автоматически вызывать любой код, объявленный вами в своем обратном вызове, каждый раз, когда Three.js визуализирует новый кадр. Чтобы создать цикл анимации, добавьте в обработчик событияonLoad
на предыдущем шаге следующее:renderer.setAnimationLoop(() => {});
- Установите положение камеры в цикле анимации.
Затем вызовитеmoveCamera
, чтобы обновить карту. Здесь свойства объектаmapOptions
, который использовался для загрузки карты, используются для определения положения камеры:map.moveCamera({ "tilt": mapOptions.tilt, "heading": mapOptions.heading, "zoom": mapOptions.zoom });
- Обновляйте камеру каждый кадр.
Последний шаг! Обновите объектmapOptions
в конце каждого кадра, чтобы задать положение камеры для следующего кадра. В этом коде операторif
используется для увеличения наклона до тех пор, пока не будет достигнуто максимальное значение наклона 67,5, а затем заголовок немного меняется в каждом кадре, пока камера не завершит полный поворот на 360 градусов. Как только желаемая анимация завершена, вsetAnimationLoop
передаетсяnull
, чтобы отменить анимацию, чтобы она не работала вечно.if (mapOptions.tilt < 67.5) { mapOptions.tilt += 0.5 } else if (mapOptions.heading <= 360) { mapOptions.heading += 0.2; } else { renderer.setAnimationLoop(null) }
Теперь ваш хук onContextRestored
должен выглядеть так:
webGLOverlayView.onContextRestored = ({gl}) => {
renderer = new THREE.WebGLRenderer({
canvas: gl.canvas,
context: gl,
...gl.getContextAttributes(),
});
renderer.autoClear = false;
loader.manager.onLoad = () => {
renderer.setAnimationLoop(() => {
map.moveCamera({
"tilt": mapOptions.tilt,
"heading": mapOptions.heading,
"zoom": mapOptions.zoom
});
if (mapOptions.tilt < 67.5) {
mapOptions.tilt += 0.5
} else if (mapOptions.heading <= 360) {
mapOptions.heading += 0.2;
} else {
renderer.setAnimationLoop(null)
}
});
}
}
9. Поздравления
Если все прошло по плану, теперь у вас должна быть карта с большой 3D-булавкой, которая выглядит так:
Что вы узнали
В этой кодлабе вы узнали кучу вещей; вот основные моменты:
- Реализация
WebGLOverlayView
и его хуков жизненного цикла. - Интеграция Three.js в карту.
- Основы создания сцены Three.js, включая камеры и освещение.
- Загрузка и управление 3D-моделями с помощью Three.js.
- Управление и анимация камеры для карты с помощью
moveCamera
.
Что дальше?
WebGL и компьютерная графика в целом — сложная тема, поэтому всегда есть чему поучиться. Вот несколько ресурсов, которые помогут вам начать:
- Документация WebGL Overlay View
- Начало работы с WebGL .
- Документация Three.js
- Помогите нам создать наиболее полезный для вас контент, ответив на вопрос ниже: «codelabs/maps-platform/shared/_next-lab-survey.lab.md» Нет ли нужной вам лаборатории кода в списке выше? Запросите его с новым выпуском здесь .