Fotorealistyczne kafelki 3D są w standardowym formacie glTF OGC, co oznacza, że do tworzenia wizualizacji 3D możesz użyć 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 tutaj.
Kontrola użytkowników
Mechanizm renderowania kafelków CesiumJS ma standardowy zestaw elementów sterujących użytkownika.
Działanie | Opis |
---|---|
Widok przesuwany | Kliknij i przeciągnij lewym przyciskiem myszy |
Powiększenie | Kliknij prawym przyciskiem myszy i przeciągnij lub obróć kółko myszy |
Obróć widok | Ctrl + kliknięcie w lewo/prawo i przeciągnięcie lub kliknięcie i przeciągnięcie środkowym przyciskiem |
Sprawdzone metody
Aby skrócić czas wczytywania 3D w CesiumJS, można zastosować kilka metod. Na przykład:
Aby włączyć jednoczesne żądania, dodaj następującą instrukcję do kodu HTML renderowania:
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = <REQUEST_COUNT>
Im większa wartość
REQUEST_COUNT
, tym szybciej wczytują się kafelki. Jednak podczas wczytywania w przeglądarce Chrome, gdyREQUEST_COUNT
jest większa niż 10 i masz wyłączoną pamięć podręczną, możesz napotkać znany problem w Chrome. W większości przypadków zalecamyREQUEST_COUNT
o wartości 18, aby uzyskać optymalną wydajność.Włącz pomijanie poziomów szczegółów. Więcej informacji znajdziesz w tym artykule.
Aby prawidłowo wyświetlać atrybucje danych, włącz showCreditsOnScreen: true
. Więcej informacji znajdziesz w artykule Zasady.
Dane renderowania
Aby określić liczbę klatek, sprawdź, ile razy na sekundę jest wywoływana metoda requestAnimationFrame.
Aby dowiedzieć się, jak obliczamy opóźnienie klatek, spójrz na klasę PerformanceDisplay.
Przykłady mechanizmu renderowania CesiumJS
Możesz użyć mechanizmu renderowania CesiumJS z kafelkami 3D interfejsu Map Tiles API, podając główny adres URL zbioru kafelków.
Prosty przykład
Poniższy przykład inicjuje mechanizm renderowania CesiumJS, a następnie wczytuje zbiór kafelków główny.
<!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 o włączaniu trybu renderowania żądania.
Strona HTML będzie się renderować w sposób pokazany tutaj.
Integracja interfejsu Places API
Aby uzyskać więcej informacji, możesz używać CesiumJS z interfejsem Places API. Możesz użyć widżetu autouzupełniania, aby przejść do widocznego obszaru Miejsc. Ten przykład korzysta z interfejsu Places Autocomplete API, który można włączyć, postępując zgodnie z tymi instrukcjami, oraz 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 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 drona
Możesz sterować kamerą, aby animować się za pomocą pola kafelkowego. W połączeniu z interfejsami Places API i Elevation API ta animacja symuluje interaktywny lot drona nad dowolnym ważnym miejscem.
Ten przykładowy kod przybliża Ci miejsce wybrane 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>
Rysuj linie łamane i etykiety
Ten przykładowy kod pokazuje, jak dodać do mapy linie łamane i etykiety. Do mapy możesz dodawać linie łamane, aby pokazywać trasy dojazdu i piesze, pokazywać granice nieruchomości lub obliczać czas jazdy i pieszo. Możesz też uzyskać atrybuty bez renderowania sceny.
Możesz zabrać użytkowników na wycieczkę po okolicy lub pokazać sąsiednie nieruchomości, które są aktualnie na wyprzedaży, a następnie dodać do sceny obiekty 3D, takie jak billboardy.
Możesz podsumować wycieczkę, wyświetlić listę oglądanych obiektów i wyświetlić je 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 CEz możesz krążyć wokół wybranego miejsca w ten sposób, aby uniknąć kolizji z budynkami. Możesz też ustawić przezroczystość budynku, gdy porusza się przez nie kamera.
Najpierw ustaw kamerę w określonym punkcie, a potem utwórz jej orbitę, aby zaprezentować swój zasób. Możesz to zrobić, korzystając z funkcji lookAtTransform
kamery w połączeniu 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 w Unreal
Aby używać wtyczki Cesium for Unreal z interfejsem 3D Tiles API, wykonaj poniższe czynności.
Zainstaluj wtyczkę Cesium for Unreal.
Utwórz nowy projekt Unreal.
Połącz się z interfejsem Google PhotoRealistyczny 3D Tiles API.
Otwórz okno Cesium, wybierając z menu Cesium > Cesium.
Wybierz Pusty zestaw kafelków 3D.
W Szkicowniku ze świata otwórz panel Details, wybierając ten Cesium3DTileset.
Zmień wartość opcji Źródło z Z cezium Ion na Z adresu URL.
Jako adres URL wpisz URL kafelków Google 3D.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Włącz opcję Pokaż środki na ekranie, aby prawidłowo wyświetlać atrybucje.
To otwiera przed Tobą świat. Aby przejść do dowolnej szerokości geograficznej, wybierz element CesiumGeoreference w panelu Szkicownik, a następnie zmień Szerokość/długość geograficzna/wysokość w panelu Szczegóły.
Praca z Cesium w Unity
Aby używać fotorealistycznych kafelków z cesium w Unity, wykonaj te czynności.
Utwórz nowy projekt w Unity.
Dodaj nowy rejestr o ograniczonym zakresie w sekcji Menedżer pakietów (za pomocą Edytora > Ustawienia projektu).
Nazwa: Cesium
URL: https://unity.pkg.cesium.com
Zakresy: com.cesium.unity
Zainstaluj pakiet Cesium for Unity.
Połącz się z interfejsem Google Photoreal 3D Tiles API.
Otwórz okno Cesium, wybierając z menu Cesium > Cesium.
Kliknij Pusty zestaw kafelków 3D.
W panelu bocznym po lewej stronie w opcji Źródło kafelków w sekcji Źródło wybierz Z adresu URL (zamiast „Z Cesium Ion”).
Jako adres URL wpisz adres URL kafelków Google 3D.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
- Włącz opcję Pokaż środki na ekranie, aby prawidłowo wyświetlać atrybucje.
To otwiera przed Tobą świat. Aby przejść do dowolnej szerokości geograficznej, wybierz element CesiumGeoreference w Hierarchii scen, a następnie zmień szerokość, długość i położenie geograficzne punktu początkowego w inspektorze.
Praca z deklaracja.gl
deck.gl to oparta na technologii WebGL platforma JavaScript, która umożliwia tworzenie wydajnych wizualizacji danych na dużą skalę.
Atrybucja
Sprawdź, czy atrybucje danych są prawidłowo wyświetlane, wyodrębniając pole copyright
z kafelków gltf asset
, a następnie wyświetlając je w wyrenderowanym widoku. Więcej informacji znajdziesz w artykule Atrybucja danych z sieci reklamowej.
przykłady mechanizmu renderowania site.gl
Prosty przykład
Poniższy przykład inicjuje mechanizm renderowania site.gl, a następnie wczytuje miejsce w 3D. Pamiętaj, aby w kodzie zastąpić 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 tle realistycznych kafelków 3D w Zdjęciach Google
Deck.gl TerrainExtension renderuje w przeciwnym razie dane 2D na powierzchni 3D. Możesz na przykład zasłonić dane GeoJSON podstawy budynku na geometrię kafelków 3D fotorealistycznych.
W poniższym przykładzie wizualizowana jest warstwa budynków z wielokątami dostosowanymi 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>