Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







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





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) {

casen:

// statements

break;

casem:

// 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(inti = 0; i < 10; ++i) {

...

}

while(n < 10) {

...

}

do{

...

} while(n < 10);

 

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

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

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

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

Statement Description

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

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

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

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

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

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

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

 

Функции

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

 

Определения

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

returnType functionName([accessModifier] type1 variable1,

[accessModifier] type2 varaible2,

...)

{

// function body

returnreturnValue; // unless returnType is void

}

 

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

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

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

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

floatHornerEvalPolynomial(floatcoeff[10], floatx);

 

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

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

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

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

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

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

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

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

 

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

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

 

Вычислительная инвариантность

GLSL не гарантирует, что два идентичных вычисления в разных шейдерах дадут одинаковые результаты. Это ничем не отличается от того, как работают вычислительные приложения в ПК, когда оптимизация выбора может привести к микро-отличиям в результатах. Такие маленькие нестыковки могут создать трудности при многопроходных алгоритмах, для которых необходима постоянность производимых вычислений для каждого шейдера. В GLSL есть два метода закрепления инвариантности между шейдерами, доступные по командам invariant или precise.

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

uniform floatten; // application sets this to 10.0

const floatf = sin(10.0); // computed on compiler host

floatg = sin(ten); // computed on graphics device

voidmain()

{

if(f == g) // f and g might be not equal

;

}

В этом примере, не имеет значения, применялись ли invariant или precise к использованным переменным, так как они влияют только на 2 вычисления в графическом оборудовании.

 

Квалификатор invariant

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

Переменная вывода заявленная в invariant может быть как встроенной переменной, так и определяемой пользователем. Например:

invariantgl_Position;

invariant centroid out vec3Color;

 

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

Для отладки, возможно удобнее применить invariant ко всем изменяемым переменным в шейдере. Это можно сделать с помощью процессорного деректива вершинного шейдера.

#pragmaSTDGL invariant(all)

Глобальная инвариантность такого рода удобна для отладки, однако, скорее всего скажется на производительности шейдера. Для гарантирования инвариантности обычно требуется отключение оптимизаций, которые мог бы произвести компилятор GLSL.

 

Квалификатор precise

Квалификатор precise может применяться к любой вычисленной переменной или возвратному значению функции. Несмотря на свое название, его функция не заключается в повышении точности, а скорее в повышении воспроизводимости вычисления. В основном он используется в мозаичных шейдерах, для предотвращения появления зазоров в геометрии. Основы мозаичного шейдера описаны в Главе 9, “Мозаичные шейдеры”, также дополнительно там описывается применение квалификатора precise.

В общих чертах, о применение precise вместо invariant можно сказать, что когда вам нужно получить одинаковый результат из выражения, даже если значения в этом выражении изменяются так, что это не влияет математически на результат. Например, следующее выражение должно иметь один и тот же результат, даже если значения a и b переставить местами, и если переставить c и d? и даже если поменять местами значения a и c, и b и d, и т.д.

Location = a * b + c * d;

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

precisegl_Position;

precise out vec3Location;

precise vec3subdivide(vec3P1, vec3P2) { ... }

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

Особенностью использования precise при компиляции является то, что выражения (как то, что выше) не может быть вычислено двумя разными способами умножения для двух операций умножения. Например, инструкция для первого умножения и комбинации умножение-сложение для второго. Потому что эти инструкции дадут немного разные результаты для одинаковых значений. Поскольку это стало недопустимым с использованием precise, компилятор не сможет это сделать. Но поскольку применение умножения-сложения важно для исполнительности, было бы нежелательно запретить их полностью. Поэтому есть встроенная функция fma(), которая четко говорит, что это допустимо.

precise out floatresult;

...

floatf = c * d;

floatresult = fma(a, b, f);

Конечно её стоит использовать только в том слаче, если вы не хотите перестановки a и c, иначе использование precise потеряет смысл.

 

Процессор шейдера

Первым шагом в компиляции шейдера на GLSL является синтаксический анализ предпроцессором. Схоже тому как работает предпроцессор “С”, есть некоторое количество указаний по созданию условных компиляционных блоков и определению переменных. Однако в отличие от предпроцессора “С”, не существует включения файлов (#include).

 

Указания предпроцессора

Таблица 2.9 перечисляет указания, принимаемые GLSL предпроцессором и их функции.

Таблица 2.9GLSL указания предпроцессора









Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2018 zdamsam.ru Размещенные материалы защищены законодательством РФ.