Эта статья является вольным переводом официальной документации по языку Pixel Bender от корпорации Adobe. Хочу сразу заметить, что это перевод именно Pixel Bender Language Reference, а не Pixel Bender Developer's Guide. Как подсказывает Гугл, данная тема еще не всплывала в Рунете и поэтому мне хотелось бы исправить столь досадное упущение)) В переводе были намеренно опущены вопросы программирования под Adobe Photoshop и Adobe AfterEffects, т.к. меня интересовало только написание фильтров под Flash Player.
Pixel Bender является высокопроизводительной графической технологией программирования, предназначенной для обработки изображений.
Pixel Bender kernel — это C-подобный язык с расширениями для обработки изображений. Он основан на GLSL, который, в свою очередь, основан на С. Основы синтаксиса языка должны быть знакомы любому C-программисту.
Основной единицей обработки изображений в Pixel Bender, является ядро (kernel) (Прим. пер.: Я не знаю как точнее перевести это слово, поэтому доверился Гуглу ;)). Каждое программа на Pixel Bender'е определяет одно ядро. Ядро является объектом, который содержит результат обработки одного пиксела функцией с произвольным числом аргументов, которые могут быть получены от одного или нескольких исходных изображений.
Adobe предоставляет Pixel Bender Toolkit IDE — интегрированную среду разработки для написания программ на языке Pixel Bender. Работа с Pixel Bender Toolkit IDE описана в Pixel Bender Developer’s Guide (Прим. пер.: IDE халявная. Взять версию под Windows можно отсюда).
Во время разработки, вы можете запускать программы в Pixel Bender Toolkit IDE, которая предоставляет для этого удобный интерфейс. Для получения информации о Pixel Bender Toolkit IDE, см. Pixel Bender Developer’s Guide.
Для запуска фильтров во Flash Player'е вы должны сохранять ваши файлы с расширением .pbj.
Клиентское приложение может по-своему организовывать доступ к параметрам запуска и работы фильтра:
Доступными для использования являются следующие директивы препроцессора (аналогичные директивам препроцессора в языке С):
#if
#ifdef
#defined
#endif
#elif
#define
Поскольку Flash Player работает на широком спектре оборудования, только часть языка Pixel Bender доступна для использования в Flash Player. Далее приведен перечень ограничений, накладываемых Flash Player'ом на использование языка Pixel Bender:
В каждой программе, написанной на Pixel Bender задается один блок кода, содержащий набор метаданных, заключенных в угловые скобки, и другой блок кода, описывающий ядро, набор переменных и выполняемые операции, заключенный в фигурные скобки.
Каждое ядро должно начинаться с указания версии языка, на которой пишется код.
Первая часть ядра определяет блок метаданных, состоящий из группы пар имя-значение, заключенный в угловые скобки:
Следующие значения метаданных являются предопределенными:
namespace — Обязательно. Пространство имен, в котором определено ядро.
vendor — Обязательно. Издатель.
version — Обязательно. Целое число, номер версии реализации этого ядра. Это не тоже самое, что languageVersion (!).
description — Необязательно. Описание работы фильтра.
Например:
Вторая часть определения ядра представляет собой набор переменных и функций, заключенных в фигурные скобки. Ядро должно содержать по крайней мере определение функции evaluatePixel(), а все остальное является необязательным.
Объявление переменных обычно содержат в себе объявление пикселов входного и выходного изображения. Также могут быть включены параметры и константы, которые будут использоваться в функциях.
Основная функция, evaluatePixel(), применяется для ввода изображений или изображения, над которым выполняется преобразование, результатом которого является один пиксел.
До определения функции evaluatePixel() могут быть (необязательно) описаны:
Параметры могут включать данные, которые описывают этот параметр или накладывают ограничения на его использование. Эти данные будут доступны внутри клиентских приложений после компиляции, и также помогают программисту решить, каким образом спроектировать пользовательский интерфейс, который бы позволял пользователям установить значение параметра.
Значения данных заключаются в угловые скобки, следующие за объявлением параметра.
Имена являются строками. Значения — константами любого допустимого типа Pixel Bender. Для типов int, float и bool определение типа происходит автоматически. Для других типов необъодимо определить константное значение допустимого типа (например: float2(1.0, -1.0 )) или строку ограниченную двойными кавычками. Например:
Этот параметр накладывает ограничения на возможные значения:
minValue — минимально допустимое значение
maxValue — максимально допустимое значение
defaultValue — значение по умолчанию
description — описание параметра, которое можно использовать в клиентском приложении в качестве подсказки.
Определение функции ядра должно соответствовать этим условиям:
Все, кроме evaluatePixel(), является необязательным.
Синтаксис функции:
Pixel Bender является строготипизированным языком. Нет автоматических преобразований типов, за одним исключением: между векторными типами данных с плавающей точкой и типами данных матриц. Есть несколько типов данных, каждый из которых определен в пределах определенного набора операторов и собственных функций.
Pixel Bender поддерживает следующие базовые типы данных:
bool — логический тип данных
int — целое число
float — число с плавающей точкой
pixel1 — определяет значение одного канала изображения. Цифра «1» отличает данный тип данных от аналогичных ему, но определяющих значения нескольких каналов изображения. Паременная данного типа представлена числом с плавающей точкой и занимает 32 бита памяти.
Все эти типы данных могут участвовать в числовых операциях.
Типы данных bool, int, и float могут быть преобразованы из одного в другой с помощью обычных правил в С-стиле:
type(expression)
Например:
Тип данных pixel1 может быть взаимозаменяемым с типом данных float.
Примечание:
Тип данных int занимает 16 бит памяти (без учета знака), но его реализация может занимать и более 16 бит памяти. Можно совершать преобразования между типами int и float. Когда результат преобразования из типа int в тип float не может быть представлен как тип int, значение переменной становится неопределенным (undefined).
Pixel Bender поддерживает 2-х, 3-х и 4-х элементные аналоги для каждого скалярного типа данных:
float2 bool2 int2 pixel2
float3 bool3 int3 pixel3
float4 bool4 int4 pixel4
Инициализация любого типа (включая пиксельный) представлена общей формой:
vectorType(element1 [, element2...])
Например:
Есть также сокращенный вариант записи (следующие выражения эквивалентны):
Вы можете получить доступ к значению векторной переменной по индексу или имени по следующим правилам:
Например, чтобы получить значение первого элемента вектора myVectorValue, вы можете использовать любой из следующих вариантов записи:
myVectorValue[0]
myVectorValue.r
myVectorValue.x
myVectorValue.s
Pixel Bender поддерживает свиззлинг для выбора и переопределения порядка следования элементов вектора. Для вектора с n-количеством элементов значения могут быть указаны следом за оператором точки. Соответствующие значения элементов вектора формируют новый результат с таким количеством элементов, как и у присваиваемой переменной. Этот синтаксис можно использовать для изменнения порядка следования, для удаления или повторения элементов вектора. Например:
Указатели из отдельных последовательностей не могут быть объединены:
Указатели индексов также могут быть применены и в левой части выражения присваивания. В этом случае индексы не могут повторяться. Эта возможность используется для записи маскировки (Прим. пер.: в оригинале — write-masking). С правой стороны выражения присваивания должно быть правильное количество аргументов:
float3 vec3;
float2 vec2;
vec3.xy = vec2; // устанавливает значения элементов вектора vec2 элементам вектора vec3с индексами 0 и 1
vec3.xz = vec2; // устанавливает значения элементов вектора vec2 элементам вектора vec3с индексами 0 и 2
Взаимодействие:
Свиззлинг и запись маскировки могут быть использованы одновременно по обе стороны выражения присваивания:
Существует вероятность появления сложностей между свиззлингом и операцией присваивания. Рассмотрим следующий пример:
Упрощенный вариант этой записи можно представить в следующем виде:
Проблема в том, что значение g.y во второй строке было изменено. Правильным решением была бы следующая запись:
Преобразования между векторными типами данных допустимы при условии, что размеры операндов присваивания равны. Само преобразование аналогично преобразованию между скалярными типами данных:
type(expression)
Например:
Есть следующие виды матриц:
float2x2
float3x3
float4x4
Создание матриц с помощью конструктора подразумевает использование векторов типа float для указания значений матриц, или указания значений скалярных переменных типа float для каждого элемента матрицы в порядке следования «столбец-ряд» или смеси из векторов и скалярных переменных типа float:
float2x2( float2, float2 )
float2x2( float, float,
float, float )
float3x3( float3, float3, float3 )
float3x3( float, float, float,
float, float, float,
float, float, float )
float4x4( float4, float4, float4, float4 )
float4x4( float, float, float, float,
float, float, float, float,
float, float, float, float,
float, float, float, float )
Вы также можете инициализировать матрицу одной скалярной переменной типа float, которая будет определять значения элементов матрицы на главной диагонали. Все остальные значения будут установлены в ноль:
float2x2( float )
float3x3( float )
float4x4( float )
Для получения доступа к значениям элементов матрицы используйте следующий синтаксис:
matrix[ столбец ][ ряд ]
Если опустить указание ряда, то выбирается целиком один столбец и возвращается переменная векторного типа подходящей размерности:
matrix[ столбец ]
Типы данных изображений.
Pixel Bender поддерживает также переменные типа image. Они представлены следующими типами данных:
image1
image2
image3
image4
Переменные данных типов не могут быть созданны или использованны в выражениях. Однако они могут быть переданы в качестве аргументов во встроенные функции языка.
Тип данных void.
Функции, которые не возвращают значений должны быть определены с типом void.
Pixel Bender определяет следующие типы операторов для арифметических операций над скалярными типами данных. Здесь они указаны в порядке приоритета выполнения. Скобки могут быть использованы для изменения этого порядка:
. Выбор элемента переменной
++ — Постфиксные операторы инкремента и декремента
++ — Префиксные операторы инкремента и декремента
— ! Унарный оператор отрицания, логическое «НЕ»
* / Умножение, деление
+ — Сложение, вычитание
< > <= >= Сравнения
== != Равенство
&& Логическое «И»
^^ Логическое «ИСКЛЮЧАЮЩЕЕ ИЛИ»
|| Логическое «ИЛИ»
= += -= *= /= Группировка операторов
?: Краткая запись операторов ветвления. Данный оператор может быть использован только для выбора между двумя переменными или константами (с правой стороны), но не выражений.
Стандартные арифметические операторы (+, -, *, /) могут быть использованы как для операций над скалярными, так и над векторными и матричными типами данных. Бинарный оператор может быть применен к двум векторным операндам только в том случае, если они имеют одинаковый размер. В этом случае операция выполняется для каждого элемента вектора. Например:
float3 x, y, z;
z = x + y;
Эта запись эквивалентна следующей:
z[ 0 ] = x[ 0 ] + y[ 0 ];
z[ 1 ] = x[ 1 ] + y[ 1 ];
z[ 2 ] = x[ 2 ] + y[ 2 ];
Группировка скалярных и векторных паременных также допустима. Например:
float3 x, y;
float w;
x = y * w;
Эта запись эквивалентна следующей:
x[ 0 ] = y[ 0 ] * w;
x[ 1 ] = y[ 1 ] * w;
x[ 2 ] = y[ 2 ] * w;
Важным исключением из этого правила является перемножение матриц между собой и матриц с векторными переменными. Перемножение осуществляется по правилам линейной алгербы (а не покомпонентно):
float2x2 * float2x2 Перемножние матриц по правилам линейной алгебры
float3x3 * float3x3
float4x4 * float4x4
float2x2 * float2 Перемножение столбцов на вектор
float3x3 * float3
float4x4 * float4
float2 * float2x2 Перемножение рядов на вектор
float3 * float3x3
float4 * float4x4
Математические функции:
Как и арифметические операторы, математические функции могут выполняться над векторными типами данных. В этом случае они работают покомпонентно. Если не определено иное, то все углы указаны в радианах.
float radians( float degrees ) Преобразование градусов в радианы
float2 radians( float2 degrees )
float3 radians( float3 degrees )
float4 radians( float4 degrees )
float degrees( float radians ) Преобразование радианов в градусы
float2 degrees ( float2 radians )
float3 degrees ( float3 radians )
float4 degrees ( float4 radians )
float sin( float radians ) Возвращает синус аргумента
float2 sin( float2 radians )
float3 sin( float3 radians )
float4 sin( float4 radians )
float cos( float radians ) Возвращает косинус аргумента
float2 cos( float2 radians )
float3 cos( float3 radians )
float4 cos( float4 radians )
float tan( float radians ) Возвращает тангенс аргумента. Если x==pi/2.0 возвращается undefined
float2 tan( float2 radians )
float3 tan( float3 radians )
float4 tan( float4 radians )
float asin( float x ) Возвращается арксинус аргумента. Возвращаемое значение находится в диапазоне [-pi/2..pi/2]
float2 asin( float2 x )
float3 asin( float3 x )
float4 asin( float4 x )
float acos( float x ) Возвращает арккосинус аргумента. Возвращаемое значение находится в диапазоне [0..pi]
float2 acos( float2 x )
float3 acos( float3 x )
float4 acos( float4 x )
float atan( float y_over_x ) Возвращает арктангенс аргумента. Возвращаемое значение находится в диапазоне [-pi/2..pi/2]
float2 atan( float2 y_over_x)
float3 atan( float3 y_over_x)
float4 atan( float4 y_over_x)
float atan( float y, float x ) Возвращает арктангенс выражения y / x. Возвращаемое значение находится в диапазоне [-pi..pi]
float2 atan( float2 y, float2 x )
float3 atan( float3 y, float3 x )
float4 atan( float4 y, float4 x )
float pow( float x, float y ) Возвращает x в степени y и undefined если х < 0
float2 pow ( float2 x, float2 y )
float3 pow ( float3 x, float3 y )
float4 pow ( float4 x, float4 y )
float exp( float x ) Возвращает e в степени х (Прим. пер.: не помню как называется эта величина:))
float2 exp( float2 x )
float3 exp( float3 x )
float4 exp( float4 x )
float exp2( float x ) Возвращает 2 в степени х
float2 exp2( float2 x )
float3 exp2( float3 x )
float4 exp2( float4 x )
float log( float x ) Возвращает натуральный логарифм числа х
float2 log( float2 x )
float3 log( float3 x )
float4 log( float4 x )
float log2( float x ) Возвращает натуральный логарифм числа х с основанием 2
float2 log2( float2 x )
float3 log2( float3 x )
float4 log2( float4 x )
float sqrt( float x ) Возвращает положительный квадратный корень числа х и undefined если х < 0
float2 sqrt( float2 x )
float3 sqrt( float3 x )
float4 sqrt( float4 x )
float inverseSqrt( float x ) Возвращает обратное положительному квадратному корню от числа х и undefined если х < 0
float2 inverseSqrt( float2 x )
float3 inverseSqrt( float3 x )
float4 inverseSqrt( float4 x )
float abs( float x ) Если x >= 0, возвращает x, иначе возвращает -x
float2 abs( float2 x )
float3 abs( float3 x )
float4 abs( float4 x )
float sign( float x ) Если x < 0, возвращает -1
float2 sign( float2 x ) Если x == 0, возвращает 0
float3 sign( float3 x ) Если x > 0, возвращает 1
float4 sign( float4 x )
float floor( float x ) Округляет х в меньшую сторону (возвращает целое число)
float2 floor( float2 x )
float3 floor( float3 x )
float4 floor( float4 x )
float ceil( float x ) Округляет х в большую сторону (возвращает целое число)
float2 ceil( float2 x )
float3 ceil( float3 x )
float4 ceil( float4 x )
float fract( float x ) Возвращает x – floor(x)
float2 fract( float2 x )
float3 fract( float3 x )
float4 fract( float4 x )
float mod( float x, float y ) Возвращает x – y * floor(x/y)
float2 mod( float2 x, float2 y )
float3 mod( float3 x, float3 y )
float4 mod( float4 x, float4 y )
float min( float x, float y ) Если х < y возвращает х, иначе возвращает у
float2 min( float2 x, float2 y )
float3 min( float3 x, float3 y )
float4 min( float4 x, float4 y )
float max( float x, float y ) Если х > у, возвращает х, иначе возвращает у
float2 max( float2 x, float2 y )
float3 max( float3 x, float3 y )
float4 max( float4 x, float4 y )
float step( float x, float y ) Если у < х, возвращает 0.0, иначе возвращает 1.0
float2 step( float2 x, float2 y )
float3 step( float3 x, float3 y )
float4 step( float4 x, float4 y )
float clamp(float x, float minval, float maxval) Если x < minval, возвращает minval. Если x > maxval, возвращает maxval. Иначе возвращает x.
float2 clamp(float2 x, float2 minval, float2 maxval)
float3 clamp(float3 x, float3 minval, float3 maxval)
float4 clamp(float4 x, float4 minval, float4 maxval)
float mix(float x, float y, float a) Возвращает x * (1.0 — a) + y * a (это линейная интерполяция между x и y).
float2 mix(float2 x, float2 y, float2 a)
float3 mix(float3 x, float3 y, float3 a)
float4 mix(float4 x, float4 y, float4 a)
float smoothStep(float edge0, float edge1, float x) Если x <= edge0, возвращает 0. Если x >= edge1, возвращает 1, иначе выполняется сглаженная интерполяция (Прим. пер.: в оригинале — smooth hermite interpolation).
float2 smoothStep(float2 edge0, float2 edge1, float2 x)
float3 smoothStep(float3 edge0, float3 edge1, float3 x)
float4 smoothStep(float4 edge0, float4 edge1, float4 x)
Геометрические функции:
Эти функции работают с векторами как с целым объектом, а не рассматривают каждый элемент вектора, как отдельный.
float length(float x) Возвращает длину вектора х
float length(float2 x)
float length(float3 x)
float length(float4 x)
float distance(float x, float y) Возвращает расстояние между х и у
float distance(float2 x, float2 y)
float distance(float3 x, float3 y)
float distance(float4 x, float4 y)
float dot(float x, float y) Возвращает скалярное произведение х на у
float dot(float2 x, float2 y)
float dot(float3 x, float3 y)
float dot(float4 x, float4 y)
float3 cross(vector3 x, vector3 y) Возвращает векторное произведение х на у
float normalize(float x) Возвращает вектор с тем же направлением, что и х, но с длиной равной 1 и undefined если length(x) == 0
float2 normalize(float2 x)
float3 normalize(float3 x)
float4 normalize(float4 x)
Эти функции выполняют покомпонентное перемножение (в отличие от оператора *, который выполняет алгебраическое перемножение матриц):
float2x2 matrixCompMult(float2x2 x, float2x2 y) Возвращает покомпонентное перемножение х на у
float3x3 matrixCompMult(float3x3 x, float3x3 y)
float4x4 matrixCompMult(float4x4 x, float4x4 y)
Эти функции сравнивают вектора покомпонентно и возвращают булево значение той же размерности (соблюдая порядок сравнения):
bool2 lessThan(int2 x, int2 y) Возвращает покомпонентное сравнение x < y
bool3 lessThan(int3 x, int3 y)
bool4 lessThan(int4 x, int4 y)
bool2 lessThan(float2 x, float2 y)
bool3 lessThan(float3 x, float3 y)
bool4 lessThan(float4 x, float4 y)
bool2 lessThanEqual(int2 x, int2 y) Возвращает покомпонентное сравнение x <= y
bool3 lessThanEqual(int3 x, int3 y)
bool4 lessThanEqual(int4 x, int4 y)
bool2 lessThanEqual(float2 x, float2 y)
bool3 lessThanEqual(float3 x, float3 y)
bool4 lessThanEqual(float4 x, float4 y)
bool2 greaterThan(int2 x, int2 y) Возвращает покомпонентное сравнение x > y
bool3 greaterThan(int3 x, int3 y)
bool4 greaterThan(int4 x, int4 y)
bool2 greaterThan(float2 x, float2 y)
bool3 greaterThan(float3 x, float3 y)
bool4 greaterThan(float4 x, float4 y)
bool2 greaterThanEqual(int2 x, int2 y) Возвращает покомпонентное сравнение x >= y
bool3 greaterThanEqual(int3 x, int3 y)
bool4 greaterThanEqual(int4 x, int4 y)
bool2 greaterThanEqual(float2 x, float2 y)
bool3 greaterThanEqual(float3 x, float3 y)
bool4 greaterThanEqual(float4 x, float4 y)
bool2 equal(int2 x, int2 y) Возвращает покомпонентное сравнение x == y
bool3 equal(int3 x, int3 y)
bool4 equal(int4 x, int4 y)
bool2 equal(float2 x, float2 y)
bool3 equal(float3 x, float3 y)
bool4 equal(float4 x, float4 y)
bool2 equal(bool2 x, bool2 y)
bool3 equal(bool3 x, bool3 y)
bool4 equal(bool4 x, bool4 y)
bool2 notEqual(int2 x, int2 y) Возвращает покомпонентное сравнение x != y
bool3 notEqual(int3 x, int3 y)
bool4 notEqual(int4 x, int4 y)
bool2 notEqual(float2 x, float2 y)
bool3 notEqual(float3 x, float3 y)
bool4 notEqual(float4 x, float4 y)
bool2 notEqual(bool2 x, bool2 y)
bool3 notEqual(bool3 x, bool3 y)
bool4 notEqual(bool4 x, bool4 y)
Эти функции работают только с векторами логического типа:
bool any(bool2 x) Возвращает истину если хотя бы один элемент х является истинным
bool any(bool3 x)
bool any(bool4 x)
bool all(bool2 x) Возвращает истину если все элементы х являются истинными
bool all(bool3 x)
bool all(bool4 x)
bool2 not(bool2 x) Возвращает результат поэлементного логического отрицания
bool3 not(bool3 x)
bool4 not(bool4 x)
P.S.: Это мой первый пост на Хабре. Прошу сильно не пинать;)
Pixel Bender является высокопроизводительной графической технологией программирования, предназначенной для обработки изображений.
Pixel Bender kernel — это C-подобный язык с расширениями для обработки изображений. Он основан на GLSL, который, в свою очередь, основан на С. Основы синтаксиса языка должны быть знакомы любому C-программисту.
Основной единицей обработки изображений в Pixel Bender, является ядро (kernel) (Прим. пер.: Я не знаю как точнее перевести это слово, поэтому доверился Гуглу ;)). Каждое программа на Pixel Bender'е определяет одно ядро. Ядро является объектом, который содержит результат обработки одного пиксела функцией с произвольным числом аргументов, которые могут быть получены от одного или нескольких исходных изображений.
- Программа на языке Pixel Bender определяет именованный объект ядра, указав функцию evaluatePixel() которая выполняется над каждым пикселом исходного изображения. Каждое ядро должно содержать определение этой функции.
- Ядро может принимать любое число аргументов произвольных типов. Оно может определять внутри себя параметры и переменные, которые будут использоваться для выполнения различных операций. Pixel Bender является стоготипизированным языком.
- Pixel Bender содержит много встроенных функций для работы с пикселами.
Использование фильтров, написанных на Pixel Bender
Adobe предоставляет Pixel Bender Toolkit IDE — интегрированную среду разработки для написания программ на языке Pixel Bender. Работа с Pixel Bender Toolkit IDE описана в Pixel Bender Developer’s Guide (Прим. пер.: IDE халявная. Взять версию под Windows можно отсюда).
Во время разработки, вы можете запускать программы в Pixel Bender Toolkit IDE, которая предоставляет для этого удобный интерфейс. Для получения информации о Pixel Bender Toolkit IDE, см. Pixel Bender Developer’s Guide.
Для запуска фильтров во Flash Player'е вы должны сохранять ваши файлы с расширением .pbj.
Клиентское приложение может по-своему организовывать доступ к параметрам запуска и работы фильтра:
- Клиентское приложение обычно использует атрибут name, указанный в ядре, для обращения к данному фильтру.
- Можно указать строку с описанием работы фильтра, которую клиентское приложение будет использовать в качестве подсказки.
- При определении параметра необходимо указать метаданные (например, минимальное, максимальное значения и значение по умолчанию), которые помогают разработчику выбрать и настроить соответствующие элементы пользовательского интерфейса.
Директивы препроцессора
Доступными для использования являются следующие директивы препроцессора (аналогичные директивам препроцессора в языке С):
#if
#ifdef
#defined
#endif
#elif
#define
Поскольку Flash Player работает на широком спектре оборудования, только часть языка Pixel Bender доступна для использования в Flash Player. Далее приведен перечень ограничений, накладываемых Flash Player'ом на использование языка Pixel Bender:
- Flash Player всегда работает с объектом размером 1х1 пиксел. Функция pixelSize() всегда возвращает (1.0, 1.0), а pixelAspectRatio() всегда возвращает 1.0.
- Оператор условного перехода (?:) может быть использован только для выбора между двумя константами или переменными.
- Изображения в Pixel Bender'е имеют 32 бита на канал, но графика в Flash Player 10 имеет только 8 бит на канал. Когда фильтр работает в Adobe Flash Player, данные исходного изображения преобразуются сначала в 32 бита на канал, а затем преобразуются в 8 бит на канал, когда фильтр завершает выполнение.
- Для изменения хода выполнения программы можно использовать только операторы if и else.
- Ниже приводится перечень неподдерживаемых возможностей языка:
- Функции для работы с регионами.
- Пользовательские функции и библиотеки.
- Зависимые значения.
- Массивы.
- Язык описания графов (Прим. пер.: в оригинале — The Pixel Bender graph language).
Синтаксис ядра
В каждой программе, написанной на Pixel Bender задается один блок кода, содержащий набор метаданных, заключенных в угловые скобки, и другой блок кода, описывающий ядро, набор переменных и выполняемые операции, заключенный в фигурные скобки.
<languageVersion : 1.0;>
kernel name
<
kernel metadata pairs
>
{
kernel members
}
Каждое ядро должно начинаться с указания версии языка, на которой пишется код.
Первая часть ядра определяет блок метаданных, состоящий из группы пар имя-значение, заключенный в угловые скобки:
<
name1 : value1;
name2 : value2;
...
>;
Следующие значения метаданных являются предопределенными:
namespace — Обязательно. Пространство имен, в котором определено ядро.
vendor — Обязательно. Издатель.
version — Обязательно. Целое число, номер версии реализации этого ядра. Это не тоже самое, что languageVersion (!).
description — Необязательно. Описание работы фильтра.
Например:
<
namespace : "Pixel Bender IDE";
vendor : "Adobe";
version : 1;
description: "A sample filter";
>
Вторая часть определения ядра представляет собой набор переменных и функций, заключенных в фигурные скобки. Ядро должно содержать по крайней мере определение функции evaluatePixel(), а все остальное является необязательным.
{
[declarations]
[support functions]
void evaluatePixel()
{
statements
}
}
Объявление переменных обычно содержат в себе объявление пикселов входного и выходного изображения. Также могут быть включены параметры и константы, которые будут использоваться в функциях.
Основная функция, evaluatePixel(), применяется для ввода изображений или изображения, над которым выполняется преобразование, результатом которого является один пиксел.
До определения функции evaluatePixel() могут быть (необязательно) описаны:
- Параметры:
parameter type name
<
name1 : value1;
name2 : value2;
...
>
Параметры задаются только для чтения, в пределах функции ядра. Параметры могут быть любого (доступного для использования в рамках Flash Player) типа, кроме изображений.
- Константы:
const type name=compile-time_expression;
Значения констант определяется во время компиляции.
- input:
input type name;
Изображение, используемое в качестве аргумента функции evaluatePixel(). Его тип должен быть image1, image2, image3, или image4.
- output:
output type name;
Набор пикселов, полученный в результате выполнения функции evaluatePixel(). Его тип должен быть pixel1, pixel2, pixel3, или pixel4.
Параметры метаданных
Параметры могут включать данные, которые описывают этот параметр или накладывают ограничения на его использование. Эти данные будут доступны внутри клиентских приложений после компиляции, и также помогают программисту решить, каким образом спроектировать пользовательский интерфейс, который бы позволял пользователям установить значение параметра.
Значения данных заключаются в угловые скобки, следующие за объявлением параметра.
parameter type name
<
name1 : value1;
name2 : value2;
...
>
Имена являются строками. Значения — константами любого допустимого типа Pixel Bender. Для типов int, float и bool определение типа происходит автоматически. Для других типов необъодимо определить константное значение допустимого типа (например: float2(1.0, -1.0 )) или строку ограниченную двойными кавычками. Например:
parameter int angle
<
minValue : 0;
maxValue : 360;
defaultValue : 30;
description : "measured in degrees";
>;
Этот параметр накладывает ограничения на возможные значения:
minValue — минимально допустимое значение
maxValue — максимально допустимое значение
defaultValue — значение по умолчанию
description — описание параметра, которое можно использовать в клиентском приложении в качестве подсказки.
Определение функции ядра
Определение функции ядра должно соответствовать этим условиям:
Все, кроме evaluatePixel(), является необязательным.
Синтаксис функции:
void evaluatePixel()
{
statements
}
Типы данных языка Pixel Bender
Pixel Bender является строготипизированным языком. Нет автоматических преобразований типов, за одним исключением: между векторными типами данных с плавающей точкой и типами данных матриц. Есть несколько типов данных, каждый из которых определен в пределах определенного набора операторов и собственных функций.
Pixel Bender поддерживает следующие базовые типы данных:
bool — логический тип данных
int — целое число
float — число с плавающей точкой
pixel1 — определяет значение одного канала изображения. Цифра «1» отличает данный тип данных от аналогичных ему, но определяющих значения нескольких каналов изображения. Паременная данного типа представлена числом с плавающей точкой и занимает 32 бита памяти.
Все эти типы данных могут участвовать в числовых операциях.
Преобразования между скалярными типами данных
Типы данных bool, int, и float могут быть преобразованы из одного в другой с помощью обычных правил в С-стиле:
type(expression)
Например:
int a = int(myfloat)
Тип данных pixel1 может быть взаимозаменяемым с типом данных float.
Примечание:
Тип данных int занимает 16 бит памяти (без учета знака), но его реализация может занимать и более 16 бит памяти. Можно совершать преобразования между типами int и float. Когда результат преобразования из типа int в тип float не может быть представлен как тип int, значение переменной становится неопределенным (undefined).
Векторные типы данных
Pixel Bender поддерживает 2-х, 3-х и 4-х элементные аналоги для каждого скалярного типа данных:
float2 bool2 int2 pixel2
float3 bool3 int3 pixel3
float4 bool4 int4 pixel4
Инициализация любого типа (включая пиксельный) представлена общей формой:
vectorType(element1 [, element2...])
Например:
float3(0.5, 0.6, 0.7)
Есть также сокращенный вариант записи (следующие выражения эквивалентны):
float3(0.3);
float3(0.3, 0.3, 0.3);
Вы можете получить доступ к значению векторной переменной по индексу или имени по следующим правилам:
- С помощью оператора индекса, как к элементу массива:
vectorValue[index]
- Используя точечную нотацию для доступа к элементам в этой последовательности:
r, g, b, a
x, y, z, w
s, t, p, q
Каждому из этих элементов соответсвует индекс от 0 до 3.
Например, чтобы получить значение первого элемента вектора myVectorValue, вы можете использовать любой из следующих вариантов записи:
myVectorValue[0]
myVectorValue.r
myVectorValue.x
myVectorValue.s
Выбор и переопределение значений элементов
Pixel Bender поддерживает свиззлинг для выбора и переопределения порядка следования элементов вектора. Для вектора с n-количеством элементов значения могут быть указаны следом за оператором точки. Соответствующие значения элементов вектора формируют новый результат с таким количеством элементов, как и у присваиваемой переменной. Этот синтаксис можно использовать для изменнения порядка следования, для удаления или повторения элементов вектора. Например:
float4 vec4;
float3 no_alpha = vec4.rgb; // исключен последний элемент вектора vec4
float3 no_r = vec4.gba; // исключен первый элемент вектора vec4
float4 reversed = vec4.abgr; // изменен порядок следования элементов
float4 all_red = vec4.rrrr; // повторение значения элемента
float4 all_x = vec4.xxxx; // аналогично предыдущему
Указатели из отдельных последовательностей не могут быть объединены:
float4 vec4;
float3 no_alpha = vec4.rgz; // Ошибка!
Указатели индексов также могут быть применены и в левой части выражения присваивания. В этом случае индексы не могут повторяться. Эта возможность используется для записи маскировки (Прим. пер.: в оригинале — write-masking). С правой стороны выражения присваивания должно быть правильное количество аргументов:
float3 vec3;
float2 vec2;
vec3.xy = vec2; // устанавливает значения элементов вектора vec2 элементам вектора vec3с индексами 0 и 1
vec3.xz = vec2; // устанавливает значения элементов вектора vec2 элементам вектора vec3с индексами 0 и 2
Взаимодействие:
Свиззлинг и запись маскировки могут быть использованы одновременно по обе стороны выражения присваивания:
vec3.xz = vec4.wy;
Существует вероятность появления сложностей между свиззлингом и операцией присваивания. Рассмотрим следующий пример:
g.yz *= g.yy;
Упрощенный вариант этой записи можно представить в следующем виде:
g.y *= g.y;
g.z *= g.y;
Проблема в том, что значение g.y во второй строке было изменено. Правильным решением была бы следующая запись:
float2 temp = g.yz * g.yy;
g.yz = temp;
Преобразования между векторными типами данных
Преобразования между векторными типами данных допустимы при условии, что размеры операндов присваивания равны. Само преобразование аналогично преобразованию между скалярными типами данных:
type(expression)
Например:
float3 fvec3;
int3 ivec3;
fvec3 = float3(ivec3);
Типы матриц
Есть следующие виды матриц:
float2x2
float3x3
float4x4
Создание матриц с помощью конструктора подразумевает использование векторов типа float для указания значений матриц, или указания значений скалярных переменных типа float для каждого элемента матрицы в порядке следования «столбец-ряд» или смеси из векторов и скалярных переменных типа float:
float2x2( float2, float2 )
float2x2( float, float,
float, float )
float3x3( float3, float3, float3 )
float3x3( float, float, float,
float, float, float,
float, float, float )
float4x4( float4, float4, float4, float4 )
float4x4( float, float, float, float,
float, float, float, float,
float, float, float, float,
float, float, float, float )
Вы также можете инициализировать матрицу одной скалярной переменной типа float, которая будет определять значения элементов матрицы на главной диагонали. Все остальные значения будут установлены в ноль:
float2x2( float )
float3x3( float )
float4x4( float )
Для получения доступа к значениям элементов матрицы используйте следующий синтаксис:
matrix[ столбец ][ ряд ]
Если опустить указание ряда, то выбирается целиком один столбец и возвращается переменная векторного типа подходящей размерности:
matrix[ столбец ]
Другие типы данных
Типы данных изображений.
Pixel Bender поддерживает также переменные типа image. Они представлены следующими типами данных:
image1
image2
image3
image4
Переменные данных типов не могут быть созданны или использованны в выражениях. Однако они могут быть переданы в качестве аргументов во встроенные функции языка.
Тип данных void.
Функции, которые не возвращают значений должны быть определены с типом void.
Операторы
Pixel Bender определяет следующие типы операторов для арифметических операций над скалярными типами данных. Здесь они указаны в порядке приоритета выполнения. Скобки могут быть использованы для изменения этого порядка:
. Выбор элемента переменной
++ — Постфиксные операторы инкремента и декремента
++ — Префиксные операторы инкремента и декремента
— ! Унарный оператор отрицания, логическое «НЕ»
* / Умножение, деление
+ — Сложение, вычитание
< > <= >= Сравнения
== != Равенство
&& Логическое «И»
^^ Логическое «ИСКЛЮЧАЮЩЕЕ ИЛИ»
|| Логическое «ИЛИ»
= += -= *= /= Группировка операторов
?: Краткая запись операторов ветвления. Данный оператор может быть использован только для выбора между двумя переменными или константами (с правой стороны), но не выражений.
Операции над типами данных с несколькими элементами
Стандартные арифметические операторы (+, -, *, /) могут быть использованы как для операций над скалярными, так и над векторными и матричными типами данных. Бинарный оператор может быть применен к двум векторным операндам только в том случае, если они имеют одинаковый размер. В этом случае операция выполняется для каждого элемента вектора. Например:
float3 x, y, z;
z = x + y;
Эта запись эквивалентна следующей:
z[ 0 ] = x[ 0 ] + y[ 0 ];
z[ 1 ] = x[ 1 ] + y[ 1 ];
z[ 2 ] = x[ 2 ] + y[ 2 ];
Группировка скалярных и векторных паременных также допустима. Например:
float3 x, y;
float w;
x = y * w;
Эта запись эквивалентна следующей:
x[ 0 ] = y[ 0 ] * w;
x[ 1 ] = y[ 1 ] * w;
x[ 2 ] = y[ 2 ] * w;
Важным исключением из этого правила является перемножение матриц между собой и матриц с векторными переменными. Перемножение осуществляется по правилам линейной алгербы (а не покомпонентно):
float2x2 * float2x2 Перемножние матриц по правилам линейной алгебры
float3x3 * float3x3
float4x4 * float4x4
float2x2 * float2 Перемножение столбцов на вектор
float3x3 * float3
float4x4 * float4
float2 * float2x2 Перемножение рядов на вектор
float3 * float3x3
float4 * float4x4
Встроенные функции языка Pixel Bender
Математические функции:
Как и арифметические операторы, математические функции могут выполняться над векторными типами данных. В этом случае они работают покомпонентно. Если не определено иное, то все углы указаны в радианах.
float radians( float degrees ) Преобразование градусов в радианы
float2 radians( float2 degrees )
float3 radians( float3 degrees )
float4 radians( float4 degrees )
float degrees( float radians ) Преобразование радианов в градусы
float2 degrees ( float2 radians )
float3 degrees ( float3 radians )
float4 degrees ( float4 radians )
float sin( float radians ) Возвращает синус аргумента
float2 sin( float2 radians )
float3 sin( float3 radians )
float4 sin( float4 radians )
float cos( float radians ) Возвращает косинус аргумента
float2 cos( float2 radians )
float3 cos( float3 radians )
float4 cos( float4 radians )
float tan( float radians ) Возвращает тангенс аргумента. Если x==pi/2.0 возвращается undefined
float2 tan( float2 radians )
float3 tan( float3 radians )
float4 tan( float4 radians )
float asin( float x ) Возвращается арксинус аргумента. Возвращаемое значение находится в диапазоне [-pi/2..pi/2]
float2 asin( float2 x )
float3 asin( float3 x )
float4 asin( float4 x )
float acos( float x ) Возвращает арккосинус аргумента. Возвращаемое значение находится в диапазоне [0..pi]
float2 acos( float2 x )
float3 acos( float3 x )
float4 acos( float4 x )
float atan( float y_over_x ) Возвращает арктангенс аргумента. Возвращаемое значение находится в диапазоне [-pi/2..pi/2]
float2 atan( float2 y_over_x)
float3 atan( float3 y_over_x)
float4 atan( float4 y_over_x)
float atan( float y, float x ) Возвращает арктангенс выражения y / x. Возвращаемое значение находится в диапазоне [-pi..pi]
float2 atan( float2 y, float2 x )
float3 atan( float3 y, float3 x )
float4 atan( float4 y, float4 x )
float pow( float x, float y ) Возвращает x в степени y и undefined если х < 0
float2 pow ( float2 x, float2 y )
float3 pow ( float3 x, float3 y )
float4 pow ( float4 x, float4 y )
float exp( float x ) Возвращает e в степени х (Прим. пер.: не помню как называется эта величина:))
float2 exp( float2 x )
float3 exp( float3 x )
float4 exp( float4 x )
float exp2( float x ) Возвращает 2 в степени х
float2 exp2( float2 x )
float3 exp2( float3 x )
float4 exp2( float4 x )
float log( float x ) Возвращает натуральный логарифм числа х
float2 log( float2 x )
float3 log( float3 x )
float4 log( float4 x )
float log2( float x ) Возвращает натуральный логарифм числа х с основанием 2
float2 log2( float2 x )
float3 log2( float3 x )
float4 log2( float4 x )
float sqrt( float x ) Возвращает положительный квадратный корень числа х и undefined если х < 0
float2 sqrt( float2 x )
float3 sqrt( float3 x )
float4 sqrt( float4 x )
float inverseSqrt( float x ) Возвращает обратное положительному квадратному корню от числа х и undefined если х < 0
float2 inverseSqrt( float2 x )
float3 inverseSqrt( float3 x )
float4 inverseSqrt( float4 x )
float abs( float x ) Если x >= 0, возвращает x, иначе возвращает -x
float2 abs( float2 x )
float3 abs( float3 x )
float4 abs( float4 x )
float sign( float x ) Если x < 0, возвращает -1
float2 sign( float2 x ) Если x == 0, возвращает 0
float3 sign( float3 x ) Если x > 0, возвращает 1
float4 sign( float4 x )
float floor( float x ) Округляет х в меньшую сторону (возвращает целое число)
float2 floor( float2 x )
float3 floor( float3 x )
float4 floor( float4 x )
float ceil( float x ) Округляет х в большую сторону (возвращает целое число)
float2 ceil( float2 x )
float3 ceil( float3 x )
float4 ceil( float4 x )
float fract( float x ) Возвращает x – floor(x)
float2 fract( float2 x )
float3 fract( float3 x )
float4 fract( float4 x )
float mod( float x, float y ) Возвращает x – y * floor(x/y)
float2 mod( float2 x, float2 y )
float3 mod( float3 x, float3 y )
float4 mod( float4 x, float4 y )
float min( float x, float y ) Если х < y возвращает х, иначе возвращает у
float2 min( float2 x, float2 y )
float3 min( float3 x, float3 y )
float4 min( float4 x, float4 y )
float max( float x, float y ) Если х > у, возвращает х, иначе возвращает у
float2 max( float2 x, float2 y )
float3 max( float3 x, float3 y )
float4 max( float4 x, float4 y )
float step( float x, float y ) Если у < х, возвращает 0.0, иначе возвращает 1.0
float2 step( float2 x, float2 y )
float3 step( float3 x, float3 y )
float4 step( float4 x, float4 y )
float clamp(float x, float minval, float maxval) Если x < minval, возвращает minval. Если x > maxval, возвращает maxval. Иначе возвращает x.
float2 clamp(float2 x, float2 minval, float2 maxval)
float3 clamp(float3 x, float3 minval, float3 maxval)
float4 clamp(float4 x, float4 minval, float4 maxval)
float mix(float x, float y, float a) Возвращает x * (1.0 — a) + y * a (это линейная интерполяция между x и y).
float2 mix(float2 x, float2 y, float2 a)
float3 mix(float3 x, float3 y, float3 a)
float4 mix(float4 x, float4 y, float4 a)
float smoothStep(float edge0, float edge1, float x) Если x <= edge0, возвращает 0. Если x >= edge1, возвращает 1, иначе выполняется сглаженная интерполяция (Прим. пер.: в оригинале — smooth hermite interpolation).
float2 smoothStep(float2 edge0, float2 edge1, float2 x)
float3 smoothStep(float3 edge0, float3 edge1, float3 x)
float4 smoothStep(float4 edge0, float4 edge1, float4 x)
Геометрические функции:
Эти функции работают с векторами как с целым объектом, а не рассматривают каждый элемент вектора, как отдельный.
float length(float x) Возвращает длину вектора х
float length(float2 x)
float length(float3 x)
float length(float4 x)
float distance(float x, float y) Возвращает расстояние между х и у
float distance(float2 x, float2 y)
float distance(float3 x, float3 y)
float distance(float4 x, float4 y)
float dot(float x, float y) Возвращает скалярное произведение х на у
float dot(float2 x, float2 y)
float dot(float3 x, float3 y)
float dot(float4 x, float4 y)
float3 cross(vector3 x, vector3 y) Возвращает векторное произведение х на у
float normalize(float x) Возвращает вектор с тем же направлением, что и х, но с длиной равной 1 и undefined если length(x) == 0
float2 normalize(float2 x)
float3 normalize(float3 x)
float4 normalize(float4 x)
Эти функции выполняют покомпонентное перемножение (в отличие от оператора *, который выполняет алгебраическое перемножение матриц):
float2x2 matrixCompMult(float2x2 x, float2x2 y) Возвращает покомпонентное перемножение х на у
float3x3 matrixCompMult(float3x3 x, float3x3 y)
float4x4 matrixCompMult(float4x4 x, float4x4 y)
Эти функции сравнивают вектора покомпонентно и возвращают булево значение той же размерности (соблюдая порядок сравнения):
bool2 lessThan(int2 x, int2 y) Возвращает покомпонентное сравнение x < y
bool3 lessThan(int3 x, int3 y)
bool4 lessThan(int4 x, int4 y)
bool2 lessThan(float2 x, float2 y)
bool3 lessThan(float3 x, float3 y)
bool4 lessThan(float4 x, float4 y)
bool2 lessThanEqual(int2 x, int2 y) Возвращает покомпонентное сравнение x <= y
bool3 lessThanEqual(int3 x, int3 y)
bool4 lessThanEqual(int4 x, int4 y)
bool2 lessThanEqual(float2 x, float2 y)
bool3 lessThanEqual(float3 x, float3 y)
bool4 lessThanEqual(float4 x, float4 y)
bool2 greaterThan(int2 x, int2 y) Возвращает покомпонентное сравнение x > y
bool3 greaterThan(int3 x, int3 y)
bool4 greaterThan(int4 x, int4 y)
bool2 greaterThan(float2 x, float2 y)
bool3 greaterThan(float3 x, float3 y)
bool4 greaterThan(float4 x, float4 y)
bool2 greaterThanEqual(int2 x, int2 y) Возвращает покомпонентное сравнение x >= y
bool3 greaterThanEqual(int3 x, int3 y)
bool4 greaterThanEqual(int4 x, int4 y)
bool2 greaterThanEqual(float2 x, float2 y)
bool3 greaterThanEqual(float3 x, float3 y)
bool4 greaterThanEqual(float4 x, float4 y)
bool2 equal(int2 x, int2 y) Возвращает покомпонентное сравнение x == y
bool3 equal(int3 x, int3 y)
bool4 equal(int4 x, int4 y)
bool2 equal(float2 x, float2 y)
bool3 equal(float3 x, float3 y)
bool4 equal(float4 x, float4 y)
bool2 equal(bool2 x, bool2 y)
bool3 equal(bool3 x, bool3 y)
bool4 equal(bool4 x, bool4 y)
bool2 notEqual(int2 x, int2 y) Возвращает покомпонентное сравнение x != y
bool3 notEqual(int3 x, int3 y)
bool4 notEqual(int4 x, int4 y)
bool2 notEqual(float2 x, float2 y)
bool3 notEqual(float3 x, float3 y)
bool4 notEqual(float4 x, float4 y)
bool2 notEqual(bool2 x, bool2 y)
bool3 notEqual(bool3 x, bool3 y)
bool4 notEqual(bool4 x, bool4 y)
Эти функции работают только с векторами логического типа:
bool any(bool2 x) Возвращает истину если хотя бы один элемент х является истинным
bool any(bool3 x)
bool any(bool4 x)
bool all(bool2 x) Возвращает истину если все элементы х являются истинными
bool all(bool3 x)
bool all(bool4 x)
bool2 not(bool2 x) Возвращает результат поэлементного логического отрицания
bool3 not(bool3 x)
bool4 not(bool4 x)
P.S.: Это мой первый пост на Хабре. Прошу сильно не пинать;)