Fotorealistische 3D-Kacheln liegen im glTF-Standardformat OGC vor. Sie können also jeden Renderer verwenden, der die Spezifikation für OGC-3D-Kacheln unterstützt, um 3D-Visualisierungen zu erstellen. Cesium ist beispielsweise eine grundlegende Open-Source-Bibliothek zum Rendern von 3D-Visualisierungen.
Mit CesiumJS arbeiten
CesiumJS ist eine Open-Source-JavaScript-Bibliothek für 3D-Visualisierungen im Web. Weitere Informationen zur Verwendung von CesiumJS finden Sie unter Learn CesiumJS.
Nutzersteuerung
Der CesiumJS-Kachel-Renderer verfügt über eine Reihe von Standardsteuerelementen für Nutzer.
Aktion | Beschreibung |
---|---|
Ansicht schwenken | Mit linker Maustaste klicken und ziehen |
Zoomansicht | Mit der rechten Maustaste klicken und ziehen oder mit dem Mausrad scrollen |
Ansicht drehen | Strg + Links-/Rechtsklick und Ziehen oder mittleres Klicken und Ziehen |
Best Practices
Es gibt mehrere Ansätze, mit denen Sie die CesiumJS 3D-Ladezeiten verkürzen können. Beispiel:
Aktivieren Sie gleichzeitige Anfragen, indem Sie der Rendering-HTML die folgende Anweisung hinzufügen:
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = <REQUEST_COUNT>
Je höher
REQUEST_COUNT
, desto schneller werden die Kacheln geladen. Beim Laden in einem Chrome-Browser mitREQUEST_COUNT
größer als 10 und deaktiviertem Cache kann jedoch ein bekanntes Chrome-Problem auftreten. Für die meisten Anwendungsfälle empfehlen wir fürREQUEST_COUNT
einen Wert von 18, um eine optimale Leistung zu erzielen.Hiermit können Sie das Überspringen von Detailebenen aktivieren. Weitere Informationen finden Sie unter Cesium-Problem.
Aktivieren Sie showCreditsOnScreen: true
, damit Datenattributionen korrekt angezeigt werden. Weitere Informationen finden Sie unter Richtlinien.
Rendering-Messwerte
Die Framerate ermitteln Sie, indem Sie sehen, wie oft die Methode requestAnimationFrame pro Sekunde aufgerufen wird.
Informationen zur Berechnung der Frame-Latenz finden Sie in der Klasse PerformanceDisplay.
CesiumJS-Renderer – Beispiele
Sie können den CesiumJS-Renderer mit den 3D-Kacheln der Map Tiles API verwenden. Dazu geben Sie einfach die URL des Stammkachelsatzes an.
Einfaches Beispiel
Im folgenden Beispiel wird der CesiumJS-Renderer initialisiert und dann der Stammkachelsatz geladen.
<!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>
Informationen zu requestRenderMode
finden Sie unter Renderingmodus für Anfragen aktivieren.
Die HTML-Seite wird so gerendert, wie hier dargestellt.
Places API-Integration
Sie können CesiumJS mit der Places API verwenden, um weitere Informationen abzurufen. Mit dem Autocomplete-Widget können Sie zum Darstellungsbereich von Orten fliegen. In diesem Beispiel werden die Places Autocomplete API (gemäß dieser Anleitung) und die Maps JavaScript API aktiviert.
<!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>
Drehende Drohnenansicht
Sie können die Kamera so steuern, dass die Animation durch den Kachelsatz bewegt wird. In Kombination mit der Places API und der Elevation API simuliert die Animation einen interaktiven Drohnenflug um einen beliebigen POI.
Mit diesem Codebeispiel werden Sie um den Ort gelegt, den Sie im Widget für die automatische Vervollständigung ausgewählt haben.
<!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>
Polylinien und Beschriftungen zeichnen
In diesem Codebeispiel wird gezeigt, wie Polylinien und Labels zu einer Karte hinzugefügt werden. Sie können einer Karte Polylinien hinzufügen, um Auto- und Fußgängerrouten anzuzeigen, Grundstücksgrenzen anzuzeigen oder die Fahrt- und Fußwegdauer zu berechnen. Sie können auch Attribute abrufen, ohne die Szene zu rendern.
Sie können Nutzer auf eine ausgewählte Tour durch ein Viertel mitnehmen oder benachbarte Immobilien zeigen, die derzeit im Angebot sind, und dann 3D-Objekte wie Plakatwände hinzufügen.
Sie können eine Reise zusammenfassen, die angesehenen Unterkünfte auflisten und diese Details in virtuellen Objekten darstellen.
<!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>
Kamerakreislauf
In Cesium lässt sich die Kamera um einen POI herum drehen, um Kollisionen mit Gebäuden zu vermeiden. Alternativ können Sie Gebäude transparent machen, wenn sich die Kamera durch sie bewegt.
Befestigen Sie die Kamera zuerst an einem bestimmten Punkt. Anschließend können Sie eine Kameraorbit erstellen, um Ihr Objekt zu präsentieren. Dazu können Sie die lookAtTransform
-Funktion der Kamera mit einem Event-Listener verwenden, wie in diesem Codebeispiel gezeigt.
// 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);
});
Weitere Informationen zum Steuern der Kamera finden Sie unter Kamera steuern.
Mit Cesium for Unreal arbeiten
So verwenden Sie das Cesium for Unreal-Plug-in mit der 3D Tiles API:
Installieren Sie das Cesium for Unreal-Plug-in.
Erstelle ein neues Unreal-Projekt.
Stellen Sie eine Verbindung zur Google Photonatural 3D Tiles API her.
Öffnen Sie das Cesium-Fenster, indem Sie im Menü Cesium > Cesium auswählen.
Wählen Sie Leeres 3D-Kachelsatz aus.
Öffnen Sie im World Outliner das Steuerfeld Details, indem Sie dieses Cesium3DTileset auswählen.
Ändern Sie die Quelle von From Cesium-Ion zu From URL.
Lege als URL die URL der Google 3D-Kacheln fest.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Aktivieren Sie Gutschriften auf dem Bildschirm anzeigen, damit Quellenangaben richtig angezeigt werden.
Damit wird die Welt geladen. Wenn Sie zu einem beliebigen LatLng-Wert wechseln möchten, wählen Sie im Bereich Gliederungseditor das Element CesiumGeoreference aus und bearbeiten Sie dann im Steuerfeld Details den Wert für Breiten-/Längengrad/Höhe des Ursprungs.
Mit Cesium for Unity arbeiten
So verwenden Sie fotorealistische Kacheln mit Cesium for Unity:
Erstellen Sie ein neues Unity-Projekt.
Fügen Sie im Abschnitt „Paketmanager“ über Editor > Projekteinstellungen eine neue Bereichsregistrierung hinzu.
Name: Cäsium
URL: https://unity.pkg.cesium.com
Bereich(e): com.cesium.unity
Installieren Sie das Cesium for Unity-Paket.
Stellen Sie eine Verbindung zur Google Photonatural 3D Tiles API her.
Öffnen Sie das Cesium-Fenster, indem Sie im Menü Cesium > Cesium auswählen.
Klicken Sie auf Leeres 3D-Kachelsatz.
Wählen Sie im linken Steuerfeld in der Option Tileset Source unter Source (Quelle) die Option From URL (Von URL) anstelle von "From Cesium Ion" (Von Cesium-Ion) aus.
Lege als URL die Google 3D-Kacheln-URL fest.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Aktivieren Sie Gutschriften auf dem Bildschirm anzeigen, damit Quellenangaben richtig angezeigt werden.
Damit wird die Welt geladen. Wenn Sie zu einem beliebigen LatLng-Wert wechseln möchten, wählen Sie in der Szenenhierarchie das CesiumGeoreference-Element aus und bearbeiten Sie dann den Breiten- und Längengrad sowie die Höhe des Ursprungs im Inspector.
Mit deck.gl arbeiten
deck.gl auf Basis von WebGL ist ein Open-Source-JavaScript-Framework für leistungsstarke Datenvisualisierungen in großem Maßstab.
Attribution
Achten Sie darauf, dass Datenattributionen korrekt angezeigt werden. Extrahieren Sie dazu das Feld copyright
aus den Kacheln gltf asset
und zeigen Sie es dann in der gerenderten Ansicht an. Weitere Informationen finden Sie unter Datenattributionen anzeigen.
Beispiele für deck.gl-Renderer
Einfaches Beispiel
Im folgenden Beispiel wird der deck.gl-Renderer initialisiert und dann ein Ort in 3D geladen. Ersetzen Sie in Ihrem Code YOUR_API_KEY durch Ihren tatsächlichen API-Schlüssel.
<!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>
2D-Ebenen auf fotorealistischen 3D-Kacheln von Google visualisieren
Mit der TerrainExtension von deck.gl werden ansonsten 2D-Daten auf einer 3D-Oberfläche gerendert. Beispielsweise können Sie den GeoJSON-Inhalt eines Gebäudeumrisses über die Geometrie der fotorealistischen 3D-Kacheln legen.
Im folgenden Beispiel wird eine Ebene von Gebäuden visualisiert, bei denen die Polygone an die Oberfläche der fotorealistischen 3D-Kacheln angepasst wurden.
<!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>