前面已经了解了一些Stage3D的基础与工作原理,今天我准备继续深入了解下隐藏于Stage3D API背后的神秘代码 AGAL。
废话不多说直接进入主题,老规矩先搞清楚什么是AGAL? AGAL是干什么的?
名称 描述 说明
mov 移动 移动 source1 数据到 destination
add 相加 destination = source1 + source2
sub 相减 destination = source1 - source2
mul 相乘 destination = source1 * source2
div 相除 destination = source1 / source2
rcp 倒数 destination = 1 / source1
min 最小值 destination = minimum(source1 , source2)
max 最大值 destination = minimum(source1 , source2)
frc 取小数 destination = source1 - (float) floor(source1)
sqt 平方根 destination = sqrt(source1)
rsq 平方根倒数 destination = 1 / sqrt(source1)
pow 指数 destination = pow(source1 , source2)
log 2 为底的对数 destination = log_2(source1)
exp 2 为底的指数 destination = 2^source1
nrm 标准化 destination = normalize(source1)
sin 正弦 destination = sin(source1)
cos 余弦 destination = cos(source1)
abs 绝对值 destination = abs(source1)
neg 负值 destination = -source1
sat 饱和值 destination = maximum(minimum(source1 , 1) , 0)
kil 抛弃(只限片断着色器) 假如单一分量小于 0 便放弃绘图
tex 材质取样(只限片断着色器) 依据 source1 坐标从 source2 材质取样
sge 分量运算(set-if-greater-equal) destination = source1 >= source2 1 : 0
slt 分量运算(set-if-less-than) destination = source1 < source2 1 : 0
crs 向量外积(cross product) destination.x = source1.y * source2.z - source1.z * source2.y destination.y = source1.z * source2.x - source1.x * source2.z destination.z = source1.x * source2.y - source1.y * source2.x
dp3 向量内积(dot product) destination = source1.x * source2.x + source1.y * source2.y + source1.z * source2.z
dp4 向量内积(dot product) destination = source1.x * source2.x + source1.y * source2.y + source1.z * source2.z + source1.w * source2.w
m33 3x3 矩阵相乘 destination.x = (source1.x * source2[0].x) + (source1.y * source2[0].y) + (source1.z * source2[0].z) destination.y = (source1.x * source2[1].x) + (source1.y * source2[1].y) + (source1.z * source2[1].z) destination.z = (source1.x * source2[2].x) + (source1.y * source2[2].y) + (source1.z * source2[2].z)
m44 4x4 矩阵相乘 destination.x = (source1.x * source2[0].x) + (source1.y * source2[0].y) + (source1.z * source2[0].z) + (source1.w * source2[0].w) destination.y = (source1.x * source2[1].x) + (source1.y * source2[1].y) + (source1.z * source2[1].z) + (source1.w * source2[1].w) destination.z = (source1.x * source2[2].x) + (source1.y * source2[2].y) + (source1.z * source2[2].z) + (source1.w * source2[2].w) destination.w = (source1.x * source2[3].x) + (source1.y * source2[3].y) + (source1.z * source2[3].z) + (source1.w * source2[3].w)
m34 3x4 矩阵相乘 destination.x = (source1.x * source2[0].x) + (source1.y * source2[0].y) + (source1.z * source2[0].z) + (source1.w * source2[0].w) destination.y = (source1.x * source2[1].x) + (source1.y * source2[1].y) + (source1.z * source2[1].z) + (source1.w * source2[1].w) destination.z = (source1.x * source2[2].x) + (source1.y * source2[2].y) + (source1.z * source2[2].z) + (source1.w * source2[2].w)
ifz, inz, ife, ine, ifg, ifl, ieg, iel, els, eif, rep, erp, brk, sgn 从AGALMiniAssembler里面看到还有这些opcode ifz, inz, ife, ine, ifg, ifl, ieg, iel, els, eif, rep, erp, brk, sgn 不过实际测试发现在目前这版 Flash Player 尚未支持
AGAL Registers 缓存器
缓存器 定义 权限
顶点着色器 片断着色器 AS3编译器
vc0 - vc127 顶点矩阵常量 读 写
va0 - va7 顶点缓冲属性 读 写
vt0 - vt7 顶点临时变量 读/写
op 顶点着色器最终输出的对象 写
v0 - v7 变量 写 读
fc0 - fc27 片断常量 读 写
ft0 - ft7 片断临时变量 读/写
fs0 - fs7 片断纹理采样器 读/写
oc 片断着色器最终输出的对象 写
这些寄存器涉及顶点着色器的输入VertexBuffer。因此,他们只可用在顶点着色器。
为了指派一个VertexBuffer到指定的属性寄存器,在这个函数中使用正确的索引号Context3D::setVertexBufferAt()。
从着色器中访问该属性寄存器的语法:va<n>,其中<n>是属性寄存器的索引号。
总共有8个用于顶点着色器的属性寄存器。
Constant Registers 常量寄存器
这些寄存器是为了从ActionScript传递参数到着色器。通过Context3D::setProgramConstants()函数完成。
从着色器中访问这些寄存器的语法:vc<n>,用于顶点着色器,fc<n>,用于像素着色器,其中<n>是常量寄存器的索引号。
有128个用于顶点着色器和28个用于像素着色器的常量寄存器。
Temporary Registers 临时寄存器
这些寄存器供着色器在临时计算时使用。
访问它们的语法:vt<n>(点)和 ft<n> (像素),其中<n>是寄存器的序号。
有8个可用于顶点着色器,8个可用于像素着色器。
输出寄存器存储顶点和像素着色器的计算输出。对于顶点着色器是一个顶点剪辑空间的位置。对于像素着色器是该像素的颜色。
访问这些寄存器的语法:op,用于顶点着色器,oc,用于像素着色器。
显然只有一个用于顶点和像素着色器的输出寄存器。
这些寄存器用来从顶点着色器向像素着色器传递数据。
这些寄存器用来传递从顶点着色器到像素着色器的数据。所传数据被GPU转换,从而使像素着色器接收到正确的值,用于正在处理的像素。
用这种方法传递的典型数据是顶点的颜色或纹理的UV坐标。
访问这些寄存器的语法:v<n>,其中<n>是寄存器序号。
有8个变量寄存器可用。
Texture Samplers 纹理采样寄存器
纹理采样寄存器是用来接收从基于UV坐标系的纹理中的颜色值。
纹理的指定通过ActionScript使用方法 Context3D::setTextureAt()。
纹理采样的使用语法是:ft<n> <flags>,其中<n>是采样序号,<flags>是一个或多个用于指定应如何取样的标志集。
<flags>是一个以逗号分隔的字符串集,其定义是:
纹理维度。可以是:2d, 3d, cube
多重材质映射。可以是:nomip, mipnone, mipnearest, mipnone
纹理滤镜。可以是:nearest, linear
重复纹理。可以是:repeat, wrap, clamp.
好了,举例来说,一个标准的没有多重材质映射的2D纹理,进行线性滤镜采样到临时寄存器ft1中,用下行:
“tex ft1, v0, fs0 <2d,linear,nomip> “
其中变量寄存器v0保存以内插值替换的纹理UV坐标。
顶点和像素着色器例子解释
现在我们返回到着色器的例子,并解释其运作。
我们假设顶点在VertexBuffer中包含着顶点的位置,偏移量是0,纹理的UV偏移量是3。
我们希望我们的顶点着色器转换顶点位置到剪辑空间里,并传递UV到像素着色器。
执行以下代码:
m44 op, va0, vc0 // pos to clipspace
mov v0, va1 // copy uv
用下面的方法可将此矩阵写入到着色器:
像素着色器采样纹理,并复制颜色到输出寄存器。
mov oc, ft1
这就是我们的第一个顶点和像素着色器!