AGSL 与 GLSL 之间的区别

AGSL 和 GLSL 的语法非常相似,只需极少的更改即可将许多 GLSL fragment 着色器效果引入 Android。AGSL 将其 GLSL 功能集修复为 GLSL ES 1.0(OpenGL ES 2.0 使用的着色语言),以尽可能扩大设备覆盖范围。

GLSL fragment 着色器可以控制光栅器和混合硬件之间 GPU 的整个行为。该着色器会执行所有计算颜色的工作,它生成的颜色正是馈送给流水线混合阶段的颜色。使用 AGSL 编写着色器时,您正在对 Android 图形管道的一个阶段进行编程。很多语言差异都源于这种语言。

着色器执行

就像在 GLSL 着色器中一样,AGSL 着色器会在主函数中开始执行。��� GLSL 不同,该函数将“局部”坐标中的着色器位置作为参数。这类似于 gl_FragCoord,但不是帧缓冲区坐标,这些坐标可能在调用着色器之前已经过转换。然后,您的着色器会以 vec4 的形式返回像素颜色中等或高精度(类似于 GLSL 中的 out vec4 colorgl_FragColor)。

mediump vec4 main(in vec2 fragCoord)

坐标空间

GLSL 与 AGSL 坐标空间

使用 GLSL 绘制的着色器与使用 AGSL 绘制近乎完全相同的着色器

默认情况下,AGSL 和 GLSL 使用不同的坐标空间。在 GLSL 中,fragment 坐标 (fragCoord) 相对于左下角而言。AGSL 与画布的屏幕坐标系匹配,这意味着 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 引入了 halfshort 类型,它们也表示中等精度。

矢量类型可以声明为名为 <base type><columns>。您可以使用 float2(而非 vec2)和 bool4(而非 bvec4)。矩阵类型可以声明为名为 <base type><columns>x<rows>,因此是 float3x3,而不是 mat3。AGSL 还允许为 matvec 进行 GLSL 样式的声明,这些类型会映射到其等效的浮点数。

预处理器

AGSL 不支持 GLSL 样式的预处理器指令。将 #define 语句转换为常量变量。AGSL 的编译器支持对常量变量执行常量折叠和分支消除,因此这些操作会���高效。

颜色空间

Android 应用可通过颜色进行管理。画布的颜色空间决定了绘制的有效颜色空间。源内容(如着色器,包括 BitmapShader)也具有颜色空间。

对于某些效果(例如物理准确光照),应在线性颜色空间中进行计算。为帮助完成此任务,AGSL 提供了以下固有函数:

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

这些颜色会在工作颜色空间和 Android 的 LINEAR_EXTENDED_SRGB 颜色空间之间转换颜色。该空间使用 sRGB 原色(色域)和线性传递函数。它使用扩展范围值(低于 0.0 且高于 1.0)表示 sRGB 色域以外的值。

制服

由于 AGSL 不知道 uniform 是否包含颜色,因此它不会自动对其应用颜色转换。您可以为 half4/float4/vec4 添加 layout(color) 标签,以便让 Android 知道将制服颜色用作颜色,从而让 Android 能够将 uniform 值转换为有效的颜色空间。

在 AGSL 中,按如下方式声明 uniform:

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