В CesiumJS визуализация сцены опирается на WebGL-рендеринг, где
каждый кадр представляет собой результат последовательного выполнения
этапов обновления состояния сцены и отрисовки примитивов. Ключевую роль
играет объект Viewer, инкапсулирующий Scene,
Camera, коллекции примитивов и слои тайлов.
Жизненный цикл кадра включает:
scene.update)camera.update)scene.render)Фактическое изображение, доступное для захвата, существует только в момент завершения этапа рендеринга, когда WebGL-контекст содержит финальный буфер цвета.
Захват скриншота требует стабильного состояния кадра. В динамических сценах (анимации, потоковые данные, морфинг террейна) важным становится контроль момента фиксации.
Основные условия корректного захвата:
В CesiumJS рендер может происходить непрерывно либо по запросу. В
режиме requestRenderMode сцена обновляется только при
изменениях состояния, что уменьшает риск захвата промежуточного
кадра.
const viewer = new Cesium.Viewer("container", {
requestRenderMode: true,
maximumRenderTimeChange: Infinity
});
Основной способ получения скриншота основан на использовании HTML canvas, связанного с WebGL-контекстом:
const canvas = viewer.scene.canvas;
const image = canvas.toDataURL("image/png");
Этот метод извлекает содержимое буфера цвета и кодирует его в формат Base64.
Однако корректность результата зависит от параметров контекста WebGL. При стандартной инициализации браузер может не сохранять буфер кадров после рендера.
Для обеспечения стабильного захвата используется параметр
preserveDrawingBuffer:
const viewer = new Cesium.Viewer("container", {
contextOptions: {
webgl: {
preserveDrawingBuffer: true
}
}
});
Этот флаг заставляет WebGL сохранять содержимое буфера после завершения рендера, что делает возможным извлечение изображения в любой момент времени.
Недостатком является снижение производительности из-за отключения оптимизаций GPU.
При использовании режима requestRenderMode кадр может
отсутствовать в буфере до явного вызова отрисовки:
viewer.render();
const image = viewer.scene.canvas.toDataURL("image/png");
Внутренне это инициирует выполнение scene.render(), что
гарантирует актуальность изображения.
Наиболее точный способ синхронизации захвата связан с событием завершения рендеринга:
postRender — вызывается после отрисовки сценыpreRender — перед отрисовкойПример фиксации изображения после завершения кадра:
viewer.scene.postRender.addEventListener(function () {
const canvas = viewer.scene.canvas;
const image = canvas.toDataURL("image/png");
});
Этот подход обеспечивает захват уже полностью сформированного изображения, исключая частично отрисованные состояния.
Стандартный canvas соответствует размеру экрана, однако часто
требуется увеличение детализации изображения. Это достигается через
временное изменение devicePixelRatio или использование
масштабирования canvas.
Подход через увеличение размера сцены:
viewer.resolutionScale = 2.0;
viewer.render();
const image = viewer.scene.canvas.toDataURL("image/png");
viewer.resolutionScale = 1.0;
Увеличение разрешения приводит к более плотной отрисовке сцены, что улучшает качество итогового изображения, особенно при картографических данных и текстурах высокого разрешения.
Полученная строка Base64 может быть преобразована в файл:
function downloadImage(dataUrl) {
const link = document.createElement("a");
link.href = dataUrl;
link.download = "scene.png";
link.click();
}
Альтернативный подход использует Blob для более
эффективной работы с памятью:
const canvas = viewer.scene.canvas;
canvas.toBlob(function (blob) {
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "scene.png";
link.click();
});
При работе с CesiumJS возникают ограничения, связанные с безопасностью браузера и особенностями WebGL:
Если сцена использует ресурсы с других доменов без CORS-заголовков,
canvas становится «загрязнённым», и методы toDataURL и
toBlob блокируются.
Источники риска:
Флаг preserveDrawingBuffer:
В динамических сценах (перемещение камеры, анимация времени суток, движение объектов) момент захвата должен быть синхронизирован с завершением кадра.
Часто используется комбинация:
clock.shouldAnimate = false)postRenderЭто позволяет получить кадр, соответствующий конкретному состоянию временной шкалы сцены.
В сложных сценариях применяется рендеринг вне экрана с использованием
OffscreenCanvas или headless-браузеров (например,
Puppeteer). CesiumJS может быть инициализирован в среде без DOM, если
доступен WebGL-контекст.
Принцип работы:
ViewerЭтот подход применяется для генерации картографических изображений на сервере.
При использовании динамических источников (например, CZML или 3D Tiles) важно учитывать асинхронную подгрузку данных. Скриншот, сделанный до завершения загрузки плиток, может содержать пустые области.
Типичный контроль включает:
tileset.readyPromisescene.globe.tilesLoadedCesiumJS объединяет множество визуальных слоёв:
Скриншот фиксирует итоговый композит всех слоёв, поэтому любые изменения визуального состояния сцены должны быть завершены до момента захвата.
Особое внимание требуется при использовании постобработки (bloom,
depth of field), так как она применяется после основного рендера и может
не попасть в захват без корректной синхронизации с
postRender.
Для получения детерминированного изображения используется стратегия фиксации состояния сцены:
viewer.render()Такой подход обеспечивает стабильный визуальный результат независимо от внешних событий обновления сцены.