Фотореалистичные 3D-тайлы представлены в формате glTF, соответствующем стандарту OGC , что означает, что для создания 3D-визуализаций можно использовать любой рендерер, поддерживающий спецификацию OGC 3D Tiles. Например, Cesium — это базовая библиотека с открытым исходным кодом для рендеринга 3D-визуализаций.
Работа с CesiumJS
CesiumJS — это библиотека JavaScript с открытым исходным кодом для 3D-визуализации в веб-среде. Более подробную информацию об использовании CesiumJS можно найти в разделе «Изучение CesiumJS» .
Пользовательские элементы управления
Средство визуализации тайлов CesiumJS имеет стандартный набор пользовательских элементов управления.
| Действие | Описание |
|---|---|
| панорамный вид | Щелкните левой кнопкой мыши и перетащите |
| Увеличить изображение | Щелкните правой кнопкой мыши и перетащите курсор, или прокрутите колесико мыши. |
| Повернуть вид | Ctrl + щелчок левой/правой кнопкой мыши и перетаскивание, или щелчок средней кнопкой мыши и перетаскивание. |
Передовые методы
Существует несколько способов сократить время загрузки 3D-графики в CesiumJS. Например:
Для включения одновременных запросов добавьте в HTML-код следующее выражение:
Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = <REQUEST_COUNT>Чем выше
REQUEST_COUNT, тем быстрее загружаются плитки. Однако при загрузке в браузере Chrome соREQUEST_COUNTбольше 10 и отключенным кэшированием вы можете столкнуться с известной проблемой Chrome . В большинстве случаев мы рекомендуем значениеREQUEST_COUNTравное 18 для оптимальной производительности.Включите возможность пропуска уровней детализации. Для получения дополнительной информации см. эту проблему в Cesium .
Для корректного отображения данных об авторстве включите showCreditsOnScreen: true . Дополнительную информацию см. в разделе «Политики» .
Метрики рендеринга
Чтобы определить частоту кадров, посмотрите, сколько раз в секунду вызывается метод requestAnimationFrame .
Чтобы узнать, как рассчитывается задержка кадра, ознакомьтесь с классом PerformanceDisplay .
Примеры рендеринга в CesiumJS
Вы можете использовать рендерер CesiumJS с 3D-тайлами Map Tiles API, просто указав URL корневого набора тайлов.
Простой пример
В следующем примере инициализируется рендерер CesiumJS, а затем загружается корневой набор тайлов.
<!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>
Для получения информации о requestRenderMode см. раздел «Включение режима рендеринга запроса» .
HTML-страница отображается так, как показано здесь.

Интеграция API Places
Для получения дополнительной информации можно использовать CesiumJS с Places API . Виджет автозаполнения позволяет перейти в область просмотра Places. В этом примере используется Places Autocomplete API, который активируется в соответствии с этими инструкциями , и Maps JavaScript API, который активируется в соответствии с этими инструкциями .
<!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>
Вид с вращающегося дрона
Вы можете управлять камерой для анимации по всему набору тайлов. В сочетании с API мест и API высот эта анимация имитирует интерактивный облет дроном любой интересующей точки.
Этот пример кода переместит вас в выбранное вами место в виджете автозаполнения.
<!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>
Нарисуйте ломаные линии и подписи.
Этот пример кода демонстрирует, как добавить полилинии и метки на карту. Вы можете добавить полилинии на карту, чтобы показать маршруты движения на автомобиле и пешком, границы участков или рассчитать продолжительность поездки на автомобиле и пешком. Вы также можете получить атрибуты, не отображая при этом саму сцену.
Вы можете предложить пользователям специально подобранную экскурсию по району или показать соседние объекты недвижимости, которые в данный момент выставлены на продажу, а затем добавить в сцену 3D-объекты, такие как рекламные щиты.
Вы можете составить краткое описание поездки, перечислив просмотренные объекты недвижимости и отобразив эти данные в виртуальных объектах.
<!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>
орбита камеры
В Cesium можно вращать камеру вокруг интересующей точки, избегая столкновений со зданиями. Также можно сделать здания прозрачными, когда камера проходит сквозь них.
Сначала зафиксируйте камеру на определенной точке, затем создайте орбиту камеры, чтобы продемонстрировать свой объект. Это можно сделать, используя функцию lookAtTransform камеры с обработчиком событий, как показано в этом примере кода.
// 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);
});
Для получения дополнительной информации об управлении камерой см. раздел «Управление камерой».
Работа с Cesium для Unreal Engine
Для использования плагина Cesium for Unreal с API 3D-тайлов выполните следующие шаги.
Установите плагин Cesium для Unreal Engine.
Создайте новый проект Unreal Engine.
Подключитесь к API Google Photorealistic 3D Tiles.
Откройте окно Cesium, выбрав в меню Cesium > Cesium .
Выберите набор пустых 3D-плиток .
В окне World Outliner откройте панель Details , выбрав этот набор тайлов Cesium3DTileset .
Измените источник с " Из Cesium Ion" на "Из URL" .
Укажите URL-адрес Google 3D Tiles.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY- Включите опцию «Показывать титры на экране» , чтобы корректно отображать информацию об авторах.
Это загрузит мир. Чтобы перейти к любой широте и долготе, выберите элемент CesiumGeoreference на панели Outliner , а затем отредактируйте исходные широту/долготу/высоту на панели Details .
Работа с Cesium для Unity
Чтобы использовать фотореалистичные тайлы с Cesium для Unity, выполните следующие действия.
Создайте новый проект Unity.
Добавьте новый реестр с ограниченной областью видимости в разделе «Менеджер пакетов» (через «Редактор > Настройки проекта »).
Название: Цезий
URL: https://unity.pkg.cesium.com
Область применения: com.cesium.unity
Установите пакет Cesium for Unity.
Подключитесь к API Google Photorealistic 3D Tiles.
Откройте окно Cesium, выбрав в меню Cesium > Cesium .
Нажмите «Набор пустых 3D-плиток» .
На левой боковой панели в разделе «Источник набора тайлов» в подразделе «Источник» выберите «Из URL» (вместо «Из Cesium Ion»).
Укажите URL-адрес Google 3D Tiles.
https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY- Включите опцию «Показывать титры на экране» , чтобы корректно отображать информацию об авторах.
Это загрузит мир. Чтобы переместиться в любую точку по координатам широты и долготы, выберите элемент CesiumGeoreference в иерархии сцены , а затем отредактируйте исходные координаты широты/долготы/высоты в инспекторе .
Работа с deck.gl
deck.gl , работающий на основе WebGL, — это JavaScript-фреймворк с открытым исходным кодом для высокопроизводительной визуализации больших объемов данных.
Атрибуция
Чтобы корректно отображать информацию об авторских правах на данные, извлеките поле copyright из asset tiles.gltf и отобразите его в отображаемом представлении. Дополнительную информацию см. в разделе «Отображение информации об авторских правах на данные» .
примеры рендерера deck.gl
Простой пример
В следующем примере инициализируется рендерер deck.gl, а затем загружается 3D-объект. В своем коде обязательно замените YOUR_API_KEY на ваш фактический ключ 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>
Визуализация 2D-слоев поверх фотореалистичных 3D-плиток Google.
Расширение TerrainExtension из файла deck.gl позволяет отображать двумерные данные на трехмерной поверхности. Например, вы можете наложить GeoJSON-данные контура здания на геометрию фотореалистичных трехмерных плиток.
В следующем примере слой зданий визуализируется с помощью полигонов, адаптированных к поверхности фотореалистичных 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>