Fabric спецификация

Общая концепция Fabric-описания материала

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

Основная идея заключается в том, что материал описывается как JSON-структура, содержащая:

  • тип материала или набор компонентов
  • входные параметры (uniforms)
  • GLSL-фрагменты кода
  • правила композиции нескольких материалов

Fabric используется в механизмах MaterialAppearance, EllipsoidSurfaceAppearance, а также в описаниях сущностей CZML и некоторых стилях Entity.


Базовая структура Fabric-объекта

Типичная структура Fabric выглядит следующим образом:

{
  type: 'Color',
  uniforms: {
    color: Cesium.Color.RED
  }
}

или в расширенной форме:

{
  type: 'MyCustomMaterial',
  uniforms: {
    time: 0.0,
    speed: 2.0
  },
  source: `
    czm_material czm_getMaterial(czm_materialInput materialInput)
    {
      czm_material material = czm_getDefaultMaterial(materialInput);

      material.diffuse = vec3(1.0, 0.0, 0.0);
      material.alpha = 1.0;

      return material;
    }
  `
}

Основные поля Fabric

type

Определяет тип материала.

  • встроенные типы: Color, Image, Checkerboard, Stripe, PolylineGlow и др.
  • пользовательские типы: произвольное имя, связанное с source

uniforms

Объект параметров, передаваемых в шейдер.

Примеры значений:

  • числа (float)
  • векторы (Cartesian2, Cartesian3)
  • цвета (Color)
  • текстуры (Image → sampler2D)
uniforms: {
  color: Cesium.Color.BLUE.withAlpha(0.5),
  repeat: new Cesium.Cartesian2(4.0, 4.0),
  time: 1.0
}

source

GLSL-код фрагментного шейдера, реализующий логику материала.

Обязательная функция:

czm_material czm_getMaterial(czm_materialInput materialInput)

Она должна возвращать структуру czm_material, содержащую:

  • diffuse — базовый цвет
  • alpha — прозрачность
  • дополнительные поля (emission, specular и др.)

components

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

{
  components: {
    diffuse: ['diffuseMap', 'colorOverlay'],
    alpha: 'alphaMask'
  }
}

Компонентный подход позволяет комбинировать несколько Fabric-описаний в единый материал.


Встроенные типы материалов

CesiumJS предоставляет набор предопределённых Fabric-материалов.

Color

Простейший материал, задающий сплошной цвет.

{
  type: 'Color',
  uniforms: {
    color: Cesium.Color.YELLOW
  }
}

Image

Использует текстуру.

{
  type: 'Image',
  uniforms: {
    image: 'texture.png',
    repeat: new Cesium.Cartesian2(2.0, 2.0)
  }
}

Checkerboard

Шахматный паттерн.

{
  type: 'Checkerboard',
  uniforms: {
    evenColor: Cesium.Color.WHITE,
    oddColor: Cesium.Color.BLACK,
    repeat: new Cesium.Cartesian2(8.0, 8.0)
  }
}

Stripe

Полосатый материал.

{
  type: 'Stripe',
  uniforms: {
    horizontal: true,
    offset: 0.0,
    repeat: 5.0
  }
}

PolylineGlow

Используется для линий с эффектом свечения.

{
  type: 'PolylineGlow',
  uniforms: {
    glowPower: 0.2,
    color: Cesium.Color.CYAN
  }
}

Пользовательский Fabric-материал

Пользовательский материал создаётся через комбинацию type и source.

Базовая структура

const customMaterial = {
  fabric: {
    type: 'CustomPulse',
    uniforms: {
      frequency: 10.0,
      color: Cesium.Color.ORANGE
    },
    source: `
      czm_material czm_getMaterial(czm_materialInput materialInput)
      {
        czm_material material = czm_getDefaultMaterial(materialInput);

        float intensity = abs(sin(materialInput.st.s * frequency));

        material.diffuse = color.rgb * intensity;
        material.alpha = 1.0;

        return material;
      }
    `
  }
};

Работа с GLSL внутри Fabric

GLSL-код в Fabric имеет доступ к встроенным Cesium переменным:

  • materialInput.st — UV-координаты
  • czm_frameNumber — номер кадра
  • czm_viewerPosition — позиция камеры
  • czm_material — структура результата

Пример динамического эффекта:

float wave = sin(materialInput.st.t * 10.0 + czm_frameNumber * 0.1);

CZML и Fabric-материалы

В CZML Fabric используется для описания материалов объектов напрямую в JSON-потоке.

{
  "polygon": {
    "material": {
      "fabric": {
        "type": "Stripe",
        "uniforms": {
          "evenColor": {
            "rgba": [255, 0, 0, 255]
          },
          "oddColor": {
            "rgba": [0, 0, 255, 255]
          },
          "repeat": 10.0
        }
      }
    }
  }
}

Особенность CZML заключается в сериализации типов Cesium в JSON-формат, где цвета и векторы представлены примитивными структурами.


Интеграция Fabric с Appearance

Fabric является основой для MaterialAppearance:

const appearance = new Cesium.MaterialAppearance({
  material: Cesium.Material.fromType('Color', {
    color: Cesium.Color.GREEN
  })
});

или через явное Fabric-описание:

const material = new Cesium.Material({
  fabric: {
    type: 'Color',
    uniforms: {
      color: Cesium.Color.RED
    }
  }
});

Композиция материалов

Композиционные Fabric позволяют накладывать эффекты слоями.

Пример комбинирования:

{
  components: {
    diffuse: ['baseTexture', 'lightingEffect'],
    alpha: 'fadeEffect'
  }
}

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


Производительность и особенности выполнения

Fabric напрямую транслируется в GLSL, поэтому:

  • каждый уникальный Fabric создаёт отдельную шейдерную программу
  • чрезмерное количество уникальных материалов увеличивает число shader programs
  • uniforms обновляются CPU → GPU на каждый кадр при изменении

Критические моменты:

  • динамические source ухудшают batching геометрии
  • текстуры в uniforms увеличивают нагрузку на память GPU
  • сложные математические операции внутри GLSL влияют на FPS

Частые шаблоны использования

Анимация через time uniform

uniforms: {
  time: 0.0
}
float wave = sin(materialInput.st.s * 10.0 + time);

Маскирование прозрачности

material.alpha = step(0.5, materialInput.st.t);

Градиентная заливка

material.diffuse = mix(colorA.rgb, colorB.rgb, materialInput.st.t);

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

  • отсутствует доступ к полноценному vertex shader в большинстве случаев
  • нет произвольных буферов данных, кроме uniforms
  • строгая структура возвращаемого czm_material
  • ограниченная совместимость между типами appearances

Связь Fabric и внутреннего материала Cesium

Fabric не является самостоятельной системой рендеринга, а транслируется в:

  • GLSL fragment shader
  • uniform bindings WebGL
  • стандартный pipeline Cesium Scene Renderer

Это делает Fabric промежуточным DSL (domain-specific language) между JavaScript и GPU-шейдером.


Типичные ошибки при работе с Fabric

  • использование JavaScript-синтаксиса внутри source
  • отсутствие возврата czm_material
  • несоответствие типов uniforms (например, передача массива вместо Cartesian3)
  • попытка использовать динамические структуры внутри GLSL

Расширенные возможности

Fabric поддерживает:

  • условную логику в GLSL (if, for)
  • математические функции Cesium (czm_saturation, czm_luminance)
  • встроенные константы и координатные преобразования
  • смешивание текстур и процедурных генераторов

Пример смешанного эффекта:

float noise = fract(sin(dot(materialInput.st, vec2(12.9898,78.233))) * 43758.5453);
material.diffuse = mix(color.rgb, vec3(noise), 0.5);