AGSL 和 GLSL 之间的区别

AGSL 和 GLSL 在语法上非常相似,允许将许多 GLSL 片段着色器效果以最小的更改转移到 Android。AGSL 将其 GLSL 功能集修复为 GLSL ES 1.0(OpenGL ES 2.0 使用的着色语言),以提供最大的设备覆盖范围。

GLSL 片段着色器控制光栅化器和混合硬件之间 GPU 的整个行为。该着色器完成所有计算颜色的工作,它生成的颜色正是馈送到管道的混合阶段的内容。当您使用 AGSL 编写着色器时,您正在编程 Android 图形管道的阶段。许多语言差异都源于此。

着色器执行

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

mediump vec4 main(in vec2 fragCoord)

坐标空间

GLSL vs AGSL coordinate spaces

使用 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 引入了 halfshort 类型,它们也表示中精度。

向量类型可以声明为命名 <基类型><列>。您可以使用 float2 代替 vec2,以及 bool4 代替 bvec4。矩阵类型可以声明为命名 <基类型><列>x<行>,因此 float3x3 代替 mat3。AGSL 还允许 GLSL 风格的 matvec 声明,这些类型映射到它们的浮点等效项。

预处理器

AGSL 不支持 GLSL 风格的 预处理器 指令。将 #define 语句转换为 const 变量。AGSL 的编译器支持 const 变量的常量折叠和分支消除,因此这些将非常高效。

色彩空间

Android 应用是色彩管理的。Canvas 的色彩空间决定了绘图的工作色彩空间。源内容(如着色器,包括 BitmapShader)也具有色彩空间。

对于某些效果,例如物理精确的光照,应该在线性色彩空间中进行数学运算。为了帮助实现这一点,AGSL 提供了这些内在函数

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

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

统一变量

由于 AGSL 不知道统一变量是否包含颜色,因此它不会自动向它们应用颜色转换。您可以使用 layout(color) 来标记 half4/float4/vec4,这可以让 Android 知道统一变量将用作颜色,从而允许 Android 将统一变量值转换为工作色彩空间。

在 AGSL 中,像这样声明统一变量

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

在 Android 代码中,您可以像这样设置统一变量

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