Fotorealistyczne kafelki 3D są w standardowym formacie glTF OGC, co oznacza, że do tworzenia wizualizacji 3D możesz używać dowolnego mechanizmu renderowania, który obsługuje specyfikację kafelków 3D OGC. Na przykład Cesium to podstawowa biblioteka open source do renderowania wizualizacji 3D.
Praca z CesiumJS
CesiumJS to biblioteka JavaScript typu open source do wizualizacji 3D w internecie. Więcej informacji o korzystaniu z CesiumJS znajdziesz w artykule Learn CesiumJS (Nauka CesiumJS).
Kontrola użytkowników
Moduł renderowania kafelków CesiumJS ma standardowy zestaw elementów sterujących.
| Działanie | Opis |
|---|---|
| Przesuń widok | Kliknięcie lewym przyciskiem i przeciągnięcie |
| Powiększ | Kliknij prawym przyciskiem i przeciągnij lub przewiń kółkiem myszy. |
| Obracanie widoku | Ctrl + kliknięcie lewym/prawym przyciskiem myszy i przeciągnięcie lub kliknięcie środkowym przyciskiem myszy i przeciągnięcie |
Sprawdzone metody
Istnieje kilka sposobów na skrócenie czasu wczytywania CesiumJS 3D. Na przykład:
Włącz żądania jednoczesne, dodając do kodu HTML renderowania to wyrażenie:
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = <REQUEST_COUNT>Im wyższa wartość
REQUEST_COUNT, tym szybciej ładują się kafelki. Jeśli jednak wczytujesz w przeglądarce Chrome zREQUEST_COUNTwiększym niż 10 i wyłączoną pamięcią podręczną, możesz napotkać znany problem z Chrome. W większości przypadków zalecamy ustawienieREQUEST_COUNTna 18, aby uzyskać optymalną wydajność.Włącz pomijanie poziomów szczegółowości. Więcej informacji znajdziesz w tym zgłoszeniu problemu z Cesium.
Upewnij się, że prawidłowo wyświetlasz informacje o źródle danych, włączając showCreditsOnScreen: true. Więcej informacji znajdziesz w artykule na temat zasad.
Dane dotyczące renderowania
Aby sprawdzić liczbę klatek na sekundę, zobacz, ile razy na sekundę wywoływana jest metoda requestAnimationFrame.
Aby dowiedzieć się, jak obliczane jest opóźnienie klatek, zapoznaj się z klasą PerformanceDisplay.
Przykłady renderowania CesiumJS
Możesz używać mechanizmu renderowania CesiumJS z kafelkami 3D interfejsu Map Tiles API, podając po prostu adres URL głównego zestawu kafelków.
Prosty przykład
Poniższy przykład inicjuje mechanizm renderowania CesiumJS, a następnie wczytuje główny zbiór kafelków.
<!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>
Informacje o requestRenderMode znajdziesz w artykule Włączanie trybu renderowania żądania.
Strona HTML jest renderowana w sposób pokazany tutaj.

Integracja z Places API (nowość)
Aby uzyskać więcej informacji, możesz użyć CesiumJS z Places API (New). Możesz użyć widżetu autouzupełniania, aby przejść do widocznego obszaru Miejsc. Ten przykład korzysta z interfejsu Autouzupełnianie miejsc API, który można włączyć, postępując zgodnie z tymi instrukcjami, oraz z interfejsu Maps JavaScript API, który można włączyć, postępując zgodnie z tymi instrukcjami.
<!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>
Obracający się widok z drona
Możesz sterować kamerą, aby animować zbiór kafelków. W połączeniu z interfejsem Places API (nowym) i Elevation API ta animacja symuluje interaktywny przelot drona nad dowolnym ciekawym miejscem.
Ten przykładowy kod pozwala na przelot nad miejscem wybranym w widżecie autouzupełniania.
<!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>
Rysowanie linii łamanych i etykiet
Ten przykładowy kod pokazuje, jak dodać do mapy linie łamane i etykiety. Możesz dodawać do mapy linie łamane, aby pokazywać trasy dojazdu i trasy piesze, granice nieruchomości lub obliczać czas dojazdu i czas przejścia. Możesz też pobierać atrybuty bez renderowania sceny.
Możesz zabrać użytkowników na wycieczkę po okolicy lub pokazać im sąsiednie nieruchomości, które są obecnie na sprzedaż, a następnie dodać do sceny obiekty 3D, takie jak billboardy.
Możesz podsumować podróż, wyświetlając listę odwiedzonych miejsc i szczegółowe informacje o nich w postaci obiektów wirtualnych.
<!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 kamery
W Cesium możesz obracać kamerę wokół interesującego Cię punktu, unikając kolizji z budynkami. Możesz też ustawić przezroczystość budynków, gdy kamera przechodzi przez nie.
Najpierw zablokuj kamerę na punkcie, a następnie utwórz orbitę kamery, aby zaprezentować zasób. Możesz to zrobić, używając funkcji lookAtTransform kamery z detektorem zdarzeń, jak pokazano w tym przykładowym kodzie.
// 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);
});
Więcej informacji o sterowaniu kamerą znajdziesz w artykule Sterowanie kamerą.
Praca z Cesium for Unreal
Aby używać wtyczki Cesium for Unreal z interfejsem 3D Tiles API, wykonaj te czynności.
Zainstaluj wtyczkę Cesium for Unreal.
Utwórz nowy projekt Unreal.
Połącz się z interfejsem Google Photorealistic 3D Tiles API.
Otwórz okno Cesium, wybierając w menu Cesium > Cesium.
Wybierz Blank 3D Tiles Tileset (Pusty zestaw kafelków 3D).
W World Outliner otwórz panel Details, wybierając Cesium3DTileset.
thought Zmień Źródło z Z Cesium Ion na Z URL-a.
Ustaw adres URL na adres URL kafelków 3D Google.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY- Włącz opcję Pokaż informacje o autorach na ekranie, aby prawidłowo wyświetlać atrybucje.
Spowoduje to wczytanie świata. Aby przejść do dowolnej lokalizacji, wybierz element CesiumGeoreference w panelu Outliner, a następnie zmień wartości Origin Latitude/Longitude/Height (Szerokość/długość geograficzna/wysokość punktu początkowego) w panelu Details (Szczegóły).
Praca z Cesium for Unity
Aby używać fotorealistycznych kafelków z Cesium for Unity, wykonaj te czynności.
Utwórz nowy projekt Unity.
Dodaj nowy rejestr zakresu w sekcji Menedżer pakietów (Edytor > Ustawienia projektu).
Nazwa: Cez
URL: https://unity.pkg.cesium.com
Zakresy: com.cesium.unity
Zainstaluj pakiet Cesium for Unity.
Połącz się z interfejsem Google Photorealistic 3D Tiles API.
Otwórz okno Cesium, wybierając w menu Cesium > Cesium.
Kliknij Blank 3D Tiles Tileset (Pusty zestaw kafelków 3D).
W panelu po lewej stronie w opcji Tileset Source (Źródło zbioru kafelków) w sekcji Source (Źródło) wybierz From URL (Z adresu URL) (zamiast From Cesium Ion).
Ustaw adres URL na adres URL kafelków 3D Google.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY- Włącz opcję Pokaż informacje o autorach na ekranie, aby prawidłowo wyświetlać atrybucje.
Spowoduje to wczytanie świata. Aby przejść do dowolnej szerokości i długości geograficznej, wybierz element CesiumGeoreference w sekcji Scene Hierarchy (Hierarchia sceny), a następnie zmień szerokość/długość geograficzną/wysokość punktu początkowego w sekcji Inspector (Inspektor).
Praca z deck.gl
deck.gl, oparty na WebGL, to platforma JavaScript typu open source do tworzenia wysokowydajnych, wielkoskalowych wizualizacji danych.
Atrybucja
Upewnij się, że prawidłowo wyświetlasz informacje o autorach danych, wyodrębniając pole copyright z gltf kafelków asset, a następnie wyświetlając je w wyrenderowanym widoku. Więcej informacji znajdziesz w artykule Wyświetlanie atrybucji danych.
Przykłady renderowania deck.gl
Prosty przykład
Poniższy przykład inicjuje mechanizm renderowania deck.gl, a następnie wczytuje miejsce w 3D. W kodzie zastąp YOUR_API_KEY rzeczywistym kluczem interfejsu 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>
Wizualizacja warstw 2D na fotorealistycznych kafelkach 3D Google
Rozszerzenie TerrainExtension deck.gl renderuje dane 2D na powierzchni 3D. Możesz na przykład nałożyć GeoJSON konturu budynku na geometrię fotorealistycznych kafelków 3D.
W poniższym przykładzie warstwa budynków jest wizualizowana za pomocą wielokątów dostosowanych do powierzchni fotorealistycznych kafelków 3D.
<!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>