AGAL是什么

在这篇文章中,你将会得到有关如何使用着色语言的介绍。它涵盖一种称为AGAL(Adobe图形汇编语言)的低级别的着色语言基础,也包括Stage3D API。您将学到什么是AGAL,它是如何工作的,以及如何将它作为您基于Stage3D的ActionScript应用程序的一部分来使用。

理解着色语言

在深入具体的AGAL之前,如果先来理解什么什么是着色语言,以及你能如何使用它来创建一个着色器,则不失为一个好主意。

着色器不是使用ActionScript编写的。 也不是使用C + +或任何其他通用语言所编写的。

着色器通常使用一种特殊的语言,被称之为着色语言。

着色器是在GPU上运行的程序,所以编写着色器最有效率的方法就是使用一种专门为GPU设计的语言。 这就是为什么你会使用这些特殊的着色语言来编写着色器,而不是使用那些为CPU编码而设计的通用语言。

有一些着色语言多年来一直被使用,对于两个标准的原生3D平台(OpenGL和DirectX):GLSL和HLSL是最常用的两个着色语言。

对于Stage3D API,Adobe公司创建了两个新的着色语言来创建GPU程序:AGAL和Pixel Bender 3D。


AGAL和Pixel Bender 3D概述

AGAL(Adobe图形汇编语言)是一种汇编语言。 它是一个非常低级的语言,这非常接近GPU的实际执行。 GPU(CPU亦是如此)并不能够直接的理解高级语言,例如ActionScript,以及那些包含变量,类等等的语言。 GPU只能理解初级的机器语言指令。 在通信管道的某处有一个编译器,它能够将高层次语言的复杂的命令转换成一系列低层次的机器语言指令。

使用AGAL,你能够直接编写低级别的命令,类似于GPU可以理解的命令。

Pixel Bender 3D是一个更高层次的语言,所以它比AGAL更容易使用。 Pixel Bender 3D是 Pixel Bender的扩展,但它已经为了使用3D和着色器来工作而被更新。

当涉及到Pixel Bender 3D和AGAL的选择时,二者各有利弊。 Pixel Bender 3D肯定是一个更容易使用的语言,所以它只需要少量的时间便能编写一个复杂的着色器。

另一方面,AGAL更接近GPU的工作方式。 因此,你将会更好地理解在你的渲染管道中究竟发生了什么。 您能够亲手优化您的着色器,而不是让编译器为你去做。 所以,如果您投入了时间去学习它,那么你就有可能使用AGAL创造出更好的更优化的着色器。

如果你的目标是学习Stage3D是如何工作的,那么AGAL也是一个不错的选择。 AGAL能够使您运行更为接近GPU的命令,所以它更容易理解真正发生了什么。

重要的是要注意,当您使用Pixel Bender 3D,是在编译时预编译着色器。 当您使用AGAL时,着色器程序以字符串的形式进入渲染管道,然后在运行时组装成目标代码。 因此,你能够使用AGAL动态创建着色器。

出于教育目的来使用Stage3D进行工作,我认为最好的选择是以学习AGAL为起点。


AGAL语法

AGAL是一种汇编语言。 如果您过去一直使用ActionScript,那么,像AGAL这样的语言最初看上去会有些奇怪。

这里是AGAL顶点着色的一个例子:

[plain]  view plain copy
  1. m44 op, va0, vc0   
  2. mov v0, va1  

我将描述上面例子中的语法,这样您就可以破译这些汇编语言的意思。

着色器的每一行都是一个命令行,它被操作符所指定,操作符是由三个字符串所组成。

AGAL代码行的语法包括以下内容:

[plain]  view plain copy
  1. <opcode> <destination>, <source 1>, <source 2 or sampler>  

这很关键,记住此语法AGAL就不再像是一个不可读的二进制字符串了。

在操作码之后,根据命令,还可能有目标,以及一个或两个来源。目标和来源被称为寄存器:即供着色器使用的小块GPU内存区。在后面的教程中,我将更详细的介绍寄存器。来源包含在操作中所要使用的值,目标则用来存储结果。


识别AGAL主要操作码

AGAL约有30个不同的操作码。 你可以在Program 3D reference documentation档中找到完整的可用操作码的列表。 下面是一些最常见的操作码。

    mov: moves data from source1 to destination, component-wise
    add: destination = source1 + source2, component-wise
    sub: destination = source1 ¨C source2, component-wise
    mul: destination = source1 * source2, component-wise
    div: destination = source1 / source2, component-wise
    dp3: dot product (3 components) between source1 and source2
    dp4: dot product (4 components) between source1 and source2
    m44: multiplication between 4 components vector in source1 and 4¡Á4 matrix in source2
    tex: texture sample. Load from texture at source2 at coordinates source1.

    图1和图2提供了一个完整的AGAL命令集的概述。


图1.AGAL内存,算术,三角和代数相关的操作码。


图2.AGAL向量和矩阵,条件,纹理采样相关的操作码。


使用AGAL寄存器

AGAL不像ActionScript和其他高级语言那样来使用变量存储数据。 AGAL只使用寄存器。

寄存器是GPU中的小块内存区域,供AGAL程序(着色器)执行时使用。 寄存器即可用于存储AGAL命令的来源,也可用于存储目标。

您也可以通过这些寄存器将参数传递到着色器。

每个寄存器为128位,能包含4个浮点数值。 每一个值被称为寄存器的组件。

寄存器组件可以通过“坐标”存取器(xyzw)和色彩存取器(rgba)存取。

所以,寄存器的第一个组件,既可以这样存取:

[plain]  view plain copy
  1. <register name>.x  

也可以这样存取

[plain]  view plain copy
  1. <register name>.r  

寄存器有时包含坐标数据,有时也包含颜色数据。 通过使用合适的存取方式,可以使你的代码更清晰,更容易阅读。

上面的一些操作码,像“add”,在运行时组件会很智能的执行他们的操作。 这意味着加法操作是按照组件到组件的方式来执行的,所以x组件被加到x组件上,y组件被加到y组件上,等等。

一共有6种可用的寄存器

1.Attribute registers 属性寄存器

这些寄存器引用了从顶点着色器输入的VertexBuffer中的顶点属性数据。因此,他们只能在顶点着色器中被使用。

这是顶点着色器负责处理的主要数据流,。 VertexBuffer中的每个顶点属性都有其自己的属性寄存器。

为了将一个VertexBuffer属性分配到一个特定的属性寄存器中,你可以使用Context3D:setVertexBufferAt(),通过适当的索引。

在着色器中,你可以通过以下语法访问属性注册器:va<n>,其中<n>属性寄存器的索引号。

总共有8个用于顶点着色器的属性寄存器。


2.Constant registers 常量寄存器

这些寄存器是为了从ActionScript向着色器传递参数的目的而服务的。 通过执行Context3D:setProgramConstants()等系列函数来达到这一目的。

在着色器中使用如下语法能够访问到这些寄存器:对于顶点着色器可以使用vc<n>,对于像素着色器可以使用fc(n),其中<n>是常量寄存器的索引号

有128个用于顶点着色器和28个用于像素着色器的常量寄存器。


3.Temporary registers 临时寄存器

这些寄存器供着色器在临时计算时使用。 由于AGAL不使用变量,您可以使用临时寄存器来存储整个代码中的数据。

可以使用如下语法访问临时寄存器:vt<n>(顶点着色器)和ft<n>(像素着色器)<n>是寄存器编号。

分别有8个临时寄存器用于顶点着色器和像素着色器。


4.Output registers 输出寄存器

输出寄存器存储顶点和像素着色器的计算输出。 对于顶点着色器,输出的是顶点位置。 对于像素着色器,它输出像素的颜色。

这些寄存器可以通过语法op(顶点着色器)和oc(像素着色器)来进行访问。

显然只有一个用于顶点和像素着色器的输出寄存器。


5.Varying Registers 变量寄存器

这些寄存器用于将数据从顶点着色器传递至像素着色器。 这些数据通过GPU被传递被正确插入,使得像素着色器对于那些正在被处理的像素收到了正确的值。

用这种方法传递的典型数据是顶点的颜色或纹理的UV坐标。

这些寄存器可以通过以下语法被访问:v<n>,其中<n>寄存器编号。

共有8个可用的变量寄存器。


6.Texture sampler registers 纹理采样寄存器

纹理采样寄存器是用来采集基于UV坐标系的纹理中的颜色值。

通过ActionScript调用Context3D::setTextureAt()指定要使用的纹理。

使用纹理采样器的语法是:fs<n> <flags>,其中<n>是取样索引,<flags>是一个或多个标志,指定应如何抽样。

<flags>是一个逗号分隔的字符串,它的定义如下:

    texture dimension. Options: 2d, cube
    mip mapping. Options: nomip (or mipnone , they are the same) , mipnearest, miplinear
    texture filtering. Options: nearest, linear
    texture repeat. Options: repeat, wrap, clamp

例如,对于一个标准的没有多重材质映射的2D纹理,进行线性滤镜采样到临时寄存器ft1,我们将使用如下代码:

[plain]  view plain copy
  1. tex ft1, v0, fs0 <2d,linear,nomip>  

创建一个AGAL着色器示例

在本节中,你将通过一个着色器的例子​​更好的理解它的工作原理。

假设在顶点缓冲区的顶点包含顶点的位置,偏移量为0,以及顶点颜色,偏移量为3,代码看起来像这样:

[javascript]  view plain copy
  1. var vertices:Vector.<Number> = Vector.<Number>([ -0.3,-0.3,0, 1, 0, 0, // x, y, z, r, g, b   
  2.                                                  -0.3, 0.3, 0, 0, 1, 0,   
  3.                                                   0.3, 0.3, 0, 0, 0, 1]);  

我们的目标是保证顶点着色器正确的变换顶点的位置,并传递每一个顶点的颜色到像素着色器。

您可以用下面的代码实现:

[javascript]  view plain copy
  1. m44 op, va0, vc0 // pos to clipspace   
  2. mov v0, va1 // copy color  

第一行代码在顶点输入的属性寄存器v0和通过从ActionScript传递进来的转换矩阵之间进行了一次4*4的矩阵乘法。 在透视渲染中,通常将模型空间转换至剪辑空间,因此我们假设转换矩阵被ActionScript传递至常量寄存器vc0。

注:剪辑空间和透视投影将在下一个教程进行更详细的讨论。

矩阵可以被着色器传递至寄存器vc0,通过调用:

[javascript]  view plain copy
  1. Context3D::setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, matrix, true );  

顶点着色器第二行的意思是,拷贝顶点颜色数据到变量寄存器v0,使它能够被GPU插入(interpolated)和传递至像素着色器。

像素着色器简单的拷贝变量着色器v0的颜色内容到输出寄存器oc:

[javascript]  view plain copy
  1. mov oc, v0  

因此,这个顶点/像素着色器组合就是通过从ActionScript传递的变换矩阵对3D模型进行了变换。并且应用了顶点颜色。

就是这样! 你的第一个顶点和像素着色器已经完成了。
使用Program3D和AGAL Mini Assembler编译一个简单的ActionScript应用程序吧。

但是,你怎么样才能将这些AGAL代码实际融入到一个ActionScript应用程序呢?这便是Stage3D API的用武之地。

[javascript]  view plain copy
  1. var program:Program3D = context3D.createProgram();  

在使用Program3D(着色器)渲染之前,你首先需要把它上传到GPU。你可以通过调用方法:

[javascript]  view plain copy
  1. Program3D::upload(vertexByteCode: ByteArray, fragmentByteCode:ByteArray);  

此方法为了将它上传至GPU,需要以编译完成的目标码,顶点的版本以及片段着色器做为输入。

将AGAL着色器编译成目标码的一个好方法是使用AGAL Mini Assembler:它是一个实用工具,能够将顶点和像素着色器的源文件以字符串的形式作为输入,并在运行时编译成目标码。

你可以在这里下载AGAL Mini Assembler。

因此,首先你要使用AGAL Mini Assembler去编译上面所讨论的顶点和像素着色器。

[javascript]  view plain copy
  1. var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();   
  2. vertexShaderAssembler.assemble( Context3DProgramType.VERTEX, "m44 op, va0, vc0\n" + // pos to clipspace   
  3.                                                              "mov v0, va1" // copy color );   
  4. var fragmentShaderAssembler : AGALMiniAssembler= new AGALMiniAssembler();   
  5. fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT, "mov oc, v0" );  

然后将顶点和像素着色器程序上传至GPU:

[javascript]  view plain copy
  1. var program:Program3D = context3D.createProgram();   
  2. program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);  

使用ActionScript与AGAL进行通讯

着色器不能独自存活。 它是被基于ActionScript应用程序的主Stage3D所使用。 因此,它需要应用程序向他发送需要处理的数据。

在一般情况下,着色器需要VertexBuffer数据(顶点属性),纹理,和额外的着色器可能需要从ActionScript获得的参数,如变换矩阵。

在渲染时,在使用Program3D,以及相关的VertexBuffers和纹理之前,你需要激活他们,通过使用下面的调用:
[javascript]  view plain copy
  1. Contex3D::setProgram(program:Program3D)  
  2. Context3D::setVertexBufferAt(index:int, buffer:VertexBuffer3D, bufferOffset:int, format:String)  
  3. Context3D::setTextureAt(sampler:int, texture:TextureBase)  

****Note that setVertexBufferAt enables a specific Vertex Attribute at a certain offset in the Vertex Buffer (parameter 3), and associates it to an Attribute Register (stream) specified by index (first parameter).

setTextureAt方法通过第一个参数“sampler”能够使纹理联合起来。

这是这些语法在渲染之前正确的使用方法:

[javascript]  view plain copy
  1. // vertex position to attribute register 0   
  2. context3D.setVertexBufferAt (0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);   
  3. // assign texture to texture sampler 0   
  4. context3D.setTextureAt( 0, texture );   
  5. // assign shader program  
  6. context3D.setProgram( program );  

在使用这些方法中的任何一个之前,你必须确定它们已经通过使用各自的上传方法被上传至GPU:
[javascript]  view plain copy
  1. Program3D::upload()  
  2. VertexBuffer3D::uploadFromVector(data:Vector.<Number>, startVertex:int, numVertices:int)  
  3. Texture::uploadFromBitmapData(source:BitmapData, miplevel:uint = 0)  
然后,你会希望把已经传递至着色器的参数做为常量存储在常量寄存器中。 为了编写ActionScript的Vector或Matrix3D,你可以分别使用如下方法:
[javascript]  view plain copy
  1. Context3D::setProgramConstantsFromVector(programType:String, firstRegister:int, data:Vector.<Number>, numRegisters:int = -1)  
  2. Context3D::setProgramConstantsFromMatrix(programType:String, firstRegister:int, matrix:Matrix3D, transposedMatrix:Boolean = false)  

所以,如果你需要传递一个基本的旋转矩阵至你的着色器,你应该这样做:

[javascript]  view plain copy
  1. var m:Matrix3D = new Matrix3D();   
  2. m.appendRotation(getTimer()/50, Vector3D.Z_AXIS);   
  3. context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);  

矩阵被存储到常量寄存器0中,供顶点着色器使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值