Серия знаний OPENGL ES 2.0 (3) — функция SHADER и грамматика GLSL (I)

Для получения дополнительных знаний о графике, пожалуйста, обратите внимание на мой публичный аккаунт: Attack on Code Home

В первом разделе мы представили основную функцию OpenGL ES и GLSL, заключающуюся в отрисовке изображений в буфере рисования. Хотя шейдер, созданный GLSL, перемежается с OpenGL ES, в процессе мы можем видеть, что два шейдера (вершинный шейдер и фрагментный шейдер) относительно независимы по сравнению с другими модулями OpenGL ES. Эти два шейдера похожи на две функции с вводом и выводом. Некоторые параметры передаются из OpenGL ES, вычисляются в шейдере, а затем передаются другим модулям GPU. В этом разделе давайте подробнее рассмотрим функции шейдера. Затем, начиная с этого раздела, мы будем использовать в общей сложности четыре раздела, чтобы поговорить о синтаксисе GLSL и о том, как писать шейдеры на языке GLSL.

Функция шейдера

Существует два типа шейдеров, соответствующих OpenGL ES 2.0: вершинный шейдер и фрагментный шейдер.

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

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

Файлы шейдеров на самом деле выглядят как обычные файлы .c или .cpp. Будет предобработка, будут определены какие-то переменные, есть главная функция, по переменным будут производиться какие-то расчеты, будут получены какие-то результаты.

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

Структура фрагментного шейдера в основном такая же, как в VS. Конечным результатом, вычисляемым в основной функции, является значение цвета gl_FragColor пикселя.

VS похож на PS, но есть некоторые отличия, а также некоторые ключевые слова, которые мы никогда раньше не видели. С этого момента в четырех разделах мы будем изучать синтаксис GLSL и то, как писать шейдеры на языке GLSL.

Предварительная обработка GLSL

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

Синтаксис предварительной обработки в шейдере аналогичен синтаксису, с которым мы знакомы. Шейдер поддерживает следующие методы предварительной обработки.

Если в строке есть только один #, такое использование поддерживается, но эта строка будет проигнорирована. Перед # можно ставить только пробелы или табуляции, и если за ним есть содержимое, это инструкция.

#define и #undef аналогичны c/c++, оба используются для определения определений макросов. За последующим выбором могут следовать или не следовать параметры макроса.

#if, #ifdef, #ifndef, #else, #elif, #endif Эти макросы с условным суждением аналогичны макросам в C++, но есть некоторые отличия.За этими макросами могут следовать только цифровые операции или определения макросов, определенные в define. Идентификаторы, не определенные в define, не будут по умолчанию равны 0 и при их использовании вызовут ошибку. Алфавитные константы не поддерживаются.

В операторе дефис ## или sizeof не поддерживается.

Мы также приводим несколько примеров, совместимых с C++, таких как оператор &&, который вычисляет операцию справа только тогда, когда слева не 0. Другим примером является оператор || или, который выполняет операцию справа только тогда, когда слева равен 0. Там, где не задействована никакая операция, если используется неопределенный идентификатор, об ошибке не будет сообщено.

Операции предварительной обработки выполняются во время компиляции.

#error поместит информацию об ошибке в журнал шейдера, и мы сможем получить журнал шейдера через API OpenGL ES. Вся информация после #error до начала новой строки появится в логе шейдера. Есть шейдер с #error, будем считать его неверным шейдером.

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

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

Так как некоторые проверки выполняются во время препроцессинга GLSL, если нужно ввести какие-то расширения, то их нужно вводить раньше. В препроцессинге введение расширения вводится через #extension.При импорте за #extension следует имя расширения или все.Все означает все расширения, поддерживаемые компилятором. Затем следует двоеточие и поведение.

Когда требуется поведение, это означает, что текущий шейдер должен использовать определенное расширение, если указанное расширение не поддерживает, вернуть ошибку.

Когда поведение включено, это означает, что текущий шейдер откроет определенный синтаксис расширения. Чуть слабее, чем require, поэтому, если указанное расширение не поддерживает, верните предупреждение.

И #extension all required, и #extension all enable вернут ошибку.

Когда поведение является предупреждением, также открывается грамматика расширения.Если расширение определяет некоторые ситуации предупреждения, то, если оно не поддерживается другим расширением, которое было включено или требуется, в противном случае, как только эти ситуации предупреждения будут обнаружены, он сообщит предупреждать. Если за #extension следует all, все предупреждения, определенные в расширении, будут выдавать предупреждения при их обнаружении. Если указанное расширение не поддерживается, вернуть предупреждение.

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

Исходное состояние компилятора эквивалентно выполнению команды: #extension all:disable. Указывает, что текущий шейдер следует грамматическим правилам, указанным в спецификации, и не вводит никаких расширений.

#extension — это способ управления расширением с нижнего уровня и обычно указывает, какие комбинации расширений необходимо поддерживать. Говоря последовательно, последнее #расширение переопределит предыдущее #расширение. А #extension all переопределит все предыдущие. А только предупредить и отключить поддержку всех.

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

Каждое расширение имеет соответствующее определение макроса, которое определяется в реализации расширения. Все в шейдере вы можете использовать #ifdef, чтобы определить, определен ли макрос. Если он определен, значит введено расширение, соответствующее макросу, то синтаксис, введенный расширением, можно использовать в коде, если он не определен, новый синтаксис, введенный расширением, использовать нельзя.

#version используется для определения номера версии языка, используемого шейдером. Если вы используете GLSL100, напишите здесь 100 после #version. Если это значение меньше 100 или больше, чем в последней версии GLSL, оно неверно. Это поле теоретически должно существовать во всех шейдерах, но в GLSL100 предварительная обработка #version 100 не требуется, поскольку номер версии GLSL по умолчанию равен 100. Так что если #version не прописан в шейдере, то по умолчанию используется #version 100.

#version должен быть написан перед шейдером, и перед ним могут быть только комментарии или пробелы.

За #line будет следовать константа, например #line 10. После выполнения этой инструкции следующая строка кода считается строкой 10.

За #line также могут следовать две константы, например #line 10 100. После выполнения этой инструкции следующая строка кода считается строкой 10. И номер первой строки строки будет считаться 100. Затем, начиная с этой строки, номер строки и номер строки будут увеличиваться до следующей директивы #line.

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

В шейдере есть несколько предопределенных определений макросов, таких как LINE, это определение макроса представляет количество строк в текущей строке + 1.

Другим примером является FILE, который представляет имя файла текущего файла.

ВЕРСИЯ представляет текущую версию GLSL, обычно используются GLSL1.0 и 1.3, а соответствующие ВЕРСИИ — 100 и 130.

GL_ES будет определен как 1 в системе ES, что в основном используется для определения того, работает ли текущий шейдер в системе ES.

Все определения макросов, начинающиеся с __ или GL_, зарезервированы, то есть разработчики не могут определять определения макросов таких правил.

GLSL-аннотации

Синтаксис аннотаций шейдера точно такой же, как синтаксис C и C++, с которым мы знакомы. Оба используют /**/ и // для обозначения комментариев. Если полный комментарий целиком выражен одной строкой, то в глазах компилятора это один пробел.

В дополнение к предварительной обработке в Shader также есть переменные и основные функции и т. д. Эти синтаксисы будут подробно описаны в следующих статьях.

Guess you like

Origin blog.csdn.net/u012124438/article/details/128355949