AGAL Registers 暂存器:
vc0 - vc127 : vertex constant, read only in Vertex Shader, write only in AS3
va0 - va7 : vertex attribute, read only in Vertex Shader, write only in AS3
vt0 - vt7 : vertex temporary, read/write in Vertex Shader
op : vertex output position, write only in Vertex Shader
v0 - v7 : varying, write only in Vertex Shader, read only in Fragment Shader
fc0 - fc27 : fragment constant, read only in Fragment Shader, write only in AS3
ft0 - ft7 : fragment temporary, read/write in Fragment Shader
fs0 - fs7 : fragment texture sampler, read/write in Fragment Shader
oc : fragment output color, write only in Fragment Shader
暂存器感觉有点象是高阶语言的变量
根据用途也有区分写入权限等等
从 AS3 只能写入资料到 vc, va, fc
vc, va, vt, op 暂存器只能用于顶点着色器,fc, ft, fs, oc 暂存器只能用于片段着色器
v 暂存器则是唯一可以在顶点着色器设定,然后从片段着色器读取的沟通方式
op 是顶点着色器最后输出的对象
oc 是片段着色器最后输出的对象
而暂存器的数量也是有限制的
vc 最多有 128 个可用,fc 也有 28 个可用
其它的大多只有 8 个可用
op, oc 应该是各只有一个了
以上这些暂存器每个资料容量似乎都是 float4
可以用 x, y, z, w 单独使用个别 float
从 AS3 设定 vc, va, fc 暂存器的方式
以下是透过 Context3D 从一个 Matrix3D 设定 vc0 - vc3
因为一个暂存器大小是 float4,而 Matrix3D 是 4x4
所以从 0 开始设下去就等于设定了 vc0 - vc3
cxt3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, new Matrix3D());
只要将第一个参数改为 FRAGMENT 就变成设定 fc 暂存器
cxt3D.setProgramConstantsFromMatrix(Context3DProgramType.FRAGMENT, 0, new Matrix3D());
va 暂存器设定方式
要先用 Context3D 建立 VertexBuffer,并且指定顶点数量与每个点资料量 (一个资料 32bit)
以下建立四个顶点,每个顶点 32bit * 5
var vertexBuffer:VertexBuffer3D = cxt3D.createVertexBuffer(4, 5);
vertexBuffer.uploadFromVector(Vector.<Number>([
-1 , 1 , 0 , 0 , 0 ,
-1 , -1 , 1 , 0 , 0 ,
1 , -1 , 1 , 0 , 1 ,
1 , 1 , 0 , 0 , 1 ]), 0, 4);
// 将顶点资料的 0-1 个 32bit 资料设定到 va0 的 x , y
cxt3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
// 将顶点资料的 2-4 个 32bit 资料设定到 va1 的 x , y , z
cxt3D.setVertexBufferAt(1, vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_3);
vc, va, fc 都可以从 AS3 设定,主要的差异在哪?
vc, fc 算是常数值,对于单次着色时的每个点,数值都是固定的
va 对于单次着色时的每个点,数值会依照 index buffer 内的 index 值,内插出 vertex attribute 数值来使用
AGAL Opcode 指令:
基本语法
[opcode] [destination] [source1] [source2 or sampler]
没有使用到的栏位必须设为 0 (应该是指 bytecode)
mov move 分量移动 移动 source1 资料到 destination
add add 分量相加 destination = source1 + source2
sub subtract 分量相减 destination = source1 - source2
mul multiply 分量相乘 destination = source1 * source2
div divide 分量相除 destination = source1 / source2
rcp reciprocal 分量倒数 destination = 1 / source1
min minimum 分量最小值 destination = minimum(source1 , source2)
max maximum 分量最大值 destination = maximum(source1 , source2)
frc fractional 分量取小数 destination = source1 - (float) floor(source1)
sqt square 分量平方根 destination = sqrt(source1)
rsq recip. root 分量平方根倒数 destination = 1 / sqrt(source1)
pow power 分量指数 destination = pow(source1 , source2)
log logarithm 2 为底分量对数 destination = log_2(source1)
exp exponential 2 为底分量指数 destination = 2^source1
nrm normalize 分量标准化 destination = normalize(source1)
sin sine 分量正弦 destination = sin(source1)
cos cosine 分量余弦 destination = cos(source1)
abs absolute 分量绝对值 destination = abs(source1)
neg negate 分量负值 destination = -source1
sat saturate 分量饱和值 destination = maximum(minimum(source1 , 1) , 0)
kil kill / discard (fragment shader only)
假如单一分量小于 0 便放弃绘图
If single scalar source component is less than zero, fragment is discarded and not drawn to the frame buffer.
The destination register must be all 0.
tex texture sample (fragment shader only)
依据 source1 坐标从 source2 材质取样
destination = load from texture source2 at coordinates source1.
In this source2 must be in sampler format.
sge set-if-greater-equal
分量运算,假如 source1 大于等于 source2,目标为 1,否则目标为 0
destination = source1 >= source2 ? 1 : 0
slt set-if-less-than
分量运算,假如 source1 小于 source2,目标为 1,否则目标为 0
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 multiply 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 multiply 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 multiply 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)
从 AGALMiniAssembler 里面看到还有这些 opcode
ifz, inz, ife, ine, ifg, ifl, ieg, iel, els, eif, rep, erp, brk, sgn
不过实际测试发现在目前这版 Flash Player 尚未支援
Error: Error #3621: AGAL validation failed: Invalid opcode, ifg is not implemented in this version at token 2 of fragment program.
AGAL 基本语法:
vc0, va0 作 4x4 矩阵转型后指定到输出剪辑空间 (output clipspace)
m44 op, va0, vc
以上语法等于以下个别分量的单独作内积
dp4 op.x, va0, vc0
dp4 op.y, va0, vc1
dp4 op.z, va0, vc2
dp4 op.w, va0, vc3
从 va1 复制到 v0 给 fragment shader 使用
mov v0, va1
等于
mov v0, va1.xyzw
注意 xyzw 顺序
mov v0, va1.yxzw
实际上是等于
mov v0.x, va1.y
mov v0.y, va1.x
mov v0.z, va1.z
mov v0.w, va1.w