Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
калачева перевод.docx
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
237.97 Кб
Скачать

Заявления

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

Арифметические операции

Ни один текст, описывающий язык не может считаться полным без обязательной таблицы операторов (см. Таблицу 2.6). Операторы перечислены в убывающем порядке предшествования. В целом, типы, которыми оперируют должны такими же, а для векторов и матриц операнды должны быть того же измерения. В таблице, интегральные типы включают int и uinit и их векторы, типы с плавающей запятой включают float и double, и их векторы и матрицы, arithmetic типы включают все интегральные и с плавающей запятой, а any дополнительно включают массивы и структуры.

Перегруженные операторы

Большинство операторов в GLSL - перегруженные, что означает, что они оперируют различными наборами данных. Точнее, арифметические операции (в том числе, пред- и пост-инкремента и -декремента) для векторов и матриц хорошо описаны в GLSL. Например, для умножения вектора и матрицы (помните, что последовательность операнд важна; умножение матриц некоммутативно, для вашего сведения), используйте следующию операцию:

vec3 v;

mat3 m;

vec3 result = v * m;

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

vec2 a, b, c;

mat2 m, u, v;

c = a * b; // c = (a.x*b.x, a.y*b.y)

m = u * v; // m = (u00*v00+u01*v10 u00*v01+u01*v11

// u01*v00+u11*v10 u10*v01+u11*v11)

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

Таблица 2.6 GLSL операторы и их предшествование

Предшеств. Операторы Приемл. типы Описание

1 ( ) --- Группировка операций

2 [ ] arrays, matrices, vectors Нижняя индексация массивов

f( ) functions Запросы функций и конструкторов

. (period) structures Доступ к полям функций или методов

++ -- arithmetic Пост-инкремент и -декремент

3 ++ -- arithmetic Пре-инкремент и -декремент

+ - arithmetic Унарный позитив или отрицание

~ integer Унарный по-битовый not

! bool Унарный логический not

4 * / % arithmetic Операции умножения

5 + - arithmetic Операции сложения

6 << >> integer По-битовые операции

7 < > <= >= arithmetic Рациональные операции

8 == != any Операции равенств

9 & integer По-битовый and

10 ^ integer Bit-wise exclusive or

11 | integer Bit-wise inclusive or

12 && bool Logical and operation

13 ^^ bool Logical exclusive-or operation

14 || bool Logical or operation

15 a ? b : c bool ? any : any Ternary selection operation (inline ‘‘if’’

operation; if (a) then (b) else (c))

16 = any Назначение

+= -= arithmetic Арифметическое назначение

*= /= arithmetic

%= <<= >>= integer

&= ^= |= integer

17 , (comma) any Последовательность операций

Управление потоками

Логические структуры контроля в GLSL это популярные if-else и swtich операторы. Как и на “С”, раздел else - необязательный и разные операторы требуют отдельный блок.

if (truth) {

// true clause

}

else {

// false clause

}

Похоже тому, как это происходит на “С”, операторы switch доступны в знакомом виде (начиная с GLSL 1.30):

switch (int_value) {

case n:

// statements

break;

case m:

// statements

break;

default:

// statements

break;

}

Switch операторы GLSL также принимают операторы выбора “fall-through”, это такие, в которые не оканчиваются разрывом. Каждый выбор требует исполнения оператора до окончания switch (до зарывающей скобки). Также, в отличае от С++, ни один оператор не может стоять перед оператором выбора. Если switch не соответствует ни одного выбора, и ярлык по умолчанию присутствует, тогда его выполняют.

Циклические структуры

GLSL поддерживает знакомые по “С” типы for, while и do … while циклы.

Цикл ofr позволяет заявку переменной шага цикла в начальном блоке цикла. Шаг цикла заявленный таким образом действитетлен только внутри цикла.

declared in this manner is only for the lifetime of the loop.

for (int i = 0; i < 10; ++i) {

...

}

while (n < 10) {

...

}

do {

...

} while (n < 10);

Операторы контроля потока

Дополнительные операторы контроля доступны в GLSLю Таблица 2.7 перечисляет доступные операторы контроля потока.

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

Table 2.7 GLSL операторы контроля потока

Statement Description

break Обрывает исполнение блока цикла, и продолжает исполнеие кода за ним

continue Обрывает текущий шаг цикла охватывающий блок цикла, начиная со

следующего шага цикла

return [result] Возвращается из текущей подпрограммы, при необходимости указывая

значения для возврата из функции (при условии, что это значение соответствует типу возврата охватываемой функции)

discard Отсеивает текущий фрагмент и останавливает исполнение шейдера.

Оператор discard действителен только в программах фрагментного шейдера.

Функции

Функции позволяют вам заместить выполнение обычного кода запросом функции. Это, конечно, позволяет сократить код, уменьшив вероятность возникновения ошиюки. GLSL определяет некоторое количество встроенных функций, которые перечислены в Appendix C, а также работает с определяемыми пользователем функциями. Функции, определяемые пользователем могут быть определены в единые объект шейдера для последующего применения в разных шейдерах.

Определения

Синтаксис определения функий очень похож на “С”, с разницой в модификаторах доступа к переменным:

returnType functionName([accessModifier] type1 variable1,

[accessModifier] type2 varaible2,

...)

{

// function body

return returnValue; // unless returnType is void

}

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

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

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

Функции должны быть или заданы по прототипу, или определаться в своем body, до того, как будут запрошены. Точно также как в С++, компилятор должен видет определение функции до того как она будет применена, иначе произойдет ошибка. Если функция используется объектом шейдера, отличным от того, где она определена, необходимо заявить прототип. Прототип это лишь заголовок функции без всего её body. Вот пример прототипа:

float HornerEvalPolynomial(float coeff[10], float x);

Квалификаторы параметров

Хотя функции GLSL и могут изменять и возвращать значения после своего выполнения, в них нет понятия указателя или отсылки, как в “С” и С++. Вместо этого, параметры функций имеют ассоциированные с ними квалификаторы параметров, которые указывают, далжны ли данные копироваться из или в функцию по ее исполнении. Таблица 2.8 перечисляет доступные в GLSL квалификаторы параметров.

Таблица 2.8 GLSL Модификаторы доступа к параметрам функций

Модификатор Описание

in Значение, копируемое в функцию (умолчание, если не указано иначе)

const in Значение только для чтения

out Значение копируемое из функции (неопределенное при попадании в функцию)

inout Значение копируемое и в, и из функции

Ключевое слово in необязательно, так как если переменная не имеет при себе модификатора доступа, она по умолчанию будет распознаваться как in. Однако, если значение переменной нужно вывести из функции, необходимо добавить обозначение модификатора out (для данных только вывода) или inout (для ввода-вывода). Запись в переменную не определенную одним из этих модификаторов приведет к ошибке при компиляции.

Дополнительно, для проверки при компиляции, не изменяет ли функция переменную только для ввода, можно добавить модификатор “const in”, который даст компилятору команду не вписывать данную переменную в функцию. Если этого не сделать и записать в функцию переменную только для чтения, это повлияет только на локальную копию в функции.