AGSL 快速参考

AGSL 的设计旨在与 GLSL ES 1.0 大致兼容。如需了解详情,请参阅 OpenGL ES Shading Language 文档中的等效函数。本文档尽可能尝试指出 AGSL 和 GLSL 之间的差异。

类型

AGSL 支持 GLSL ES 1.0 类型,并提供了额外的表示向量和矩阵类型的方式。AGSL 还支持额外的 shorthalf 类型来表示中等精度。

基本类型

类型 说明
void 无函数返回值或空参数列表。 与 GLSL 不同,没有 void 返回类型的函数必须返回一个值。
bool, bvec2, bvec3, bvec4
(bool2, bool3, bool4).
布尔标量/向量
int, ivec2, ivec3, ivec4
(int2, int3, int4)
highp 有符号整数/向量
float, vec2, vec3, vec4
(float2, float3, float4)
highp(单精度)浮点标量/向量
short, short2, short3, short4 等效于 mediump int 有符号整数/向量
half, half2, half3, half4 等效于 mediump float 标量/向量
mat2, mat3, mat4
(float2x2, float3x3, float4x4)
2x2、3x3、4x4 float 矩阵
half2x2, half3x3, half4x4 等效于 mediump float 矩阵类型

精度和范围最小值

这些是根据 OpenGL ES 2.0 规范,与每个修饰符关联的最低保证精度和范围。由于大多数设备支持 ES 3.0,它们将拥有更多保证的 highp 精度/范围和 int mediump 范围。精度修饰符可以应用于标量、向量和矩阵变量及参数。仅保证以下列出的最小值;lowp 的精度不一定实际低于 mediump,而 mediump 的精度也不一定低于 highp。AGSL 当前在最终输出中将 lowp 转换为 mediump

修饰符 'float' 范围 'float' 幅值范围 'float' 精度 'int' 范围
highp \(\left\{-2^{62},2^{62}\right\}\) \(\left\{2^{-62},2^{62}\right\}\) 相对值:\(2^{-16}\) \(\left\{-2^{16},2^{16}\right\}\)
mediump \(\left\{-2^{14},2^{14}\right\}\) \(\left\{2^{-14},2^{14}\right\}\) 相对值:\(2^{-10}\) \(\left\{-2^{10},2^{10}\right\}\)
lowp \(\left\{-2,2\right\}\) \(\left\{2^{-8},2\right\}\) 绝对值:\(2^{-8}\) \(\left\{-2^{8},2^{8}\right\}\)

除了数组数字下标语法(例如 var[num])之外,长度为 2-4 的向量的分量名称用单个字母表示。分量可以进行重组 (swizzle) 和复制。例如:vect.yxvect.yy

vect.xyzw - 在访问表示点/法线的向量时使用

vect.rgba - 在访问表示颜色的向量时使用

vect.LTRB - 在向量表示矩形时使用(GLSL 中没有)

在 AGSL 中,0 和 1 可用于在该通道中生成常量 0 或 1。例如:vect.rgb1 == vec4(vect.rgb,1)

结构体和数组

结构体的声明语法与 GLSL 相同,但 AGSL 仅支持全局范围内的结构体。

struct type-name {
 members
} struct-name; // optional variable declaration.

仅支持具有显式数组大小的 1 维数组,使用 C 风格或 GLSL 风格语法均可

<base type>[<array size>] 变量名 - 例如:half[10] x;

<base type> 变量名[<array size>] - 例如:half x[10];

数组不能从函数返回、复制、赋值或比较。数组限制会传播到包含数组的结构体。数组只能使用常量或循环变量进行索引。

限定符

类型 说明
const 编译时常量,或只读函数参数。
uniform 在处理的图元中,值不会改变。Uniforms 通过 RuntimeShader 方法从 Android 传递,包括 setColorUniformsetFloatUniformsetIntUniformsetInputBuffersetInputShader
in 用于传入的函数参数。这是默认值。
out 用于传出的函数参数。必须使用与函数定义相同的精度。
inout 用于既作为输入也作为输出的函数参数。必须使用与函数定义相同的精度。

变量声明

声明必须在显式的大括号作用域内。以下示例中声明 y 是不允许的

if (condition)
    int y = 0;

矩阵/结构体/数组基础

矩阵构造函数示例

当使用单个值构造矩阵时,对角线上的所有值都赋予该值,其余值都赋予零。因此,float2x2(1.0) 将创建一个 2x2 单位矩阵。

当使用多个值构造矩阵时,首先填充列(列主序)。

请注意,与 GLSL 不同,AGSL 不支持减少传入向量组件数量的构造函数,但您可以使用重组 (swizzling) 来达到相同的效果。要在 AGSL 中以与 GLSL 相同的行为从 vec4 构造 vec3,请指定 vec3 nv = quadVec.xyz

结构体构造函数示例

struct light { float intensity; float3 pos; };
// literal integer constants auto-converted to floating point
light lightVar = light(3, float3(1, 2, 3.0));

矩阵分量

使用数组下标语法访问矩阵的分量。

float4x4 m; // represents a matrix
m[1] = float4(2.0); // sets second column to all 2.0
m[0][0] = 1.0; // sets upper left element to 1.0
m[2][3] = 2.0; // sets 4th element of 3rd column to 2.0

结构体字段

使用点运算符 . 选择结构体字段。运算符包括

运算符 说明
. 字段选择器
==, != 相等性
= 赋值

数组元素

使用数组下标运算符 [ ] 访问数组元素。例如

diffuseColor += lightIntensity[3] * NdotL;

运算符

按优先级顺序列出。关系运算符和相等性运算符 > < <= >= == != 的计算结果为布尔值。要逐分量比较向量,请使用 lessThan()equal() 等函数。

运算符 说明 结合性
1 () 括号分组 不适用
2 [] () . ++ -- 数组下标、函数调用和构造函数、结构体字段或方法选择器、重组 (swizzle)、后缀递增和递减 从左到右
3 ++ -- + - ! 前缀递增和递减、一元运算符 从右到左
4 * / 乘法和除法 从左到右
5 + - 加法和减法 从左到右
7 < > <= >= 关系运算符 从左到右
8 == != 相等性/不等性 从左到右
12 && 逻辑与 从左到右
13 ^^ 逻辑异或 从左到右
14 || 逻辑或 从左到右
15 ?\: 选择(三元运算符) 从左到右
16 = += -= *= /= 赋值和算术赋值 从左到右
17 , 序列运算符 从左到右

矩阵和向量运算

应用于标量值时,算术运算符的结果是标量。对于除了取模之外的运算符,如果一个操作数是标量,另一个是向量或矩阵,则按分量执行运算,结果是相同的向量或矩阵类型。如果两个操作数都是相同大小的向量,则按分量执行运算(并返回相同的向量类型)。

运算 说明
m = f * m 按分量执行的标量值矩阵乘法
v = f * v 按分量执行的标量值向量乘法
v = v * v 按分量执行的向量值向量乘法
m = m + m 矩阵按分量相加
m = m - m 矩阵按分量相减
m = m * m 线性代数乘法

如果一个操作数是与矩阵的行或列大小匹配的向量,则可以使用乘法运算符进行代数行向量或列向量乘法。

运算 说明
m = v * m 行向量 * 矩阵线性代数乘法
m = m * v 矩阵 * 列向量线性代数乘法

使用内置函数进行向量点积、叉积和按分量乘法

函数 说明
f = dot(v, v) 向量点积
v = cross(v, v) 向量叉积
m = matrixCompMult(m, m) 按分量乘法

程序控制

函数调用 值传递并返回结果
迭代 for (<init>;<test>;<next>)
{ break, continue }
选择 if ( ) { }
if ( ) { } else { }
switch () { break, case } - default case 在最后
跳转 break, continue, return
(不允许使用 discard)
入口 half4 main(float2 fragCoord)

For 循环限制

与 GLSL ES 1.0 类似,'for' 循环相当有限;编译器必须能够展开循环。这意味着初始化式、测试条件和 next 语句必须使用常量,以便所有内容都可以在编译时计算。此外,next 语句仅限于使用 ++, --, +=, 或 -=

内置函数

GT(通用类型)是 floatfloat2float3float4halfhalf2half3half4

这些函数大多数是逐分量操作的(函数应用于每个分量)。如果不是这种情况,会进行说明。

角度和三角函数

指定为角度的函数参数假定单位为弧度。这些函数在任何情况下都不会导致除以零错误。如果比率的除数为 0,则结果将是不确定的。

函数 说明
GT radians(GT degrees) 将角度转换为弧度
GT degrees(GT radians) 将弧度转换为角度
GT sin(GT angle) 标准正弦
GT cos(GT angle) 标准余弦
GT tan(GT angle) 标准正切
GT asin(GT x) 返回正弦值为 x 的角度,范围为 $ \left[-{\pi\over 2},{\pi\over 2}\right] $
GT acos(GT x) 返回余弦值为 x 的角度,范围为 $ \left[0,\pi\right] $
GT atan(GT y, GT x) 返回反正切为 $ \left[{y\over x}\right] $ 的角度,范围为 $ \left[-\pi,\pi\right] $
GT atan(GT y_over_x) 返回反正切为 y_over_x 的角度,范围为 $ \left[-{\pi\over 2},{\pi\over 2}\right] $

指数函数

函数 说明
GT pow(GT x, GT y) 返回 $ x^y $
GT exp(GT x) 返回 $ e^x $
GT log(GT x) 返回 $ ln(x) $
GT exp2(GT x) 返回 $ 2^x $
GT log2(GT x) 返回 $ log_2(x) $
GT sqrt(GT x) 返回 $ \sqrt{x} $
GT inversesqrt(GT x) 返回 $ 1\over{\sqrt{x}} $

常用函数

函数 说明
GT abs(GT x) 绝对值
GT sign(GT x) 根据 x 的符号返回 -1.0、0.0 或 1.0
GT floor(GT x) 小于等于 x 的最接近整数
GT ceil(GT x) 大于等于 x 的最接近整数
GT fract(GT x) 返回 x 的小数部分
GT mod(GT x, GT y) 返回 x 模 y 的值
GT mod(GT x, float y) 返回 x 模 y 的值
GT min(GT x, GT y) 返回 x 或 y 的最小值
GT min(GT x, float y) 返回 x 或 y 的最小值
GT max(GT x, GT y) 返回 x 或 y 的最大值
GT max(GT x, float y) 返回 x 或 y 的最大值
GT clamp(GT x, GT minVal, GT maxVal) 返回 x 钳制在 minVal 和 maxVal 之间。
GT clamp(GT x, float minVal, float maxVal) 返回 x 钳制在 minVal 和 maxVal 之间
GT saturate(GT x) 返回 x 钳制在 0.0 和 1.0 之间
GT mix(GT x, GT y, GT a) 返回 x 和 y 的线性混合
GT mix(GT x, GT y, float a) 返回 x 和 y 的线性混合
GT step(GT edge, GT x) 如果 x < edge 返回 0.0,否则返回 1.0
GT step(float edge, GT x) 如果 x < edge 返回 0.0,否则返回 1.0
GT smoothstep(GT edge0, GT edge1, GT x) 当 edge0 < x < edge1 时执行 Hermite 0 和 1 之间的插值
GT smoothstep(float edge0, float edge1, GT x) 当 edge0 < x < edge1 时执行 Hermite 0 和 1 之间的插值

几何函数

这些函数将向量作为向量进行操作,而不是逐分量操作。GT 是大小为 2-4 的 float/half 向量。

函数 说明
float/half length (GT x) 返回向量长度
float/half distance(GT p0, GT p1) 返回点之间的距离
float/half dot(GT x, GT y) 返回点积
float3/half3 cross(float3/half3 x, float3/half3 y) 返回叉积
GT normalize(GT x) 将向量标准化为长度 1
GT faceforward(GT N, GT I, GT Nref) 如果 dot(Nref, I) < 0 返回 N,否则返回 -N。
GT reflect(GT I, GT N) 反射方向 I - 2 * dot(N,I) * N。
GT refract(GT I, GT N, float/half eta) 返回折射向量

矩阵函数

类型 mat 是任意方阵类型。

函数 说明
mat matrixCompMult(mat x, mat y) x 与 y 按分量相乘
mat inverse(mat m) 返回 m 的逆矩阵

向量关系函数

逐分量比较 x 和 y。特定调用的输入向量和返回向量的大小必须匹配。T 是整数和浮点向量类型的联合。BV 是与输入向量大小匹配的布尔向量。

函数 说明
BV lessThan(T x, T y) x < y
BV lessThanEqual(T x, T y) x <= y
BV greaterThan(T x, T y) x > y
BV greaterThanEqual(T x, T y) x >= y
BV equal(T x, T y) x == y
BV equal(BV x, BV y) x == y
BV notEqual(T x, T y) x != y
BV notEqual(BV x, BV y) x != y
bool any(BV x) 如果 x 的任何分量为 true,则为 true
bool all(BV x) 如果 x 的所有分量都为 true,则为 true
BV not(BV x) x 的逻辑补码

颜色函数

函数 说明
vec4 unpremul(vec4 color) 将颜色值转换为非预乘 alpha
half3 toLinearSrgb(half3 color) 颜色空间转换为线性 SRGB
half3 fromLinearSrgb(half3 color) 颜色空间转换

着色器采样(评估)

不支持采样器类型,但您可以评估其他着色器。如果您需要采样纹理,可以创建一个 BitmapShader 对象,并将其作为 uniform 添加。您可以对任何着色器执行此操作,这意味着您可以直接评估任何 Android Shader,而无需先将其转换为 Bitmap,包括其他 RuntimeShader 对象。这提供了巨大的灵活性,但评估复杂的着色器可能会很耗费资源,尤其是在循环中。

uniform shader image;

image.eval(coord).a   // The alpha channel from the evaluated image shader

原始缓冲区采样

虽然大多数图像包含应进行色彩管理的颜色,但有些图像包含并非实际颜色的数据,包括存储法线、材质属性(例如粗糙度)、高度图或恰好存储在图像中的任何其他纯数学数据的图像。在 AGSL 中使用这些类型的图像时,可以使用 RuntimeShader#setInputBuffer 将 BitmapShader 作为通用原始缓冲区使用。这将避免颜色空间转换和过滤。