08 - Программирование с использованием шейдеров

0

No comments posted yet

Comments

Slide 1

Программирование с использованием шейдеров

Slide 2

Кратко об OpenGL OpenGL – развитие программного интерфейса IrisGL фирмы Silicon Graphics, Inc. Цель создания библиотеки - обеспечение низкоуровневого доступа к возможностям графического аппаратного обеспечения, не теряя платформенной независимости

Slide 3

Хронология событий 1992г. - Open GL 1.0 1997г. – Open GL 1.1 Появились текстурные объекты и массивы вершин 1998г. – Open GL 1.2 3D-текстуры и функции обработки изображений 2001г. – OpenGL 1.3 Кубические текстуры, сжатые текстуры, мультитекстурирование 2002г. – OpenGL 1.4 Автоматическое генерирование mip-уровней текстур, доп. функции смешивания, depth-текстуры, рисование множественных массивов вершин одной командой 2003г. – OpenGL 1.5 Vertex Buffer Objects, Shadow mapping comparison functions, Occlusion queries, Non-Power-of-Two textures

Slide 4

Open GL 2.0 Опубликован в 2004 году Основное нововведение – высокоуровневой язык шейдеров GLSL (OpenGL Shading Language), предоставляющих приложениям возможность реализации собственных механизмов рендеринга при помощи замены стандартных обработчиков вершин и фрагментов

Slide 5

Диаграмма работы стандартного конвейера OpenGL Основные этапы работы стандартного графического конвейера OpenGL Обработка вершин Трансформация вершин и нормалей Расчет освещения в вершинах Генерирование текстурных координат Обработка примитивов Сборка примитивов Отсечение Проецирование вершин Обработка фрагментов Растеризация примитивов, наложение текстур Операции над пикселями

Slide 6

Что такое шейдер? Шейдер (англ. – shader) – целостный кусок кода на языке шейдеров, предназначенный для выполнения на одном из программируемых процессоров В OpenGL 2.0 введены два типа шейдеров Вершинные шейдеры Фрагментные шейдеры

Slide 7

Для чего нужны шейдеры? OpenGL предоставляет программистам гибкий, но статический интерфейс для рисования графики Шейдеры позволяют приложению переопределить стандартный способ обработки графики на некоторых этапах рендеринга С помощью шейдеров стало возможным применение продвинутых технологий рендеринга в реальном времени

Slide 8

Вершинный процессор Это программируемый модуль, который выполняет операции над входными значениями вершин и другими связанными с ними данными. Вершинный процессор выполняет: Преобразование вершин Преобразование и нормализация нормалей Генерирование и преобразование текстурных координат Настройка освещения Наложение цвета на материал

Slide 9

Входные и выходные данные вершинного процессора Вершинный процессор Встроенные переменные атрибутов: gl_Color, gl_Normal, gl_Vertex, gl_MultiTexCoord0 и др. Определенные пользователем переменные атрибутов: StartColor, Velocity, Elevation, Tangent и т.п. Определенные пользователем uniform-переменые: Time, EyePosition, LightPosition и т.п. Встроенные uniform-переменые: gl_ModelViewMatrix, gl_FrontMaterial, gl_LightSource[0..n], gl_Fog и т.п. Встроенные varying-переменные: gl_FrontColor, gl_BackColor, gl_FogFragCoord и др. Специальные выходные переменные: gl_Position, gl_PointSize, gl_ClipVertex Определенные пользователем varying-переменные: Normal, ModelCoord, RefractionIndex, Density и т.п. Карты текстур

Slide 10

Uniform-переменные Используются для передачи редко изменяемых данных как вершинному, так и фрагментному шейдеру Uniform-переменные не могут задаваться между вызовами glBegin() и glEnd() OpenGL поддерживает как встроенные, так и определенные пользователем uniform-переменные Для передачи значения uniform-переменной приложение должно сначала определить расположение данной переменной (индекс) по имени

Slide 11

Attribute-переменные вершинного шейдера Представляют собой данные, передаваемые вершинному шейдеру от приложения Могут задавать значения атрибутов либо между glBegin()/glEnd(), либо при помощи функций, работающих с вершинными массивами OpenGL поддерживает как встроенные, так и определенные пользователем attribute-переменные gl_Normal, gl_Vertex, gl_Color

Slide 12

Varying-переменные Данные в varying-переменных передаются из вершинного шейдера в фрагментный Бывают как встроенными, так и определенными пользователем Для каждой вершины значение соответствующей varying-переменной будет своим В процессе растеризации происходит интерполяция значений varying-переменных с учетом перспективы

Slide 13

Фрагментный процессор Это программируемый модуль, выполняющий операции над фрагментами и другими связанными с ними данными ФП выполняет следующие стандартные операции: Операции над интерполируемыми значениями Доступ к текстурам Наложение текстур Создание эффекта тумана Смешивание цветов

Slide 14

Входные и выходные данные фрагментного процессора Фрагментный процессор Встроенные varying-переменные: gl_Color, gl_SecondaryColor, gl_TexCoord[0..n], gl_FogFragCoord Специальные входные переменные: gl_FragCoord gl_FrontFacing Определенные пользователем varying-переменные: Normal, ModelCoord, RefractionIndex, Density и т.п. Специальные выходные переменные: gl_FragColor gl_FragDepth Определенные пользователем uniform-переменные: ModelScaleFactor, AnimationPhase, WeightingFactor и т.п. Карты текстур Встроенные uniform-переменые: gl_ModelViewMatrix, gl_FrontMaterial, gl_LightSource[0..n], gl_Fog и т.п.

Slide 15

Фрагментный процессор не заменяет следующие операции: Покрытие Проверка на видимость Отсечение по прямоугольнику (scissors test) Тест трафарета Тест прозрачности Тест глубины Отсечение по трафарету Смешивание цветов Логические операции Dithering Определение видимости плоскостей

Slide 16

Входные данные фрагментного процессора Встроенные varying-переменные Определенные разработчиком varying-переменные Имена и типы должны совпадать с именами varying-переменных, определенных в вершинном шейдере Встроенные uniform-переменные Определенные разработчиком uniform-переменные

Slide 17

Язык программирования шейдеров GLSL

Slide 18

Цели, преследуемые языком шейдеров OpenGL Обеспечение хорошей совместимости с OpenGL Использование гибкости графических ускорителей ближайшего будущего Предоставление независимости от графического ускорителя Увеличение производительности Легкость использования Обеспечение актуальности языка в будущем Невмешательство в более высокие уровни параллельной обработки Легкость разработки программ

Slide 19

Совместимость с OpenGL Язык GLSL разработан для использования совместно с OpenGL Предоставляются программируемые альтернативы стандартной функциональности OpenGL Язык и программируемые им процессоры имеют как минимум ту же функциональность, какую они заменяют Доступ к текущим состояниям OpenGL

Slide 20

Использование гибкости акселераторов ближайшего будущего Язык предоставляет необходимый уровень абстракции для данной предметной области Поддержка большого количества операций над скалярными и векторными величинами Исчезла необходимость развитие частичных расширений функциональности OpenGL

Slide 21

Независимость от графического ускорителя Предшествующие расширения закончились созданием интерфейсов на языке ассемблера Ухудшает переносимость программ Высокоуровневой язык обеспечивает уровень абстракции, достаточный для переносимости Производители ускорителей используют гибкость языка для внедрения новейших архитектур и технологий компиляции

Slide 22

Увеличение производительности Современные компиляторы высокоуровневых языков генерируют код, практически не уступающий по производительности вручную написанному коду Высокоуровневой код может с легкостью компилироваться в более компактный и быстрый код, учитывающий возможности современных графических процессоров Для кода на языке ассемблера может потребоваться переписывание кода

Slide 23

Легкость использования Легкость освоения языка программистами, знакомыми с Си и Си++ Язык для программируемых процессоров (в т.ч. и будущих) должен быть один и очень простой

Slide 24

Актуальность языка в будущем При разработке GLSL были приняты во внимание особенности ранее созданных языков, таких как C и RenderMan Язык тщательно стандартизован Ожидается, что ранее написанные программы будут актуальны и через 10 лет

Slide 25

Невмешательство в более высокие уровни параллельной обработки Современные графические ускорители выполняют параллельную обработку вершин и фрагментов Язык проектировался с учетом возможного распараллиливания обработки на более высоких уровнях

Slide 26

Легкость разработки программ Язык шейдеров GLSL не поддерживает указатели и ссылки, параметры передаются по значению Нет проблемы с алиасингом Облегчается работа оптимизирующего компилятора

Slide 27

Связь с языком C Точка входа в шейдерную программу – функция void main(), с кодом внутри фигурных скобок Константы, идентификаторы, операторы, выражения и предложения имеют много общего с языком C Циклы, ветвление, вызовы функций также аналогичны с языком C Многострочные комментарии

Slide 28

Дополнение к языку C Векторные типы данных для чисел с плавающей запятой, целых и булевых значений 2-х, 3-х и 4-х мерные векторы Матричные типы данных для чисел с плавающей запятой Матрицы 2x2, 3x3 и 4x4 Дискретизаторы (sampler-ы) для доступа к текстурам Спецификаторы attribute, uniform и varying входных и выходных переменных Встроенные переменные состояния OpenGL Начинаются с префикса gl_- gl_FragColor, gl_Position Множество встроенных функций, необходимых

Slide 29

Дополнения к языку из C++ Перегрузка функций Конструкторы Объявление переменных в произвольном месте программы, а не только в начале блока Тип bool Однострочные комментарии Функции должны быть объявлены до их первого использования одним из следующих способов Определением тела функции Объявлением прототипа

Slide 30

Не поддерживаемые возможности C Отсутствие неявного приведения типов float f = 0; // ошибка float f = 0.0; // правильно Нет поддержки указателей, строк, символов и операций над ними Нет чисел с плавающей запятой двойной точности Нет коротких, длинных и беззнаковых целых Нет union, enum и побитовых операторов Язык не файловый Нет директив типа #include и других ссылок на имена файлов

Slide 31

Прочие отличия Вместо операторов приведения типов используются конструкторы Входные и выходные параметры функций передаются по значению Входные параметры функции обозначаются in Выходные параметры – out Входные и выходные одновременно – inout

Slide 32

Пример простейшего вершинного шейдера void main() { /* то же самое, что и gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; но обеспечивает инвариантность преобразования координат */ gl_Position = ftransform(); gl_FrontColor = gl_Color; }

Slide 33

Пример простейшего фрагментного шейдера void main() { gl_FragColor = gl_Color; }

Slide 34

Загрузка, компиляция и компоновка шейдерных программ

Slide 35

Модель подготовки OpenGL-шейдеров Приложение Исходный код шейдера Компилятор Объектный код шейдера Компоновщик Объектный код программы Графический ускоритель OpenGL API

Slide 36

Шаг 1 – создание шейдерного объекта Для начала необходимо создать шейдерный объект (структура данных драйвера OpenGL для работы с шейдером) Для создания шейдерного объекта служит функция glCreateShaderObjectARB Возвращенный данной функцией объект имеет тип GLhandleARB и используется приложением для дальнейшей работы с шейдерным объектом

Slide 37

Пример создания шейдера // создание вершинного шейдера GLhandleARB vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); // создание фрагментного шейдера GLhandleARB fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);

Slide 38

Шаг 2 – загрузка исходного кода шейдера в шейдерный объект Исходный код шейдера – массив строк, состоящих из символов Каждая строка может состоять из нескольких обычных строк, разделенных символом конца строки Для передачи исходного кода приложение должно передать массив строк в OpenGL при помощи glShaderSourceARB

Slide 39

Пример загрузки исходного кода в шейдерный объект const GLcharARB shaderSource1[] = “исходный код шейдера - начало”; const GLcharARB shaderSource2[] = “исходный код шейдера - окончание”; GLcharARB const * shaderSources[] = { shaderSource1, shaderSource2 }; glShaderSourceARB(vertexShader, 2, shaderSources, NULL); const GLcharARB shaderSource1[] = “исходный код шейдера - начало”; const GLcharARB** pShaderSource = &shaderSource; glShaderSourceARB(vertexShader, 1, pShaderSource, NULL); В случае, когда исходный код находится в одной строке, задача слегка упрощается:

Slide 40

Шаг 3 – компиляция шейдерного объекта Компиляция шейдерного объекта преобразует исходный код шейдера из текстового представления в объектный код Скомпилированные шейдерные объекты могут быть в дальнейшем связаны с программным объектом, для ее дальнейшей компоновки Компиляция шейдерного объекта осуществляется при помощи функции glCompileShaderARB

Slide 41

Пример компиляции шейдерного объекта glCompileShaderARB(shader); // проверяем успешность компиляции GLint compileStatus; glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus); if (compileStatus != GL_TRUE) { printf(“Shader compilation error”); return 0; }

Slide 42

Шаг 4 – создание программного объекта Программный объект включает в себя один или более шейдеров и заменяет собой часть стандартной функциональности OpenGL Программный объект создается при помощи функции glCreateProgramObjectARB Возвращенный данной функцией программный объект имеет тип GLhandleARB и может быть использован для дальнейшей работы с программным объектом

Slide 43

Пример создания программного объекта GLhandleARB program = glCreateProgramObjectARB();

Slide 44

Шаг 5 – связывание шейдерных объектов с программным объектом Приложение может использовать несколько программных объектов, собранных из разных шейдеров Для указания OpenGL, какие шейдеры с данной программой используются, служит функция glAttachObjectARB, выполняющая присоединение шейдерного объекта к программному объекту

Slide 45

Пример связывания шейдерных объектов с шейдерной программой GLhandleARB program; GLhandleARB vertexShader; GLhandleARB fragmentShader; // … glAttachObjectARB(program, vertexShader); glAttachObjectARB(program, fragmentShader);

Slide 46

Шаг 6 – компоновка шейдерной программы После связывания скомпилированных шейдерных объектов с программным объектом программу необходимо скомпоновать Скомпонованный программный объект можно использовать для включения в процесс рендеринга Компоновка программы осуществляется при помощи функции glLinkProgramARB

Slide 47

Пример компоновки программного объекта glLinkProgramARB(program); GLint linkStatus; glGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linkStatus); if (linkStatus != GL_TRUE) { printf(“Program linking error”); }

Slide 48

Шаг 7 – валидация программного объекта Необязательный шаг, позволяющий проверить скомпонованную программу на корректность Например, получить сведения о возможных причинах неэффективной работы шейдерной программы Проверка корректности скомпонованной программы осуществляется при помощи функции glValidateProgramARB

Slide 49

Пример валидации шейдерной программы void Validate() { // ... glValidateProgramARB(program); GLint validationStatus; glGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &validationStatus); PrintInfoLog(program) if (validationStatus != GL_TRUE) { return; } // ... } void PrintInfoLog(GLhandleARB object) { GLcharARB buffer[10000]; GLsizei length; glGetInfoLogARB(object, sizeof(buffer) - 1, &length, buffer); printf(“%s”, buffer); }

Slide 50

Шаг 8 – установка шейдерной программы как часть текущего состояния OpenGL Приложение может скомпоновать одну или несколько шейдерных программ Каждая программа может реализовывать тот или иной способ рендеринга Данные программы могут быть установлены в текущее состояние для рендеринга при помощи функции glUseProgramObjectARB При этом стандартные механизмы рендеринга вершин и/или фрагментов будут заменены на определенные пользователем

Slide 51

Пример установки программного объекта // делаем программный объект активным glUseProgramObjectARB(program); // выполняем настройку программного объекта и рендеринг объектов // ... // переключаемся на стандартный механизм рендеринга glUseProgramObjectARB(NULL);

Slide 52

Удаление программ и шейдеров Ставшие ненужными шейдерные и программные объекты необходимо удалить при помощи функции glDeleteObjectARB Шейдерные объекты, с помощью которых была скомпонована шейдерная программа можно удалять – программный объект при этом сохранит работоспособность

Slide 53

Пример удаления шейдерных и программных объектов glDeleteObjectARB(program); glDeleteObjectARB(vertexShader); glDeleteObjectARB(fragmentShader);

Slide 54

Передача параметров в шейдерную программу

Slide 55

Передача значений uniform-переменных в шейдерную программу Приложение может задать значение uniform-переменной программного объекта с заданным расположением при помощи функции glUniformARB Программный объект должен быть предварительно сделан активным Расположение uniform-переменной по ее имени можно получить при помощи функции glGetUniformLocationARB

Slide 56

Пример передачи uniform-переменной в шейдер // делаем программный объект активным glUseProgramObjectARB(program); // получаем расположение uniform-переменной phase (предполагается, что данная переменная объявлена в одном из шейдеров с квалификатором uniform) GLint phaseLocation = glGetUniformLocationARB(program, "phase"); // задаем значение данной переменной (предполагается, что переменная имеет тип float (суффикс 1f в имени функции glUniform*ARB) glUniform1fARB(phaseLocation, 0.8f); // деактивируем шейдерную программу glUseProgramObjectARB(NULL);

Slide 57

Передача attribute-переменных шейдерной программе Значение attribute-переменной с известным расположением может быть передано шейдеру при помощи функции glVertexAttrib*ARB внутри glBegin()/glEnd() перед вызовом glVertex() Целый массив атрибутов вершин может быть передан вершинному шейдеру при помощи функции glVertexAttribPointerARB Узнать расположение attribute-переменной можно при помощи функции glGetAttribLocationARB

Slide 58

Пример передачи значения attribute-переменной отдельно взятой вершины // получаем расположение атрибута vertex2 GLint vertex2Location = glGetAttribLocationARB(program, "vertex2"); // делаем программный объект активным glUseProgramObjectARB(program); glBegin(GL_TRIANGLES); // задаем значение attribute-переменной vertex2, объявленной как vec3 glVertexAttrib3fARB(vertex2Location, 0, 0.5f, 1); glVertex3f(0, 0, 0); glVertexAttrib3fARB(vertex2Location, 2, 0.5f, 1); glVertex3f(0, 1, 0); glVertexAttrib3fARB(vertex2Location, 3, 0.5f, 1); glVertex3f(0, 0, 1); glEnd(); glUseProgramObjectARB(NULL);

Slide 59

Пример передачи массива attribute-переменных шейдеру // получаем расположение атрибута vertex2 GLint vertex2Location = glGetAttribLocationARB(program, "vertex2"); // делаем программный объект активным glUseProgramObjectARB(program); // задаем параметры массива атрибутов и массива вершин (в данном случае attribute-переменная vertex2 объявлена как vec3) glVertexAttribPointerARB(vertex2Location, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &g_shapeVertices[0].x1); glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &g_shapeVertices[0]); // разрешаем доступ к массивам вершин и атрибутов glEnableVertexAttribArrayARB(vertex2Attribute); glEnableClientState(GL_VERTEX_ARRAY); // рисуем массив примитивов glDrawArrays(GL_LINE_LOOP, 0, NUMBER_OF_VERTICES); // запрещаем доступ к массивам вершин и атрибутов glDisableVertexAttribArrayARB(vertex2Attribute); glDisableClientState(GL_VERTEX_ARRAY); // делаем программу неактивной glUseProgramObjectARB(NULL);

Slide 60

Основы языка программирования шейдеров OpenGL

Slide 61

Типы данных GLSL поддерживает следующие типы данных Скалярные типы Векторы Матрицы Дискретизаторы (samplers) Структуры Массивы Тип void

Slide 62

Скалярные типы данных float – целое число с плавающей запятой float f; float g, h = 2.4; float scale = 3.0; int – целое число (как минимум 16 разрядов) int i = 0x18; int numberOfTextures = 5; Особенности: нет побитовых операций, не происходит переполнения или исчезновения значащих разрядов bool – булева переменная bool pointIsOutsideThePlane; bool overflow; Конструкции if-else принимают только булевы значения

Slide 63

Векторные типы данных Векторы чисел c плавающей запятой vec2, vec3, vec4 vec3 normal; vec4 color = vec4(0.3, 0.1, 0.2, 1.0); Векторы целых чисел ivec2, ivec3, ivec4 ivec3 v(3, 2, 1); Векторы булевых значений bvec2, bvec3, bvec4 bvec2 usage(true, false); bvec3 intersectionFlags;

Slide 64

Адресация элементов вектора По индексам pos[3] = 5.0; По именам Вектор рассматривается как координаты или направление: x, y, z, w position.z -= 1.0; Вектор рассматривается как значение цвета: r, g, b, a gl_Color.g = 0.1; Вектор рассматривается как координаты текстуры: s, t, p, q gl_TexCoord[1].s = 0.4;

Slide 65

Матрицы В GLSL поддерживаются встроенные матрицы из чисел с плавающей запятой mat2 mat3 mat4 Матрицу можно рассматривать как массив столбцов векторов mat4 transform; vec4 col2 = transform[2]; // третий столбец матрицы

Slide 66

Дискретизаторы В стандарте OpenGL не определено, в каком виде будут реализованы текстурные модули Доступ к текстурному объекту (выборка из текстуры) осуществляется при помощи дискретизатора (sampler) Типы дискретизаторов sampler1D sampler2D sampler3D samplerCube sampler1DShadow sampler2DShadow

Slide 67

Структуры Объявление структуры похоже на их объявление в языке C struct LightSource { vec3 position; vec3 color; }; LightSource light1; Структуры могут быть объявлены внутри других структур В состав структур могут входить массивы Битовые поля не поддерживаются

Slide 68

Массивы Язык допускает создание массивов любых типов vec4 points[10]; // массив из 10 элементов (индексы от 0 до 9) points[3].x = 3.0; // ссылка на четвертый элемент

Slide 69

Объявление массивов без указания размеров Допускается объявлять массивы без указания размера, если выполняется одно из условий: Перед ссылкой на массив он объявлен еще раз с указанием размера того же типа vec4 points[]; // размер неизвестен vec4 points[10]; // размер 10 элементов vec4 points[]; // ошибка – размер уже определен vec4 points[20]; // ошибка – размер уже определен Индексы, ссылающиеся на массив – константы времени компиляции vec4 points[]; // размер неизвестен points[3].z = 0.3; // размер – 4 элемента points[5].y = 3.4; // размер – 6 элементов

Slide 70

Тип void Используется для указания, что функция не возвращает никакого значения void main() { … }

Slide 71

Объявления и область видимости Переменные могут объявляться по мере необходимости (как в C++), а не в начале блока Область видимости ограничена блоком, в котором переменная была объявлена Исключение – нельзя объявлять переменные внутри оператора if Область видимости переменной, объявленной в операторе for заканчивается в конце тела цикла

Slide 72

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

Slide 73

Инициализаторы Инициализация может быть совмещена вместе с объявлением переменной float a, b = 3.0, c; Константные переменные должны быть обязательно инициализированы const int size = 4; Attribute, uniform и varying-переменные при объявлении нельзя инициализировать attribute float temparature; uniform int size; varying float transparency;

Slide 74

Инициализация составных типов Для инициализации составных типов используются конструкторы vec4 v = vec4(1.0, 2.0, 3.0, 4.0); vec4 v; v = vec4(1.0, 2.0, 3.0, 4.0); mat2 m(1.0, 2.0, 3.0, 4.0); // элементы матрицы перечисляются по столбцам Дискретизаторы не имеют конструкторов Возможно инициализация структур с помощью конструкторов Элементы перечисляются в порядке их объявления в структуре

Slide 75

Спецификаторы переменных attribute Используется для объявления переменной-атрибута вершины, значение которой задается приложением для каждой отдельно взятой вершины uniform Используется для объявления переменной, значение которой задается приложением для группы примитивов varying Используется для объявления переменной, посредством которой вершинный шейдер передает результаты вычислений фрагментному шейдеру const Константы времени компиляции, не видимые вне шейдера, в котором объявлены

Slide 76

Переменные без спецификаторов Переменные в глобальной области видимости, объявленные без спецификаторов могут использоваться совместно шейдерами одного типа, скомпонованными в одну программу Время существования таких переменных ограничено одним запуском шейдера Понятие «статических переменных» отсутствует Сохранение значения переменной между запусками шейдера препятствовало бы параллельной обработке вершин и фгагментов

Slide 77

Последовательное выполнение Программа на языке шейдеров OpenGL выполняется последовательно Точка входа в шейдер – функция void main() Перед входом в функцию выполняется инициализация глобальных переменных Операторы for, while, do-while огранизуют циклическое выполнение Условное выполнение обеспечивается операторами if-else и оператором ?: В операторе ?: типы 2-го и 3-го операндов должны совпадать Оператор discard может запретить запись фрагмента в кадровый буфер Операторы goto и switch отсутствуют

Slide 78

Функции, определяемые пользователем Функции объявляются аналогично C++ Допускается перегрузка функций Более строгий контроль над типами входных и выходных параметров Запрещен явный или косвенный рекурсивный вызов функции Для аргументов можно задать следующие спецификаторы in – аргумент копируется при входе out – аргумент копируется при выходе inout – аргумент копируется как при входе, так и при выходе К аргументам может применяться спецификатор const не применим к out и inout-параметрам

Slide 79

Примеры объявления функций void ComputeCoord(in vec3 normal, vec3 tangent, inout vec3 coord); vec3 ComputeCoord(const vec3 normal, vec3 tangent, in vec3 coord);

Slide 80

Встроенные функции В языке GLSL есть обширный набор встроенных функций Полный набор встроенных функций можно найти в спецификации языка Любая из встроенных функций может быть переопределена в шейдере

Slide 81

Операции Операции в основном объявляются аналогично операциям в языке C Отсутствуют побитовые операции Многие операции применимы как к скалярным, так и к векторным операндам

Slide 82

Обращение к компонентам векторов и Swizzling При обращении к элементам векторов можно перечислять компоненты, к которым проводится обращение vec4 v4; vec4 v41 = v4.rgba; vec3 v3 = v4.rgb; v4.b = 4.3; v4.yx = v4.xy; v4.xy = v3.rr;

Slide 83

Покомпонентные операции Если к вектору применяется какой-либо оператор, операция выполняется так же, как если бы она выполнялась над каждым компонентом вектора в отдельности vec3 v, u; float f; v = u + f; // v.x = u.x + f; v.y = u.y + f; v.z = u.z + f; vec2 v, y, w; v = y + w; // v.x = y.x + w.x; v.y = y.y + w.y; Исключение – умножение вектора на матрицу или матрицы на вектор производит математическое, а не покомпонентное умножение

Slide 84

Препроцессор Поддерживаются директивы препроцессора #define, #undef, #if, #ifdef, #ifndef, #else, #elif, #defined, #error, #line, #pragma Имеется набор встроенных макросов __LINE__, __FILE__, __VERSION__

Slide 85

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

Slide 86

Ссылки http://en.wikipedia.org/wiki/GLSL http://www.gamedev.ru/articles/read.shtml?id=20123 http://wingman.org.ru/glsl-api http://www.opengl.org/documentation/glsl/

URL: