1. Prima di iniziare
Questo codelab ti insegna a utilizzare le funzionalità basate su WebGL dell'API Maps JavaScript per controllare ed eseguire il rendering sulla mappa vettoriale in tre dimensioni.
Prerequisiti
Questo codelab presuppone una conoscenza intermedia di JavaScript e dell'API Maps JavaScript. Per scoprire le nozioni di base sull'utilizzo dell'API Maps JavaScript, prova il codelab Aggiungere una mappa al tuo sito web (JavaScript).
Obiettivi didattici
- Generazione di un ID mappa con la mappa vettoriale per JavaScript abilitata.
- Controllare la mappa con l'inclinazione e la rotazione programmatica.
- Rendering di oggetti 3D sulla mappa con
WebGLOverlayView
e Three.js. - Animare i movimenti della videocamera con
moveCamera
.
Che cosa ti serve
- Un account Google Cloud Platform con la fatturazione attivata
- Una chiave API Google Maps Platform con l'API Maps JavaScript attivata
- Conoscenza intermedia di JavaScript, HTML e CSS
- Un editor di testo o un IDE a tua scelta
- Node.js
2. Configurazione
Per il passaggio di attivazione riportato di seguito, devi abilitare l'API Maps JavaScript.
Configurare Google Maps Platform
Se non hai ancora un account Google Cloud Platform e un progetto con la fatturazione abilitata, consulta la guida Guida introduttiva a Google Maps Platform per creare un account di fatturazione e un progetto.
- Nella console Cloud, fai clic sul menu a discesa del progetto e seleziona il progetto che vuoi utilizzare per questo codelab.
- Abilita le API e gli SDK di Google Maps Platform richiesti per questo codelab in Google Cloud Marketplace. Per farlo, segui i passaggi descritti in questo video o in questa documentazione.
- Genera una chiave API nella pagina Credenziali di Cloud Console. Puoi seguire i passaggi descritti in questo video o in questa documentazione. Tutte le richieste a Google Maps Platform richiedono una chiave API.
Configurazione di Node.js
Se non lo hai ancora fatto, vai alla pagina https://nodejs.org/ per scaricare e installare il runtime Node.js sul computer.
Node.js include il gestore di pacchetti npm, che devi installare per le dipendenze di questo codelab.
Scaricare il modello di progetto iniziale
Prima di iniziare questo codelab, segui questi passaggi per scaricare il modello di progetto iniziale e il codice della soluzione completa:
- Scarica o crea una fork del repository GitHub per questo codelab all'indirizzo https://github.com/googlecodelabs/maps-platform-101-webgl/. Il progetto iniziale si trova nella directory
/starter
e include la struttura di base dei file necessaria per completare il codelab. Tutto ciò che ti serve per lavorare si trova nella directory/starter/src
. - Dopo aver scaricato il progetto iniziale, esegui
npm install
nella directory/starter
. Vengono installate tutte le dipendenze necessarie elencate inpackage.json
. - Una volta installate le dipendenze, esegui
npm start
nella directory.
Il progetto iniziale è stato configurato per l'utilizzo di webpack-dev-server, che compila ed esegue il codice che scrivi localmente. webpack-dev-server ricarica automaticamente l'app nel browser ogni volta che apporti modifiche al codice.
Se vuoi vedere l'esecuzione del codice della soluzione completa, puoi completare i passaggi di configurazione riportati sopra nella directory /solution
.
Aggiungere la chiave API
L'app iniziale include tutto il codice necessario per caricare la mappa con JS API Loader, quindi tutto ciò che devi fare è fornire la chiave API e l'ID mappa. JS API Loader è una semplice libreria che astrae il metodo tradizionale di caricamento dell'API Maps JavaScript in linea nel modello HTML con un tag script
, consentendoti di gestire tutto nel codice JavaScript.
Per aggiungere la chiave API, procedi nel seguente modo nel progetto iniziale:
- Apri
app.js
. - Nell'oggetto
apiOptions
, imposta la chiave API come valore diapiOptions.apiKey
.
3. Generare e utilizzare un ID mappa
Per utilizzare le funzionalità basate su WebGL dell'API Maps JavaScript, devi disporre di un ID mappa con la mappa vettoriale abilitata.
Generare un ID mappa
- Nella console Google Cloud, vai a "Google Maps Platform" > "Gestione mappe".
- Fai clic su "CREA NUOVO ID MAPPA".
- Nel campo "Nome mappa", inserisci un nome per l'ID mappa.
- Nel menu a discesa "Tipo di mappa", seleziona "JavaScript". Verrà visualizzata la sezione "Opzioni JavaScript".
- Nella sezione "Opzioni JavaScript", seleziona il pulsante di opzione "Vettore", la casella di controllo "Inclinazione" e la casella di controllo "Rotazione".
- Facoltativo. Nel campo "Descrizione", inserisci una descrizione per la chiave API.
- Fai clic sul pulsante "Avanti". Viene visualizzata la pagina "Dettagli ID mappa".
- Copia l'ID mappa. Lo utilizzerai nel passaggio successivo per caricare la mappa.
Utilizzare un ID mappa
Per caricare la mappa vettoriale, devi fornire un ID mappa come proprietà nelle opzioni quando crei l'istanza della mappa. Se vuoi, puoi anche fornire lo stesso ID mappa quando carichi l'API Maps JavaScript.
Per caricare la mappa con il tuo ID mappa:
- Imposta l'ID mappa come valore di
mapOptions.mapId
.
Quando crei un'istanza della mappa, l'ID mappa indica a Google Maps Platform quale delle tue mappe caricare per una determinata istanza. Puoi riutilizzare lo stesso ID mappa in più app o in più visualizzazioni all'interno della stessa app.const mapOptions = { "tilt": 0, "heading": 0, "zoom": 18, "center": { lat: 35.6594945, lng: 139.6999859 }, "mapId": "YOUR_MAP_ID" };
Controlla l'app in esecuzione nel browser. La mappa vettoriale con inclinazione e rotazione abilitate dovrebbe essere caricata correttamente. Per verificare se l'inclinazione e la rotazione sono attivate, tieni premuto il tasto Maiusc e trascina con il mouse o utilizza i tasti freccia della tastiera.
Se la mappa non viene caricata, verifica di aver fornito una chiave API valida in apiOptions
. Se la mappa non si inclina e non ruota, verifica di aver fornito un ID mappa con inclinazione e rotazione attive in apiOptions
e mapOptions
.
Il file app.js
dovrebbe ora avere il seguente aspetto:
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. Implementare WebGLOverlayView
WebGLOverlayView
ti offre l'accesso diretto allo stesso contesto di rendering WebGL utilizzato per il rendering della mappa base vettoriale. Ciò significa che puoi eseguire il rendering di oggetti 2D e 3D direttamente sulla mappa utilizzando WebGL, nonché le librerie grafiche basate su WebGL più diffuse.
WebGLOverlayView
espone cinque hook nel ciclo di vita del contesto di rendering WebGL della mappa che puoi utilizzare. Ecco una breve descrizione di ogni hook e del relativo utilizzo:
onAdd()
: Chiamato quando l'overlay viene aggiunto a una mappa chiamandosetMap
su un'istanzaWebGLOverlayView
. Qui devi svolgere qualsiasi lavoro correlato a WebGL che non richiede l'accesso diretto al contesto WebGL.onContextRestored()
: chiamato quando il contesto WebGL diventa disponibile, ma prima che venga eseguito il rendering di qualsiasi elemento. Qui devi inizializzare gli oggetti, associare lo stato ed eseguire qualsiasi altra operazione che richieda l'accesso al contesto WebGL, ma che può essere eseguita al di fuori della chiamataonDraw()
. In questo modo puoi configurare tutto ciò che ti serve senza aggiungere un sovraccarico eccessivo al rendering effettivo della mappa, che è già a uso intensivo della GPU.onDraw()
: chiamato una volta per frame quando WebGL inizia a eseguire il rendering della mappa e di qualsiasi altro elemento che hai richiesto. Dovresti svolgere il minor lavoro possibile inonDraw()
per evitare problemi di prestazioni nel rendering della mappa.onContextLost()
: chiamato quando il contesto di rendering WebGL viene perso per qualsiasi motivo.onRemove()
: chiamato quando l'overlay viene rimosso dalla mappa chiamandosetMap(null)
su un'istanzaWebGLOverlayView
.
In questo passaggio, creerai un'istanza di WebGLOverlayView
e implementerai tre dei relativi hook del ciclo di vita: onAdd
, onContextRestored
e onDraw
. Per mantenere il codice pulito e più facile da seguire, tutto il codice per l'overlay verrà gestito nella funzione initWebGLOverlayView()
fornita nel modello iniziale per questo codelab.
- Crea un'istanza
WebGLOverlayView()
.
L'overlay è fornito dall'API Maps JavaScript ingoogle.maps.WebGLOverlayView
. Per iniziare, crea un'istanza aggiungendo quanto segue ainitWebGLOverlayView()
:const webGLOverlayView = new google.maps.WebGLOverlayView();
- Implementa hook del ciclo di vita.
Per implementare gli hook del ciclo di vita, aggiungi quanto segue ainitWebGLOverlayView()
:webGLOverlayView.onAdd = () => {}; webGLOverlayView.onContextRestored = ({gl}) => {}; webGLOverlayView.onDraw = ({gl, transformer}) => {};
- Aggiungi l'istanza dell'overlay alla mappa.
Ora chiamasetMap()
nell'istanza di overlay e passa la mappa aggiungendo quanto segue ainitWebGLOverlayView()
:webGLOverlayView.setMap(map)
- Chiama il numero
initWebGLOverlayView
.
L'ultimo passaggio consiste nell'eseguireinitWebGLOverlayView()
aggiungendo quanto segue alla funzione immediatamente richiamata nella parte inferiore diapp.js
:initWebGLOverlayView(map);
Il tuo initWebGLOverlayView
e la funzione immediatamente richiamata dovrebbero ora essere simili a questo:
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);
})();
Questo è tutto ciò che ti serve per implementare WebGLOverlayView
. Successivamente, configurerai tutto il necessario per visualizzare un oggetto 3D sulla mappa utilizzando Three.js.
5. Configurare una scena three.js
L'utilizzo di WebGL può essere molto complicato perché richiede di definire manualmente tutti gli aspetti di ogni oggetto e altro ancora. Per semplificare notevolmente le cose, in questo codelab utilizzerai Three.js, una popolare libreria grafica che fornisce un livello di astrazione semplificato sopra WebGL. Three.js offre un'ampia gamma di funzioni utili che fanno di tutto, dalla creazione di un renderer WebGL al disegno di forme di oggetti 2D e 3D comuni, al controllo di telecamere, trasformazioni di oggetti e molto altro ancora.
In Three.js esistono tre tipi di oggetti di base necessari per visualizzare qualsiasi elemento:
- Scena: un "contenitore" in cui vengono visualizzati e sottoposti a rendering tutti gli oggetti, le sorgenti luminose, le texture e così via.
- Fotocamera: una fotocamera che rappresenta il punto di vista della scena. Sono disponibili più tipi di videocamere e a una singola scena possono essere aggiunte una o più videocamere.
- Renderer: un renderer che gestisce l'elaborazione e la visualizzazione di tutti gli oggetti nella scena. In Three.js,
WebGLRenderer
è il più utilizzato, ma alcuni altri sono disponibili come fallback nel caso in cui il client non supporti WebGL.
In questo passaggio, caricherai tutte le dipendenze necessarie per Three.js e configurerai una scena di base.
- Carica three.js
Per questo codelab avrai bisogno di due dipendenze: la libreria Three.js e GLTF Loader, una classe che ti consente di caricare oggetti 3D nel formato GL Trasmission Format (gLTF). Three.js offre caricatori specializzati per molti formati di oggetti 3D diversi, ma è consigliabile utilizzare gLTF.
Nel codice riportato di seguito, viene importata l'intera libreria Three.js. In un'app di produzione probabilmente vorrai importare solo le classi di cui hai bisogno, ma per questo codelab importa l'intera libreria per semplificare le cose. Tieni presente inoltre che GLTF Loader non è incluso nella libreria predefinita e deve essere importato da un percorso separato nella dipendenza. Questo è il percorso in cui puoi accedere a tutti i caricatori forniti da Three.js.
Per importare Three.js e GLTF Loader, aggiungi quanto segue all'inizio diapp.js
:import * as THREE from 'three'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
- Crea una scena three.js.
Per creare una scena, crea un'istanza della classeScene
di Three.js aggiungendo quanto segue all'hookonAdd
:scene = new THREE.Scene();
- Aggiungi una videocamera alla scena.
Come accennato in precedenza, la videocamera rappresenta la prospettiva di visualizzazione della scena e determina il modo in cui Three.js gestisce il rendering visivo degli oggetti all'interno di una scena. Senza una videocamera, la scena non viene "vista", il che significa che gli oggetti non vengono visualizzati perché non vengono renderizzati.
Three.js offre una serie di diverse videocamere che influiscono sul modo in cui il renderer tratta gli oggetti rispetto a elementi come prospettiva e profondità. In questa scena, utilizzeraiPerspectiveCamera
, il tipo di videocamera più comunemente utilizzato in Three.js, progettato per emulare il modo in cui l'occhio umano percepirebbe la scena. Ciò significa che gli oggetti più lontani dalla videocamera appariranno più piccoli di quelli più vicini, la scena avrà un punto di fuga e così via.
Per aggiungere una videocamera prospettica alla scena, aggiungi quanto segue all'hookonAdd
: Concamera = new THREE.PerspectiveCamera();
PerspectiveCamera
, puoi anche configurare gli attributi che compongono il punto di vista, inclusi i piani vicino e lontano, le proporzioni e il campo visivo (FOV). Nel complesso, questi attributi costituiscono ciò che è noto come frustum di visualizzazione, un concetto importante da comprendere quando si lavora in 3D, ma al di fuori dell'ambito di questo codelab. La configurazione predefinita diPerspectiveCamera
sarà sufficiente. - Aggiungi fonti di luce alla scena.
Per impostazione predefinita, gli oggetti visualizzati in una scena Three.js appaiono neri, indipendentemente dalle texture applicate. Questo perché una scena Three.js imita il comportamento degli oggetti nel mondo reale, dove la visibilità del colore dipende dalla luce che si riflette su un oggetto. In breve, niente luce, niente colore.
Three.js fornisce una serie di diversi tipi di luci, di cui ne utilizzerai due: AmbientLight
: fornisce una sorgente luminosa diffusa che illumina uniformemente tutti gli oggetti della scena da tutte le angolazioni. In questo modo, la scena avrà una quantità di luce di base per garantire che le texture di tutti gli oggetti siano visibili.DirectionalLight
: fornisce una luce che proviene da una direzione della scena. A differenza di come funzionerebbe una luce posizionata nel mondo reale, i raggi luminosi che emanano daDirectionalLight
sono tutti paralleli e non si diffondono man mano che si allontanano dalla sorgente luminosa.
Puoi configurare il colore e l'intensità di ogni luce per creare effetti di illuminazione aggregati. Ad esempio, nel codice riportato di seguito, la luce ambientale fornisce una luce bianca soffusa per l'intera scena, mentre la luce direzionale fornisce una luce secondaria che colpisce gli oggetti con un'angolazione verso il basso. Nel caso della luce direzionale, l'angolo viene impostato utilizzandoposition.set(x, y ,z)
, dove ogni valore è relativo al rispettivo asse. Ad esempio,position.set(0,1,0)
posizionerebbe la luce direttamente sopra la scena sull'asse Y, puntando verso il basso.
Per aggiungere le sorgenti luminose alla scena, aggiungi quanto segue all'hookonAdd
: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);
L'hook onAdd
ora dovrebbe avere il seguente aspetto:
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);
}
La scena è ora configurata e pronta per il rendering. Successivamente, configurerai il renderer WebGL e visualizzerai la scena.
6. Esegui il rendering della scena
È il momento di eseguire il rendering della scena. Fino a questo punto, tutto ciò che hai creato con Three.js è inizializzato nel codice, ma è essenzialmente inesistente perché non è ancora stato sottoposto a rendering nel contesto di rendering WebGL. WebGL esegue il rendering di contenuti 2D e 3D nel browser utilizzando l'API Canvas. Se hai già utilizzato l'API Canvas, probabilmente hai familiarità con il context
di un canvas HTML, in cui viene eseguito il rendering di tutti gli elementi. Quello che forse non sai è che questa è un'interfaccia che espone il contesto di rendering grafico OpenGL tramite l'API WebGLRenderingContext
nel browser.
Per semplificare la gestione del renderer WebGL, Three.js fornisce WebGLRenderer
, un wrapper che semplifica la configurazione del contesto di rendering WebGL in modo che Three.js possa eseguire il rendering delle scene nel browser. Nel caso della mappa, tuttavia, non è sufficiente eseguire il rendering della scena Three.js nel browser insieme alla mappa. Three.js deve essere visualizzato nello stesso contesto di rendering della mappa, in modo che sia la mappa sia gli oggetti della scena Three.js vengano visualizzati nello stesso spazio del mondo. In questo modo, il renderer può gestire le interazioni tra gli oggetti sulla mappa e quelli nella scena, ad esempio l'occlusione, che è un modo elegante per dire che un oggetto nasconde alla vista gli oggetti che si trovano dietro di lui.
Sembra piuttosto complicato, vero? Fortunatamente, Three.js viene di nuovo in soccorso.
- Configura il renderer WebGL.
Quando crei una nuova istanza diWebGLRenderer
Three.js, puoi fornire il contesto di rendering WebGL specifico in cui vuoi che venga eseguito il rendering della scena. Ricordi l'argomentogl
passato all'hookonContextRestored
? L'oggettogl
è il contesto di rendering WebGL della mappa. Devi solo fornire il contesto, il canvas e gli attributi all'istanzaWebGLRenderer
, tutti disponibili tramite l'oggettogl
. In questo codice, anche la proprietàautoClear
del renderer è impostata sufalse
, in modo che il renderer non cancelli il suo output ogni frame.
Per configurare il renderer, aggiungi quanto segue all'hookonContextRestored
:renderer = new THREE.WebGLRenderer({ canvas: gl.canvas, context: gl, ...gl.getContextAttributes(), }); renderer.autoClear = false;
- Esegui il rendering della scena.
Una volta configurato il renderer, chiamarequestRedraw
sull'istanzaWebGLOverlayView
per comunicare all'overlay che è necessario un nuovo disegno al rendering del frame successivo, quindi chiamarender
sul renderer e trasmetti la scena e la videocamera Three.js da eseguire il rendering. Infine, cancella lo stato del contesto di rendering WebGL. Si tratta di un passaggio importante per evitare conflitti di stato GL, poiché l'utilizzo di WebGL Overlay View si basa sullo stato GL condiviso. Se lo stato non viene reimpostato alla fine di ogni chiamata di disegno, i conflitti di stato GL potrebbero causare l'errore del renderer.
Per farlo, aggiungi quanto segue all'hookonDraw
in modo che venga eseguito ogni frame:webGLOverlayView.requestRedraw(); renderer.render(scene, camera); renderer.resetState();
I tuoi hook onContextRestored
e onDraw
ora dovrebbero avere il seguente aspetto:
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. Eseguire il rendering di un modello 3D sulla mappa
Ok, hai tutti i pezzi al loro posto. Hai configurato la visualizzazione overlay WebGL e creato una scena Three.js, ma c'è un problema: non c'è nulla. A questo punto, è il momento di eseguire il rendering di un oggetto 3D nella scena. Per farlo, utilizzerai il caricatore GLTF importato in precedenza.
I modelli 3D sono disponibili in molti formati diversi, ma per Three.js il formato gLTF è il preferito per le sue dimensioni e le prestazioni di runtime. In questo codelab, un modello da visualizzare nella scena è già fornito in /src/pin.gltf
.
- Crea un'istanza del caricatore di modelli.
Aggiungi quanto segue aonAdd
:loader = new GLTFLoader();
- Carica un modello 3D.
I caricatori di modelli sono asincroni ed eseguono un callback una volta che il modello è stato caricato completamente. Per caricarepin.gltf
, aggiungi il seguente codice aonAdd
:const source = "pin.gltf"; loader.load( source, gltf => {} );
- Aggiungi il modello alla scena.
Ora puoi aggiungere il modello alla scena aggiungendo quanto segue al callbackloader
. Tieni presente che viene aggiuntogltf.scene
, nongltf
:scene.add(gltf.scene);
- Configura la matrice di proiezione della videocamera.
L'ultima cosa che devi fare per visualizzare correttamente il modello sulla mappa è impostare la matrice di proiezione della videocamera nella scena Three.js. La matrice di proiezione è specificata come arrayMatrix4
di Three.js, che definisce un punto nello spazio tridimensionale insieme a trasformazioni, come rotazioni, taglio, scala e altro ancora.
Nel caso diWebGLOverlayView
, la matrice di proiezione viene utilizzata per indicare al renderer dove e come eseguire il rendering della scena Three.js rispetto alla basemap. Ma c'è un problema. Le posizioni sulla mappa sono specificate come coppie di coordinate di latitudine e longitudine, mentre le posizioni nella scena Three.js sono coordinateVector3
. Come avrai intuito, calcolare la conversione tra i due sistemi non è semplice. Per risolvere il problema,WebGLOverlayView
passa un oggettocoordinateTransformer
all'hook del ciclo di vitaOnDraw
che contiene una funzione chiamatafromLatLngAltitude
.fromLatLngAltitude
accetta un oggettoLatLngAltitude
oLatLngAltitudeLiteral
e, facoltativamente, un insieme di argomenti che definiscono una trasformazione per la scena, quindi li converte in una matrice di proiezione della visualizzazione del modello (MVP). Tutto quello che devi fare è specificare dove sulla mappa vuoi che venga visualizzata la scena Three.js, nonché come vuoi che venga trasformata, eWebGLOverlayView
fa il resto. A questo punto, puoi convertire la matrice MVP in un arrayMatrix4
Three.js e impostare la matrice di proiezione della videocamera.
Nel codice riportato di seguito, il secondo argomento indica a WebGl Overlay View di impostare l'altitudine della scena Three.js a 120 metri dal suolo, in modo che il modello sembri fluttuare.
Per impostare la matrice di proiezione della videocamera, aggiungi quanto segue all'hookonDraw
:const latLngAltitudeLiteral = { lat: mapOptions.center.lat, lng: mapOptions.center.lng, altitude: 120 } const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral); camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
- Trasforma il modello.
Noterai che il segnaposto non è perpendicolare alla mappa. Nella grafica 3D, oltre allo spazio globale che ha i propri assi x, y e z che determinano l'orientamento, ogni oggetto ha anche il proprio spazio oggetto con un insieme indipendente di assi.
Nel caso di questo modello, non è stato creato con quella che normalmente considereremmo la "parte superiore" del pin rivolta verso l'asse Y, quindi devi trasformare l'oggetto per orientarlo nel modo desiderato rispetto allo spazio globale chiamandorotation.set
. Tieni presente che in Three.js la rotazione è specificata in radianti, non in gradi. In genere è più facile pensare in gradi, quindi è necessario eseguire la conversione appropriata utilizzando la formuladegrees * Math.PI/180
.
Inoltre, il modello è un po' piccolo, quindi lo ridimensionerai in modo uniforme su tutti gli assi chiamandoscale.set(x, y ,z)
.
Per ruotare e scalare il modello, aggiungi quanto segue nel callbackloader
dionAdd
prima discene.add(gltf.scene)
che aggiunge il file gLTF alla scena:gltf.scene.scale.set(25,25,25); gltf.scene.rotation.x = 180 * Math.PI/180;
Ora il pin è verticale rispetto alla mappa.
I tuoi hook onAdd
e onDraw
ora dovrebbero avere il seguente aspetto:
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();
}
Poi ci sono le animazioni della videocamera.
8. Animare la videocamera
Ora che hai eseguito il rendering di un modello sulla mappa e puoi spostare tutto in tre dimensioni, la cosa successiva che probabilmente vorrai fare è controllare il movimento a livello di programmazione. La funzione moveCamera
ti consente di impostare contemporaneamente le proprietà di centro, zoom, inclinazione e direzione della mappa, offrendoti un controllo preciso sull'esperienza utente. Inoltre, moveCamera
può essere chiamato in un ciclo di animazione per creare transizioni fluide tra i frame a una frequenza di quasi 60 frame al secondo.
- Attendi il caricamento del modello.
Per creare un'esperienza utente fluida, ti consigliamo di attendere l'inizio dello spostamento della videocamera fino al caricamento del modello gLTF. Per farlo, aggiungi il gestore di eventionLoad
del caricatore all'hookonContextRestored
:loader.manager.onLoad = () => {}
- Crea un loop di animazione.
Esistono diversi modi per creare un ciclo di animazione, ad esempio utilizzandosetInterval
orequestAnimationFrame
. In questo caso, utilizzerai la funzionesetAnimationLoop
del renderer Three.js, che chiamerà automaticamente qualsiasi codice dichiarato nel suo callback ogni volta che Three.js esegue il rendering di un nuovo frame. Per creare il ciclo di animazione, aggiungi quanto segue al gestore eventionLoad
nel passaggio precedente:renderer.setAnimationLoop(() => {});
- Imposta la posizione della videocamera nel ciclo di animazione.
Dopodiché, chiamamoveCamera
per aggiornare la mappa. Qui, le proprietà dell'oggettomapOptions
utilizzato per caricare la mappa vengono utilizzate per definire la posizione della videocamera:map.moveCamera({ "tilt": mapOptions.tilt, "heading": mapOptions.heading, "zoom": mapOptions.zoom });
- Aggiorna la videocamera ogni frame.
Ultimo passaggio. Aggiorna l'oggettomapOptions
alla fine di ogni fotogramma per impostare la posizione della videocamera per il fotogramma successivo. In questo codice, viene utilizzata un'istruzioneif
per incrementare l'inclinazione fino a raggiungere il valore massimo di 67,5, quindi la direzione viene modificata leggermente a ogni frame finché la videocamera non ha completato una rotazione di 360 gradi. Una volta completata l'animazione desiderata,null
viene passato asetAnimationLoop
per annullare l'animazione in modo che non venga eseguita per sempre.if (mapOptions.tilt < 67.5) { mapOptions.tilt += 0.5 } else if (mapOptions.heading <= 360) { mapOptions.heading += 0.2; } else { renderer.setAnimationLoop(null) }
L'hook onContextRestored
ora dovrebbe avere il seguente aspetto:
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. Complimenti
Se tutto è andato secondo i piani, ora dovresti avere una mappa con un grande segnaposto 3D simile a questo:
Che cosa hai imparato
In questo codelab hai imparato molte cose. Ecco i punti salienti:
- Implementare
WebGLOverlayView
e i relativi hook del ciclo di vita. - Integrazione di Three.js nella mappa.
- Le nozioni di base per creare una scena Three.js, incluse le videocamere e l'illuminazione.
- Caricamento e manipolazione di modelli 3D utilizzando Three.js.
- Controllare e animare la videocamera per la mappa utilizzando
moveCamera
.
Passaggi successivi
WebGL e la computer grafica in generale sono argomenti complessi, quindi c'è sempre molto da imparare. Ecco alcune risorse per iniziare:
- Documentazione sulla visualizzazione sovrapposta WebGL
- Inizia a utilizzare WebGL.
- Documentazione di Three.js
- Aiutaci a creare i contenuti che ritieni più utili rispondendo alla domanda riportata di seguito: "codelabs/maps-platform/shared/_next-lab-survey.lab.md". Il codelab che ti interessa non è elencato sopra? Richiedilo con un nuovo problema qui.