Различия между AGSL и GLSL

Синтаксис AGSL и GLSL очень похож, поэтому многие эффекты фрагментных шейдеров GLSL можно перенести в Android с минимальными изменениями. AGSL фиксирует набор функций GLSL в GLSL ES 1.0 (язык шейдинга, используемый OpenGL ES 2.0), чтобы обеспечить максимальный охват устройств.

Фрагментный шейдер GLSL управляет всем поведением графического процессора между растеризатором и аппаратным обеспечением смешивания. Этот шейдер выполняет всю работу по вычислению цвета, и сгенерированный им цвет – это именно то, что подается на этап смешивания конвейера. Когда вы пишете шейдер в AGSL, вы программируете этап графического конвейера Android. Многие языковые различия проистекают из этого.

Выполнение шейдеров

Как и в шейдере GLSL, шейдер AGSL начинает выполнение в основной функции. В отличие от GLSL, функция принимает в качестве параметра положение шейдера в локальных координатах. Это похоже на gl_FragCoord, но вместо координат буфера кадров эти координаты могли быть преобразованы до вызова шейдера. Затем шейдер возвращает цвет пикселя в виде vec4 со средней или высокой точностью (аналогично out vec4 color или gl_FragColor в GLSL).

mediump vec4 main(in vec2 fragCoord)

Пространство координат

Пространства координат GLSL и AGSL

Шейдер, нарисованный с помощью GLSL, и почти идентичный шейдер, нарисованный с помощью AGSL

По умолчанию AGSL и GLSL используют разные координатные пространства. В GLSL координата фрагмента (fragCoord) отсчитывается от левого нижнего угла. AGSL соответствует системе координат экрана Canvas, то есть ось Y начинается в левом верхнем углу. При необходимости вы можете преобразовать одно пространство в другое, передав разрешение в качестве униформы и используя resolution.y - fragCoord.y для значения оси Y. Вы также можете применить к шейдеру локальную матрицу преобразования.

// AGSL to GLSL coordinate space transformation matrix
val localMatrix = Matrix()
localMatrix.postScale(1.0f, -1.0f)
localMatrix.postTranslate(0.0f, viewHeight)
gridShader.setLocalMatrix(localMatrix)

Точность и типы

Поддерживаются модификаторы точности, совместимые с GLSL, но в AGSL также есть типы half и short, которые тоже представляют среднюю точность.

Векторные типы можно объявлять как именованные <базовый тип><столбцы>. Вместо vec2 можно использовать float2, а вместо bvec4 – bool4. Типы матриц можно объявлять как именованные <базовый тип><столбцы>x<строки>, поэтому float3x3 вместо mat3. AGSL также позволяет использовать объявления в стиле GLSL для mat и vec, и эти типы сопоставляются с их эквивалентами с плавающей запятой.

Препроцессор

AGSL не поддерживает директивы препроцессора в стиле GLSL. Преобразуйте инструкции #define в переменные const. Компилятор AGSL поддерживает свертывание констант и устранение ветвей для переменных const, поэтому они будут эффективными.

Цветовые пространства

В приложениях для Android поддерживается управление цветом. Цветовое пространство холста определяет рабочее цветовое пространство для рисования. У исходного контента (например, шейдеров, включая BitmapShader) также есть цветовые пространства.

Для некоторых эффектов, таких как физически точное освещение, математические вычисления должны выполняться в линейном цветовом пространстве. Чтобы помочь в этом, AGSL предоставляет следующие встроенные функции:

half3 toLinearSrgb(half3 color)
half3 fromLinearSrgb(half3 color)

Они преобразуют цвета между рабочим цветовым пространством и цветовым пространством Android LINEAR_EXTENDED_SRGB. В этом пространстве используются основные цвета sRGB (гамма) и линейная передаточная функция. Он представляет значения за пределами гаммы sRGB, используя значения расширенного диапазона (ниже 0,0 и выше 1,0).

Военная форма

Поскольку AGSL не знает, содержат ли униформы цвета, он не будет автоматически применять к ним преобразование цвета. Вы можете пометить half4/float4/vec4 с помощью layout(color), чтобы сообщить Android, что униформа будет использоваться в качестве цвета. Это позволит Android преобразовать значение униформы в рабочее цветовое пространство.

В AGSL объявите униформу следующим образом:

layout(color) uniform half4 iColor;  // Input color
uniform float2 iResolution;          // Viewport resolution (pixels)

В коде Android вы можете задать uniform-переменную следующим образом:

shader.setColorUniform("iColor", Color.GREEN)
shader.setFloatUniform("iResolution", canvas.width.toFloat(), canvas.height.toFloat())