I riquadri 3D fotorealistici sono nel formato glTF standard OGC, il che significa che puoi utilizzare qualsiasi renderer che supporta la specifica OGC 3D Tiles per creare le tue visualizzazioni 3D. Ad esempio, Cesium è una libreria open source di base per il rendering di visualizzazioni 3D.
Lavorare con CesiumJS
CesiumJS è una libreria JavaScript open source per la visualizzazione 3D sul web. Per ulteriori informazioni sull'utilizzo di CesiumJS, consulta Imparare a utilizzare CesiumJS.
Controlli utente
Il visualizzatore di tile CesiumJS ha un insieme standard di controlli utente.
Azione | Descrizione |
---|---|
Panoramica della visualizzazione | Fai clic con il tasto sinistro del mouse e trascina |
Visualizzazione zoom | Fai clic con il tasto destro del mouse e trascina oppure scorri con la rotellina del mouse |
Ruotare la visualizzazione | Ctrl + clic e trascinamento con il tasto sinistro/destro del mouse oppure clic e trascinamento con il tasto centrale del mouse |
Best practice
Esistono diversi approcci che puoi adottare per ridurre i tempi di caricamento di CesiumJS 3D. Ad esempio:
Attiva le richieste simultanee aggiungendo la seguente dichiarazione al rendering HTML:
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = <REQUEST_COUNT>
Più elevato è il valore
REQUEST_COUNT
, più rapidamente vengono caricati i riquadri. Tuttavia, se carichi il report in un browser Chrome conREQUEST_COUNT
maggiore di 10 e la cache disattivata, potresti riscontrare un problema noto di Chrome. Per la maggior parte dei casi d'uso, consigliamo un valoreREQUEST_COUNT
pari a 18 per prestazioni ottimali.Attivare l'opzione per saltare i livelli di dettaglio. Per ulteriori informazioni, consulta questo problema di Cesium.
Assicurati di mostrare correttamente le attribuzioni dei dati attivando
showCreditsOnScreen: true
. Per ulteriori informazioni, consulta
Norme.
Metriche di rendering
Per trovare la frequenza fotogrammi, controlla quante volte al secondo viene chiamato il metodo requestAnimationFrame.
Per scoprire come viene calcolata la latenza del frame, consulta la classe PerformanceDisplay.
Esempi di renderer CesiumJS
Puoi utilizzare il renderer CesiumJS con i set di tessere 3D dell'API Map Tiles semplicemente fornendo l'URL del set di tessere principale.
Esempio semplice
L'esempio seguente inizializza il renderer CesiumJS e carica il tileset di primo livello.
<!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
Attivare la modalità di rendering della richiesta.
La pagina HTML viene visualizzata come mostrato di seguito.
Integrazione dell'API Places
Puoi utilizzare CesiumJS con l'API Places per recuperare ulteriori informazioni. Puoi utilizzare il widget di completamento automatico per passare al viewport di Luoghi. Questo esempio utilizza l'API Places Autocomplete, attivata seguendo queste istruzioni, e l'API Maps JavaScript, attivata seguendo queste istruzioni.
<!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>
Visualizzazione del drone in rotazione
Puoi controllare la videocamera per animare il set di tessere. Se combinata con l'API Places e l'API Elevation, questa animazione simula un sorvolo interattivo di un drone su qualsiasi punto d'interesse.
Questo esempio di codice ti consente di volare sopra il luogo selezionato nel widget di completamento automatico.
<!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>
Disegna polilinee ed etichette
Questo esempio di codice mostra come aggiungere polilinee ed etichette a una mappa. Puoi aggiungere polilinee a una mappa per mostrare indicazioni stradali e percorsi a piedi, per mostrare confini di proprietà o per calcolare le durate di guida e a piedi. Puoi anche recuperare gli attributi senza eseguire il rendering della scena.
Potresti accompagnare gli utenti in un tour guidato di un quartiere oppure mostrare le proprietà vicine attualmente in vendita e aggiungere alla scena oggetti 3D come i cartelloni pubblicitari.
Potresti riepilogare un viaggio, elencando le proprietà che hai visualizzato, visualizzando 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 fotocamera
In Cesium, puoi far ruotare la fotocamera attorno a un punto d'interesse, evitando collisioni con gli edifici. In alternativa, puoi rendere trasparenti gli edifici quando la videocamera li attraversa.
Innanzitutto, blocca la fotocamera su un punto, quindi puoi creare un'orbita della fotocamera per mettere in evidenza la tua risorsa. A questo scopo, puoi utilizzare la funzione
lookAtTransform
della fotocamera con un gestore 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 ulteriori informazioni sul controllo della videocamera, consulta Controllare la videocamera
Lavorare con Cesium per Unreal
Per utilizzare il plug-in Cesium per Unreal con l'API 3D Tiles, segui i passaggi riportati di seguito.
Installa il plug-in Cesium per Unreal.
Crea un nuovo progetto Unreal.
Collegarti all'API Photorealistic 3D Tiles di Google.
Apri la finestra Cesium selezionando Cesium > Cesium dal menu.
Seleziona Serie di riquadri di riquadri 3D vuoti.
In World Outliner, apri il riquadro Dettagli selezionando questo Cesium3DTileset.
Modifica Origine da Da Ione di cesio a Da URL.
Imposta l'URL come URL di Google 3D Tiles.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Attiva Mostra i riconoscimenti sullo schermo per visualizzare correttamente le attribuzioni.
Il mondo viene caricato. Per spostarti su qualsiasi LatLng, seleziona l'elemento CesiumGeoreference nel riquadro Outliner e poi modifica Latitudine/Longitudine/Altezza origine nel riquadro Dettagli.
Lavorare con Cesium per Unity
Per utilizzare i tessere fotorealistiche con Cesium per Unity, segui i passaggi riportati di seguito.
Crea un nuovo progetto Unity.
Aggiungi un nuovo registry con ambito nella sezione Gestione pacchetti (tramite Editor > Impostazioni progetto).
Nome: Cesium
URL: https://unity.pkg.cesium.com
Ambiti: com.cesium.unity
Installa il pacchetto Cesium per Unity.
Connettiti all'API Photorealistic 3D Tiles di Google.
Apri la finestra Cesium selezionando Cesium > Cesium dal menu.
Fai clic su Serie di riquadri di riquadri 3D vuoti.
Nel riquadro a sinistra, nell'opzione Origine set di riquadri in Origine, selezionare Da URL (anziché Da Cesium Ion).
Imposta l'URL sull'URL di Google 3D Tiles.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Attiva Mostra i riconoscimenti sullo schermo per visualizzare correttamente le attribuzioni.
Il mondo viene caricato. Per spostarti in qualsiasi punto LatLng, seleziona l'elemento CesiumGeoreference nella Gerarchia scena e poi modifica la latitudine/la longitudine/l'altezza di origine nell'Ispezione.
Lavorare con 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 dai tessere gltf asset
e poi visualizzandolo nella visualizzazione visualizzata. Per maggiori informazioni, consulta la pagina Mostrare le attribuzioni dei dati.
Esempi di visualizzatori deck.gl
Esempio semplice
Nell'esempio seguente viene inizializzato il renderer deck.gl e poi viene caricato 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
La componente TerrainExtension di deck.gl esegue il rendering di dati altrimenti 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>