Material система

Система материалов (Material System) в CesiumJS предназначена для управления визуальным отображением поверхностей геометрических объектов. Материалы определяют цвет, текстуры, прозрачность, процедурные эффекты, освещение и многие другие характеристики визуализации.

Материалы используются в различных сущностях и примитивах:

  • Polygon
  • Rectangle
  • Ellipse
  • Corridor
  • Polyline
  • Wall
  • GroundPrimitive
  • Primitive
  • ClassificationPrimitive

В основе системы лежит объект Cesium.Material, который инкапсулирует шейдерную логику и набор параметров, используемых во время рендеринга.


Назначение материалов

Материал отвечает за вычисление итогового цвета пикселя поверхности.

При отрисовке объекта Cesium выполняет следующие этапы:

  1. Определяет геометрию объекта.
  2. Вычисляет координаты поверхности.
  3. Передаёт параметры материала в GPU.
  4. Выполняет фрагментный шейдер.
  5. Получает финальный цвет каждого пикселя.

Благодаря этому одна и та же геометрия может отображаться совершенно по-разному без изменения её формы.

Например:

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

Использование простого цвета

Наиболее распространённый вариант — применение однотонного цвета.

const viewer = new Cesium.Viewer("cesiumContainer");

viewer.entities.add({
    polygon: {
        hierarchy: Cesium.Cartesian3.fromDegreesArray([
            30, 50,
            31, 50,
            31, 51,
            30, 51
        ]),
        material: Cesium.Color.BLUE
    }
});

В данном случае Cesium автоматически создаёт материал типа Color.

Эквивалентная запись:

material: new Cesium.ColorMaterialProperty(
    Cesium.Color.BLUE
)

MaterialProperty

На уровне Entity API материалы обычно задаются через классы, наследуемые от MaterialProperty.

Основные представители:

Класс Назначение
ColorMaterialProperty Однотонный цвет
ImageMaterialProperty Текстура
GridMaterialProperty Сетка
StripeMaterialProperty Полосы
CheckerboardMaterialProperty Шахматный узор
PolylineGlowMaterialProperty Светящаяся линия
PolylineOutlineMaterialProperty Контур линии

Пример:

material: new Cesium.ColorMaterialProperty(
    Cesium.Color.RED
)

ImageMaterialProperty

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

viewer.entities.add({
    rectangle: {
        coordinates: Cesium.Rectangle.fromDegrees(
            20,
            40,
            25,
            45
        ),
        material: new Cesium.ImageMaterialProperty({
            image: "textures/grass.jpg"
        })
    }
});

После загрузки изображения оно будет наложено на прямоугольник.


Прозрачность изображения

material: new Cesium.ImageMaterialProperty({
    image: "textures/logo.png",
    transparent: true
})

Флаг transparent сообщает движку о необходимости учитывать альфа-канал текстуры.


Цветовое смешивание

Текстуру можно дополнительно окрашивать.

material: new Cesium.ImageMaterialProperty({
    image: "textures/ground.jpg",
    color: Cesium.Color.YELLOW.withAlpha(0.5)
})

Получается результат смешивания текстуры и указанного цвета.


Повторение текстуры

Параметр repeat определяет количество повторов изображения.

material: new Cesium.ImageMaterialProperty({
    image: "textures/brick.jpg",
    repeat: new Cesium.Cartesian2(10, 10)
})

Текстура будет повторяться десять раз по каждой оси.


GridMaterialProperty

Создаёт процедурную сетку.

material: new Cesium.GridMaterialProperty({
    color: Cesium.Color.WHITE,
    cellAlpha: 0.2,
    lineCount: new Cesium.Cartesian2(10, 10)
})

Результат напоминает координатную сетку.


Параметры Grid

new Cesium.GridMaterialProperty({
    color: Cesium.Color.WHITE,
    cellAlpha: 0.1,
    lineCount: new Cesium.Cartesian2(8, 8),
    lineThickness: new Cesium.Cartesian2(2, 2),
    lineOffset: new Cesium.Cartesian2(0, 0)
})

Основные настройки:

Параметр Назначение
color Цвет линий
cellAlpha Прозрачность ячеек
lineCount Количество линий
lineThickness Толщина
lineOffset Смещение

StripeMaterialProperty

Материал формирует полосы.

material: new Cesium.StripeMaterialProperty({
    evenColor: Cesium.Color.WHITE,
    oddColor: Cesium.Color.BLACK,
    repeat: 16
})

Получается чередование цветов.


Вертикальные полосы

material: new Cesium.StripeMaterialProperty({
    orientation:
        Cesium.StripeOrientation.VERTICAL,
    evenColor: Cesium.Color.BLUE,
    oddColor: Cesium.Color.YELLOW,
    repeat: 20
})

Горизонтальные полосы

material: new Cesium.StripeMaterialProperty({
    orientation:
        Cesium.StripeOrientation.HORIZONTAL,
    evenColor: Cesium.Color.RED,
    oddColor: Cesium.Color.WHITE
})

CheckerboardMaterialProperty

Шахматный материал.

material: new Cesium.CheckerboardMaterialProperty({
    evenColor: Cesium.Color.WHITE,
    oddColor: Cesium.Color.BLACK,
    repeat: new Cesium.Cartesian2(8, 8)
})

Визуально создаётся шахматный рисунок.


Настройка размера клеток

material: new Cesium.CheckerboardMaterialProperty({
    evenColor: Cesium.Color.GRAY,
    oddColor: Cesium.Color.DARKGRAY,
    repeat: new Cesium.Cartesian2(20, 20)
})

Чем больше значение repeat, тем меньше клетки.


Светящиеся линии

Для полилиний существует отдельный тип материалов.

PolylineGlowMaterialProperty

viewer.entities.add({
    polyline: {
        positions:
            Cesium.Cartesian3.fromDegreesArray([
                30, 50,
                40, 55
            ]),
        width: 10,
        material:
            new Cesium.PolylineGlowMaterialProperty({
                glowPower: 0.3,
                color: Cesium.Color.CYAN
            })
    }
});

Эффект напоминает неоновое свечение.


Параметры свечения

new Cesium.PolylineGlowMaterialProperty({
    glowPower: 0.25,
    taperPower: 0.5,
    color: Cesium.Color.LIME
})
Параметр Описание
glowPower Сила свечения
taperPower Сужение к краям
color Цвет

Контурные линии

PolylineOutlineMaterialProperty

material:
    new Cesium.PolylineOutlineMaterialProperty({
        color: Cesium.Color.YELLOW,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 2
    })

Позволяет создать цветную линию с контуром.


Анимируемые материалы

Практически любой параметр материала может изменяться во времени.

Пример динамического цвета:

const colorProperty =
    new Cesium.CallbackProperty(
        function(time) {
            const seconds =
                Cesium.JulianDate.secondsDifference(
                    time,
                    viewer.clock.startTime
                );

            return Cesium.Color.RED.withAlpha(
                Math.abs(Math.sin(seconds))
            );
        },
        false
    );

viewer.entities.add({
    polygon: {
        hierarchy: positions,
        material: colorProperty
    }
});

Прозрачность будет плавно изменяться.


Низкоуровневый объект Cesium.Material

На уровне Primitive API используется объект Cesium.Material.

Создание материала по имени:

const material =
    Cesium.Material.fromType(
        "Color"
    );

Передача параметров

const material =
    Cesium.Material.fromType("Color");

material.uniforms.color =
    Cesium.Color.ORANGE;

Uniform-переменные автоматически передаются в шейдер.


Стандартные типы материалов

Cesium содержит встроенный набор материалов.

Наиболее используемые:

Color
Image
Grid
Stripe
Checkerboard
PolylineGlow
PolylineOutline
Fade
Water
RimLighting
ElevationContour
ElevationRamp
SlopeRamp
AspectRamp

Некоторые из них доступны только через низкоуровневый API.


Материал Water

Материал воды создаёт анимированную поверхность.

const waterMaterial =
    Cesium.Material.fromType("Water");

Настройка воды

waterMaterial.uniforms.baseWaterColor =
    Cesium.Color.BLUE;

waterMaterial.uniforms.blendColor =
    Cesium.Color.CYAN;

waterMaterial.uniforms.waveFrequency =
    1000.0;

waterMaterial.uniforms.animationSpeed =
    0.01;

waterMaterial.uniforms.amplitude =
    10.0;

Основные параметры:

Uniform Назначение
baseWaterColor Основной цвет
blendColor Дополнительный оттенок
waveFrequency Частота волн
animationSpeed Скорость
amplitude Амплитуда

Fade Material

Материал плавного исчезновения.

const material =
    Cesium.Material.fromType("Fade");

Настройки:

material.uniforms.fadeInColor =
    Cesium.Color.YELLOW;

material.uniforms.fadeOutColor =
    Cesium.Color.RED;

material.uniforms.maximumDistance =
    0.5;

Часто применяется для радиолокационных эффектов.


Пользовательские материалы

Система допускает создание собственных материалов на GLSL.

Структура регистрации:

Cesium.Material._materialCache.addMaterial(
    "CustomMaterial",
    {
        fabric: {
            type: "CustomMaterial",
            uniforms: {
                color: Cesium.Color.RED
            },
            source: `
                czm_material czm_getMaterial(
                    czm_materialInput materialInput
                )
                {
                    czm_material material =
                        czm_getDefaultMaterial(
                            materialInput
                        );

                    material.diffuse =
                        color.rgb;

                    material.alpha =
                        color.a;

                    return material;
                }
            `
        }
    }
);

После регистрации материал становится доступным по имени.


Fabric API

Fabric представляет собой декларативное описание материала.

Структура:

{
    fabric: {
        type: "...",
        uniforms: {},
        source: "..."
    }
}

Компоненты:

Элемент Назначение
type Имя материала
uniforms Входные данные
source GLSL-код

Uniform-переменные

Uniform — это значения, доступные во всех вызовах шейдера.

Пример:

uniforms: {
    color: Cesium.Color.BLUE,
    speed: 2.0,
    intensity: 0.8
}

Использование в GLSL:

material.diffuse = color.rgb;

Работа с координатами текстуры

Материал получает данные через объект materialInput.

Наиболее важные поля:

materialInput.st

Координаты текстуры в диапазоне:

0..1

По оси S:

слева → направо

По оси T:

снизу → вверх

Пример градиента

vec2 st = materialInput.st;

material.diffuse =
    vec3(st.x, st.y, 0.0);

По поверхности будет отображён цветовой переход.


Создание процедурного узора

vec2 st = materialInput.st;

float stripe =
    step(
        0.5,
        fract(st.x * 20.0)
    );

material.diffuse =
    vec3(stripe);

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


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

Для анимации часто применяется uniform времени.

uniforms: {
    time: 0.0
}

Обновление:

material.uniforms.time =
    performance.now() / 1000;

В шейдере:

float pulse =
    abs(sin(time));

material.alpha =
    pulse;

Получается эффект пульсации.


Комбинирование материалов

Fabric позволяет объединять несколько материалов.

Пример концепции:

materials: {
    diffuseMap: {
        type: "Image"
    },
    glow: {
        type: "Color"
    }
}

Такой подход позволяет создавать сложные визуальные эффекты из отдельных строительных блоков.


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

Наиболее быстрыми считаются:

  1. Color
  2. Stripe
  3. Checkerboard
  4. Grid

Более затратными являются:

  1. Image
  2. Water
  3. Пользовательские GLSL-материалы
  4. Многослойные Fabric-конструкции

Основные факторы нагрузки:

  • количество uniform-переменных;
  • сложность GLSL-кода;
  • объём текстур;
  • число вызовов функций;
  • количество математических операций на пиксель;
  • прозрачность;
  • частое обновление параметров.

При работе с тысячами объектов предпочтительно переиспользовать материалы и минимизировать количество уникальных шейдерных программ, поскольку каждая новая конфигурация материала приводит к дополнительным затратам на компиляцию и управление графическим конвейером GPU.