1. Avant de commencer
Cet atelier de programmation vous explique comment contrôler et rendre des objets sur la carte vectorielle en trois dimensions grâce aux éléments géographiques utilisant WebGL de l'API Maps JavaScript.
Conditions préalables
Cet atelier de programmation suppose des connaissances intermédiaires de JavaScript et de l'API Maps JavaScript. Pour découvrir les bases de l'utilisation de cette API, suivez l'atelier de programmation Ajouter une carte à votre site Web (JavaScript).
Points abordés
- Générer un ID de carte, avec la carte vectorielle pour JavaScript activée
- Contrôler la carte avec l'inclinaison et la rotation programmatiques
- Afficher des objets en 3D sur la carte avec
WebGLOverlayView
et Three.js - Animer les mouvements de la caméra avec
moveCamera
Prérequis
- Un compte Google Cloud Platform pour lequel la facturation est activée
- Une clé API Google Maps Platform pour laquelle l'API Maps JavaScript est activée
- Des connaissances intermédiaires en JavaScript, HTML et CSS
- Un éditeur de texte ou un IDE de votre choix
- Node.js
2. Configuration
Pour réaliser l'étape ci-dessous, vous devez activer l'API Maps JavaScript.
Configurer Google Maps Platform
Si vous ne disposez pas encore d'un compte Google Cloud Platform ni d'un projet pour lequel la facturation est activée, consultez le guide Premiers pas avec Google Maps Platform pour savoir comment créer un compte de facturation et un projet.
- Dans Cloud Console, cliquez sur le menu déroulant des projets, puis sélectionnez celui que vous souhaitez utiliser pour cet atelier de programmation.
- Activez les API et les SDK Google Maps Platform requis pour cet atelier de programmation dans Google Cloud Marketplace. Pour ce faire, suivez les étapes indiquées dans cette vidéo ou dans cette documentation.
- Générez une clé API sur la page Identifiants de Cloud Console. Vous pouvez suivre la procédure décrite dans cette vidéo ou dans cette documentation. Toutes les requêtes envoyées à Google Maps Platform nécessitent une clé API.
Configurer Node.js
Si vous ne l'avez pas encore fait, accédez à https://nodejs.org/ afin de télécharger et d'installer l'environnement d'exécution Node.js sur votre ordinateur.
Node.js est fourni avec le gestionnaire de packages npm, dont vous avez besoin pour installer les dépendances pour cet atelier de programmation.
Télécharger le modèle de projet initial
Avant de commencer cet atelier de programmation, procédez comme suit pour télécharger le modèle de projet initial, ainsi que le code complet de la solution :
- Téléchargez ou dupliquez le dépôt GitHub de cet atelier de programmation depuis https://github.com/googlecodelabs/maps-platform-101-webgl/. Le projet initial se trouve dans le répertoire
/starter
et inclut la structure de base de fichier dont vous avez besoin pour suivre l'atelier de programmation. Tous les éléments avec lesquels vous devez travailler se trouvent dans le répertoire/starter/src
. - Après avoir téléchargé le projet initial, exécutez
npm install
dans le répertoire/starter
. Cette opération installe toutes les dépendances nécessaires indiquées danspackage.json
. - Une fois les dépendances installées, exécutez
npm start
dans le répertoire.
Le projet initial a été configuré pour vous permettre d'utiliser webpack-dev-server, qui compile et exécute le code que vous rédigez en local. webpack-dev-server actualise aussi automatiquement votre application dans le navigateur chaque fois que vous modifiez le code.
Si vous souhaitez voir le code complet de la solution s'exécuter, vous pouvez suivre la procédure de configuration ci-dessus dans le répertoire /solution
.
Ajouter votre clé API
L'application de démarrage inclut l'ensemble du code nécessaire pour charger la carte avec le chargeur d'API JavaScript. Il vous suffit donc de fournir votre clé API et votre ID de carte. Le chargeur d'API JavaScript est une bibliothèque simple qui extrait la méthode traditionnelle de chargement de l'API Maps JavaScript intégrée dans le modèle HTML avec une balise script
. Vous pouvez ainsi tout gérer dans le code JavaScript.
Pour ajouter votre clé API, procédez comme suit dans le projet initial :
- Ouvrez
app.js
. - Dans l'objet
apiOptions
, définissez votre clé API en tant que valeur deapiOptions.apiKey
.
3. Générer et utiliser un ID de carte
Pour utiliser les éléments géographiques WebGL de l'API Maps JavaScript, vous avez besoin d'un ID de carte, avec la carte vectorielle activée.
Générer un ID de carte
- Dans Google Cloud Console, accédez à Google Maps Platform > Gestion des cartes.
- Cliquez sur "CRÉER UN ID DE CARTE".
- Dans le champ "Nom de la carte", saisissez le nom de votre ID de carte.
- Dans le menu déroulant "Type de carte", sélectionnez "JavaScript". Les options JavaScript s'affichent.
- Sous "Options JavaScript", cochez les cases "Vecteur", "Inclinaison" et "Rotation".
- (Facultatif) Dans le champ "Description", saisissez la description de votre clé API.
- Cliquez sur le bouton "Suivant". La page "Détails de l'ID de carte" s'affiche.
- Copiez l'ID de carte. Vous l'utiliserez à l'étape suivante pour charger la carte.
Utiliser un ID de carte
Pour charger la carte vectorielle, vous devez fournir un ID de carte en tant que propriété dans les options lorsque vous instanciez la carte. Vous pouvez également fournir le même ID de carte lorsque vous chargez l'API Maps JavaScript.
Pour charger la carte avec votre ID de carte, procédez comme suit :
- Définissez votre ID de carte en tant que valeur de
mapOptions.mapId
.
Fournir l'ID de carte au moment où vous instanciez la carte indique à Google Maps Platform quelles sont les cartes à charger pour une instance donnée. Vous pouvez réutiliser le même ID de carte dans plusieurs applications ou dans plusieurs vues d'une même application.const mapOptions = { "tilt": 0, "heading": 0, "zoom": 18, "center": { lat: 35.6594945, lng: 139.6999859 }, "mapId": "YOUR_MAP_ID" };
Vérifiez l'application exécutée dans votre navigateur. La carte vectorielle (avec l'inclinaison et la rotation activées) doit se charger correctement. Pour vérifier si l'inclinaison et la rotation sont activées, maintenez la touche Maj enfoncée, et faites glisser la carte avec votre souris ou utilisez les touches fléchées du clavier.
Si la carte ne se charge pas, vérifiez que vous avez fourni une clé API valide dans apiOptions
. Si l'inclinaison et la rotation ne fonctionnent pas sur la carte, vérifiez que vous avez fourni un ID de carte avec l'inclinaison et la rotation activées dans apiOptions
et mapOptions
.
Votre fichier app.js
devrait désormais se présenter comme suit :
import { Loader } from '@googlemaps/js-api-loader';
const apiOptions = {
"apiKey": 'YOUR_API_KEY',
"version": "beta"
};
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. Implémenter WebGLOverlayView
WebGLOverlayView
vous permet d'accéder directement au même contexte de rendu WebGL que celui utilisé pour afficher la carte de base vectorielle. Ainsi, vous pouvez rendre des objets 2D et 3D directement sur la carte à l'aide de WebGL et avec des bibliothèques graphiques WebGL populaires.
WebGLOverlayView
expose cinq hooks dans le cycle de vie du contexte de rendu WebGL de la carte que vous pouvez utiliser. Voici une brève description des différents hooks et de leur utilisation :
onAdd()
: appelé lorsque la superposition est ajoutée à une carte en appelantsetMap
sur une instanceWebGLOverlayView
. C'est ici que vous devez effectuer vos tâches liées à WebGL qui ne nécessitent pas d'accéder directement au contexte WebGL.onContextRestored()
: appelé lorsque le contexte WebGL devient disponible, mais avant le rendu de tout objet. C'est ici que vous devez initialiser les objets, lier l'état et effectuer toute autre action nécessitant d'accéder au contexte WebGL, mais pouvant être exécutée en dehors de l'appelonDraw()
. Vous pouvez ainsi configurer tout ce dont vous avez besoin sans trop surcharger le rendu réel de la carte, qui utilise déjà beaucoup le GPU.onDraw()
: appelé une fois par image, une fois que WebGL commence à rendre la carte et tout autre élément demandé. Vous devez travailler le moins possible dansonDraw()
pour éviter tout problème de performances dans le rendu de la carte.onContextLost()
: appelé lorsque le contexte de rendu WebGL est perdu pour une raison quelconque.onRemove()
: appelé lorsque la superposition est supprimée de la carte en appelantsetMap(null)
sur une instanceWebGLOverlayView
.
Dans cette étape, vous allez créer une instance de WebGLOverlayView
et implémenter trois de ses hooks de cycle de vie : onAdd
, onContextRestored
et onDraw
. Pour que tout soit plus simple et plus facile à suivre, l'ensemble du code de superposition sera géré dans la fonction initWebGLOverlayView()
fournie dans le modèle de projet initial de cet atelier de programmation.
- Créez une instance
WebGLOverlayView()
.
La superposition est fournie par l'API Maps JavaScript dansgoogle.maps.WebGLOverlayView
. Pour commencer, créez une instance en ajoutant le code suivant àinitWebGLOverlayView()
:const webGLOverlayView = new google.maps.WebGLOverlayView();
- Implémentez des hooks de cycle de vie.
Pour implémenter les hooks de cycle de vie, ajoutez le code suivant àinitWebGLOverlayView()
:webGLOverlayView.onAdd = () => {}; webGLOverlayView.onContextRestored = ({gl}) => {}; webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {};
- Ajoutez l'instance de superposition à la carte.
Appelez maintenantsetMap()
sur l'instance de superposition et transmettez-le dans la carte en ajoutant le code suivant àinitWebGLOverlayView()
:webGLOverlayView.setMap(map)
- Appelez
initWebGLOverlayView
.
La dernière étape consiste à exécuterinitWebGLOverlayView()
en ajoutant le code suivant à la fonction appelée immédiatement en bas du fichierapp.js
:initWebGLOverlayView(map);
Votre fonction initWebGLOverlayView
et la fonction appelée immédiatement devraient désormais se présenter comme suit :
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);
})();
Vous n'avez besoin de rien d'autre pour implémenter WebGLOverlayView
. Vous allez ensuite configurer tout ce dont vous avez besoin pour rendre un objet 3D sur la carte à l'aide de Three.js.
5. Configurer une scène Three.js
Utiliser WebGL peut être très compliqué, car cette API nécessite de définir tous les aspects de chaque objet manuellement, très minutieusement. Pour vous faciliter la tâche, vous allez utiliser Three.js dans cet atelier de programmation. Il s'agit d'une bibliothèque graphique populaire dotée d'une couche d'abstraction simplifiée reposant sur WebGL. Three.js propose un large éventail de fonctions pratiques, permettant de créer un moteur de rendu WebGL, dessiner des formes courantes d'objets en 2D et 3D, contrôler les caméras, transformer des objets et bien plus encore.
Trois types d'objets de base sont nécessaires dans Three.js pour afficher n'importe quel élément :
- Scène : un "conteneur" dans lequel tous les objets, sources de lumière, textures, etc. sont rendus et affichés.
- Caméra : représente le point de vue de la scène. Plusieurs types de caméras sont disponibles, et vous pouvez ajouter une ou plusieurs caméras à une même scène.
- Moteur de rendu : gère le traitement et l'affichage de tous les objets de la scène. Dans Three.js,
WebGLRenderer
est le moteur le plus utilisé, mais quelques autres sont disponibles en tant que solutions de secours au cas où le client ne serait pas compatible avec WebGL.
Dans cette étape, vous allez charger toutes les dépendances nécessaires à Three.js et configurer une scène de base.
- Chargez triple.js.
Pour cet atelier de programmation, vous aurez besoin de deux dépendances : la bibliothèque Three.js et le chargeur glTF, une classe qui vous permet de charger des objets 3D au format glTF (GL Transmission Format). Three.js propose des chargeurs spécialisés pour de nombreux formats d'objets 3D. Toutefois, nous vous recommandons d'utiliser glTF.
Dans le code ci-dessous, la totalité de la bibliothèque Three.js est importée. Dans une application de productivité, vous souhaiterez probablement n'importer que les classes dont vous avez besoin. Toutefois, pour cet atelier de programmation, importez l'intégralité de la bibliothèque pour faire plus simple. Notez également que le chargeur glTF n'est pas inclus dans la bibliothèque par défaut. De plus, il doit être importé à partir d'un chemin distinct dans la dépendance, à savoir le chemin qui vous permet d'accéder à tous les chargeurs fournis par Three.js.
Pour importer Three.js et le chargeur glTF, ajoutez le code suivant en haut du fichierapp.js
:import * as THREE from 'three'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
- Créez une scène Three.js.
Pour créer une scène, instanciez la classeScene
de Three.js en ajoutant le code suivant au hookonAdd
:scene = new THREE.Scene();
- Ajoutez une caméra à la scène.
Comme indiqué précédemment, la caméra représente le point de vue de la scène et détermine comment Three.js gère le rendu visuel des objets d'une scène. Sans caméra, la scène n'est en fait pas "vue", ce qui signifie que les objets n'apparaissent pas, car ils ne sont pas rendus.
Three.js propose plusieurs caméras différentes qui influent sur la manière dont le moteur de rendu traite les objets en fonction d'éléments tels que la perspective et la profondeur. Dans cette scène, vous allez utiliserPerspectiveCamera
, le type de caméra le plus courant dans Three.js. Il est conçu pour émuler la façon dont l'œil humain percevrait la scène. Autrement dit, les objets plus éloignés de la caméra paraîtront plus petits que ceux qui sont plus proches, la scène comportera un point de fuite, etc.
Pour ajouter une caméra de perspective à la scène, ajoutez le code suivant au hookonAdd
:
Aveccamera = new THREE.PerspectiveCamera();
PerspectiveCamera
, vous pouvez également configurer les attributs qui composent le point de vue, y compris les plans éloignés et rapprochés, les proportions et le champ visuel. Collectivement, ces attributs font partie de ce que l'on appelle le frustum de vue, un concept important que vous devez comprendre pour travailler dans l'environnement 3D. Il ne fait toutefois pas l'objet de cet atelier de programmation. La configuration par défaut dePerspectiveCamera
suffira. - Ajoutez des sources de lumière à la scène.
Par défaut, les objets rendus dans une scène Three.js apparaîtront en noir, quelles que soient les textures qui leur sont appliquées. En effet, une scène Three.js imite le comportement des objets dans le monde réel, où la visibilité des couleurs dépend de la lumière se réfléchissant sur un objet. En bref, pas de lumière, pas de couleur.
Three.js propose plusieurs types d'éclairages différents. Vous en utiliserez deux : AmbientLight
: fournit une source de lumière diffuse qui éclaire tous les objets de la scène de façon uniforme, sous tous les angles. La scène bénéficie ainsi d'une quantité de lumière de référence qui permet de rendre visibles les textures de tous les objets.DirectionalLight
: fournit une lumière provenant d'une direction donnée dans la scène. Contrairement à la façon dont une lumière positionnée fonctionnerait dans le monde réel, les rayons lumineux émis parDirectionalLight
sont tous parallèles. Ils ne se propagent pas et ne se diffusent pas lorsqu'ils s'éloignent de la source de lumière.
Vous pouvez configurer la couleur et l'intensité de chaque lumière pour créer des effets d'éclairage combinés. Dans le code ci-dessous, par exemple, la lumière ambiante fournit une lumière blanche tamisée pour l'ensemble de la scène, tandis que la lumière directionnelle fournit une lumière secondaire qui touche les objets selon un angle descendant. Dans le cas de la lumière directionnelle, l'angle est défini à l'aide deposition.set(x, y ,z)
, chaque valeur étant relative à l'axe respectif. Ainsi,position.set(0,1,0)
placerait la lumière directement au-dessus de la scène sur l'axe y pointant directement vers le bas, par exemple.
Pour ajouter les sources de lumière à la scène, ajoutez le code suivant au 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);
Votre hook onAdd
devrait désormais se présenter comme suit :
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);
}
Votre scène est maintenant configurée et prête à être rendue. Vous allez ensuite configurer le moteur de rendu WebGL et rendre la scène.
6. Rendre la scène
Le moment est venu d'effectuer le rendu de votre scène. Jusqu'ici, tous les éléments que vous avez créés avec Three.js sont initialisés dans le code, mais n'existent pas dans l'absolu. En effet, ils n'ont pas encore été rendus dans le contexte de rendu WebGL. WebGL permet de rendre des contenus 2D et 3D dans le navigateur à l'aide de l'API Canvas. Si vous avez déjà utilisé l'API Canvas, vous connaissez probablement l'élément context
d'un canevas HTML, où tout le rendu est effectué. Par contre, vous ignorez peut-être qu'il s'agit d'une interface qui affiche le contexte de rendu graphique OpenGL via l'API WebGLRenderingContext
dans le navigateur.
Pour simplifier l'utilisation du moteur de rendu WebGL, Three.js fournit WebGLRenderer
, un wrapper qui permet de configurer le contexte de rendu WebGL assez facilement afin que Three.js puisse afficher les scènes dans le navigateur. Toutefois, dans le cas de la carte, rendre uniquement la scène Three.js dans le navigateur avec la carte ne suffit pas. Three.js doit s'afficher dans exactement le même contexte de rendu que la carte, de sorte que la carte et tous les objets de la scène Three.js soient rendus dans le même espace mondial. Cela permet au moteur de rendu de gérer les interactions entre les objets sur la carte et les objets de la scène, comme une occlusion : ce terme élaboré signifie qu'un objet en masque d'autres derrière lui.
Cela semble assez compliqué, n'est-ce pas ? Heureusement, Three.js vient de nouveau à la rescousse.
- Configurez le moteur de rendu WebGL.
Lorsque vous créez une instance duWebGLRenderer
de Three.js, vous pouvez lui fournir le contexte de rendu WebGL spécifique dans lequel vous souhaitez qu'il affiche votre scène. Vous souvenez-vous de l'argumentgl
transmis au hookonContextRestored
? Cet objetgl
correspond au contexte de rendu WebGL de la carte. Il vous suffit de fournir le contexte, son canevas et ses attributs à l'instanceWebGLRenderer
. Tous sont disponibles via l'objetgl
. Dans ce code, la propriétéautoClear
du moteur de rendu est également définie surfalse
. Ainsi, le moteur n'efface pas son résultat à chaque image.
Pour configurer le moteur de rendu, ajoutez le code suivant au hookonContextRestored
:renderer = new THREE.WebGLRenderer({ canvas: gl.canvas, context: gl, ...gl.getContextAttributes(), }); renderer.autoClear = false;
- Effectuez le rendu de la scène.
Une fois le moteur de rendu configuré, appelezrequestRedraw
sur l'instanceWebGLOverlayView
pour indiquer à la superposition qu'un nouveau dessin est nécessaire lorsque l'image suivante s'affiche. Ensuite, appelezrender
sur le moteur de rendu et transmettez-lui la caméra et la scène Three.js aux fins du rendu. Enfin, effacez l'état du contexte de rendu WebGL. Cette étape est importante pour éviter les conflits d'état GL, car l'utilisation de la vue en superposition WebGL repose sur l'état GL partagé. Si l'état n'est pas réinitialisé à la fin de chaque appel de dessin, les conflits d'état GL peuvent entraîner l'échec du moteur de rendu.
Pour ce faire, ajoutez le code suivant au hookonDraw
afin qu'il soit exécuté à chaque image :webGLOverlayView.requestRedraw(); renderer.render(scene, camera); renderer.resetState();
Vos hooks onContextRestored
et onDraw
devraient désormais se présenter comme suit :
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. Rendre un modèle 3D sur la carte
Bien, vous disposez de tous les éléments nécessaires. Vous avez configuré la vue en superposition WebGL et créé une scène Three.js, mais un problème est survenu : celle-ci n'affiche rien. Vous allez donc maintenant rendre un objet 3D dans la scène. Pour ce faire, vous allez utiliser le chargeur glTF que vous avez importé précédemment.
Les modèles 3D sont disponibles dans de nombreux formats différents. Cependant, pour Three.js, le format glTF est recommandé en raison de sa taille et de ses performances d'exécution. Dans cet atelier de programmation, un modèle à afficher dans la scène est déjà fourni dans /src/pin.gltf
.
- Créez une instance de chargeur de modèle.
Ajoutez le code suivant àonAdd
:loader = new GLTFLoader();
- Chargez un modèle 3D.
Les chargeurs de modèles sont asynchrones et exécutent un rappel une fois le modèle complètement chargé. Pour chargerpin.gltf
, ajoutez le code suivant àonAdd
:const source = "pin.gltf"; loader.load( source, gltf => {} );
- Ajoutez le modèle à la scène.
Vous pouvez maintenant ajouter le modèle à la scène en ajoutant le code suivant au rappelloader
. Notez que c'estgltf.scene
qui est ajouté, et nongltf
:scene.add(gltf.scene);
- Configurez la matrice de projection de la caméra.
La dernière étape pour que le modèle s'affiche correctement sur la carte consiste à définir la matrice de projection de la caméra dans la scène Three.js. La matrice est définie comme un tableauMatrix4
dans Three.js, qui définit un point dans un espace tridimensionnel ainsi que des transformations telles que les rotations, le cisaillement, l'échelle, etc.
Dans le cas deWebGLOverlayView
, la matrice de projection permet d'indiquer au moteur de rendu où et comment rendre la scène Three.js par rapport à la carte de base. Il y a cependant un problème. Les emplacements sur la carte correspondent à des paires de coordonnées (latitude et longitude), tandis que les emplacements dans la scène Three.js sont des coordonnées de typeVector3
. Comme vous vous en doutez sûrement, le calcul des conversions entre les deux systèmes n'est pas simple. Pour résoudre ce problème,WebGLOverlayView
transmet un objetcoordinateTransformer
au hook de cycle de vieOnDraw
contenant une fonction appeléefromLatLngAltitude
.fromLatLngAltitude
prend un objetLatLngAltitude
ouLatLngAltitudeLiteral
, et éventuellement un ensemble d'arguments qui définissent une transformation pour la scène, puis les convertit en une matrice de projection de vue de modèle pour vous. Il vous suffit de préciser où vous souhaitez que la scène Three.js soit rendue sur la carte, ainsi que la méthode de transformation.WebGLOverlayView
s'occupe du reste. Vous pouvez ensuite convertir la matrice de projection de vue de modèle en tableauMatrix4
dans Three.js et définir la matrice de projection de la caméra sur ce tableau.
Dans le code ci-dessous, le deuxième argument indique à la vue en superposition WebGL de définir l'altitude de la scène Three.js à 120 mètres au-dessus du sol, ce qui donne l'impression que le modèle flotte.
Pour définir la matrice de projection de la caméra, ajoutez le code suivant au 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);
- Transformez le modèle.
Vous constaterez que le repère n'est pas perpendiculaire à la carte. Dans les graphismes en 3D, en plus de l'espace mondial qui comporte ses propres axes x, y et z déterminant l'orientation, chaque objet dispose également de son propre espace objet avec un ensemble indépendant d'axes.
Dans le cas de ce modèle, il n'a pas été créé avec ce que nous considérons normalement comme le "haut" du repère faisant face à l'axe y. Vous devez donc transformer l'objet pour l'orienter de la façon souhaitée par rapport à l'espace mondial en appelantrotation.set
. Notez que dans Three.js, la rotation est indiquée en radians et non en degrés. Il est généralement plus facile de penser en degrés. Par conséquent, vous devez effectuer la conversion appropriée avec la formuledegrees * Math.PI/180
.
De plus, comme le modèle est un peu petit, vous le mettrez à l'échelle de façon uniforme sur tous les axes en appelantscale.set(x, y ,z)
.
Pour faire pivoter le modèle et le mettre à l'échelle, ajoutez le code suivant dans le rappelloader
deonAdd
avantscene.add(gltf.scene)
, qui ajoute le fichier glTF à la scène :gltf.scene.scale.set(25,25,25); gltf.scene.rotation.x = 180 * Math.PI/180;
Le repère se trouve maintenant à la verticale par rapport à la carte.
Vos hooks onAdd
et onDraw
devraient désormais se présenter comme suit :
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();
}
Passons maintenant aux animations de la caméra.
8. Animer la caméra
Maintenant que vous avez rendu un modèle sur la carte et que vous pouvez déplacer tous les éléments de façon tridimensionnelle, vous souhaiterez sans doute pouvoir ensuite contrôler ce mouvement par programmation. La fonction moveCamera
vous permet de définir simultanément les propriétés du centre, du zoom, de l'inclinaison et de la direction. Vous bénéficiez ainsi d'un contrôle précis sur l'expérience utilisateur. En outre, il est possible d'appeler moveCamera
dans une boucle d'animation pour créer des transitions fluides entre les images, à une fréquence de près de 60 images par seconde.
- Attendez que le modèle soit chargé.
Pour créer une expérience utilisateur fluide, attendez que le modèle glTF soit chargé pour commencer à déplacer la caméra. Pour ce faire, ajoutez le gestionnaire d'événementsonLoad
du chargeur au hookonContextRestored
:loader.manager.onLoad = () => {}
- Créez une boucle d'animation.
Il existe plusieurs façons de créer une boucle d'animation, par exemple en utilisantsetInterval
ourequestAnimationFrame
. Dans ce cas, vous utiliserez la fonctionsetAnimationLoop
du moteur de rendu Three.js, qui appelle automatiquement tout code déclaré dans son rappel chaque fois que Three.js rend une nouvelle image. Pour créer la boucle d'animation, ajoutez le code suivant au gestionnaire d'événementsonLoad
à l'étape précédente :renderer.setAnimationLoop(() => {});
- Définissez la position de la caméra dans la boucle d'animation.
Ensuite, appelezmoveCamera
pour mettre à jour la carte. Ici, les propriétés de l'objetmapOptions
utilisé pour charger la carte servent à définir la position de la caméra :map.moveCamera({ "tilt": mapOptions.tilt, "heading": mapOptions.heading, "zoom": mapOptions.zoom });
- Mettez à jour la caméra à chaque image.
Dernière étape. Mettez à jour l'objetmapOptions
à la fin de chaque image pour définir la position de la caméra pour l'image suivante. Dans ce code, une instructionif
est utilisée pour augmenter l'inclinaison jusqu'à ce que la valeur maximale de 67,5 soit atteinte. Ensuite, la direction est modifiée légèrement à chaque image, jusqu'à ce que la caméra ait effectué une rotation complète à 360 degrés. Une fois l'animation souhaitée terminée,null
est transmis àsetAnimationLoop
afin d'annuler cette animation, de sorte qu'elle ne s'exécute pas éternellement.if (mapOptions.tilt < 67.5) { mapOptions.tilt += 0.5 } else if (mapOptions.heading <= 360) { mapOptions.heading += 0.2; } else { renderer.setAnimationLoop(null) }
Votre hook onContextRestored
devrait désormais se présenter comme suit :
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. Félicitations
Si tout s'est déroulé comme prévu, vous devez normalement avoir une carte avec un grand repère 3D semblable à celui-ci :
Ce que vous avez appris
Dans cet atelier de programmation, vous avez appris différentes choses, et particulièrement les points suivants :
- Implémenter
WebGLOverlayView
et ses hooks de cycle de vie - Intégrer Three.js à la carte
- Les bases pour créer une scène Three.js, y compris les caméras et l'éclairage
- Charger et manipuler des modèles 3D à l'aide de Three.js
- Contrôler et animer la caméra pour la carte à l'aide de
moveCamera
Étapes suivantes
WebGL et l'infographie en général sont des sujets complexes, pour lesquels il y a toujours matière à apprendre. Pour commencer, familiarisez-vous avec les ressources suivantes :
- Documentation sur la vue en superposition WebGL
- Premiers pas avec WebGL
- Documentation Three.js
- Aidez-nous à créer le contenu qui vous semble le plus utile en répondant à la question ci-dessous : «codelabs/maps-platform/shared/_next-lab-survey.lab.md» L'atelier de programmation que vous souhaitez suivre ne figure pas dans la liste ci-dessus ? Demandez-le en décrivant un nouveau problème ici.