Water материал

Материал Water в CesiumJS представляет собой процедурный шейдерный материал, предназначенный для имитации динамической поверхности воды на 3D-геометрии. Он основан на системе материалов Cesium и работает как на примитивах, так и на сущностях, поддерживающих MaterialAppearance и MaterialProperty. Основная задача материала — визуальная симуляция волн, отражений и цветовых градиентов водной поверхности без необходимости использования сложных физических моделей жидкости.

Архитектура материалов в CesiumJS

Система материалов CesiumJS строится вокруг концепции процедурных шейдеров, управляемых через JavaScript API. Каждый материал компилируется в GLSL и интегрируется в пайплайн рендеринга.

Материал Water является одним из предустановленных типов и регистрируется в системе как:

Cesium.Material.WaterType

Создание материала происходит через фабрику:

material: Cesium.Material.fromType("Water", {
    baseWaterColor: new Cesium.Color(0.0, 0.3, 0.5, 1.0),
    blendColor: new Cesium.Color(0.0, 0.0, 0.0, 0.0),
    normalMapUrl: "path/to/normal-map.png",
    frequency: 10.0,
    animationSpeed: 0.01,
    amplitude: 1.0,
    specularIntensity: 0.5
})

Каждый параметр влияет на итоговое поведение шейдера и визуальное восприятие поверхности.

Основные параметры Water-материала

baseWaterColor

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

Типично представляет собой оттенки синего и зелёного спектра:

baseWaterColor: new Cesium.Color(0.0, 0.2, 0.4, 1.0)

Этот цвет участвует в диффузной составляющей шейдера и задаёт общий тон воды.

blendColor

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

blendColor: new Cesium.Color(0.0, 0.0, 0.0, 0.2)

При увеличении альфа-компоненты усиливается эффект затемнения и «глубины».

normalMapUrl

Ключевой параметр, определяющий структуру поверхности воды. Нормал-карта используется для создания иллюзии волн без изменения геометрии.

normalMapUrl: "waterNormals.jpg"

Шейдер использует эту текстуру для модификации нормалей фрагментов, что создаёт эффект ряби и мелких волн.

frequency

Частота волн определяет плотность повторения нормалей на поверхности.

frequency: 10.0

Высокие значения создают мелкую, «шумную» поверхность, низкие — крупные и плавные волны.

animationSpeed

Скорость анимации управляет темпом смещения текстурных координат во времени.

animationSpeed: 0.02

Внутри шейдера используется глобальное время сцены (czm_frameNumber или czm_time) для смещения UV-координат.

amplitude

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

amplitude: 1.0

Чем выше значение, тем более выраженными становятся пики и впадины волн.

specularIntensity

Отвечает за силу зеркальных бликов от источников света.

specularIntensity: 0.8

Используется в расчёте specular-компоненты модели освещения.


Применение Water-материала на примитивах

Материал может быть применён к геометрии через Primitive и MaterialAppearance. Это наиболее гибкий способ интеграции воды в сцену.

const waterPrimitive = new Cesium.Primitive({
    geometryInstances: new Cesium.GeometryInstance({
        geometry: new Cesium.RectangleGeometry({
            rectangle: Cesium.Rectangle.fromDegrees(-80, 20, -70, 30),
            vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
        })
    }),
    appearance: new Cesium.EllipsoidSurfaceAppearance({
        material: Cesium.Material.fromType("Water", {
            baseWaterColor: Cesium.Color.AQUA,
            normalMapUrl: "waterNormals.jpg",
            frequency: 12.0,
            animationSpeed: 0.03,
            amplitude: 0.7
        })
    })
});

В этом случае поверхность воды накладывается на прямоугольную геометрию, которая интерпретируется как участок эллипсоида Земли.


Использование Water через Entity API

Entity API упрощает создание водных поверхностей за счёт абстракции геометрии и материалов.

viewer.entities.add({
    rectangle: {
        coordinates: Cesium.Rectangle.fromDegrees(-100.0, 25.0, -90.0, 35.0),
        material: new Cesium.MaterialProperty({
            fabric: {
                type: "Water",
                uniforms: {
                    baseWaterColor: Cesium.Color.BLUE,
                    blendColor: Cesium.Color.BLACK.withAlpha(0.3),
                    normalMapUrl: "waterNormals.jpg",
                    frequency: 8.0,
                    animationSpeed: 0.02,
                    amplitude: 1.2,
                    specularIntensity: 0.6
                }
            }
        })
    }
});

MaterialProperty обеспечивает реактивное обновление параметров, что позволяет динамически изменять поведение воды во времени.


Внутренний шейдер Water

Шейдер Water состоит из нескольких этапов обработки:

  1. Вычисление UV-координат
  2. Смещение координат по времени
  3. Сэмплирование нормал-карты
  4. Коррекция нормалей
  5. Освещение (diffuse + specular)
  6. Смешивание с окружающей сценой

Упрощённая логика фрагментного шейдера:

vec2 uv = st * frequency;
uv += time * animationSpeed;

vec3 normal = texture(normalMap, uv).rgb;
normal = normalize(normal * 2.0 - 1.0);

float diffuse = max(dot(normal, lightDirection), 0.0);
float specular = pow(diffuse, 32.0) * specularIntensity;

vec3 color = baseWaterColor.rgb * diffuse;
color += specular;

В реальной реализации Cesium учитывает также атмосферное рассеивание, глубину и параметры камеры.


Анимация воды и временная система

Анимация водной поверхности в CesiumJS привязана к глобальному времени сцены. Используется Scene clock:

viewer.clock.shouldAnimate = true;

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

Смещение текстур реализуется как функция времени:

UV(t) = UV + t * animationSpeed

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


Комбинирование нескольких слоёв волн

Более сложные водные поверхности создаются путём наложения нескольких нормал-карт с разными параметрами:

  • низкочастотные волны (крупные формы)
  • высокочастотные волны (мелкая рябь)

Это достигается либо модификацией шейдера, либо использованием нескольких текстур в одном материале.

Концептуальная схема:

frequency: 6.0 + 14.0
amplitude: 0.5 + 1.5
animationSpeed: 0.01 + 0.03

Каждый слой вносит собственный вклад в итоговую нормаль поверхности.


Отражения и взаимодействие с освещением

Water-материал не реализует полноценные физические отражения экранного пространства (SSR), однако использует приближённые модели бликов и отражений неба.

Основные компоненты:

  • specular highlight от солнца
  • градиентное смешивание цвета
  • зависимость от угла обзора камеры

При низком угле обзора поверхность становится более отражающей, что имитирует эффект Френеля.


Оптимизация производительности

При использовании Water-материала критически важно учитывать нагрузку на GPU:

  • нормал-карты должны быть оптимизированы (размер 256–1024 px)
  • избегается избыточное количество слоёв волн
  • рекомендуется ограничивать область воды геометрией, а не глобальным покрытием
  • использование MaterialAppearance предпочтительнее кастомных шейдеров при стандартных сценариях

Также важным фактором является количество одновременно анимируемых водных поверхностей в сцене.


Ограничения модели Water

Несмотря на визуальную выразительность, материал имеет ряд ограничений:

  • отсутствует физическая симуляция жидкости
  • нет взаимодействия с объектами сцены (волны не реагируют на корабли или берег)
  • отражения приближённые
  • глубина не влияет на динамику волн, только на цветовые градиенты

Эти ограничения компенсируются производительностью и простотой интеграции в глобусную модель CesiumJS.


Интеграция с глобальной сценой Cesium

Water-материал тесно связан с системой рендеринга сцены Cesium:

  • учитывает положение камеры
  • синхронизируется с освещением сцены
  • адаптируется к кривизне эллипсоида Земли
  • работает в контексте tiled terrain и imagery layers

Это позволяет размещать водные поверхности на любых участках планеты без дополнительных преобразований координат.


Использование в реальных сценах

Water-материал применяется для:

  • океанов и морей
  • озёр и водохранилищ
  • декоративных водных поверхностей в 3D-сценах
  • симуляции погодных эффектов в глобусных приложениях

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