Композиция эффектов

Архитектура цепочки постобработки

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

Базовая единица композиции — PostProcessStage. Он представляет собой изолированный шейдерный проход, работающий на полном экране. Несколько стадий объединяются в PostProcessStageCollection, которая управляет порядком выполнения и зависимостями.

Внутри движка используется концепция графа постобработки: результат рендеринга сцены проходит через последовательность framebuffer-переключений, где каждый этап может:

  • модифицировать цвет пикселей
  • анализировать глубину
  • использовать дополнительные текстуры (bloom, depth, normal)
  • комбинировать результат с предыдущими стадиями

Ключевой принцип композиции — последовательное наложение эффектов с сохранением промежуточных буферов.


PostProcessStage как базовый элемент композиции

Каждый stage представляет собой GLSL-шейдер с унифицированным интерфейсом входных данных:

  • color texture (цвет сцены)
  • depth texture (глубина)
  • normal texture (при включённых буферах нормалей)
  • uniform-параметры пользователя

Типовая структура stage:

const grayscaleStage = new Cesium.PostProcessStage({
    fragmentShader: `
        uniform sampler2D colorTexture;
        varying vec2 v_textureCoordinates;

        void main() {
            vec4 color = texture2D(colorTexture, v_textureCoordinates);
            float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
            gl_FragColor = vec4(vec3(gray), color.a);
        }
    `
});

Stage не имеет состояния между кадрами. Композиция достигается за счёт внешнего управления коллекцией стадий.


PostProcessStageCollection и порядок выполнения

Все эффекты сцены агрегируются через scene.postProcessStages. Этот контейнер управляет:

  • порядком применения эффектов
  • включением и отключением стадий
  • объединением совместимых эффектов
  • синхронизацией с кадром рендеринга
viewer.scene.postProcessStages.add(grayscaleStage);

Порядок добавления определяет последовательность выполнения. Это критично, поскольку каждый следующий stage получает уже изменённый буфер изображения.

Композиция работает по принципу:

Scene Render → Stage 1 → Stage 2 → Stage 3 → Screen

Любое изменение порядка приводит к изменению визуального результата даже при одинаковых шейдерах.


Каскадирование эффектов и накопление результата

При последовательной композиции каждый stage может использовать результат предыдущего как входной цветовой буфер. Это создаёт каскадную структуру обработки изображения.

Типовой пример цепочки:

  1. тональная коррекция
  2. bloom
  3. vignette
  4. цветокоррекция LUT

Каждый шаг работает поверх уже изменённого изображения:

scene.postProcessStages.add(bloomStage);
scene.postProcessStages.add(vignetteStage);
scene.postProcessStages.add(colorCorrectionStage);

Внутренне Cesium переключает framebuffer между стадиями, сохраняя промежуточные результаты в текстурах.


Комбинирование нескольких эффектов в одном stage

Для уменьшения количества проходов применяется объединение логики в одном шейдере. Composite stage позволяет инкапсулировать несколько эффектов:

const compositeStage = new Cesium.PostProcessStage({
    fragmentShader: `
        uniform sampler2D colorTexture;
        varying vec2 v_textureCoordinates;

        void main() {
            vec4 color = texture2D(colorTexture, v_textureCoordinates);

            // vignette
            float dist = distance(v_textureCoordinates, vec2(0.5));
            color.rgb *= smoothstep(0.8, 0.2, dist);

            // grayscale blend
            float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
            color.rgb = mix(color.rgb, vec3(gray), 0.3);

            gl_FragColor = color;
        }
    `
});

Такой подход уменьшает количество framebuffer-переключений и повышает производительность.


Использование глубины в композиции

Depth texture является ключевым элементом сложных эффектов. Он позволяет учитывать пространственную структуру сцены при постобработке.

Примеры использования:

  • depth-based fog
  • outline по границам объектов
  • DOF (depth of field)
  • edge detection

Пример эффекта глубинного тумана:

const fogStage = new Cesium.PostProcessStage({
    fragmentShader: `
        uniform sampler2D colorTexture;
        uniform sampler2D depthTexture;
        uniform float fogDensity;

        varying vec2 v_textureCoordinates;

        void main() {
            float depth = czm_readDepth(depthTexture, v_textureCoordinates);
            vec4 color = texture2D(colorTexture, v_textureCoordinates);

            float fog = exp(-depth * fogDensity);
            vec3 fogColor = vec3(0.7, 0.8, 0.9);

            color.rgb = mix(fogColor, color.rgb, fog);

            gl_FragColor = color;
        }
    `,
    uniforms: {
        fogDensity: 0.02
    }
});

Глубина выступает как фактор смешивания между исходным изображением и эффектом среды.


Композитные зависимости и ограничение конфликтов

Некоторые эффекты несовместимы при одновременном применении из-за конкуренции за framebuffer или глубинные данные. Cesium решает это через внутреннюю систему приоритетов.

Основные классы конфликтов:

  • несколько эффектов, модифицирующих глубину
  • конкурирующие full-screen passes с alpha blending
  • повторное использование texture units

При построении композиции учитывается:

  • порядок стадий
  • необходимость промежуточных буферов
  • наличие required textures

Blending и режимы смешивания

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

Типовые режимы:

  • additive blending
  • multiplicative blending
  • screen blending
  • alpha compositing

Пример эффекта свечения:

const glowStage = new Cesium.PostProcessStage({
    fragmentShader: `
        uniform sampler2D colorTexture;
        varying vec2 v_textureCoordinates;

        void main() {
            vec4 color = texture2D(colorTexture, v_textureCoordinates);
            vec3 glow = color.rgb * color.rgb;

            gl_FragColor = vec4(color.rgb + glow * 0.5, color.a);
        }
    `
});

Такие эффекты усиливают яркие области без разрушения базового изображения.


Динамическое управление цепочкой эффектов

Композиция не является статичной. Стадии могут добавляться и удаляться во время работы сцены.

scene.postProcessStages.remove(bloomStage);
scene.postProcessStages.add(edgeStage);

Это позволяет перестраивать граф постобработки в зависимости от состояния сцены:

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

Каждое изменение приводит к пересборке внутреннего pipeline.


Производительность композиции

Каждый stage добавляет:

  • один full-screen draw call
  • дополнительное чтение/запись framebuffer
  • использование texture memory

Критическим фактором становится количество проходов. При росте цепочки эффектов линейно увеличивается нагрузка GPU.

Оптимизация достигается через:

  • объединение шейдеров
  • отключение невидимых стадий
  • использование low-resolution buffers
  • отказ от лишних depth-based операций

Пользовательские композиционные графы

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

  • вход — текстуры сцены
  • ребра — зависимости между эффектами
  • выход — финальный framebuffer

Пример структуры:

Scene
 ├── Tone Mapping
 │     ├── Bloom
 │     └── Color Grading
 └── Edge Detection
       └── Outline Composite

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


Влияние прозрачности и blending сцены

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

Особое значение имеют:

  • premultiplied alpha
  • корректная работа tone mapping перед blending
  • сохранение глубины при alpha blending

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


Комбинация сценических и постпроцессных эффектов

Постобработка не существует изолированно от сценического рендеринга. Некоторые эффекты могут быть реализованы на уровне материалов (shaders материалов), а другие — только через post process.

Разделение задач:

  • материал: локальные эффекты объекта
  • post process: глобальные эффекты сцены

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