Manuals
Manuals




This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English

Материалы

Материалы используются для выражения того, как графический компонент (спрайт, тайловая карта, шрифт, GUI-нода, модель и т.д.) должны быть отрендерены.

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

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

Чтобы создать материал, кликните правой кнопкой мыши по нужной папке в обозревателе Assets и выберите New... ▸ Material. (Вы также можете выбрать File ▸ New... в меню, а затем выбрать Material). Укажите имя нового файла материала и нажмите Ok.

Material file

Новый материал откроется в Material Editor.

Material editor

Файл материала содержит следующую информацию:

Name
Уникальное имя материала. Оно используется для включения материала в сборку через ресурс Render и также используется в функции API рендеринга render.enable_material(). Имя должно быть уникальным.
Vertex Program
Файл программы вершинного шейдера (.vp), используемый при рендеринге с этим материалом. Программа выполняется на GPU для каждой вершины примитива компонента. Она вычисляет положение вершины на экране и может также передавать “изменяемые” переменные, которые интерполируются и подаются на вход фрагментной программе.
Fragment Program
Файл программы фрагментного шейдера (.fp), используемый при рендеринге с этим материалом. Программа запускается на GPU для каждого фрагмента (пикселя) примитива и определяет цвет этого фрагмента. Обычно это достигается путем выборки из текстуры и вычислений на основе входящих данных (переменные или константы).
Vertex Constants
Константы (uniform), передаваемые в вершинную программу шейдера. См. ниже список доступных констант.
Fragment Constants
Константы (uniform), передаваемые в фрагментную программу шейдера. См. ниже список доступных констант.
Samplers
При необходимости вы можете настроить конкретные сэмплеры в файле материала. Добавьте сэмплер, укажите имя, соответствующее использованному в шейдере, и задайте параметры обертки и фильтрации по своему усмотрению.
Tags
Теги, ассоциированные с материалом. В движке они представлены в виде битовой маски, используемой в render.predicate() для выбора компонентов, которые нужно отрисовать вместе. Подробнее см. Документацию по рендеру. Максимальное количество тегов в проекте — 32.

Атрибуты

Атрибуты шейдера (также называемые потоками вершин или вершинными атрибутами) — это механизм, с помощью которого GPU получает вершины из памяти для рендеринга геометрии. Вершинный шейдер задает набор потоков через ключевое слово attribute, и в большинстве случаев Defold автоматически создает и привязывает эти данные на основе имени потока. Однако в некоторых случаях вы можете захотеть передавать больше данных на вершину для реализации специфических эффектов, которые движок по умолчанию не предоставляет. Атрибут вершины можно настроить с помощью следующих полей:

Name
Имя атрибута. Аналогично шейдерным константам, конфигурация атрибута будет использоваться только в случае совпадения с атрибутом, указанным в программе вершинного шейдера.
Semantic type
Семантический тип указывает смысл того, что представляет атрибут и/или как он должен отображаться в редакторе. Например, указание SEMANTIC_TYPE_COLOR отобразит виджет выбора цвета, хотя данные по-прежнему передаются как есть из движка в шейдер.
  • SEMANTIC_TYPE_NONE — значение по умолчанию, просто передает данные в буфер вершин
  • SEMANTIC_TYPE_POSITION — координаты вершины; можно использовать вместе с пространством координат
  • SEMANTIC_TYPE_TEXCOORD — текстурные координаты
  • SEMANTIC_TYPE_PAGE_INDEX — индекс страницы
  • SEMANTIC_TYPE_COLOR — вызывает отображение цветового виджета в инспекторе
  • SEMANTIC_TYPE_NORMAL — нормаль вершины
  • SEMANTIC_TYPE_TANGENT — касательная вершины
  • SEMANTIC_TYPE_WORLD_MATRIX — мировая матрица вершины
  • SEMANTIC_TYPE_NORMAL_MATRIX — матрица нормалей вершины
  • SEMANTIC_TYPE_TEXTURE_TRANSFORM_2D — генерирует для атрибута матрицу преобразования текстуры 3x3 на вершину. Для particle-компонентов движок предоставляет матрицу, которая преобразует координаты в пространство атласа для свойства image компонента. Для sprite-компонентов движок предоставляет матрицу для каждого изображения, используемого компонентом (при использовании multi-texturing). Для model-компонентов предоставляется единичная матрица.
Data type
Тип данных, используемый для хранения атрибута.
  • TYPE_BYTE — знаковый 8-битный байт
  • TYPE_UNSIGNED_BYTE — беззнаковый 8-битный байт
  • TYPE_SHORT — знаковое 16-битное значение
  • TYPE_UNSIGNED_SHORT — беззнаковое 16-битное значение
  • TYPE_INT — знаковое целое число
  • TYPE_UNSIGNED_INT — беззнаковое целое число
  • TYPE_FLOAT — число с плавающей точкой (по умолчанию)
Normalize
Если включено, драйвер GPU нормализует значение. Это полезно, если не требуется полная точность — например, цвет часто задается байтами 0..255, но в шейдере работает как 0..1.
Coordinate space
Некоторые семантические типы поддерживают задание координат в разных пространствах. Например, для реализации “билбординга” можно использовать как локальные, так и мировые координаты.
Vector type
Тип векторного значения атрибута.
  • VECTOR_TYPE_SCALAR — скаляр
  • VECTOR_TYPE_VEC2 — вектор из 2 элементов
  • VECTOR_TYPE_VEC3 — вектор из 3 элементов
  • VECTOR_TYPE_VEC4 — вектор из 4 элементов (по умолчанию)
  • VECTOR_TYPE_MAT2 — матрица 2x2
  • VECTOR_TYPE_MAT3 — матрица 3x3
  • VECTOR_TYPE_MAT4 — матрица 4x4
Step function
Указывает, как атрибут должен передаваться в вершинный шейдер. Используется в основном для инстансинга.
  • Vertex — один раз на вершину (по умолчанию)
  • Instance — один раз на экземпляр, например для мировых матриц
Value
Значение атрибута. Может быть переопределено для каждого компонента, в противном случае используется значение по умолчанию. Внимание: для default атрибутов (position, texture coordinates и page indices) это значение игнорируется.

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

Семантика атрибутов по умолчанию

Система материалов автоматически присваивает семантику атрибутам по их именам во время исполнения:

  • position - semantic type: SEMANTIC_TYPE_POSITION
  • texcoord0 - semantic type: SEMANTIC_TYPE_TEXCOORD
  • texcoord1 - semantic type: SEMANTIC_TYPE_TEXCOORD
  • page_index - semantic type: SEMANTIC_TYPE_PAGE_INDEX
  • color - semantic type: SEMANTIC_TYPE_COLOR
  • normal - semantic type: SEMANTIC_TYPE_NORMAL
  • tangent - semantic type: SEMANTIC_TYPE_TANGENT
  • mtx_world - semantic type: SEMANTIC_TYPE_WORLD_MATRIX
  • mtx_normal - semantic type: SEMANTIC_TYPE_NORMAL_MATRIX
  • mtx_texture_transform_2d - semantic type: SEMANTIC_TYPE_TEXTURE_TRANSFORM_2D

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

Задание пользовательских атрибутов во время исполнения

Как и в случае с пользовательскими шейдерными константами, вы можете изменять значения вершинных атрибутов во время исполнения через go.get, go.set и go.animate:

Custom material attribute

go.set("#sprite", "tint", vmath.vector4(1,0,0,1))

go.animate("#sprite", "tint", go.PLAYBACK_LOOP_PINGPONG, vmath.vector4(1,0,0,1), go.EASING_LINEAR, 2)

Однако при обновлении вершинных атрибутов есть особенности: возможность использовать новое значение зависит от семантики атрибута. Например, компонент спрайта поддерживает SEMANTIC_TYPE_POSITION, и если вы попытаетесь переопределить атрибут с этой семантикой, то компонент проигнорирует новое значение, поскольку семантика требует, чтобы данные всегда исходили от позиции спрайта.

Компоненты Model также предоставляют доступ к пользовательским атрибутам материала через go.get(), go.set() и go.animate(). Например, после определения атрибута my_attribute в материале модели:

go.set("#model", "my_attribute", vmath.vector4(1, 0, 0, 1))
go.animate("#model", "my_attribute", go.PLAYBACK_LOOP_PINGPONG,
    vmath.vector4(0, 1, 0, 1), go.EASING_LINEAR, 2)

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

В случаях, когда вершинный атрибут является либо скаляром, либо вектором, отличным от Vec4, данные все равно можно задавать через go.set:

-- Последние два компонента vec4 не будут использоваться!
go.set("#sprite", "sprite_position_2d", vmath.vector4(my_x,my_y,0,0))
go.animate("#sprite", "sprite_position_2d", go.PLAYBACK_LOOP_PINGPONG, vmath.vector4(1,2,0,0), go.EASING_LINEAR, 2)

То же самое справедливо и для матричных атрибутов: если атрибут использует матричный тип, отличный от Mat4, данные также можно задавать через go.set.

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

Использование атрибута преобразования текстуры для перевода UV-координат в пространство атласа:

#version 140

in vec3 position;
in vec4 texcoord0;
in mat3 texture_transform_2d;

out vec2 var_texcoord0;

void main()
{
  // Извлечь позицию из преобразования
  vec2 atlas_pos = texture_transform_2d[2].xy;
  // Извлечь масштаб из преобразования
  vec2 atlas_size = vec2(
      length(texture_transform_2d[0].xy),
      length(texture_transform_2d[1].xy)
  );
  // Преобразовать в локальные UV (0..1)
  vec2 localUV = (texcoord0 - atlas_pos) / atlas_size;

  // Альтернативно, если UV-координаты уже находятся в диапазоне 0..1,
  // можно напрямую преобразовать их в пространство атласа, умножив на матрицу:
  vec2 transformedUv = texture_transform_2d * texcoord0;

  // Передать значение во фрагментный шейдер
  var_texcoord0 = localUV;

  // ... оставшаяся часть вершинного шейдера
}

Инстансинг

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

Инстансинг на данный момент доступен только для компонентов типа Model.

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

  • Один и тот же материал используется во всех экземплярах. Инстансинг работает даже если материал был задан через render.enable_material()
  • Материал должен быть сконфигурирован для использования вершин в локальном пространстве
  • В материале должен быть хотя бы один атрибут, повторяющийся на каждый экземпляр
  • Значения констант должны быть одинаковыми у всех экземпляров. Их можно передавать через пользовательские вершинные атрибуты или иными способами (например, через текстуру)
  • Все экземпляры должны использовать одни и те же ресурсы шейдера, такие как текстуры или буферы хранения

Чтобы указать, что атрибут должен повторяться на каждый экземпляр, установите для него Step function в Instance. Это делается автоматически для некоторых семантик по имени (см. таблицу Default attribute semantics), но также может быть установлено вручную в редакторе материалов, задав Step function как Instance.

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

Instancing setup

Материал настроен с одним пользовательским атрибутом, повторяющимся на каждый экземпляр:

Instancing material

Вершинный шейдер использует несколько атрибутов, повторяющихся на каждый экземпляр:

// Атрибуты на вершину
attribute highp vec4 position;
attribute mediump vec2 texcoord0;
attribute mediump vec3 normal;

// Атрибуты на экземпляр
attribute mediump mat4 mtx_world;
attribute mediump mat4 mtx_normal;
attribute mediump vec4 instance_color;

Обратите внимание, что mtx_world и mtx_normal по умолчанию будут использовать step function Instance. Это можно изменить в редакторе материалов, добавив соответствующие записи и установив Step function в Vertex, чтобы атрибут повторялся на вершину, а не на экземпляр.

Чтобы убедиться, что инстансинг работает, можно воспользоваться веб-профайлером. В приведённом примере, так как единственное различие между экземплярами куба — это атрибуты на экземпляр, отрисовка осуществляется одним вызовом:

Instancing draw calls

Обратная совместимость

OpenGL 3.1 на настольных системах и OpenGL ES 3.0 на мобильных предоставляют инстансинг как основную возможность. Более старые контексты OpenGL ES и WebGL могут поддерживать его через расширение, например ANGLE_instanced_arrays; другие старые адаптеры его не поддерживают. Если инстансинг недоступен, рендеринг по умолчанию продолжает работать, но может быть менее производительным.

Используйте graphics.get_adapter_info(), чтобы определить поддержку и при необходимости выбрать более дешёвый материал или исключить содержимое с большим количеством экземпляров. Поле features представляет собой массив поддерживаемых констант возможностей, а не таблицу с этими константами в качестве ключей:

local function has_context_feature(feature)
    local adapter_info = graphics.get_adapter_info()
    for _, supported_feature in ipairs(adapter_info.features) do
        if supported_feature == feature then
            return true
        end
    end
    return false
end

local instancing_supported = has_context_feature(
    graphics.CONTEXT_FEATURE_INSTANCING
)

Вершинные и фрагментные константы

Шейдерные константы или “uniform”-ы — это значения, которые передаются из движка в вершинные или фрагментные программы шейдеров. Для использования константы вы задаете ее в файле материала либо через свойство Vertex Constant либо через свойство Fragment Constant. Соответствующие uniform переменные должны быть определены в программе шейдера. Следующие константы могут быть установлены в материале:

CONSTANT_TYPE_WORLD
Мировая матрица. Используйте ее для преобразования вершин в пространство мира. Для некоторых типов компонентов, вершины уже расположены в пространстве мира, когда они отправляются вершинной программе (в виду пакетирования). В таких случаях, умножение на мировую матрицу в шейдере выдаст некорректные результаты.
CONSTANT_TYPE_VIEW
Матрица вида. Используйте ее для преобразования вершин в пространство отображения (камеры).
CONSTANT_TYPE_PROJECTION
Проекционная матрица. Используйте ее для преобразования вершин в пространство экрана.
CONSTANT_TYPE_VIEWPROJ
Матрица с уже перемноженными матрицей вида и проекционной матрицы.
CONSTANT_TYPE_WORLDVIEW
Матрица с уже перемноженными матрицей мира и предыдущей матрицы (перемножение матрицы вида на проекционную).
CONSTANT_TYPE_WORLDVIEWPROJ
Матрица с уже перемноженными матрицами мира, вида и проекционной.
CONSTANT_TYPE_WORLD_INVERSE
Обратная мировая матрица. Используется для преобразования из мирового пространства обратно в локальное пространство объекта.
CONSTANT_TYPE_VIEW_INVERSE
Обратная матрица вида. Используется для преобразования из пространства камеры обратно в мировое пространство.
CONSTANT_TYPE_PROJECTION_INVERSE
Обратная матрица проекции. Используется для преобразования из пространства отсечения обратно в пространство камеры.
CONSTANT_TYPE_VIEWPROJ_INVERSE
Обратная матрица комбинированных матриц вида и проекции. Используется для преобразования из пространства отсечения обратно в мировое пространство.
CONSTANT_TYPE_WORLDVIEW_INVERSE
Обратная матрица комбинированных мировой матрицы и матрицы вида. Используется для преобразования из пространства камеры обратно в локальное пространство объекта.
CONSTANT_TYPE_WORLDVIEWPROJ_INVERSE
Обратная матрица комбинированных мировой матрицы, матрицы вида и матрицы проекции. Используется для преобразования из пространства отсечения обратно в локальное пространство объекта. Эти обратные константы позволяют не вычислять обратную матрицу в шейдере.
CONSTANT_TYPE_NORMAL
Матрица для вычисления ориентации по нормали. Мировое преобразование может включать не-нормированное (non-uniform) масштабирование, которое ломает ортогональность скомбинированного мир-на-отображение преобразования. Матрица нормалей используется, чтобы избежать проблем с направлениями когда преобразовываются нормали. (Нормальная матрица — это транспонированная инверсия матрицы мир-на-отображение.)
CONSTANT_TYPE_TIME
Предоставляемый движком vector4, где .x — время, прошедшее с запуска движка, .y — дельта времени с предыдущего кадра, а .z и .w пока равны нулю. Движок автоматически обновляет это значение; вызывать go.set() не требуется. Пример приведён в руководстве по Shadertoy.

Объявите константу Time с именем time в современном uniform-блоке GLSL:

uniform fragment_inputs
{
    vec4 time;
};
CONSTANT_TYPE_USER
Константа типа vector4, которую вы можете использовать для любых собственных данных, которые вы хотите передать в программу шейдера. Вы можете установить начальное значение константы в месте ее определения, но она изменяема через функции go.set() / go.animate(). Также вы можете получить ее значение через go.get(). Изменение константы материала одного экземпляра компонента ломает пакетирование для рендеринга и приведет к дополнительным вызовам отрисовки.

Пример:

go.set("#sprite", "tint", vmath.vector4(1,0,0,1))

go.animate("#sprite", "tint", go.PLAYBACK_LOOP_PINGPONG, vmath.vector4(1,0,0,1), go.EASING_LINEAR, 2)
CONSTANT_TYPE_USER_MATRIX4
Константа типа matrix4, которую можно использовать для передачи любых пользовательских данных в программу шейдера. Вы можете задать начальное значение при определении, но она доступна для изменения через функции go.set() / go.animate(), а также получить текущее значение через go.get(). Изменение значения константы у отдельного экземпляра компонента ломает пакетирование и приводит к дополнительным вызовам отрисовки.

Пример:

go.set("#sprite", "m", vmath.matrix4())

Константы материала GUI-ноды

В GUI-скрипте читайте и изменяйте константы материала ноды с помощью gui.get() и gui.set(), а не функций go. Поддерживаются компоненты векторов, матричные константы и массивы констант. Индексы массивов в таблице параметров начинаются с 1:

local node = gui.get_node("button")

local tint = gui.get(node, "tint")
gui.set(node, "tint.x", 0.5)
gui.set(node, "light_matrix", vmath.matrix4())
gui.set(node, "tint_array", vmath.vector4(1, 0, 0, 1), { index = 1 })

Чтобы константа CONSTANT_TYPE_USER или CONSTANT_TYPE_USER_MATRIX4 была доступна через go.get() и go.set() либо через gui.get() и gui.set(), она должна использоваться в программе шейдера. Если константа определена в материале, но не используется в программе, она будет удалена из материала и станет недоступной во время выполнения.

Сэмплеры

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

Компоненты Sprite, Tile Map, GUI и Particle FX автоматически привязывают текстуру изображения к первому объявленному sampler2D. Компоненты Sprite также поддерживают несколько текстур: каждый сэмплер, объявленный в материале, становится именованным слотом изображения в компоненте Sprite. Первая текстура предоставляет данные анимации спрайта и определяет последовательность кадров. Для каждого кадра идентификатор его изображения используется для поиска соответствующего изображения во всех дополнительных текстурах, каждая из которых предоставляет собственные UV-координаты. Поэтому назначенным атласам или тайловым источникам нужны совпадающие идентификаторы кадров и изображения похожей формы; различия форм при упаковке полигонов могут вызвать затекание текстур. Подробнее см. в разделе Многотекстурные спрайты.

Для компонента или процесса рендеринга, не предоставляющего дополнительного слота текстуры, используйте render.enable_texture(), чтобы привязать дополнительные текстурные сэмплеры из рендер-скрипта.

Sprite sampler

-- mysprite.fp
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D MY_SAMPLER;
void main()
{
    gl_FragColor = texture2D(MY_SAMPLER, var_texcoord0.xy);
}

Вы можете задать настройки сэмплера для компонента добавив сэмплер по имени в файле материалов. Если вы не устанавливаете свой сэмплер в файле материалов, будут использованы глобальные настройки graphics проекта.

Sampler settings

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

Model samplers

-- mymodel.fp
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D TEXTURE_1;
uniform lowp sampler2D TEXTURE_2;
void main()
{
    lowp vec4 color1 = texture2D(TEXTURE_1, var_texcoord0.xy);
    lowp vec4 color2 = texture2D(TEXTURE_2, var_texcoord0.xy);
    gl_FragColor = color1 * color2;
}

Model

Настройки сэмплера

Name
Имя сэмплера. Это имя должно совпадать с заданной в фрагментном шейдере sampler2D переменной.
Wrap U/W
Режим развертки для осей U и V:
  • WRAP_MODE_REPEAT – повторит данные текстуры вне диапазона [0,1].
  • WRAP_MODE_MIRRORED_REPEAT – повторит данные текстуры вне диапазона [0,1], но каждое второе повторение будет зеркально отражено.
  • WRAP_MODE_CLAMP_TO_EDGE — будет приводить данные текстуры со значениями больше 1.0 к значению 1.0, а любые значения меньше 0.0 будут приводиться к значению 0.0 — то есть крайние пиксели будут повторяться до края.
Filter Min/Mag
Фильтрация для увеличения и уменьшения. Ближайшая фильтрация требует меньше вычислений, чем линейная интерполяция, но может привести к артефактам алиасинга. Линейная интерполяция часто дает более плавные результаты :
  • Default — использует параметр фильтрации по умолчанию, указанный в файле game.project в секции Graphics, как Default Texture Min Filter и Default Texture Mag Filter.
  • FILTER_MODE_NEAREST – использует тексель с координатами ближайшими к центру пикселя.
  • FILTER_MODE_LINEAR – устанавливает взвешенное линейное среднее для массива текселей 2x2, которые лежат ближе всего к центру пикселя .
  • FILTER_MODE_NEAREST_MIPMAP_NEAREST – выбирает ближайшее значение текселя в отдельной MIP-карте.
  • FILTER_MODE_NEAREST_MIPMAP_LINEAR – выбирает ближайший тексель из двух ближайших лучших вариантов MIP-карт и затем линейно интерполирует между этими двумя значениями.
  • FILTER_MODE_LINEAR_MIPMAP_NEAREST – линейное интерполирование в пределах отдельной MIP-карты.
  • FILTER_MODE_LINEAR_MIPMAP_LINEAR – использует линейную интерполяцию для вычисления значения на каждой из двух карт, а затем выполняет линейную интерполяцию между этими двумя значениями.
Max Anisotropy
Анизотропная фильтрация — это продвинутая техника фильтрации, при которой берется несколько выборок и их результаты смешиваются. Этот параметр управляет уровнем анизотропии для сэмплеров текстур. Если анизотропная фильтрация не поддерживается GPU, параметр не будет иметь эффекта и по умолчанию будет установлен в значение 1.

Буферы констант

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

self.constants = render.constant_buffer() -- <1>
self.constants.tint = vmath.vector4(1, 0, 0, 1) -- <2>
...
render.draw(self.my_pred, self.constants) -- <3>
  1. Создаем новый буфер констант
  2. Устанавливаем константу tint в ярко-красный
  3. Рисуем предикат используя наши собственные константы

Учтите, что элементы констант буфера ссылаются как обычная Lua таблица, но вы не можете итерироваться по буферу с помощью вызовов pairs() или ipairs().