Стилизация 3D Tiles

Технология 3D Tiles предназначена для эффективной передачи и визуализации больших наборов трёхмерных данных: зданий, инфраструктуры, фотограмметрии, BIM-моделей и облаков точек. В CesiumJS механизм стилизации позволяет изменять внешний вид объектов непосредственно на стороне клиента без необходимости модификации исходных данных.

Стили применяются через класс Cesium.Cesium3DTileStyle и позволяют:

  • изменять цвет объектов;
  • скрывать или отображать элементы по условиям;
  • изменять прозрачность;
  • использовать атрибуты объектов для визуального анализа;
  • создавать тематические карты и аналитические представления;
  • выполнять классификацию объектов по категориям.

Стиль назначается через свойство style объекта Cesium3DTileset.

const tileset = await Cesium.Cesium3DTileset.fromUrl(
    "tiles/buildings/tileset.json"
);

viewer.scene.primitives.add(tileset);

tileset.style = new Cesium.Cesium3DTileStyle({
    color: "color('red')"
});

После применения стиля все объекты тайлсета будут окрашены в красный цвет.


Структура объекта Cesium3DTileStyle

Конструктор принимает объект с набором правил оформления.

tileset.style = new Cesium.Cesium3DTileStyle({
    color: "color('blue')",
    show: true
});

Основные свойства:

Свойство Назначение
color Цвет объекта
show Отображение или скрытие
meta Пользовательские метаданные
defines Пользовательские выражения

Пример:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: "color('green')",
    show: "${height} > 50"
});

Здания выше 50 метров будут отображаться, остальные станут невидимыми.


Язык выражений стилей

Система стилизации использует собственный язык выражений, похожий на JavaScript и GLSL.

Обращение к атрибутам объекта осуществляется через конструкцию:

${property}

Например:

${height}
${name}
${buildingType}

Выражение:

"${height} > 100"

возвращает логическое значение.

Арифметические операции:

"${height} * 2"
"${height} + 10"
"${height} / 5"

Логические операторы:

"${height} > 50 && ${height} < 100"
"${type} === 'office'"

Тернарный оператор:

"${height} > 100 ? color('red') : color('green')"

Использование атрибутов объектов

Многие наборы данных содержат свойства объектов.

Пример структуры объекта:

{
    "id": 101,
    "name": "Business Center",
    "height": 145,
    "floors": 35
}

Эти поля становятся доступны в стилях.

Окраска по высоте:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: `
        ${height} > 100 ?
        color('red') :
        color('blue')
    `
});

Управление видимостью объектов

Свойство show позволяет фильтровать элементы.

Показ только высоких зданий:

tileset.style = new Cesium.Cesium3DTileStyle({
    show: "${height} > 80"
});

Отображение только жилых зданий:

tileset.style = new Cesium.Cesium3DTileStyle({
    show: "${usage} === 'residential'"
});

Сложное условие:

tileset.style = new Cesium.Cesium3DTileStyle({
    show:
        "${height} > 50 && " +
        "${usage} === 'office'"
});

Использование функции color()

Создание цветов осуществляется функцией:

color(name)

Примеры:

color('red')
color('green')
color('blue')
color('yellow')
color('white')

Применение:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: "color('yellow')"
});

Цвета в формате RGBA

Можно задавать компоненты цвета явно.

color(r, g, b, a)

Значения находятся в диапазоне от 0 до 1.

Полупрозрачный красный:

color(1.0, 0.0, 0.0, 0.5)

Пример:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: "color(0.0, 0.5, 1.0, 0.7)"
});

Условная окраска объектов

Наиболее распространённый способ стилизации — использование условий.

tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            ["${height} >= 150", "color('red')"],
            ["${height} >= 100", "color('orange')"],
            ["${height} >= 50", "color('yellow')"],
            ["true", "color('green')"]
        ]
    }
});

Проверка выполняется сверху вниз.

Первая подходящая строка определяет итоговый стиль.


Тематическая визуализация зданий

Классификация по назначению объекта:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            [
                "${usage} === 'residential'",
                "color('green')"
            ],
            [
                "${usage} === 'office'",
                "color('blue')"
            ],
            [
                "${usage} === 'industrial'",
                "color('orange')"
            ],
            [
                "true",
                "color('gray')"
            ]
        ]
    }
});

Результат:

  • жилые здания — зелёные;
  • офисы — синие;
  • промышленные объекты — оранжевые;
  • остальные — серые.

Градиентная окраска

Вместо дискретных категорий можно использовать плавное изменение цвета.

Пример на основе высоты:

tileset.style = new Cesium.Cesium3DTileStyle({
    color:
        "mix(color('green'), color('red'), " +
        "${height} / 200)"
});

Чем выше объект, тем ближе цвет к красному.


Использование функции mix()

Функция смешивает два цвета.

mix(colorA, colorB, factor)

Где:

  • 0 — первый цвет;
  • 1 — второй цвет.

Пример:

mix(
    color('blue'),
    color('red'),
    0.5
)

Результатом станет фиолетовый оттенок.

Практический пример:

tileset.style = new Cesium.Cesium3DTileStyle({
    color:
        "mix(color('cyan'), color('magenta'), ${temperature}/50)"
});

Прозрачность объектов

Прозрачность управляется альфа-каналом.

Полупрозрачные здания:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: "color('white', 0.4)"
});

Или:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: "rgba(255,255,255,0.4)"
});

Условная прозрачность:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: `
        ${height} > 100
        ? color('red',0.9)
        : color('red',0.2)
    `
});

Работа с облаками точек

Point Cloud Tiles также поддерживают стили.

Простейший пример:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: "color('white')"
});

Окраска по высоте:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            ["${POSITION}[2] > 100", "color('red')"],
            ["${POSITION}[2] > 50", "color('yellow')"],
            ["true", "color('green')"]
        ]
    }
});

Здесь используется координата Z точки.


Использование встроенных семантик

Cesium предоставляет специальные значения.

Например:

${POSITION}

Координаты текущего объекта.

${POSITION_ABSOLUTE}

Абсолютное положение в мировой системе координат.

Пример:

"${POSITION}[2] > 200"

Пользовательские определения через defines

Для сложных выражений удобно создавать промежуточные переменные.

tileset.style = new Cesium.Cesium3DTileStyle({
    defines: {
        isTall: "${height} > 100"
    },
    color: {
        conditions: [
            ["${isTall}", "color('red')"],
            ["true", "color('blue')"]
        ]
    }
});

Преимущества:

  • читаемость;
  • повторное использование;
  • упрощение поддержки.

Использование метаданных

Свойство meta позволяет формировать вычисляемые значения.

tileset.style = new Cesium.Cesium3DTileStyle({
    meta: {
        info:
            "'Высота: ' + ${height}"
    }
});

Метаданные могут использоваться в пользовательских интерфейсах.


Динамическое изменение стиля

Стиль можно заменять во время работы приложения.

function applyRedStyle() {
    tileset.style =
        new Cesium.Cesium3DTileStyle({
            color: "color('red')"
        });
}

Переключение режимов:

function applyHeightStyle() {
    tileset.style =
        new Cesium.Cesium3DTileStyle({
            color: {
                conditions: [
                    [
                        "${height} > 100",
                        "color('red')"
                    ],
                    [
                        "true",
                        "color('green')"
                    ]
                ]
            }
        });
}

Комбинирование условий отображения и цвета

Цвет и видимость могут работать совместно.

tileset.style = new Cesium.Cesium3DTileStyle({
    show: "${height} > 20",

    color: {
        conditions: [
            ["${height} > 100", "color('red')"],
            ["${height} > 50", "color('orange')"],
            ["true", "color('green')"]
        ]
    }
});

Результат:

  • здания ниже 20 метров скрываются;
  • остальные получают цвет согласно диапазону высоты.

Стилизация фотограмметрии

Для фотограмметрических моделей часто требуется аналитическая визуализация.

Подсветка высоких участков:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            ["${Height} > 150", "color('red')"],
            ["${Height} > 100", "color('yellow')"],
            ["true", "color('white')"]
        ]
    }
});

Фотограмметрия обычно содержит меньше пользовательских атрибутов, поэтому доступность свойств зависит от конкретного источника данных.


Производительность стилизации

Стиль вычисляется для большого количества объектов, поэтому выражения должны оставаться максимально простыми.

Рекомендуется:

  • избегать длинных цепочек условий без необходимости;
  • использовать defines для повторяющихся вычислений;
  • не создавать сложные строковые операции;
  • использовать диапазоны вместо множества отдельных сравнений;
  • обновлять стиль только при реальной необходимости.

Нежелательный пример:

"${height} > 10 &&
 ${height} < 20 &&
 ${usage} === 'office' &&
 ${year} > 2000 &&
 ${floors} > 5"

Более удобный вариант:

defines: {
    modernOffice:
        "${usage} === 'office' && " +
        "${year} > 2000"
}

Практический пример комплексной стилизации

tileset.style = new Cesium.Cesium3DTileStyle({

    defines: {
        highBuilding:
            "${height} > 120"
    },

    show:
        "${height} > 20",

    color: {
        conditions: [

            [
                "${highBuilding}",
                "color('red',0.9)"
            ],

            [
                "${usage} === 'office'",
                "color('blue',0.8)"
            ],

            [
                "${usage} === 'residential'",
                "color('green',0.8)"
            ],

            [
                "true",
                "color('gray',0.5)"
            ]
        ]
    },

    meta: {
        title: "${name}",
        buildingHeight:
            "${height}"
    }
});

Такой стиль одновременно выполняет несколько задач:

  • скрывает низкие объекты;
  • выделяет высотные здания;
  • окрашивает сооружения по типу использования;
  • сохраняет вычисляемые метаданные;
  • использует прозрачность для повышения читаемости сцены;
  • обеспечивает тематическую визуализацию большого набора 3D Tiles без изменения исходных данных.