В данном параграфе я вкратце коснусь некоторых базовых моментов синтаксиса GLSL.
В GLSL определены следующие примитивные типы:
void: функция не возвращает никакого значения
bool: логические значения true
или false
int: целочисленные значения
float: числовые значения с плавающей точкой
vec2, vec3, vec4: двух-, трех- и четырехмерные векторы соответственно, которые содержат объекты типа float
ivec2, ivec3, ivec4: двух-, трех- и четырехмерные векторы соответственно, которые содержат объекты типа int
bvec2, bvec3, bvec4: двух-, трех- и четырехмерные векторы соответственно, которые содержат объекты типа bool
mat2, mat3, mat4: матрицы размера 2х2, 3х3 и 4х4 соответственно, которые содержат объекты типа float
sampler2D, samplerCube: специальные типы - семплеры для работы с текстурами. С помощью сэмплеров во фрагментном шейдере мы можем получить цветовые значения текстур и передать их примитиву
Как и С/С++ в GLSL можно также создавать сложные типы - структуры, которые содержать наборы примитивных типов:
struct someStruct{ int someInt; vec4 someVec; }
В GLSL мы можем не просто объявить переменную, но и добавить к ней определенное поведение. Это делается с помощью модификаторов (квалификаторов). Используются следующие модификаторы:
attribute: атрибут или часть описания вершины, которое передается из программы на WebGL в вершинный шейдер
const: константы, эти переменные определяют свое значение только один раз и в процессе программы его уже не меняют
uniform: по сути то же переменные с константными значениями, только эти значения задаются для всего примитива
varying: переменная, которая задается в вершинном шейдере и затем передается во фрагментный шейдер, где может быть использована
В использованных ранее примерах мы уже применяли модификатор в вершинном шейдере: attribute vec3 aVertexPosition;
. Здесь
aVertexPosition представляет описание вершины и имеет тип трехмерного вектора, поскольку мы используем вершину в трехмерном пространстве.
Кроме различных модификаторов мы также можем использовать квалификаторы для чисел с плавающей точкой - то есть для переменных типа float:
highp: число с плавающей точкой сохраняет максимальную точность
mediump: число со средней степенью точности
lowp: диапазон плавающей запятой от -2 до 2
Например, varying highp vec4 vColor;
- здесь каждое число float в векторе vec4 имеет высокую точность.
Кроме задаваемых разработчиком переменных GLSL имеет также небольшой набор встроенных глобальных переменных, которые могут использоваться в вершинном или фрагментном шейдерах:
gl_Position: переменная имеет тип vec4 и указывает на положение вершины. Используется в вершинном шейдере в качестве выходного параметра
gl_PointSize: имеет тип float и содержит размер точки. Используется в вершинном шейдере в качестве выходного параметра
gl_FragCoord: имеет тип vec4 и указывает на положение фрагмента в буфере фреймов. Используется во фрагментном шейдере в качестве входного параметра
gl_FontFacing: имеет тип bool и определяет, принадлежит ли фрагмент лицевому примитиву. Используется во фрагментном шейдере в качестве входного параметра
gl_PointCoord: имеет тип vec2 и указывает на позицию фрагмента внутри точки. Используется во фрагментном шейдере в качестве входного параметра
gl_FragColor: имеет тип vec4 и указывает на итоговый цвет фрагмента. Используется во фрагментном шейдере в качестве выходного параметра
gl_FragData[n]: имеет тип vec4 и указывает на цвет фрагмента для прикрепления цвета n. Используется во фрагментном шейдере в качестве выходного параметра
Например, в вершинном шейдере мы устанавливаем переменную gl_Position
для установки финальной позиции вершины:
attribute vec3 aVertexPosition; void main(void) { gl_Position = vec4(aVertexPosition, 1.0); }
Но мы можем, например, добавить сжатие по оси X, разделив значение координаты Х вершины на какой-нибудь коэффициент:
attribute vec3 aVertexPosition; const float k=2.0; void main(void) { float x = aVertexPosition.x / k; gl_Position = vec4(x, aVertexPosition.y, aVertexPosition.z, 1.0); }
В итоге фигура сожмется в два раза, так как у нас коэффициент 2.0. Переменная aVertexPosition
представляет вектор
{x, y, z}, поэтому мы можем обратиться к каждой составляющей отдельно: aVertexPosition.x / k
. И затем установить все составляющие
вектора gl_Position.
GLSL обладает рядом встроенных функций, которые мы впоследствии будем использовать в своих программах. Некоторые из них:
dot(x, y): возвращает скалярное произведение векторов x и y
cross(x, y): возвращает векторное произведение векторов x и y
matrixCompMult(mat x, mat y): возвращает произведение матриц x и y, которые должны быть одной размерности
normalize(x): возвращает нормализованный вектор x, то есть такой вектор, у которого длина равна 1
reflect(t, n): отражает вектор t вдоль вектора n
sin(angle): возвращает синус угла angle
cos(angle): возвращает косинус угла angle
pow(x, y): возвращает x в степени y
max(x, y): возвращает максимальное из двух значений
min(x, y): возвращает минимальное из двух значений