I riquadri 3D fotorealistici sono nel formato glTF standard OGC, ovvero puoi utilizzare qualsiasi renderer che supporti le specifiche dei riquadri 3D OGC per creare le tue visualizzazioni 3D. Ad esempio, Cesium è una libreria open source di base per il rendering di visualizzazioni 3D.
Utilizza CesiumJS
CesiumJS è una libreria JavaScript open source per la visualizzazione 3D sul web. Per ulteriori informazioni sull'uso di CesiumJS, consulta Scopri CesiumJS.
Controlli utente
Il renderer del riquadro CesiumJS dispone di un insieme standard di controlli utente.
Azione | Descrizione |
---|---|
Panoramica | Fare clic e trascinare con il tasto sinistro |
Visualizzazione zoom | Fai clic con il tasto destro del mouse e trascina oppure scorri la rotellina del mouse |
Ruota visualizzazione | Ctrl + clic con il tasto sinistro/destro e trascina oppure fai clic e trascina con il tasto centrale |
best practice
Esistono diversi approcci per ridurre i tempi di caricamento di CesiumJS 3D. Ad esempio:
Attiva le richieste simultanee aggiungendo la seguente istruzione all'HTML di rendering:
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = <REQUEST_COUNT>
Più alto è il valore
REQUEST_COUNT
, più rapido sarà il caricamento dei riquadri. Tuttavia, durante il caricamento in un browser Chrome con più di 10REQUEST_COUNT
e la cache disattivata, potresti riscontrare un problema di Chrome noto. Per la maggior parte dei casi d'uso, consigliamo un valoreREQUEST_COUNT
pari a 18 per ottenere prestazioni ottimali.Consente di saltare i livelli di dettaglio. Per ulteriori informazioni, consulta questo problema di Cesio.
Assicurati di visualizzare correttamente le attribuzioni dei dati attivando
showCreditsOnScreen: true
. Per ulteriori informazioni, consulta le norme.
Metriche di rendering
Per trovare la frequenza fotogrammi, guarda quante volte al secondo viene chiamato il metodo requestAnimationFrame.
Per vedere come viene calcolata la latenza dei frame, consulta la classe PerformanceDisplay.
Esempi di renderer CesiumJS
Puoi utilizzare il renderer CesiumJS con i riquadri 3D dell'API Map Tiles semplicemente fornendo l'URL del set di riquadri principale.
Esempio semplice
L'esempio seguente inizializza il renderer CesiumJS e quindi carica il riquadro di riquadro principale.
<!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 delle richieste.
La pagina HTML viene visualizzata come mostrato qui.
Integrazione dell'API Places
Puoi utilizzare CesiumJS con l'API Places per recuperare ulteriori informazioni. Con il widget Autocomplete puoi raggiungere "l'area visibile" di Places. In questo esempio vengono utilizzati 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 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>
Vista rotante del drone
Puoi controllare la videocamera per l'animazione all'interno del set di riquadri. Se combinata con l'API Places e l'API Elevation, questa animazione simula un cavalcavia interattivo con drone di qualsiasi punto d'interesse.
Questo esempio di codice ti vola in un punto qualsiasi del 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>
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, per mostrare i confini delle proprietà o per calcolare la durata in auto e a piedi. Puoi anche recuperare attributi senza eseguire il rendering della scena.
Potresti accompagnare gli utenti in un tour selezionato di un quartiere oppure mostrare le proprietà vicine attualmente in vendita e aggiungere oggetti 3D come cartelloni pubblicitari alla scena.
Potresti riassumere un viaggio, elencando le proprietà che hai visualizzato e mostrando 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 fotocamera
Nel Cesio puoi orbitare intorno alla fotocamera un punto d'interesse, evitando collisioni con edifici. In alternativa, puoi rendere trasparenti gli edifici quando la videocamera li attraversa.
Per prima cosa, blocca la videocamera su un punto, quindi puoi creare un'orbita della videocamera
per mostrare l'asset. A questo scopo, utilizza la funzione lookAtTransform
della videocamera 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 ulteriori informazioni sul controllo della videocamera, consulta Controllare la videocamera
Work with Cesium for Unreal
Per utilizzare il plug-in Cesium for Unreal con l'API 3D Tiles, procedi nel seguente modo.
Installa il plug-in Cesium for Unreal.
Crea un nuovo progetto Unreal.
Connettiti all'API Google Photorealistic 3D Tiles.
Apri la finestra Cesium selezionando Cesium > Cesium dal menu.
Seleziona Set di riquadri 3D vuoti.
Nel World Outliner, apri il riquadro Details selezionando questo Cesium3DTileset.
Modifica il valore di Origine da From Cesium Ion in Da URL.
Imposta l'URL come URL dei riquadri 3D di Google.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Attiva Mostra i crediti sullo schermo per visualizzare correttamente le attribuzioni.
così il mondo intero. Per spostarti su un LatLng, seleziona l'elemento CesiumGeoreference nel riquadro Outliner, quindi modifica Latitudine/Longitudine/Altezza dell'origine nel riquadro Details.
Collabora con Cesium per Unity
Per utilizzare riquadri fotorealistici con Cesium per Unity, procedi nel seguente modo.
Crea un nuovo progetto Unity.
Aggiungi un nuovo registro di ambito nella sezione Gestione pacchetti (tramite Editor > Impostazioni progetto).
Nome: cesio
URL: https://unity.pkg.cesium.com
Ambito/i: 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 Set di riquadri 3D vuoti.
Nel riquadro a sinistra, nell'opzione Origine del set di riquadri in Origine, seleziona Da URL (anziché Da Ione di Cesio).
Imposta l'URL su quello dei riquadri 3D di Google.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Attiva Mostra i crediti sullo schermo per visualizzare correttamente le attribuzioni.
così il mondo intero. Per spostarti su un LatLng, seleziona l'elemento CesiumGeoreference in Gerarchia della scena, quindi modifica Latitudine/Longitudine/Altezza dell'origine in Ispezionatore.
Lavora con deck.gl
deck.gl, con tecnologia WebGL, è un framework JavaScript open source per la visualizzazione di dati su larga scala ad alte prestazioni.
Attribuzione
Per assicurarti di visualizzare correttamente le attribuzioni dei dati, estrai il campo copyright
dai riquadri gltf asset
per poi mostrarlo nella vista visualizzata. Per
ulteriori informazioni, consulta
Attribuzioni dei dati della Rete Display.
Esempi di renderer deck.gl
Esempio semplice
L'esempio seguente inizializza il renderer deck.gl, quindi carica un luogo in 3D. Assicurati di sostituire YOUR_API_KEY nel codice con la 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>
Visualizza livelli 2D su riquadri 3D fotorealistici di Google
La funzionalità deck.gl TerrainExtension visualizza i dati altrimenti 2D su una superficie 3D. Ad esempio, puoi coprire il GeoJSON di una superficie di un edificio sulla Geometria dei riquadri 3D fotorealistici.
Nel seguente esempio, viene visualizzato un livello di edifici 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>