1. Hinweis
In diesem Codelab lernen Sie, wie Sie mit den WebGL-gestützten Funktionen der Maps JavaScript API die Vektorkarte in drei Dimensionen steuern und rendern können.
Vorbereitung
Dieses Codelab setzt voraus, dass du Grundkenntnisse in JavaScript und der Maps JavaScript API hast. Im Grundlagen-Codelab zur Maps JS API finden Sie im Artikel Karte zu Ihrer Website hinzufügen (JavaScript).
Lerninhalte
- Generieren einer Karten-ID mit der Vektorkarte für aktiviertes JavaScript
- Karte mit programmatischer Neigung und Rotation steuern
- Rendering von 3D-Objekten auf der Karte mit
WebGLOverlayView
und Three.js - Kamerabewegungen mit
moveCamera
animieren.
Voraussetzungen
- Google Cloud Platform-Konto mit aktivierter Abrechnung
- Ein Google Maps Platform API-Schlüssel mit aktivierter Maps JavaScript API
- Grundkenntnisse in JavaScript, HTML und CSS
- Texteditor oder IDE deiner Wahl
- Node.js
2. Einrichten
Für den nachfolgenden Aktivierungsschritt musst du die Maps JavaScript API aktivieren.
Google Maps Platform einrichten
Wenn Sie noch kein Google Cloud Platform-Konto und kein Projekt mit aktivierter Abrechnung haben, lesen Sie den Leitfaden Erste Schritte mit der Google Maps Platform, um ein Rechnungskonto und ein Projekt zu erstellen.
- Klicken Sie in der Cloud Console auf das Drop-down-Menü für Projekte und wählen Sie das Projekt aus, das Sie für dieses Codelab verwenden möchten.
- Aktivieren Sie im Google Cloud Marketplace die für dieses Codelab erforderlichen Google Maps Platform APIs und SDKs. Folgen Sie dazu der Anleitung in diesem Video oder dieser Dokumentation.
- Generieren Sie in der Cloud Console auf der Seite Anmeldedaten einen API-Schlüssel. Folgen Sie der Anleitung in diesem Video oder dieser Dokumentation. Für alle Anfragen an die Google Maps Platform ist ein API-Schlüssel erforderlich.
Node.js-Einrichtung
Wenn Sie dies noch nicht getan haben, rufen Sie https://searchads.org/ auf, um die Node.js-Laufzeit auf Ihren Computer herunterzuladen und zu installieren.
Node.js enthält den npm-Paketmanager, den Sie zum Installieren von Abhängigkeiten für dieses Codelab benötigen.
Projektstartvorlage herunterladen
Bevor Sie mit diesem Codelab beginnen, müssen Sie Folgendes tun, um die Startprojektvorlage sowie den vollständigen Lösungscode herunterzuladen:
- Laden Sie das GitHub-Repository für dieses Codelab unter https://github.com/googlecodelabs/maps-platform-101-webgl/ herunter. Das Starter-Projekt befindet sich im Verzeichnis
/starter
und enthält die grundlegende Dateistruktur, die Sie für das Codelab benötigen. Alles, was du brauchst, findest du im Verzeichnis/starter/src
. - Führen Sie nach dem Herunterladen des Starter-Projekts
npm install
im Verzeichnis/starter
aus. Dadurch werden alle erforderlichen Abhängigkeiten installiert, die inpackage.json
aufgeführt sind. - Führen Sie nach der Installation der Abhängigkeiten
npm start
im Verzeichnis aus.
Das Starter-Projekt wurde so eingerichtet, dass Sie webpack-dev-server verwenden, der den von Ihnen lokal geschriebenen Code kompiliert und ausführt. Wenn Sie Codeänderungen vornehmen, wird Ihre App von webpack-dev-server automatisch im Browser neu geladen.
Wenn Sie möchten, dass der vollständige Lösungscode ausgeführt wird, führen Sie die oben genannten Einrichtungsschritte im Verzeichnis /solution
aus.
Eigenen API-Schlüssel hinzufügen
Die Starter-App enthält den gesamten Code, der zum Laden der Karte mit dem JS API-Ladegerät erforderlich ist. Sie müssen also nur Ihren API-Schlüssel und die Karten-ID angeben. Der JS API Loader ist eine einfache Bibliothek, die die herkömmliche Methode zum Laden der Maps JS API in die HTML-Vorlage mit einem script
-Tag abstrahiert. Dadurch können Sie alles in JavaScript-Code verarbeiten.
So fügen Sie den API-Schlüssel im Startprojekt hinzu:
- Öffnen Sie
app.js
. - Lege im
apiOptions
-Objekt deinen API-Schlüssel als Wert vonapiOptions.apiKey
fest.
3. Karten-ID generieren und verwenden
Um die WebGL-basierten Funktionen der Maps JavaScript API zu verwenden, benötigst du eine Karten-ID mit aktivierter Vektorkarte.
Karten-ID generieren
- Gehen Sie in der Google Cloud Console zu „Google Maps Platform' > Map Management'.
- Klicken Sie auf NEUE KARTEN-ID ERSTELLEN'.
- Geben Sie in das Feld „Kartenname&name“ einen Namen für die Karten-ID ein.
- Wählen Sie im Drop-down-Menü „Kartentyp'“ die Option „JavaScript'“ aus. „JavaScript-Optionen“ wird angezeigt.
- Aktivieren Sie unter „JavaScript-Optionen“ das Optionsfeld „Vector'“ und „Neigung“ sowie das Kästchen „Rotation'“.
- Optional: Gib in das Feld „Beschreibung“ eine Beschreibung für deinen API-Schlüssel ein.
- Klicken Sie auf die Schaltfläche „Weiter“. Die Seite „Karten-ID-Details“ wird angezeigt.
- Kopieren Sie die Karten-ID. Diese Datei benötigen Sie im nächsten Schritt, um die Karte zu laden.
Karten-ID verwenden
Zum Laden der Vektorkarte müssen Sie in den Optionen eine Karten-ID als Eigenschaft angeben, wenn Sie die Karte instanziieren. Sie können auch beim Laden der Maps JavaScript API dieselbe Karten-ID angeben.
So laden Sie die Karte mit Ihrer Karten-ID:
- Lege deine Karten-ID als Wert für
mapOptions.mapId
fest.
Wenn Sie die Karten-ID beim Instanziieren der Karte angeben, wird der Google Maps Platform mitgeteilt, welche Ihrer Karten für eine bestimmte Instanz geladen werden sollen. Sie können dieselbe Karten-ID dann für mehrere Apps und Aufrufe einer App verwenden.const mapOptions = { "tilt": 0, "heading": 0, "zoom": 18, "center": { lat: 35.6594945, lng: 139.6999859 }, "mapId": "YOUR_MAP_ID" };
Überprüfen Sie die in Ihrem Browser ausgeführte App. Die Vektorkarte mit aktivierter Neigungs- und Rotation sollte geladen werden. Um zu prüfen, ob Neigung und Rotation aktiviert sind, halten Sie die Umschalttaste gedrückt und ziehen Sie entweder mit der Maus oder verwenden Sie die Pfeiltasten auf der Tastatur.
Wenn die Karte nicht geladen wird, überprüfe, ob du einen gültigen API-Schlüssel in apiOptions
angegeben hast. Wenn die Karte nicht geneigt und gedreht wird, sehen Sie nach, ob in apiOptions
und mapOptions
eine Karten-ID mit Neigung und Drehung angegeben ist.
Die Datei app.js
sollte jetzt so aussehen:
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 implementieren
WebGLOverlayView
ermöglicht dir direkten Zugriff auf denselben WebGL-Renderingkontext, mit dem die Vektorbasiskarte gerendert wird. Sie können also mithilfe von WebGL sowie beliebten WebGL-basierten Grafikbibliotheken 2D- und 3D-Objekte direkt auf der Karte rendern.
WebGLOverlayView
stellt fünf Webhooks für den Lebenszyklus des WebGL-Renderingkontexts der Karte bereit, die du verwenden kannst. Hier findest du eine kurze Beschreibung der einzelnen Webhooks und deren Bedeutung:
onAdd()
: Wird aufgerufen, wenn das Overlay zur Karte hinzugefügt wird, indemsetMap
auf einerWebGLOverlayView
-Instanz aufgerufen wird. Hier sollten Sie alle Aufgaben im Zusammenhang mit WebGL durchführen, die keinen direkten Zugriff auf den WebGL-Kontext erfordern.onContextRestored()
: Wird aufgerufen, wenn der WebGL-Kontext verfügbar ist, aber bevor etwas gerendert wird. Hier sollten Sie Objekte initialisieren, den Status binden und alle anderen Aktionen ausführen, die Zugriff auf den WebGL-Kontext benötigen, aber außerhalb desonDraw()
-Aufrufs ausgeführt werden können. So kannst du alles einrichten, was du brauchst, ohne den Overhead für das tatsächliche Rendern der Karte zu erhöhen, was bereits GPU-aufwendig ist.onDraw()
: Wird einmal pro Frame aufgerufen, sobald WebGL mit dem Rendern der Karte und anderen angeforderten Elementen beginnt. Du solltest so wenig wie möglich inonDraw()
tun, um Leistungsprobleme beim Rendern der Karte zu vermeiden.onContextLost()
: Wird aufgerufen, wenn der WebGL-Renderingkontext aus irgendeinem Grund verloren geht.onRemove()
: Wird aufgerufen, wenn das Overlay aus der Karte entfernt wird, indemsetMap(null)
in einerWebGLOverlayView
-Instanz aufgerufen wird.
In diesem Schritt erstellen Sie eine Instanz von WebGLOverlayView
und implementieren die drei zugehörigen Lebenszyklus-Webhooks onAdd
, onContextRestored
und onDraw
. Damit alles übersichtlich und übersichtlich ist, wird der gesamte Code für das Overlay mit der initWebGLOverlayView()
-Funktion verarbeitet. Diese befindet sich in der Startvorlage für dieses Codelab.
- Erstelle eine
WebGLOverlayView()
-Instanz.
Das Overlay wird von der Maps JS API ingoogle.maps.WebGLOverlayView
bereitgestellt. Erstellen Sie als Erstes eine Instanz, indem SieinitWebGLOverlayView()
Folgendes hinzufügen:const webGLOverlayView = new google.maps.WebGLOverlayView();
- Lebenszyklus-Webhooks implementieren.
Wenn Sie den Lebenszyklus-Webhooks implementieren möchten, hängen Sie Folgendes aninitWebGLOverlayView()
an:webGLOverlayView.onAdd = () => {}; webGLOverlayView.onContextRestored = ({gl}) => {}; webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {};
- Overlay-Instanz zur Karte hinzufügen
RufesetMap()
auf der Overlay-Instanz auf und übergib die Karte. Hänge dazu Folgendes aninitWebGLOverlayView()
an:webGLOverlayView.setMap(map)
- Rufen Sie einfach
initWebGLOverlayView
an.
Im letzten Schritt wirdinitWebGLOverlayView()
ausgeführt, indem Folgendes zur sofort aufgerufenen Funktion unten inapp.js
hinzugefügt wird:initWebGLOverlayView(map);
Die Funktion initWebGLOverlayView
und die sofort aufgerufene Funktion sollten nun so aussehen:
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);
})();
Das ist alles, was du brauchst, um WebGLOverlayView
zu implementieren. Als Nächstes richtest du alles ein, um ein 3D-Objekt auf der Karte mit Three.js zu rendern.
5. Two.js-Szene einrichten
Die Verwendung von WebGL kann kompliziert sein, weil Sie alle Aspekte jedes Objekts manuell und dann einige definieren müssen. Für dieses Codelab verwenden Sie am besten Three.js, eine beliebte Grafikbibliothek mit einer vereinfachten Abstraktionsebene über WebGL. Three.js bietet zahlreiche praktische Funktionen, die von der Erstellung eines WebGL-Renderers bis hin zum Zeichnen gängiger 2D- und 3D-Objektformen sowie für die Steuerung von Kameras, Objekttransformationen und vielem mehr reichen.
In Three.js gibt es drei grundlegende Objekttypen, die zum Anzeigen aller Elemente erforderlich sind:
- Ambiente: Ein &Container, in dem alle Objekte, Lichtquellen, Texturen usw. gerendert und angezeigt werden.
- Kamera: Eine Kamera, die den Blickwinkel der Szene darstellt. Es sind mehrere Kameratypen verfügbar. Eine oder mehrere Kameras können gleichzeitig aufgenommen werden.
- Renderer: Dieser Renderer verarbeitet alle Elemente in einer Szene. In Three.js wird
WebGLRenderer
am häufigsten verwendet. Einige sind jedoch auch als Fallbacks verfügbar, falls der Client WebGL nicht unterstützt.
In diesem Schritt laden Sie alle erforderlichen Abhängigkeiten für Three.js und richten eine grundlegende Szene ein.
- Laden Sie drei.js
Sie benötigen zwei Abhängigkeiten für dieses Codelab: die Three.js-Bibliothek und den GLTF-Ladeprogramm, eine Klasse, mit der 3D-Objekte im GL Trasmission Format (gLTF) geladen werden können. Three.js bietet spezielle Load-Balancer für viele 3D-Objektformate, aber die Verwendung von gLTF wird empfohlen.
Im Code unten wird die gesamte Three.js-Bibliothek importiert. In einer Produktions-App würden Sie wahrscheinlich nur die benötigten Kurse importieren, aber für dieses Codelab können Sie die gesamte Bibliothek importieren, um den Vorgang zu vereinfachen. Beachten Sie auch, dass der GLTF-Ladegerät nicht in der Standardbibliothek enthalten ist und aus einem separaten Pfad in der Abhängigkeit importiert werden muss. Dies ist der Pfad, auf den Sie auf alle Load-Balancer zugreifen können, die von Three.js bereitgestellt werden.
Fügen Sie oben inapp.js
Folgendes ein, um Three.js und die GLTF-Ladefunktion zu importieren:import * as THREE from 'three'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
- Erstellen Sie eine 3.js-Szene.
Um eine Szene zu erstellen, musst du die Three.js-KlasseScene
instanziieren, indem du Folgendes an den WebhookonAdd
anhängt:scene = new THREE.Scene();
- Fügen Sie das Sichtfeld der Kamera hinzu.
Wie bereits erwähnt, stellt die Kamera die Perspektive der Szene dar und bestimmt, wie Three.js mit dem visuellen Rendering von Objekten in einer Szene umgeht. Ohne Kamera ist die Szene praktisch nicht sichtbar. Das bedeutet, dass Objekte nicht angezeigt werden, weil sie nicht gerendert werden.
Three.js bietet eine Vielzahl verschiedener Kameras, die beeinflussen, wie Renderer Objekte in Bezug auf Perspektive und Tiefe verarbeitet. In dieser Szene verwenden SiePerspectiveCamera
, den am häufigsten verwendeten Kameratyp in Three.js. Damit wird die Sicht des menschlichen Auges emuliert. Das bedeutet, dass Objekte, die weiter von der Kamera entfernt sind, kleiner dargestellt werden als Objekte, die sich näher befinden, und einen Punkt mit einem Fluchtpunkt.
Um eine perspektivische Kamera in eine Szene aufzunehmen, hängen Sie Folgendes an den HookonAdd
an:
Mitcamera = new THREE.PerspectiveCamera();
PerspectiveCamera
können Sie auch die Attribute konfigurieren, aus denen der Blickwinkel besteht, einschließlich der Nah- und Fernebenen, des Seitenverhältnisses und des Sichtfelds (Fokus). Insgesamt bilden diese Attribute den sogenannten Frustum, also ein wichtiges Konzept für die 3D-Darstellung, aber nicht im Rahmen dieses Codelabs. Die Standardkonfiguration fürPerspectiveCamera
reicht aus. - Fügen Sie Lichtquellen hinzu.
Objekte, die in einer Three.js-Szene gerendert werden, sind standardmäßig schwarz, unabhängig von den angewendeten Texturen. Das liegt daran, dass eine Three.js-Szene die Umgebung von Objekten imitiert, bei der die Farbe von einem Licht reflektiert wird, das von einem Objekt reflektiert wird. Kurz gesagt: Kein Licht, keine Farbe.
Three.js bietet verschiedene Lampen, für die zwei Lampen verwendet werden: AmbientLight
: Stellt eine diffuse Lichtquelle bereit, die alle Objekte in der Sahne aus allen Perspektiven gleichmäßig beleuchtet. Dadurch erhält die Szene einen Grundlichtlicht, damit die Texturen aller Objekte gut sichtbar sind.DirectionalLight
: Zeigt an, dass ein Licht aus einer Richtung im Bild kommt. Anders als bei der Positionierung eines Positionslichts in der realen Welt sind die Lichtstrahlen, die vonDirectionalLight
ausstrahlen, alle parallel und nicht verstreut und verstreut, wenn sie sich weiter von der Lichtquelle entfernen.
Farbe und Intensität der einzelnen Lichtquellen lassen sich so konfigurieren, dass zusammengefasste Lichteffekte entstehen. Im folgenden Code beispielsweise liefert das Umgebungslicht ein weiches weißes Licht für die gesamte Szene. Das gerichtete Licht hingegen stellt ein sekundäres Licht bereit, das Gegenstände nach unten abwinkelt. Im Hinblick auf die Richtungsrichtung ist der Winkel mitposition.set(x, y ,z)
festgelegt, wobei jeder Wert relativ zur entsprechenden Achse ist. Beispielsweise wirdposition.set(0,1,0)
das Licht direkt über dem Bild auf der y-Achse so platziert, dass es direkt nach unten zeigt.
Um die Lichtquellen der Szene hinzuzufügen, hängen Sie Folgendes an den WebhookonAdd
an: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);
Ihr onAdd
-Webhook sollte jetzt so aussehen:
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);
}
Ihre Szene ist jetzt bereit zum Rendern. Als Nächstes konfigurieren Sie den WebGL-Renderer und rendern die Szene.
6. Szene rendern
Zeit zum Rendern der Szene. Bis dahin wurden alle mit Three.js erstellten Elemente im Code initialisiert. Sie sind jedoch im Wesentlichen nicht vorhanden, da sie noch nicht in den WebGL-Renderingkontext gerendert wurden. WebGL rendert 2D- und 3D-Inhalte im Browser mit der Canvas API. Wenn Sie die Canvas API bereits verwendet haben, sind Sie wahrscheinlich mit der context
eines HTML-Canvas vertraut, in dem alle Elemente gerendert werden. Es handelt sich möglicherweise um eine Schnittstelle, die den OpenGL-Grafik-Rendering-Kontext über die WebGLRenderingContext
API im Browser anzeigt.
Für einen einfacheren Umgang mit dem WebGL-Renderer bietet Three.js WebGLRenderer
. Mit diesem Wrapper lässt sich der WebGL-Renderingkontext relativ einfach konfigurieren, sodass Three.js Szenen im Browser rendern kann. Für die Karte reicht es jedoch nicht aus, nur die Three.js-Szene im Browser neben der Karte zu rendern. Three.js muss in denselben Rendering-Kontext wie die Karte gerendert werden, damit sowohl die Karte als auch alle Objekte aus der Three.js-Szene im selben Weltraum gerendert werden. Hierdurch kann der Renderer Interaktionen zwischen Objekten auf der Karte und Objekten im Bild bearbeiten, z. B. durch einen Okklusion. Das ist eine tolle Methode, mit der Objekte, die sich hinter ihnen befinden, ausgeblendet werden.
Klingt ziemlich kompliziert, oder? Glücklicherweise ist Three.js wieder verfügbar.
- Richte den WebGL-Renderer ein.
Wenn Sie eine neue Instanz des Three.js-WebGLRenderer
s erstellen, können Sie dort den WebGL-Renderingkontext angeben, in den die Szene gerendert werden soll. Erinnern Sie sich noch an das Argumentgl
, das an den HookonContextRestored
übergeben wird? Diesesgl
-Objekt ist der WebGL-Renderingkontext der Karte. Du musst nur den Kontext, seinen Canvas und seine Attribute für dieWebGLRenderer
-Instanz bereitstellen. Alle sind über dasgl
-Objekt verfügbar. In diesem Code wird außerdem dieautoClear
-Eigenschaft des Renderers auffalse
gesetzt, damit die Renderer die Ausgabe nicht in jedem Frame löschen.
Hängen Sie zum Konfigurieren des Renderers Folgendes an den WebhookonContextRestored
an:renderer = new THREE.WebGLRenderer({ canvas: gl.canvas, context: gl, ...gl.getContextAttributes(), }); renderer.autoClear = false;
- Rendern Sie die Szene.
Sobald der Renderer konfiguriert ist, ruferequestRedraw
auf derWebGLOverlayView
-Instanz auf, um dem Overlay mitzuteilen, dass beim nächsten Frame eine Neuzeichnung erforderlich ist. Rufe dann beim Rendererrender
auf und übergebe die Three.js-Szene und -Kamera zum Rendern. Löschen Sie zuletzt den Status des WebGL-Renderingkontexts. Dies ist ein wichtiger Schritt zur Vermeidung von GL-Statuskonflikten, da die Verwendung von WebGL Overlay View auf einem gemeinsamen GL-Status basiert. Wenn der Zustand nicht am Ende jedes Zeichenaufrufs zurückgesetzt wird, kann der Renderer durch GL-Statuskonflikte fehlschlagen.
Fügen Sie dazu Folgendes an den HookonDraw
an, damit er in jedem Frame ausgeführt wird:webGLOverlayView.requestRedraw(); renderer.render(scene, camera); renderer.resetState();
Ihre onContextRestored
- und onDraw
-Webhooks sollten jetzt so aussehen:
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-Modell auf der Karte rendern
Ok, du kannst alle Komponenten verwenden. Du hast WebGl Overlay View eingerichtet und eine Three.js-Szene erstellt, aber es gibt ein Problem: da ist nichts. Als Nächstes kommt es auf das Rendering eines 3D-Objekts in der Szene an. Verwenden Sie dazu den zuvor importierten GLTF-Lademodus.
3D-Modelle sind in vielen verschiedenen Formaten verfügbar. Für Three.js ist das gLTF-Format aufgrund seiner Größe und der Laufzeitleistung das bevorzugte Format. In diesem Codelab wird in /src/pin.gltf
bereits ein Modell für das Rendering bereitgestellt.
- Erstellen Sie eine Modellloader-Instanz.
Folgender Text anonAdd
anhängen:loader = new GLTFLoader();
- Ein 3D-Modell laden
Modellladegeräte sind asynchron und führen einen Callback aus, sobald das Modell vollständig geladen ist. Hängen Sie zum Laden vonpin.gltf
Folgendes anonAdd
an:const source = "pin.gltf"; loader.load( source, gltf => {} );
- Fügen Sie das Modell zur Szene hinzu.
Jetzt kannst du das Modell der Szene hinzufügen, indem du Folgendes an denloader
-Callback anfügst. Beachten Sie, dassgltf.scene
hinzugefügt wird, nichtgltf
:scene.add(gltf.scene);
- Matrix für die Kameraprojektion konfigurieren
Schließlich müssen Sie noch etwas tun, damit das Modell auf der Karte richtig gerendert wird. Dazu müssen Sie die Projektionsmatrix der Kamera in der Three.js-Szene festlegen. Die Projektionsmatrix wird als Three.js-Matrix4
-Array angegeben. Sie definiert einen Punkt in dreidimensionalen Bereichen sowie Transformationen wie Rotationen, Scheren, Skalierung und mehr.
Im Fall vonWebGLOverlayView
wird die Projektionsmatrix verwendet, um dem Renderer mitzuteilen, wo und wie die Three.js-Szene im Verhältnis zur Basiskarte gerendert werden soll. Aber es gibt ein Problem. Orte auf der Karte werden als Koordinaten für Breiten- und Längengrad angegeben, während Orte in der Three.js-SzeneVector3
-Koordinaten sind. Die Berechnung der Conversion zwischen den beiden Systemen ist nicht einfach. Um dies zu beheben, übergibtWebGLOverlayView
eincoordinateTransformer
-Objekt an den Lebenszyklus-WebhookOnDraw
, der eine Funktion namensfromLatLngAltitude
enthält.fromLatLngAltitude
verwendet einLatLngAltitude
- oderLatLngAltitudeLiteral
-Objekt und optional eine Reihe von Argumenten, die eine Transformation für die Szene definieren. Anschließend werden diese in eine Modellansichtsprojektmatrix (MVP) umgewandelt. Sie müssen nur angeben, wo auf der Karte die Three.js-Szene gerendert werden soll. Außerdem bestimmen Sie, wie sie umgestaltet werden soll.WebGLOverlayView
erledigt den Rest. Anschließend kannst du die MVP-Matrix in ein Three.js-Matrix4
-Array umwandeln und darauf festlegen.
Im Code unten wird dem zweiten Argument mitgeteilt, dass WebGl Overlay View die Höhe der Three.js-Szene 120 m über dem Boden festlegen soll, wodurch das Modell unverankert wirkt.
Wenn Sie die Projektionsmatrix der Kamera festlegen möchten, hängen Sie Folgendes an den WebhookonDraw
an:const latLngAltitudeLiteral = { lat: mapOptions.center.lat, lng: mapOptions.center.lng, altitude: 120 } const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral); camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
- Modell transformieren.
Sie sehen, dass die Stecknadel nicht senkrecht zur Karte steht. In einem 3D-Grafikbereich hat jedes Objekt neben der Welt mit eigenen x-, y- und z-Achsen, die die Ausrichtung bestimmen, auch einen eigenen Objektbereich mit unabhängigen Achsen.
In diesem Fall wurde das Objekt nicht mit dem Element erstellt, das normalerweise die oberste Position der Markierung auf der y-Achse betrifft, sodass Sie das Objekt in die gewünschte Richtung relativ zum Weltraum ausrichten müssen. Rufen Sie dazurotation.set
auf. Beachten Sie, dass die Rotation in Three.js in Radianten und nicht in Grad angegeben wird. Es ist im Allgemeinen einfacher, in Graden nachzudenken. Daher muss die entsprechende Conversion mithilfe der Formeldegrees * Math.PI/180
erfolgen.
Außerdem ist das Modell etwas klein. Deswegen kannst du es auf allen Achsen gleichmäßig skalieren, indem duscale.set(x, y ,z)
aufrufst.
Wenn Sie das Modell drehen und skalieren möchten, fügen Sie Folgendes imloader
-Callback vononAdd
vorscene.add(gltf.scene)
hinzu. Dadurch wird das gLTF in die Szene aufgenommen:gltf.scene.scale.set(25,25,25); gltf.scene.rotation.x = 180 * Math.PI/180;
Die Markierung steht jetzt aufrecht im Verhältnis zur Karte.
Ihre onAdd
- und onDraw
-Webhooks sollten jetzt so aussehen:
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();
}
Als Nächstes kommt eine Kameraanimation.
8. Kamera animieren
Da Sie nun ein Modell auf der Karte gerendert haben und alles drei Dimensionen verschieben können, sollten Sie diese Aufgabe als Nächstes programmatisch steuern. Mit der Funktion moveCamera
kannst du die Eigenschaften der Mitte, des Zooms und der Neigung der Karte gleichzeitig festlegen. Dadurch erhältst du eine genauere Kontrolle über die Nutzererfahrung. Außerdem kann moveCamera
in einer Animationsschleife aufgerufen werden, um fließende Übergänge zwischen Frames mit einer Framerate von fast 60 Bildern pro Sekunde zu erstellen.
- Warten Sie, bis das Modell geladen ist.
Um eine optimale Nutzererfahrung zu ermöglichen, solltest du mit dem Bewegen der Kamera warten, bis das GLTF-Modell geladen wurde. Hängen Sie dazu den Lade-HandleronLoad
an den WebhookonContextRestored
an:loader.manager.onLoad = () => {}
- Animationsschleife erstellen
Es gibt mehrere Möglichkeiten, eine Animationsschleife zu erstellen, beispielsweise die Verwendung vonsetInterval
oderrequestAnimationFrame
. In diesem Fall verwenden Sie die FunktionsetAnimationLoop
des Three.js-Renderers, der jedes Mal, wenn in Three.js ein neuer Frame gerendert wird, automatisch Code aufgerufen wird, den Sie im Callback deklarieren. Fügen Sie dem Ereignis-HandleronLoad
im vorherigen Schritt Folgendes hinzu, um die Animationsschleife zu erstellen:renderer.setAnimationLoop(() => {});
- Kameraposition in der Animationsschleife festlegen
Rufe dannmoveCamera
auf, um die Karte zu aktualisieren. Hier werden die Eigenschaften desmapOptions
-Objekts, mit dem die Karte geladen wurde, zum Definieren der Kameraposition verwendet:map.moveCamera({ "tilt": mapOptions.tilt, "heading": mapOptions.heading, "zoom": mapOptions.zoom });
- Aktualisieren Sie die Kamera in jedem Frame.
Letzter Schritt! Aktualisiere dasmapOptions
-Objekt am Ende jedes Frames, um die Kameraposition für den nächsten Frame festzulegen. In diesem Code wird eineif
-Anweisung verwendet, um die Neigung zu erhöhen, bis der maximale Neigungswert von 67,5 % erreicht ist.Dann wird die Ausrichtung in jedem Frame etwas geändert, bis die Kamera eine vollständige 360°-Drehung abgeschlossen hat. Nach Abschluss der gewünschten Animation wirdnull
ansetAnimationLoop
übergeben, damit die Animation abgebrochen wird. Sie wird dann nicht dauerhaft ausgeführt.if (mapOptions.tilt < 67.5) { mapOptions.tilt += 0.5 } else if (mapOptions.heading <= 360) { mapOptions.heading += 0.2; } else { renderer.setAnimationLoop(null) }
Ihr onContextRestored
-Webhook sollte jetzt so aussehen:
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. Glückwunsch
Wenn alles wie geplant läuft, sollten Sie jetzt eine Karte mit einer großen 3D-Markierung erstellen können, die so aussieht:
Das haben Sie gelernt
In diesem Codelab haben Sie einiges gelernt. Hier die Highlights:
WebGLOverlayView
und seine Lebenszyklus-Webhooks implementieren- Three.js in die Karte einbinden
- Grundlegende Informationen zum Erstellen einer Three.js-Szene mit Kameras und Beleuchtung.
- 3D-Modelle werden geladen und mit Three.js bearbeitet.
- Mit der
moveCamera
Kamera kannst du die Kamera steuern und animieren.
Nächste Schritte
WebGL und Computergrafiken im Allgemeinen sind ein komplexes Thema. Deshalb gibt es immer viel zu lernen. Hier sind ein paar hilfreiche Ressourcen zum Thema:
- WebGL Overlay View-Dokumentation
- Erste Schritte mit WebGL
- Three.js-Dokumentation
- Helfen Sie uns bei der Erstellung der Inhalte, die Sie nützlich finden würden, indem Sie die folgende Frage beantworten: «codelabs/maps-platform/shared/_next-lab-survey.lab.md» Ist das Codelab, das Sie oben nicht aufgeführt haben, relevant? Hier können Sie ein neues Problem beantragen.