Система материалов (Material System) в CesiumJS предназначена для управления визуальным отображением поверхностей геометрических объектов. Материалы определяют цвет, текстуры, прозрачность, процедурные эффекты, освещение и многие другие характеристики визуализации.
Материалы используются в различных сущностях и примитивах:
В основе системы лежит объект Cesium.Material, который
инкапсулирует шейдерную логику и набор параметров, используемых во время
рендеринга.
Материал отвечает за вычисление итогового цвета пикселя поверхности.
При отрисовке объекта Cesium выполняет следующие этапы:
Благодаря этому одна и та же геометрия может отображаться совершенно по-разному без изменения её формы.
Например:
Наиболее распространённый вариант — применение однотонного цвета.
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
)
На уровне Entity API материалы обычно задаются через классы,
наследуемые от MaterialProperty.
Основные представители:
| Класс | Назначение |
|---|---|
| ColorMaterialProperty | Однотонный цвет |
| ImageMaterialProperty | Текстура |
| GridMaterialProperty | Сетка |
| StripeMaterialProperty | Полосы |
| CheckerboardMaterialProperty | Шахматный узор |
| PolylineGlowMaterialProperty | Светящаяся линия |
| PolylineOutlineMaterialProperty | Контур линии |
Пример:
material: new Cesium.ColorMaterialProperty(
Cesium.Color.RED
)
Позволяет использовать изображение в качестве текстуры поверхности.
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)
})
Текстура будет повторяться десять раз по каждой оси.
Создаёт процедурную сетку.
material: new Cesium.GridMaterialProperty({
color: Cesium.Color.WHITE,
cellAlpha: 0.2,
lineCount: new Cesium.Cartesian2(10, 10)
})
Результат напоминает координатную сетку.
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 | Смещение |
Материал формирует полосы.
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
})
Шахматный материал.
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, тем меньше клетки.
Для полилиний существует отдельный тип материалов.
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 | Цвет |
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
}
});
Прозрачность будет плавно изменяться.
На уровне 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.
Материал воды создаёт анимированную поверхность.
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 | Амплитуда |
Материал плавного исчезновения.
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 представляет собой декларативное описание материала.
Структура:
{
fabric: {
type: "...",
uniforms: {},
source: "..."
}
}
Компоненты:
| Элемент | Назначение |
|---|---|
| type | Имя материала |
| uniforms | Входные данные |
| source | GLSL-код |
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"
}
}
Такой подход позволяет создавать сложные визуальные эффекты из отдельных строительных блоков.
Наиболее быстрыми считаются:
Более затратными являются:
Основные факторы нагрузки:
При работе с тысячами объектов предпочтительно переиспользовать материалы и минимизировать количество уникальных шейдерных программ, поскольку каждая новая конфигурация материала приводит к дополнительным затратам на компиляцию и управление графическим конвейером GPU.