I riquadri 3D fotorealistici sono in formato glTF standard OGC, il che significa che puoi utilizzare qualsiasi renderer che supporti la specifica OGC 3D Tiles per creare le tue visualizzazioni 3D. Ad esempio, Cesium è una libreria open source fondamentale per il rendering di visualizzazioni 3D.
Utilizzare CesiumJS
CesiumJS è una libreria JavaScript open source per la visualizzazione 3D sul web. Per saperne di più sull'utilizzo di CesiumJS, consulta la pagina Learn CesiumJS.
Controlli utente
Il renderer dei riquadri CesiumJS ha un set di standard di controlli utente.
| Azione | Descrizione |
|---|---|
| Applica panning alla visualizzazione | Fai clic con il tasto sinistro del mouse e trascina |
| Visualizzazione zoom | Fai clic con il tasto destro del mouse e trascina o scorri la rotellina del mouse |
| Ruota la visualizzazione | Premi Ctrl + fai clic con il tasto sinistro/destro del mouse e trascina oppure fai clic con il tasto centrale del mouse e trascina |
Best practice
Esistono diversi approcci che puoi adottare per ridurre i tempi di caricamento 3D di CesiumJS. Ad esempio:
Abilita le richieste simultanee aggiungendo la seguente istruzione al codice HTML di rendering:
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = <REQUEST_COUNT>Più alto è il valore di
REQUEST_COUNT, più velocemente vengono caricati i riquadri. Tuttavia, quando carichi in un browser Chrome conREQUEST_COUNTmaggiore di 10 e la cache disattivata, potresti riscontrare un problema noto di Chrome. Per la maggior parte dei casi d'uso, consigliamo un valore diREQUEST_COUNTpari a 18 per prestazioni ottimali.Abilita il salto dei livelli di dettaglio. Per saperne di più, consulta questo problema di Cesium.
Assicurati di visualizzare correttamente le attribuzioni dei dati abilitando showCreditsOnScreen: true. Per saperne di più, consulta la sezione
Norme.
Metriche di rendering
Per trovare la frequenza fotogrammi, guarda quante volte al secondo viene chiamato il requestAnimationFrame metodo.
Per vedere come viene calcolata la latenza dei frame, dai un'occhiata alla PerformanceDisplay classe.
Esempi di renderer CesiumJS
Puoi utilizzare il renderer CesiumJS con i riquadri 3D dell'API Map Tiles semplicemente fornendo l'URL del tileset root.
Esempio semplice
L'esempio seguente inizializza il renderer CesiumJS e poi carica il tileset root.
<!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>
Per informazioni su requestRenderMode, consulta la sezione
Abilitare la modalità di rendering delle richieste.
La pagina HTML viene visualizzata come mostrato qui.

Integrazione dell'API Places (Novità)
Puoi utilizzare CesiumJS con l' API Places (Novità) per recuperare ulteriori informazioni. Puoi utilizzare il widget Autocomplete per passare al riquadro di visualizzazione dei luoghi. Questo esempio utilizza l'API Places Autocomplete, che viene abilitata seguendo queste istruzioni, e l'API Maps JavaScript, che viene abilitata seguendo queste istruzioni.
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>CesiumJS 3D Tiles Places API (New) 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>
Visualizzazione del drone rotante
Puoi controllare la videocamera per animare il tileset. Se combinata con l'API Places (Novità) e l'API Elevation, questa animazione simula un sorvolo interattivo con un drone di qualsiasi punto di interesse.
Questo esempio di codice ti fa volare intorno al luogo che hai selezionato nel widget Autocomplete.
<!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>
Disegnare polilinee ed etichette
Questo esempio di codice mostra come aggiungere polilinee ed etichette a una mappa. Puoi aggiungere polilinee a una mappa per mostrare le indicazioni stradali e le indicazioni a piedi, i confini delle proprietà o per calcolare le durate di guida e a piedi. Puoi anche ottenere gli attributi senza eseguire il rendering della scena.
Potresti offrire agli utenti un tour curato di un quartiere oppure mostrare le proprietà vicine attualmente in vendita e poi aggiungere oggetti 3D come cartelloni pubblicitari alla scena.
Potresti riassumere un viaggio, elencare le proprietà che hai visualizzato e mostrare questi dettagli in oggetti virtuali.
<!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>
Orbita della videocamera
In Cesium, puoi far orbitare la videocamera intorno a un punto di interesse, evitando collisioni con gli edifici. In alternativa, puoi rendere trasparenti gli edifici quando la videocamera li attraversa.
Innanzitutto, blocca la videocamera su un punto, poi puoi creare un'orbita della videocamera per mostrare l'asset. Puoi farlo utilizzando la funzione della videocamera
lookAtTransform
con un listener di eventi, come mostrato in questo esempio di codice.
// 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);
});
Per saperne di più sul controllo della videocamera, consulta la sezione Controllare la videocamera.
Utilizzare Cesium for Unreal
Per utilizzare il plug-in Cesium for Unreal con l'API 3D Tiles, segui i passaggi riportati di seguito.
Installa il plug-in Cesium for Unreal.
Crea un nuovo progetto Unreal.
Connettiti all'API Google Photorealistic 3D Tiles.
Apri la finestra di Cesium selezionando Cesium > Cesium dal menu.
Seleziona Blank 3D Tiles Tileset.
In World Outliner, apri il riquadro Dettagli selezionando questo Cesium3DTileset.
Modifica l'opzione Origine da Da Cesium Ion a Da URL.
Imposta l'URL sull'URL dei riquadri 3D di Google.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY- Attiva l'opzione Mostra crediti sullo schermo per visualizzare correttamente le attribuzioni.
Viene caricato il mondo. Per spostarti su qualsiasi LatLng, seleziona l'elemento CesiumGeoreference nel riquadro Outliner e poi modifica Origin Latitude/Longitude/Height nel riquadro Dettagli.
Utilizzare Cesium for Unity
Per utilizzare i riquadri fotorealistici con Cesium for Unity, segui i passaggi riportati di seguito.
Crea un nuovo progetto Unity.
Aggiungi un nuovo registro con ambito nella sezione Gestore di pacchetti (tramite Editor > Impostazioni progetto).
Nome: Cesium
URL: https://unity.pkg.cesium.com
Ambiti: com.cesium.unity
Installa il pacchetto Cesium for Unity.
Connettiti all'API Google Photorealistic 3D Tiles.
Apri la finestra di Cesium selezionando Cesium > Cesium dal menu.
Fai clic su Blank 3D Tiles Tileset.
Nel riquadro a sinistra, nell'opzione Tileset Source (Origine tileset) sotto Source, seleziona From URL (Da URL) anziché From Cesium Ion.
Imposta l'URL sull'URL dei riquadri 3D di Google.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY- Attiva l'opzione Show Credits On Screen (Mostra crediti sullo schermo) per visualizzare correttamente le attribuzioni.
Viene caricato il mondo. Per spostarti su qualsiasi LatLng, seleziona l' CesiumGeoreference elemento in Scene Hierarchy (Gerarchia della scena) e poi modifica Origin Latitude/Longitude/Height in Inspector (Controllo).
Utilizzare deck.gl
deck.gl, basato su WebGL, è un framework JavaScript open source per visualizzazioni di dati su larga scala e ad alte prestazioni.
Attribuzione
Assicurati di visualizzare correttamente le attribuzioni dei dati estraendo il copyright
campo dall'asset gltf dei riquadri asset e poi visualizzandolo nella visualizzazione di rendering. Per
saperne di più, consulta la sezione
Visualizzare le attribuzioni dei dati.
Esempi di renderer deck.gl
Esempio semplice
L'esempio seguente inizializza il renderer deck.gl e poi carica un luogo in 3D. Nel codice, assicurati di sostituire YOUR_API_KEY con la tua chiave API effettiva.
<!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>
Visualizzare i livelli 2D sopra i riquadri 3D fotorealistici di Google
L'estensione TerrainExtension di deck.gl esegue il rendering dei dati 2D su una superficie 3D. Ad esempio, puoi sovrapporre il GeoJSON dell'impronta di un edificio alla geometria dei riquadri 3D fotorealistici.
Nell'esempio seguente, un livello di edifici viene visualizzato con i poligoni adattati alla superficie dei riquadri 3D fotorealistici.
<!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>