Les tuiles 3D photoréalistes sont au format glTF standard OGC. Vous pouvez donc utiliser n'importe quel moteur de rendu compatible avec la spécification OGC 3D Tiles pour créer vos visualisations 3D. Par exemple, Cesium est une bibliothèque Open Source fondamentale pour le rendu des visualisations 3D.
Utiliser CesiumJS
CesiumJS est une bibliothèque JavaScript Open Source permettant la visualisation 3D sur le Web. Pour en savoir plus sur l'utilisation de CesiumJS, consultez Learn CesiumJS.
Contrôle utilisateur
Le moteur de rendu de tuiles CesiumJS dispose d'un ensemble standard de commandes utilisateur.
Action | Description |
---|---|
Vue panoramique | Cliquez avec le bouton gauche et faites glisser la souris |
Vue Zoom | Effectuez un clic droit et faites glisser la souris, ou faites défiler la molette de la souris. |
Faire pivoter la vue | Ctrl+clic gauche/droit+déplacer ou clic du milieu+déplacer |
Bonnes pratiques
Il existe plusieurs approches pour réduire les temps de chargement 3D de CesiumJS. Exemple :
Activez les requêtes simultanées en ajoutant l'instruction suivante à votre code HTML de rendu :
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = <REQUEST_COUNT>
Plus la valeur de
REQUEST_COUNT
est élevée, plus les tuiles se chargent rapidement. Toutefois, lorsque vous chargez un navigateur Chrome avecREQUEST_COUNT
supérieur à 10 et le cache désactivé, vous pouvez rencontrer un problème connu de Chrome. Pour la plupart des cas d'utilisation, nous recommandons une valeurREQUEST_COUNT
de 18 pour des performances optimales.Activez l'option permettant d'ignorer les niveaux de détail. Pour en savoir plus, consultez ce problème Cesium.
Assurez-vous d'afficher correctement les attributions de données en activant showCreditsOnScreen: true
. Pour en savoir plus, consultez la section Règles.
Métriques de rendu
Pour trouver la fréquence d'images, regardez combien de fois par seconde la méthode requestAnimationFrame est appelée.
Pour savoir comment la latence des frames est calculée, consultez la classe PerformanceDisplay.
Exemples de rendu CesiumJS
Vous pouvez utiliser le moteur de rendu CesiumJS avec les tuiles 3D de l'API Map Tiles en fournissant simplement l'URL du tileset racine.
Exemple simple
L'exemple suivant initialise le moteur de rendu CesiumJS, puis charge le tileset racine.
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>CesiumJS 3D Tiles Simple Demo</title>
<script src="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Cesium.js"></script>
<link href="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>
<div id="cesiumContainer"></div>
<script>
// Enable simultaneous requests.
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = 18;
// Create the viewer.
const viewer = new Cesium.Viewer('cesiumContainer', {
imageryProvider: false,
baseLayerPicker: false,
geocoder: false,
globe: false,
// https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/#enabling-request-render-mode
requestRenderMode: true,
});
// Add 3D Tiles tileset.
const tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
url: "https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY",
// This property is needed to appropriately display attributions
// as required.
showCreditsOnScreen: true,
}));
</script>
</body>
Pour en savoir plus sur requestRenderMode
, consultez Activer le mode de rendu des requêtes.
La page HTML s'affiche comme indiqué ci-dessous.
Intégration de l'API Places
Vous pouvez utiliser CesiumJS avec l'API Places pour obtenir plus d'informations. Vous pouvez utiliser le widget Autocomplete pour accéder à la fenêtre d'affichage des lieux. Cet exemple utilise l'API Places Autocomplete, qui est activée en suivant ces instructions, et l'API Maps JavaScript, qui est activée en suivant ces instructions.
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>CesiumJS 3D Tiles Places API Integration Demo</title>
<script src="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Cesium.js"></script>
<link href="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>
<label for="pacViewPlace">Go to a place: </label>
<input
type="text"
id="pacViewPlace"
name="pacViewPlace"
placeholder="Enter a location..."
style="width: 300px"
/>
<div id="cesiumContainer"></div>
<script>
// Enable simultaneous requests.
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = 18;
// Create the viewer.
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: false,
baseLayerPicker: false,
requestRenderMode: true,
geocoder: false,
globe: false,
});
// Add 3D Tiles tileset.
const tileset = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: "https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY",
// This property is required to display attributions as required.
showCreditsOnScreen: true,
})
);
const zoomToViewport = (viewport) => {
viewer.entities.add({
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray([
viewport.getNorthEast().lng(), viewport.getNorthEast().lat(),
viewport.getSouthWest().lng(), viewport.getNorthEast().lat(),
viewport.getSouthWest().lng(), viewport.getSouthWest().lat(),
viewport.getNorthEast().lng(), viewport.getSouthWest().lat(),
viewport.getNorthEast().lng(), viewport.getNorthEast().lat(),
]),
width: 10,
clampToGround: true,
material: Cesium.Color.RED,
},
});
viewer.flyTo(viewer.entities);
};
function initAutocomplete() {
const autocomplete = new google.maps.places.Autocomplete(
document.getElementById("pacViewPlace"),
{
fields: [
"geometry",
"name",
],
}
);
autocomplete.addListener("place_changed", () => {
viewer.entities.removeAll();
const place = autocomplete.getPlace();
if (!place.geometry || !place.geometry.viewport) {
window.alert("No viewport for input: " + place.name);
return;
}
zoomToViewport(place.geometry.viewport);
});
}
</script>
<script
async=""
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initAutocomplete"
></script>
</body>
Vue rotative du drone
Vous pouvez contrôler la caméra pour animer le tileset. Combinée aux API Places et Elevation, cette animation simule un survol interactif en drone de n'importe quel point d'intérêt.
Cet exemple de code vous fait survoler le lieu que vous avez sélectionné dans le widget de saisie semi-automatique.
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>CesiumJS 3D Tiles Rotating Drone View Demo</title>
<script src="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Cesium.js"></script>
<link href="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>
<label for="pacViewPlace">Go to a place: </label>
<input type="text" id="pacViewPlace" name="pacViewPlace" placeholder="Enter a location..." style="width: 300px" />
<div id="cesiumContainer"></div>
<script>
// Enable simultaneous requests.
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = 18;
// Create the viewer and remove unneeded options.
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: false,
baseLayerPicker: false,
homeButton: false,
fullscreenButton: false,
navigationHelpButton: false,
vrButton: false,
sceneModePicker: false,
geocoder: false,
globe: false,
infobox: false,
selectionIndicator: false,
timeline: false,
projectionPicker: false,
clockViewModel: null,
animation: false,
requestRenderMode: true,
});
// Add 3D Tile set.
const tileset = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: "https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY",
// This property is required to display attributions.
showCreditsOnScreen: true,
})
);
// Point the camera at a location and elevation, at a viewport-appropriate distance.
function pointCameraAt(location, viewport, elevation) {
const distance = Cesium.Cartesian3.distance(
Cesium.Cartesian3.fromDegrees(
viewport.getSouthWest().lng(), viewport.getSouthWest().lat(), elevation),
Cesium.Cartesian3.fromDegrees(
viewport.getNorthEast().lng(), viewport.getNorthEast().lat(), elevation)
) / 2;
const target = new Cesium.Cartesian3.fromDegrees(location.lng(), location.lat(), elevation);
const pitch = -Math.PI / 4;
const heading = 0;
viewer.camera.lookAt(target, new Cesium.HeadingPitchRange(heading, pitch, distance));
}
// Rotate the camera around a location and elevation, at a viewport-appropriate distance.
let unsubscribe = null;
function rotateCameraAround(location, viewport, elevation) {
if(unsubscribe) unsubscribe();
pointCameraAt(location, viewport, elevation);
unsubscribe = viewer.clock.onTick.addEventListener(() => {
viewer.camera.rotate(Cesium.Cartesian3.UNIT_Z);
});
}
function initAutocomplete() {
const autocomplete = new google.maps.places.Autocomplete(
document.getElementById("pacViewPlace"), {
fields: [
"geometry",
"name",
],
}
);
autocomplete.addListener("place_changed", async () => {
const place = autocomplete.getPlace();
if (!(place.geometry && place.geometry.viewport && place.geometry.location)) {
window.alert(`Insufficient geometry data for place: ${place.name}`);
return;
}
// Get place elevation using the ElevationService.
const elevatorService = new google.maps.ElevationService();
const elevationResponse = await elevatorService.getElevationForLocations({
locations: [place.geometry.location],
});
if(!(elevationResponse.results && elevationResponse.results.length)){
window.alert(`Insufficient elevation data for place: ${place.name}`);
return;
}
const elevation = elevationResponse.results[0].elevation || 10;
rotateCameraAround(
place.geometry.location,
place.geometry.viewport,
elevation
);
});
}
</script>
<script async src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initAutocomplete"></script>
</body>
Dessiner des polylignes et des libellés
Cet exemple de code montre comment ajouter des polylignes et des libellés à une carte. Vous pouvez ajouter des polylignes à une carte pour afficher des itinéraires en voiture ou à pied, des limites de propriété ou pour calculer les durées de trajet en voiture ou à pied. Vous pouvez également obtenir des attributs sans réellement afficher la scène.
Vous pouvez proposer aux utilisateurs une visite guidée d'un quartier, ou leur montrer les propriétés voisines actuellement en vente, puis ajouter des objets 3D tels que des panneaux publicitaires à la scène.
Vous pouvez résumer un voyage en listant les propriétés que vous avez consultées et en affichant ces détails dans des objets virtuels.
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>CesiumJS 3D Tiles Polyline and Label Demo</title>
<script src="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Cesium.js"></script>
<link
href="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Widgets/widgets.css"
rel="stylesheet"
/>
</head>
<body>
<div id="cesiumContainer"></div>
<script>
// Enable simultaneous requests.
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = 18;
// Create the viewer.
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: false,
baseLayerPicker: false,
requestRenderMode: true,
geocoder: false,
globe: false,
});
// Add 3D Tiles tileset.
const tileset = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: "https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY",
// This property is required to display attributions as required.
showCreditsOnScreen: true,
})
);
// Draws a circle at the position, and a line from the previous position.
const drawPointAndLine = (position, prevPosition) => {
viewer.entities.removeAll();
if (prevPosition) {
viewer.entities.add({
polyline: {
positions: [prevPosition, position],
width: 3,
material: Cesium.Color.WHITE,
clampToGround: true,
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
},
});
}
viewer.entities.add({
position: position,
ellipsoid: {
radii: new Cesium.Cartesian3(1, 1, 1),
material: Cesium.Color.RED,
},
});
};
// Compute, draw, and display the position's height relative to the previous position.
var prevPosition;
const processHeights = (newPosition) => {
drawPointAndLine(newPosition, prevPosition);
const newHeight = Cesium.Cartographic.fromCartesian(newPosition).height;
let labelText = "Current altitude (meters above sea level):\n\t" + newHeight;
if (prevPosition) {
const prevHeight =
Cesium.Cartographic.fromCartesian(prevPosition).height;
labelText += "\nHeight from previous point (meters):\n\t" + Math.abs(newHeight - prevHeight);
}
viewer.entities.add({
position: newPosition,
label: {
text: labelText,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
pixelOffset: new Cesium.Cartesian2(0, -10),
showBackground: true,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
}
});
prevPosition = newPosition;
};
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
handler.setInputAction(function (event) {
const earthPosition = viewer.scene.pickPosition(event.position);
if (Cesium.defined(earthPosition)) {
processHeights(earthPosition);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
</script>
</body>
Orbites de la caméra
Dans Cesium, vous pouvez faire orbiter la caméra autour d'un point d'intérêt, en évitant les collisions avec les bâtiments. Vous pouvez également rendre les bâtiments transparents lorsque la caméra les traverse.
Commencez par verrouiller la caméra sur un point, puis créez une orbite de caméra pour présenter votre asset. Pour ce faire, vous pouvez utiliser la fonction lookAtTransform
de l'appareil photo avec un écouteur d'événements, comme illustré dans cet exemple de code.
// Lock the camera onto a point.
const center = Cesium.Cartesian3.fromRadians(
2.4213211833389243,
0.6171926869414084,
3626.0426275055174
);
const transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
viewer.scene.camera.lookAtTransform(
transform,
new Cesium.HeadingPitchRange(0, -Math.PI / 8, 2900)
);
// Orbit around this point.
viewer.clock.onTick.addEventListener(function (clock) {
viewer.scene.camera.rotateRight(0.005);
});
Pour en savoir plus sur le contrôle de la caméra, consultez Contrôler la caméra.
Utiliser Cesium pour Unreal
Pour utiliser le plug-in Cesium pour Unreal avec l'API 3D Tiles, suivez les étapes ci-dessous.
Installez le plug-in Cesium for Unreal.
Créez un projet Unreal.
Connectez-vous à l'API Google Photorealistic 3D Tiles.
Ouvrez la fenêtre Cesium en sélectionnant Cesium > Cesium dans le menu.
Sélectionnez Ensemble de tuiles 3D vide.
Dans l'World Outliner (Explorateur du monde), ouvrez le panneau Details (Détails) en sélectionnant Cesium3DTileset.
Remplacez la Source par Depuis une URL au lieu de Depuis Cesium Ion.
Définissez l'URL sur l'URL Google 3D Tiles.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Activez l'option Afficher les crédits à l'écran pour afficher correctement les attributions.
Cela charge le monde. Pour accéder à n'importe quel LatLng, sélectionnez l'élément CesiumGeoreference dans le panneau Outliner, puis modifiez Origin Latitude/Longitude/Height dans le panneau Details.
Utiliser Cesium pour Unity
Pour utiliser des tuiles photoréalistes avec Cesium pour Unity, procédez comme suit.
Créez un projet Unity.
Ajoutez un registre à portée limitée dans la section Package Manager (via Editor > Project Settings).
Nom : Cesium
URL : https://unity.pkg.cesium.com
Champ(s) d'application : com.cesium.unity
Installez le package Cesium pour Unity.
Connectez-vous à l'API Google Photorealistic 3D Tiles.
Ouvrez la fenêtre Cesium en sélectionnant Cesium > Cesium dans le menu.
Cliquez sur Ensemble de tuiles 3D vides.
Dans le panneau de gauche, dans l'option Source du tileset sous Source, sélectionnez Depuis l'URL (au lieu de "Depuis Cesium Ion").
Définissez l'URL sur l'URL des tuiles 3D Google.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Activez l'option Afficher les crédits à l'écran pour afficher correctement les attributions.
Cela charge le monde. Pour accéder à n'importe quel LatLng, sélectionnez l'élément CesiumGeoreference dans la hiérarchie de la scène, puis modifiez la latitude, la longitude et la hauteur de l'origine dans l'inspecteur.
Utiliser deck.gl
deck.gl, basé sur WebGL, est un framework JavaScript Open Source permettant de créer des visualisations de données à grande échelle et hautes performances.
Attribution
Assurez-vous d'afficher correctement les attributions de données en extrayant le champ copyright
des fichiers glTF des tuiles asset
, puis en l'affichant dans la vue rendue. Pour en savoir plus, consultez Afficher les attributions de données.
Exemples de rendu deck.gl
Exemple simple
L'exemple suivant initialise le moteur de rendu deck.gl, puis charge un lieu en 3D. Dans votre code, veillez à remplacer YOUR_API_KEY par votre véritable clé API.
<!DOCTYPE html>
<html>
<head>
<title>deck.gl Photorealistic 3D Tiles example</title>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<style>
body { margin: 0; padding: 0;}
#map { position: absolute; top: 0;bottom: 0;width: 100%;}
#credits { position: absolute; bottom: 0; right: 0; padding: 2px; font-size: 15px; color: white;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;}
</style>
</head>
<body>
<div id="map"></div>
<div id="credits"></div>
<script>
const GOOGLE_API_KEY = YOUR_API_KEY;
const TILESET_URL = `https://tile.googleapis.com/v1/3dtiles/root.json`;
const creditsElement = document.getElementById('credits');
new deck.DeckGL({
container: 'map',
initialViewState: {
latitude: 50.0890,
longitude: 14.4196,
zoom: 16,
bearing: 90,
pitch: 60,
height: 200
},
controller: {minZoom: 8},
layers: [
new deck.Tile3DLayer({
id: 'google-3d-tiles',
data: TILESET_URL,
loadOptions: {
fetch: {
headers: {
'X-GOOG-API-KEY': GOOGLE_API_KEY
}
}
},
onTilesetLoad: tileset3d => {
tileset3d.options.onTraversalComplete = selectedTiles => {
const credits = new Set();
selectedTiles.forEach(tile => {
const {copyright} = tile.content.gltf.asset;
copyright.split(';').forEach(credits.add, credits);
creditsElement.innerHTML = [...credits].join('; ');
});
return selectedTiles;
}
}
})
]
});
</script>
</body>
</html>
Visualiser des calques 2D sur des tuiles 3D photoréalistes Google
L'TerrainExtension de deck.gl affiche des données 2D sur une surface 3D. Par exemple, vous pouvez draper le GeoJSON de l'emprise d'un bâtiment sur la géométrie des tuiles 3D photoréalistes.
Dans l'exemple suivant, une couche de bâtiments est visualisée avec les polygones adaptés à la surface des tuiles 3D photoréalistes.
<!DOCTYPE html>
<html>
<head>
<title>Google 3D tiles example</title>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<style>
body { margin: 0; padding: 0;}
#map { position: absolute; top: 0;bottom: 0;width: 100%;}
#credits { position: absolute; bottom: 0; right: 0; padding: 2px; font-size: 15px; color: white;
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;}
</style>
</head>
<body>
<div id="map"></div>
<div id="credits"></div>
<script>
const GOOGLE_API_KEY = YOUR_API_KEY;
const TILESET_URL = `https://tile.googleapis.com/v1/3dtiles/root.json`;
const BUILDINGS_URL = 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/google-3d-tiles/buildings.geojson'
const creditsElement = document.getElementById('credits');
const deckgl = new deck.DeckGL({
container: 'map',
initialViewState: {
latitude: 50.0890,
longitude: 14.4196,
zoom: 16,
bearing: 90,
pitch: 60,
height: 200
},
controller: true,
layers: [
new deck.Tile3DLayer({
id: 'google-3d-tiles',
data: TILESET_URL,
loadOptions: {
fetch: {
headers: {
'X-GOOG-API-KEY': GOOGLE_API_KEY
}
}
},
onTilesetLoad: tileset3d => {
tileset3d.options.onTraversalComplete = selectedTiles => {
const credits = new Set();
selectedTiles.forEach(tile => {
const {copyright} = tile.content.gltf.asset;
copyright.split(';').forEach(credits.add, credits);
creditsElement.innerHTML = [...credits].join('; ');
});
return selectedTiles;
}
},
operation: 'terrain+draw'
}),
new deck.GeoJsonLayer({
id: 'buildings',
// This dataset is created by CARTO, using other Open Datasets available. More info at: https://3dtiles.carto.com/#about.
data: 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/google-3d-tiles/buildings.geojson',
stroked: false,
filled: true,
getFillColor: ({properties}) => {
const {tpp} = properties;
// quantiles break
if (tpp < 0.6249)
return [254, 246, 181]
else if (tpp < 0.6780)
return [255, 194, 133]
else if (tpp < 0.8594)
return [250, 138, 118]
return [225, 83, 131]
},
opacity: 0.2,
extensions: [new deck._TerrainExtension()]
})
]
});
</script>
</body>
</html>