1. Hinweis
In diesem Codelab erfahren Sie, wie Sie die WebGL-gestützten Funktionen der Maps JavaScript API verwenden, um die Vektorkarte dreidimensional zu steuern und zu rendern.
Vorbereitung
Für dieses Codelab sind fortgeschrittene Kenntnisse von JavaScript und der Maps JavaScript API erforderlich. Die Grundlagen der Verwendung der Maps JS API werden im Codelab zum Hinzufügen einer Karte zu Ihrer Website (JavaScript) erläutert.
Lerninhalte
- Sie generieren eine Karten-ID, für die die Vektorkarte für JavaScript aktiviert ist.
- Karte mit programmatischer Neigung und Drehung steuern
- 3D-Objekte auf der Karte mit
WebGLOverlayView
und Three.js rendern. - Kamerabewegungen mit
moveCamera
animieren.
Voraussetzungen
- Ein Google Cloud Platform-Konto mit aktivierter Abrechnung
- Ein Google Maps Platform API-Schlüssel, für den die Maps JavaScript API aktiviert ist
- Sie haben mittlere Kenntnisse in JavaScript, HTML und CSS.
- Ein Texteditor oder eine IDE Ihrer Wahl
- Node.js
2. Einrichten
Im Aktivierungsschritt unten müssen Sie die Maps JavaScript API aktivieren.
Google Maps Platform einrichten
Wenn Sie noch kein Google Cloud-Konto und kein Projekt mit aktivierter Abrechnung haben, lesen Sie bitte den Leitfaden Erste Schritte mit Google Maps Platform, um ein Rechnungskonto und ein Projekt zu erstellen.
- Klicken Sie in der Cloud Console auf das Drop-down-Menü für das Projekt und wählen Sie das Projekt aus, das Sie für dieses Codelab verwenden möchten.
- Aktivieren Sie die für dieses Codelab erforderlichen APIs und SDKs der Google Maps Platform im Google Cloud Marketplace. Folgen Sie dazu der Anleitung in diesem Video oder dieser Dokumentation.
- Generieren Sie einen API-Schlüssel in der Cloud Console auf der Seite Anmeldedaten. Folgen Sie dazu dieser Anleitung oder dieser Dokumentation. Für alle Anfragen an die Google Maps Platform ist ein API-Schlüssel erforderlich.
Node.js-Einrichtung
Wenn Sie sie noch nicht haben, rufen Sie https://nodejs.org/ auf, um die Node.js-Laufzeit auf Ihrem Computer herunterzuladen und zu installieren.
Node.js wird mit dem npm-Paketmanager geliefert, den Sie zum Installieren von Abhängigkeiten für dieses Codelab benötigen.
Projekt-Startervorlage herunterladen
Bevor Sie mit diesem Codelab beginnen, laden Sie die Starterprojektvorlage und den vollständigen Lösungscode herunter:
- Laden Sie das GitHub-Repository für dieses Codelab unter https://github.com/googlecodelabs/maps-platform-101-webgl/ herunter oder forken Sie es. Das Starterprojekt befindet sich im Verzeichnis
/starter
und enthält die grundlegende Dateistruktur, die Sie für das Codelab benötigen. Alle benötigten Dateien befinden sich im Verzeichnis/starter/src
. - Führen Sie nach dem Herunterladen des Startprojekts
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 Starterprojekt ist so eingerichtet, dass Sie webpack-dev-server verwenden können. Damit wird der von Ihnen geschriebene Code lokal kompiliert und ausgeführt. Außerdem wird Ihre App im Browser automatisch neu geladen, wenn Sie Codeänderungen vornehmen.
Wenn Sie den vollständigen Lösungscode ausführen möchten, können Sie die oben beschriebenen Einrichtungsschritte im Verzeichnis /solution
ausführen.
Eigenen API-Schlüssel hinzufügen
Die Starter-App enthält den gesamten Code, der zum Laden der Karte mit dem JS-API-Ladeprogramm erforderlich ist. Sie müssen also nur Ihren API-Schlüssel und Ihre Karten-ID angeben. Der JS API Loader ist eine einfache Bibliothek, die die herkömmliche Methode zum Inline-Laden der Maps JS API im HTML-Template mit einem script
-Tag abstrahiert. So können Sie alles im JavaScript-Code erledigen.
So fügen Sie Ihren API-Schlüssel im Starterprojekt hinzu:
- Öffnen Sie
app.js
. - Legen Sie im
apiOptions
-Objekt Ihren API-Schlüssel als Wert vonapiOptions.apiKey
fest.
3. Karten-ID generieren und verwenden
Wenn Sie die WebGL-basierten Funktionen der Maps JavaScript API verwenden möchten, benötigen Sie eine Karten-ID mit aktivierter Vektorkarte.
Karten-ID erstellen
- Rufen Sie in der Google Cloud Console „Google Maps Platform“ > „Kartenverwaltung“ auf.
- Klicken Sie auf „NEUE KARTEN-ID ERSTELLEN“.
- Geben Sie im Feld „Kartenname“ einen Namen für Ihre Karten-ID ein.
- Wählen Sie im Drop-down-Menü „Kartentyp“ die Option „JavaScript“ aus. Die Option „JavaScript-Optionen“ wird angezeigt.
- Wählen Sie unter „JavaScript-Optionen“ das Optionsfeld „Vektor“, das Kästchen „Neigung“ und das Kästchen „Drehung“ aus.
- Optional: Geben Sie im Feld „Beschreibung“ eine Beschreibung für den API-Schlüssel ein.
- Klicken Sie auf die Schaltfläche „Weiter“. Die Seite „Karten-ID-Details“ wird angezeigt.
- Kopieren Sie die Karten-ID. Sie benötigen sie im nächsten Schritt, um die Karte zu laden.
Karten-ID verwenden
Wenn Sie die Vektorkarte laden möchten, müssen Sie beim Instanziieren der Karte eine Karten-ID als Eigenschaft in den Optionen angeben. Optional können Sie auch dieselbe Karten-ID angeben, wenn Sie die Maps JavaScript API laden.
So laden Sie die Karte mit Ihrer Karten-ID:
- Legen Sie Ihre Karten-ID als Wert von
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 für mehrere Apps oder mehrere Ansichten innerhalb derselben App verwenden.const mapOptions = { "tilt": 0, "heading": 0, "zoom": 18, "center": { lat: 35.6594945, lng: 139.6999859 }, "mapId": "YOUR_MAP_ID" };
Sehen Sie sich die im Browser ausgeführte App an. Die Vektorkarte mit aktivierter Neigung und Drehung sollte geladen werden. Wenn Sie prüfen möchten, ob Neigung und Drehung aktiviert sind, halten Sie die Umschalttaste gedrückt und ziehen Sie die Karte mit der Maus oder verwenden Sie die Pfeiltasten auf der Tastatur.
Wenn die Karte nicht geladen wird, prüfen Sie, ob Sie in apiOptions
einen gültigen API-Schlüssel angegeben haben. Wenn sich die Karte nicht neigt und dreht, prüfen Sie, ob Sie eine Karten-ID mit aktivierter Neigung und Drehung in apiOptions
und mapOptions
angegeben haben.
Ihre app.js
-Datei 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
bietet direkten Zugriff auf denselben WebGL-Renderingkontext, der zum Rendern der Vektorbasiskarte verwendet wird. So können Sie 2D- und 3D-Objekte direkt auf der Karte rendern. Dazu können Sie WebGL direkt oder gängige WebGL-basierte Grafikbibliotheken verwenden.
WebGLOverlayView
bietet fünf Hooks für den Lebenszyklus des WebGL-Renderingkontexts der Karte, die Sie verwenden können. Hier finden Sie eine kurze Beschreibung der einzelnen Hooks und wofür Sie sie verwenden sollten:
onAdd()
: Wird aufgerufen, wenn das Overlay einer Karte hinzugefügt wird, indemsetMap
für eineWebGLOverlayView
-Instanz aufgerufen wird. Hier sollten Sie alle WebGL-bezogenen Aufgaben ausführen, für die kein direkter Zugriff auf den WebGL-Kontext erforderlich ist.onContextRestored()
: Wird aufgerufen, wenn der WebGL-Kontext verfügbar wird, aber bevor etwas gerendert wird. Hier sollten Sie Objekte initialisieren, den Status binden und alle anderen Aktionen ausführen, für die Zugriff auf den WebGL-Kontext erforderlich ist, die aber außerhalb desonDraw()
-Aufrufs ausgeführt werden können. So können Sie alles einrichten, was Sie benötigen, ohne die GPU-intensive Darstellung der Karte zusätzlich zu belasten.onDraw()
: Wird einmal pro Frame aufgerufen, sobald WebGL mit dem Rendern der Karte und aller anderen von Ihnen angeforderten Elemente beginnt. Sie sollten inonDraw()
so wenig Arbeit wie möglich erledigen, 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 von der Karte entfernt wird, indemsetMap(null)
für eineWebGLOverlayView
-Instanz aufgerufen wird.
In diesem Schritt erstellen Sie eine Instanz von WebGLOverlayView
und implementieren drei der zugehörigen Lebenszyklus-Hooks: onAdd
, onContextRestored
und onDraw
. Damit alles übersichtlich und leicht nachvollziehbar bleibt, wird der gesamte Code für das Overlay in der Funktion initWebGLOverlayView()
verarbeitet, die in der Startervorlage für dieses Codelab enthalten ist.
- Erstellen Sie eine
WebGLOverlayView()
-Instanz.
Das Overlay wird von der Maps JS API ingoogle.maps.WebGLOverlayView
bereitgestellt. Erstellen Sie zuerst eine Instanz, indem SieinitWebGLOverlayView()
Folgendes hinzufügen:const webGLOverlayView = new google.maps.WebGLOverlayView();
- Lebenszyklus-Hooks implementieren
Fügen SieinitWebGLOverlayView()
Folgendes hinzu, um die Lebenszyklus-Hooks zu implementieren:webGLOverlayView.onAdd = () => {}; webGLOverlayView.onContextRestored = ({gl}) => {}; webGLOverlayView.onDraw = ({gl, transformer}) => {};
- Fügen Sie die Overlay-Instanz der Karte hinzu.
Rufen Sie nunsetMap()
für die Overlay-Instanz auf und übergeben Sie die Karte, indem SieinitWebGLOverlayView()
Folgendes hinzufügen:webGLOverlayView.setMap(map)
- Rufen Sie einfach
initWebGLOverlayView
an.
Im letzten Schritt wirdinitWebGLOverlayView()
ausgeführt. Fügen Sie dazu Folgendes am Ende vonapp.js
in die sofort aufgerufene Funktion ein:initWebGLOverlayView(map);
Ihre initWebGLOverlayView
und die sofort aufgerufene Funktion sollten jetzt 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, transformer}) => {}
webGLOverlayView.setMap(map);
}
(async () => {
const map = await initMap();
initWebGLOverlayView(map);
})();
Das ist alles, was Sie für die Implementierung von WebGLOverlayView
benötigen. Als Nächstes richten Sie alles ein, was Sie zum Rendern eines 3D-Objekts auf der Karte mit Three.js benötigen.
5. three.js-Szene einrichten
Die Verwendung von WebGL kann sehr kompliziert sein, da Sie alle Aspekte jedes Objekts manuell definieren müssen. Um die Dinge zu vereinfachen, verwenden Sie in diesem Codelab Three.js, eine beliebte Grafikbibliothek, die eine vereinfachte Abstraktionsebene über WebGL bietet. Three.js bietet eine Vielzahl von praktischen Funktionen, mit denen sich unter anderem ein WebGL-Renderer erstellen, gängige 2D- und 3D-Objektformen zeichnen und Kameras und Objekttransformationen steuern lassen.
Es gibt drei grundlegende Objekttypen in Three.js, die zum Anzeigen von Inhalten erforderlich sind:
- Szene: 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 und einer Szene können eine oder mehrere Kameras hinzugefügt werden.
- Renderer: Ein Renderer, der die Verarbeitung und Darstellung aller Objekte in der Szene übernimmt. In Three.js wird
WebGLRenderer
am häufigsten verwendet. Es sind aber auch einige andere als Fallback verfügbar, falls der Client WebGL nicht unterstützt.
In diesem Schritt laden Sie alle für Three.js erforderlichen Abhängigkeiten und richten eine einfache Szene ein.
- Three.js laden
Für dieses Codelab benötigen Sie zwei Abhängigkeiten: die Three.js-Bibliothek und den GLTF-Loader, eine Klasse, mit der Sie 3D-Objekte im GL Transmission Format (gLTF) laden können. Three.js bietet spezielle Loader für viele verschiedene 3D-Objektformate, es wird jedoch empfohlen, gLTF zu verwenden.
Im folgenden Code wird die gesamte Three.js-Bibliothek importiert. In einer Produktions-App sollten Sie wahrscheinlich nur die benötigten Klassen importieren. In diesem Codelab importieren wir jedoch die gesamte Bibliothek, um die Dinge einfach zu halten. Beachten Sie auch, dass der GLTF-Loader nicht in der Standardbibliothek enthalten ist und aus einem separaten Pfad in der Abhängigkeit importiert werden muss. Über diesen Pfad können Sie auf alle von Three.js bereitgestellten Loader zugreifen.
Fügen Sie oben inapp.js
Folgendes ein, um Three.js und den GLTF-Loader zu importieren:import * as THREE from 'three'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
- Erstellen Sie eine three.js-Szene.
Um eine Szene zu erstellen, instanziieren Sie die Three.js-KlasseScene
, indem Sie Folgendes an denonAdd
-Hook anhängen:scene = new THREE.Scene();
- Fügen Sie der Szene eine Kamera hinzu.
Wie bereits erwähnt, stellt die Kamera die Perspektive der Szene dar und bestimmt, wie Three.js das visuelle Rendern von Objekten in einer Szene handhabt. Ohne Kamera wird die Szene nicht „gesehen“. Das bedeutet, dass Objekte nicht angezeigt werden, weil sie nicht gerendert werden.
Three.js bietet eine Vielzahl verschiedener Kameras, die sich darauf auswirken, wie der Renderer Objekte in Bezug auf Perspektive und Tiefe behandelt. In dieser Szene verwenden Sie diePerspectiveCamera
, den am häufigsten verwendeten Kameratyp in Three.js. Sie ist so konzipiert, dass sie die Szene so wiedergibt, wie das menschliche Auge sie wahrnehmen würde. Das bedeutet, dass Objekte, die weiter von der Kamera entfernt sind, kleiner erscheinen als Objekte, die näher sind. Außerdem hat die Szene einen Fluchtpunkt.
So fügen Sie der Szene eine Perspektivenkamera hinzu:onAdd
Mitcamera = new THREE.PerspectiveCamera();
PerspectiveCamera
können Sie auch die Attribute konfigurieren, aus denen der Blickwinkel besteht, einschließlich der nahen und fernen Ebenen, des Seitenverhältnisses und des Sichtfelds (field of vision, fov). Zusammen bilden diese Attribute den sogenannten Sichtkegel. Das ist ein wichtiges Konzept für die Arbeit in 3D, das in diesem Codelab jedoch nicht behandelt wird. Die Standardkonfiguration vonPerspectiveCamera
reicht vollkommen aus. - Fügen Sie der Szene Lichtquellen hinzu.
Standardmäßig werden Objekte, die in einer Three.js-Szene gerendert werden, schwarz dargestellt, unabhängig von den auf sie angewendeten Texturen. Das liegt daran, dass in einer Three.js-Szene das Verhalten von Objekten in der realen Welt nachgeahmt wird. Dort hängt die Sichtbarkeit von Farben davon ab, ob Licht von einem Objekt reflektiert wird. Kurz gesagt: Ohne Licht keine Farbe.
Three.js bietet eine Vielzahl verschiedener Arten von Lichtquellen, von denen Sie zwei verwenden werden: AmbientLight
: Stellt eine diffuse Lichtquelle bereit, die alle Objekte in der Szene aus allen Blickwinkeln gleichmäßig beleuchtet. So erhält die Szene eine grundlegende Lichtmenge, damit die Texturen aller Objekte sichtbar sind.DirectionalLight
: Stellt ein Licht dar, das aus einer Richtung in der Szene kommt. Anders als in der realen Welt sind die Lichtstrahlen, die vonDirectionalLight
ausgehen, alle parallel und breiten sich nicht aus, je weiter sie sich von der Lichtquelle entfernen.
Sie können die Farbe und Intensität jeder Lampe konfigurieren, um kombinierte Lichteffekte zu erzielen. Im folgenden Code sorgt das Umgebungslicht beispielsweise für ein weiches weißes Licht für die gesamte Szene, während das gerichtete Licht eine sekundäre Lichtquelle darstellt, die Objekte in einem abwärts gerichteten Winkel trifft. Beim gerichteten Licht wird der Winkel mitposition.set(x, y ,z)
festgelegt, wobei jeder Wert relativ zur jeweiligen Achse ist. Mitposition.set(0,1,0)
wird die Lichtquelle beispielsweise direkt über der Szene auf der y-Achse positioniert und zeigt senkrecht nach unten.
So fügen Sie der Szene die Lichtquellen hinzu: Hängen Sie Folgendes an denonAdd
-Hook 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
-Hook 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 eingerichtet und kann gerendert werden. Als Nächstes konfigurieren Sie den WebGL-Renderer und rendern die Szene.
6. Szene rendern
Zeit, die Szene zu rendern. Bis zu diesem Punkt wird alles, was Sie mit Three.js erstellt haben, im Code initialisiert, ist aber im Grunde nicht vorhanden, da es noch nicht im WebGL-Renderingkontext gerendert wurde. WebGL rendert 2D- und 3D-Inhalte im Browser mithilfe der Canvas API. Wenn Sie die Canvas API schon einmal verwendet haben, kennen Sie wahrscheinlich das context
eines HTML-Canvas, in dem alles gerendert wird. Was Sie vielleicht nicht wissen: Diese Schnittstelle stellt den OpenGL-Grafikrendering-Kontext über die WebGLRenderingContext
API im Browser bereit.
Um die Arbeit mit dem WebGL-Renderer zu erleichtern, bietet Three.js WebGLRenderer
, einen Wrapper, mit dem sich der WebGL-Renderingkontext relativ einfach konfigurieren lässt, sodass Three.js Szenen im Browser rendern kann. Bei der Karte reicht es jedoch nicht aus, die Three.js-Szene einfach 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 in denselben Weltraum gerendert werden. So kann der Renderer Interaktionen zwischen Objekten auf der Karte und Objekten in der Szene verarbeiten, z. B. Verdeckung. Das bedeutet, dass ein Objekt Objekte dahinter verdeckt.
Das klingt ziemlich kompliziert, oder? Glücklicherweise hilft Three.js hier wieder weiter.
- WebGL-Renderer einrichten
Wenn Sie eine neue Instanz von Three.jsWebGLRenderer
erstellen, können Sie ihr den spezifischen WebGL-Rendering-Kontext bereitstellen, in den die Szene gerendert werden soll. Erinnern Sie sich an dasgl
-Argument, das an denonContextRestored
-Hook übergeben wird? Dasgl
-Objekt ist der WebGL-Renderingkontext der Karte. Sie müssen nur den Kontext, den Canvas und die Attribute für dieWebGLRenderer
-Instanz angeben. Alle sind über dasgl
-Objekt verfügbar. In diesem Code wird dieautoClear
-Property des Renderers auch auffalse
gesetzt, damit der Renderer seine Ausgabe nicht bei jedem Frame löscht.
Hängen Sie Folgendes an denonContextRestored
-Hook an, um den Renderer zu konfigurieren:renderer = new THREE.WebGLRenderer({ canvas: gl.canvas, context: gl, ...gl.getContextAttributes(), }); renderer.autoClear = false;
- Rendern Sie die Szene.
Nachdem der Renderer konfiguriert wurde, rufen SierequestRedraw
für dieWebGLOverlayView
-Instanz auf, um dem Overlay mitzuteilen, dass beim Rendern des nächsten Frames ein erneutes Zeichnen erforderlich ist. Rufen Sie dannrender
für den Renderer auf und übergeben Sie ihm die Three.js-Szene und -Kamera, die gerendert werden sollen. Löschen Sie zum Schluss den Status des WebGL-Renderingkontexts. Dies ist ein wichtiger Schritt, um GL-Statuskonflikte zu vermeiden, da die Verwendung von WebGL Overlay View auf einem gemeinsamen GL-Status beruht. Wenn der Zustand am Ende jedes Zeichenaufrufs nicht zurückgesetzt wird, können GL-Zustandskonflikte dazu führen, dass der Renderer fehlschlägt.
Hängen Sie dazu Folgendes an denonDraw
-Hook an, damit er bei jedem Frame ausgeführt wird:webGLOverlayView.requestRedraw(); renderer.render(scene, camera); renderer.resetState();
Ihre onContextRestored
- und onDraw
-Hooks 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 hast alle Voraussetzungen erfüllt. Sie haben die WebGL-Overlay-Ansicht eingerichtet und eine Three.js-Szene erstellt, aber es gibt ein Problem: Die Szene ist leer. Als Nächstes rendern wir ein 3D-Objekt in der Szene. Dazu verwenden Sie den GLTF-Loader, den Sie zuvor importiert haben.
3D‑Modelle sind in vielen verschiedenen Formaten verfügbar. Für Three.js ist das gLTF-Format aufgrund seiner Größe und Laufzeitleistung das bevorzugte Format. In diesem Codelab wird ein Modell, das Sie in der Szene rendern können, bereits in /src/pin.gltf
bereitgestellt.
- Erstellen Sie eine Instanz des Modell-Loaders.
Hängen Sie Folgendes anonAdd
an:loader = new GLTFLoader();
- Laden Sie ein 3D-Modell.
Modell-Loader sind asynchron und führen einen Callback aus, sobald das Modell vollständig geladen wurde. Hängen Sie Folgendes anonAdd
an, umpin.gltf
zu laden:const source = "pin.gltf"; loader.load( source, gltf => {} );
- Fügen Sie das Modell der Szene hinzu.
Sie können das Modell jetzt der Szene hinzufügen, indem Sie den folgenden Code an denloader
-Callback anhängen. Beachten Sie, dassgltf.scene
und nichtgltf
hinzugefügt wird:scene.add(gltf.scene);
- Konfigurieren Sie die Kameraprojektionsmatrix.
Damit das Modell auf der Karte richtig gerendert wird, müssen Sie als Letztes die Projektionsmatrix der Kamera in der Three.js-Szene festlegen. Die Projektionsmatrix wird als Three.js-Matrix4
-Array angegeben, das einen Punkt im dreidimensionalen Raum zusammen mit Transformationen wie Rotationen, Scherung und Skalierung definiert.
BeiWebGLOverlayView
wird die Projektionsmatrix verwendet, um dem Renderer mitzuteilen, wo und wie die Three.js-Szene relativ zur Basiskarte gerendert werden soll. Es gibt jedoch ein Problem. Positionen auf der Karte werden als Koordinatenpaare für Breiten- und Längengrad angegeben, während Positionen in der Three.js-SzeneVector3
-Koordinaten sind. Wie Sie sich vielleicht schon gedacht haben, ist die Berechnung der Conversion zwischen den beiden Systemen nicht trivial. Um dieses Problem zu beheben, übergibtWebGLOverlayView
eincoordinateTransformer
-Objekt an denOnDraw
-Lifecycle-Hook, der eine Funktion namensfromLatLngAltitude
enthält.fromLatLngAltitude
akzeptiert einLatLngAltitude
- oderLatLngAltitudeLiteral
-Objekt und optional eine Reihe von Argumenten, die eine Transformation für die Szene definieren, und konvertiert sie dann in eine MVP-Matrix (Model View Projection). Sie müssen nur angeben, wo auf der Karte die Three.js-Szene gerendert werden soll und wie sie transformiert werden soll.WebGLOverlayView
übernimmt den Rest. Anschließend können Sie die MVP-Matrix in ein Three.js-Matrix4
-Array umwandeln und die Kameraprojektionsmatrix darauf festlegen.
Im folgenden Code wird mit dem zweiten Argument festgelegt, dass die Höhe der Three.js-Szene in WebGl Overlay View 120 Meter über dem Boden liegen soll. Dadurch scheint das Modell zu schweben.
So legen Sie die Kameraprojektionsmatrix fest: Hängen Sie Folgendes an denonDraw
-Hook 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
Die Markierung ist nicht senkrecht zur Karte ausgerichtet. In der 3D-Grafik hat die 3D-Welt nicht nur eigene X-, Y- und Z-Achsen, die die Ausrichtung bestimmen, sondern jedes Objekt hat auch einen eigenen Objektraum mit einem unabhängigen Satz von Achsen.
In diesem Fall wurde das Modell nicht so erstellt, dass die Oberseite des Pins nach oben in Richtung der Y-Achse zeigt. Sie müssen das Objekt also transformieren, um es wie gewünscht im Weltraum auszurichten. Rufen Sie dazurotation.set
auf. In Three.js wird die Drehung in Radianten und nicht in Grad angegeben. Es ist in der Regel einfacher, in Grad zu denken. Daher muss die entsprechende Umrechnung mit der Formeldegrees * Math.PI/180
erfolgen.
Außerdem ist das Modell etwas klein. Daher wird es durch Aufrufen vonscale.set(x, y ,z)
gleichmäßig auf allen Achsen skaliert.
Wenn Sie das Modell drehen und skalieren möchten, fügen Sie Folgendes imloader
-Callback vononAdd
vorscene.add(gltf.scene)
hinzu, wodurch das gLTF der Szene hinzugefügt wird:gltf.scene.scale.set(25,25,25); gltf.scene.rotation.x = 180 * Math.PI/180;
Der Pin steht jetzt aufrecht auf der Karte.
Ihre onAdd
- und onDraw
-Hooks 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 kommen Kameraanimationen.
8. Kamera animieren
Nachdem Sie ein Modell auf der Karte gerendert haben und alles dreidimensional bewegen können, möchten Sie diese Bewegung wahrscheinlich programmatisch steuern. Mit der Funktion moveCamera
können Sie die Eigenschaften „Mitte“, „Zoom“, „Neigung“ und „Ausrichtung“ der Karte gleichzeitig festlegen und so die Nutzerfreundlichkeit optimieren. Außerdem kann moveCamera
in einer Animationsschleife aufgerufen werden, um flüssige Übergänge zwischen Frames bei einer Framerate von fast 60 Bildern pro Sekunde zu erstellen.
- Warten Sie, bis das Modell geladen ist.
Um eine nahtlose Nutzererfahrung zu schaffen, sollten Sie mit dem Bewegen der Kamera warten, bis das gLTF-Modell geladen ist. Hängen Sie dazu denonLoad
-Event-Handler des Loaders an denonContextRestored
-Hook an:loader.manager.onLoad = () => {}
- Erstellen Sie eine Animationsschleife.
Es gibt mehrere Möglichkeiten, eine Animationsschleife zu erstellen, z. B. mitsetInterval
oderrequestAnimationFrame
. In diesem Fall verwenden Sie diesetAnimationLoop
-Funktion des Three.js-Renderers. Damit wird automatisch jeder Code aufgerufen, den Sie in seinem Callback deklarieren, wenn Three.js einen neuen Frame rendert. Fügen Sie demonLoad
-Event-Handler aus dem vorherigen Schritt Folgendes hinzu, um die Animationsschleife zu erstellen:renderer.setAnimationLoop(() => {});
- Legen Sie die Kameraposition im Animationszyklus fest.
Rufen Sie als NächstesmoveCamera
auf, um die Karte zu aktualisieren. Hier werden Eigenschaften desmapOptions
-Objekts verwendet, mit dem die Karte geladen wurde, um die Kameraposition zu definieren:map.moveCamera({ "tilt": mapOptions.tilt, "heading": mapOptions.heading, "zoom": mapOptions.zoom });
- Aktualisieren Sie die Kamera für jeden Frame.
Letzter Schritt: Aktualisieren Sie dasmapOptions
-Objekt am Ende jedes Frames, um die Kameraposition für den nächsten Frame festzulegen. In diesem Code wird mit einerif
-Anweisung die Neigung erhöht, bis der maximale Neigungswert von 67,5 erreicht ist.Anschließend wird die Ausrichtung in jedem Frame etwas geändert, bis die Kamera eine vollständige 360‑Grad-Drehung abgeschlossen hat. Sobald die gewünschte Animation abgeschlossen ist, wirdnull
ansetAnimationLoop
übergeben, um die Animation abzubrechen, damit sie nicht unendlich lange ausgeführt wird.if (mapOptions.tilt < 67.5) { mapOptions.tilt += 0.5 } else if (mapOptions.heading <= 360) { mapOptions.heading += 0.2; } else { renderer.setAnimationLoop(null) }
Ihr onContextRestored
-Hook 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 nach Plan gelaufen ist, sollte jetzt eine Karte mit einer großen 3D-Markierung angezeigt werden, die so aussieht:
Das haben Sie gelernt
In diesem Codelab haben Sie viel gelernt. Hier sind die wichtigsten Punkte:
- Implementieren von
WebGLOverlayView
und seinen Lifecycle-Hooks. - Three.js in die Karte einbinden
- Grundlagen zum Erstellen einer Three.js-Szene, einschließlich Kameras und Beleuchtung.
- 3D-Modelle mit Three.js laden und bearbeiten.
- Steuern und Animieren der Kamera für die Karte mit
moveCamera
.
Nächste Schritte
WebGL und Computergrafiken im Allgemeinen sind komplexe Themen, bei denen es immer viel zu lernen gibt. Hier sind einige Ressourcen, die Ihnen den Einstieg erleichtern:
- Dokumentation zur WebGL Overlay View
- Erste Schritte mit WebGL
- Three.js-Dokumentation
- Helfen Sie uns, die Inhalte zu erstellen, die für Sie am nützlichsten sind, indem Sie die Frage unten beantworten: „codelabs/maps-platform/shared/_next-lab-survey.lab.md“ Ist das gewünschte Codelab oben nicht aufgeführt? Hier können Sie sie mit einem neuen Problem anfordern.