【QCon】精华内容上线92%,全面覆盖“人工智能+”的典型案例!>>> 了解详情
写点什么

什么是 AGAL

  • 2011-11-10
  • 本文字数:5853 字

    阅读完需:约 19 分钟

目录

需求

预备知识

需要基本了解 Stage3D API。最好还拥有使用着色器的知识并理解可编程函数管道的操作原理。在阅读这些指令之前,一定要首先阅读这个关于 Stage3D 的系列中的前两篇教程(1. Stage3D 的工作原理,2. 顶点和片段着色器)。

用户水平

中级

需要的产品

本文将介绍使用着色语言。我将介绍使用 Stage3D API 中所包含的低级着色语言 AGAL(Adobe Graphics Assembly Language)的基本知识。您将了解 AGAL 是什么、它的工作原理,以及如何在基于 Stage3D 的 ActionScript 应用程序中使用它。

理解着色语言

在专门深入介绍AGAL 之前,最好首先理解什么是着色语言,以及如何使用它创建着色器。

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

着色器通常使用一种称为着色语言的特殊语言来编写。

着色器是在GPU 上运行的程序,所以编写着色器的最有效方式是使用一种专为GPU 而设计的语言。这正是您将使用3 种特殊的皂色语言编写着色器,而砽专为CPU 编码而设计的通用语言的原因。

有几种着色语言已使用了多年,用于两种标准的原生3D 平台(OpenGL 和DirectX):GLSL 和HLSL 是两种最常用的着色语言。

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

AGAL 和 Pixel Bender 3D 概述

AGAL(Adobe Graphics Assembly Language)是一种汇编语言。它是一种非常低级的语言,非常接近于 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 顶点着色器的一个示例:

复制代码
m44 op, va0, vc0
mov v0, va1

我将介绍上面这个示例的语法,以便您可以理解每行汇编代码的含义。

着色器的每一行是一个命令,由一个称为操作码的 3 字符字符串指定。

一行 AGAL 代码的语法如下:

<opcode> <destination>, <source 1>, <source 2 or sampler>此语法非常重要。请记住此语法,AGAL 很快就会变成看起来难念的语言。

在操作码之后,依据命令,可能是一个目标,以及一个或两个来源。目标和来源称为寄存器:GPU 中供着色器使用的小型内存区域。本章后面将更详细地介绍寄存器。来源包含操作中使用的值,目标是存储结恶果的地方。

识别AGAL 中主要的操作码

AGAL 包含大约 30 个不同的操作码。可用操作码的完整列表可在 Program 3D 参考文档中找到。以下一些最常用的操作码。

  • mov:将数据从来源 1 移动到目标,按成分运算
  • add:目标 = 来源 1 + 来源 2,按成分运算
  • sub:目标 = 来源 1 – 来源 2,按成分运算
  • mul:目标 = 来源 1 * 来源 2,按成分运算
  • div:目标 = 来源 1 / 来源 2,按成分运算
  • dp3:来源 1 和来源 2 之间的点乘(3 个成分)
  • dp4:来源 1 和来源 2 之间的点乘(4 个成分)
  • m44:来源 1 中的 4 个成本矢量和来源 2 中的 4×4 矩阵之间的倍乘
  • tex:纹理采样。从坐标“来源 1”处的“来源 2”处的纹理加载。

图 1 和图 2 概述了完整的 AGAL 命令集。

图 1. 与操作码相关的 AGAL 内存、算法、三角法和代数。 (+) 查看大图

图 2. 与操作码相关的 AGAL 矢量和矩阵、条件和纹理采样。 (+) 查看大图

使用AGAL 寄存器

AGAL 不使用变量来存储数据,像 ActionScript 和其他高级语言所做的一样。AGAL 仅使用寄存器。

寄存器是 GPU 中的小型内存区域,AGAL 程序(着色器)可在执行期间使用它们。寄存器用于存储 AGAL 命令的来源和目标。

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

每个寄存器为 128 位宽,这意味着它包含 4 个浮点值。每个值称为寄存器的一个成分。

寄存器组件可通过坐标存取器(xyzw)和通过颜色存取器(rgba)存取。

寄存器的第一个组件可这样存取:

<register name>.x也可以这样存取:

<register name>.r有时寄存器包含类似坐标的数据,而其他时候它们包含颜色数据。通过使用正确类型的存取器,您可以是代码更简洁和容易阅读。

上面的一些操作码(比如 add)按组件执行它们的运算。这意味着加运算逐个组件地执行,所以 x 组件与 x 组件相加,y 组件与 y 组件相加,依此类推。

有 6 种类型的寄存器。

1. 属性寄存器

这些寄存器引用作为顶点着色器输入的 VertexBuffer 的顶点属性数据。因此,它们仅可用于顶点着色器。

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

要将一个 VertexBuffer 属性分配给特定的属性寄存器,可以使用函数 Context3D:setVertexBufferAt() 和合适的索引。

然后从着色器,使用语法 va访问属性寄存器,其中是属性寄存器的索引编号。

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

2. 常量寄存器

这些寄存器用于处理从 ActionScript 传递到着色器的参数。这由 Context3D::setProgramConstants() 系列函数执行。

这些寄存器使用以下语法从着色器访问:对于顶点着色器,使用 vc;对于像素着色器,使用 fc,其中是常量寄存器的索引编号。

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

3. 临时寄存器

这些寄存器可用于着色器,它们用于临时计算。因为 AGAL 不使用变量,您将使用临时寄存器来存储整个代码中的数据。

临时寄存器使用语法 vt(顶点着色器)和 ft(像素着色器)来访问,其中是寄存器编号。

有 8 个临时寄存器可用于顶点着色器,8 个可用于像素寄存器。

4. 输出寄存器

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

这些寄存器可使用以下语法访问:op 用于顶点着色器,oc 用于像素着色器。

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

5. 可变寄存器

这些寄存器用于将数据从顶点着色器传递到像素着色器。传递的数据由 GPU 恰当地插入,使像素着色器能够收到被处理的像素的正确值。

以这种方式传入的典型数据是顶点颜色或纹理的 UV 坐标。

这些寄存器可使用语法 v访问,其中是寄存器编号。

有 8 个可变寄存器可用。

6. 纹理采样器寄存器

纹理采样器寄存器用于基于 UI 坐标,从纹理挑选颜色值。

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

使用纹理采样器的语法为:fs ,其中是采样器索引,是一个或多个指定应该如何采样的标志。

是一个逗号分隔的字符串集,定义:

  • 纹理维度。选项:2d、cube
  • mip 映射。选项:nomip(或 mipnone,它们是相同的)、mipnearest、miplinear
  • 纹理过滤。选项:nearest、linear
  • 纹理重复。选项:repeat、wrap、clamp

例如,一个没有 MIP 映射和现象过滤的标准 2D 纹理可以使用以下代码采样到临时寄存器 ft1 中:

tex ft1, v0, fs0 <2d,linear,nomip>在上面的示例中,可变寄存器 v0 持有插入的纹理 UV。

创建示例AGAL 着色器

在本节中,您将看到一个着色器示例,更好地理解它的操作原理。

假设顶点缓冲区中的顶点包含顶点位置(位于偏移0)和顶点颜色(位于偏移3)。该代码类似于:

复制代码
var vertices:Vector.<Number> = Vector.<Number>([
-0.3,-0.3,0, 1, 0, 0, // x, y, z, r, g, b
-0.3, 0.3, 0, 0, 1, 0,
0.3, 0.3, 0, 0, 0, 1]);

这段代码的目标是使顶点着色器正确地转换顶点位置,将每个顶点颜色传递到像素着色器。

您可以通过以下代码实现此目的:

复制代码
m44 op, va0, vc0 // pos to clipspace
mov v0, va1 // copy color

第一行在顶点输入属性寄存器 0(va0)和一个从 ActionScript 传入的变换矩阵之间执行一个 4×4 矩阵乘。当在透视图中呈现时,这通常是从模型空间到剪贴空间的变换矩阵,我们假设它从 ActionScript 传递到常量寄存器 0(vc0)。

注意:剪贴空间和透视投影将在本系列的下一个教程中更详细探讨,该教程名为使用Stage3D 和透视投影

矩阵可通过以下调用传入到着色器中的寄存器vc0 中:

Context3D::setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, matrix, true );顶点着色器的第二行将顶点颜色数据复制到可变寄存器0(v0),以便它可以由GPU 插入,传递到像素寄存器。

像素着色器将可变寄存器v0 颜色内容复制到它的输出寄存器oc:

mov oc, v0所以,这个顶点/ 像素着色器对使用从ActionScript 传入的一个变换矩阵转换3D 模型顶点,并应用顶点颜色。

就这么简单!您的第一个顶点和像素着色器。

使用Program3D 和AGAL Mini Assembler 构建示例ActionScript 应用程序

那么,如何实际地将这些AGAL 代码放在有效的ActionScript 应用程序中?这正是Stage3D API 发挥作用的地方。

var program:Program3D = context3D.createProgram();在能够使用Program3D(一个着色器)进行呈现之前,您首先需要将它上传到GPU。为此,可以调用方法

Program3D::upload(vertexByteCode: ByteArray, fragmentByteCode:ByteArray);此方法调用需要以输入的形式获得顶点和片段着色器的已编译的对象代码版本,以便将它上传到GPU。

一种将AGAL 着色器编译为对象代码的不错方式是使用 AGAL Mini Assembler:一个使用工具,以字符串形式接收顶点和像素着色器源代码作为输入,在运行时将它们编译为对象代码。

您可以在此处下载AGAL Mini Assembler。

所以,首先您将使用AGAL Mini Assembler 编译上面讨论的顶点和像素着色器。

复制代码
var vertexShaderAssembler: AGALMiniAssembler = new AGALMiniAssembler();
vertexShaderAssembler.assemble(Context3DProgramType.VERTEX, "m44 op, va0, vc0\n" + // pos to clipspace
"mov v0, va1" // copy color
);
var fragmentShaderAssembler: AGALMiniAssembler = new AGALMiniAssembler();
fragmentShaderAssembler.assemble(Context3DProgramType.FRAGMENT, "mov oc, v0");

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

复制代码
var program:Program3D = context3D.createProgram();
program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);

使用 ActionScript 与 AGAL 通信

着色器无法自行运行。它由您基于 Stage3D 的主要的 ActionScript 应用程序使用。因此,它需要应用程序向它发送需要处理的数据。

一般而言,着色器将需要 VertexBuffer 数据(顶点属性)、纹理和着色器可能需要从 ActionSript 获得的其他参数,比如一个变换矩阵。

在呈现时,在使用 Program3D 以及相关的 VertexBuffer 和纹理之前,您需要使用以下调用启用它们:

  • Contex3D::setProgram(program:Program3D)
  • Context3D::setVertexBufferAt(index:int, buffer:VertexBuffer3D, bufferOffset:int, format:String)
  • Context3D::setTextureAt(sampler:int, texture:TextureBase)

请注意,setVertexBufferAt 在顶点缓冲区中某个偏移位置启用一个特定的顶点属性(参数 3),将它与索引(第一个参数)所指定的一个属性寄存器(流)相关联。

setTextureAt 调用启用一个 Texture,并将它与第一个参数“sampler”所指定的某个纹理采样器相关联。

以下是在呈现之前使用这些调用的语法:

复制代码
// vertex position to attribute register 0
context3D.setVertexBufferAt (0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
// assign texture to texture sampler 0
context3D.setTextureAt( 0, texture );
// assign shader program
context3D.setProgram( program );

在启用任何这些属性之前,您需要确保调用相应的上传方法将它们上传到了 GPU。

  • Program3D::upload()
  • VertexBuffer3D::uploadFromVector(data:Vector., startVertex:int, numVertices:int)
  • Texture::uploadFromBitmapData(source:BitmapData, miplevel:uint = 0)

然后,您需要能够以常量的形式向您的着色器传入参数,将它们存储在常量寄存器中。为此,执行以下调用:

  • Context3D::setProgramConstantsFromVector(programType:String, firstRegister:int, data:Vector., numRegisters:int = -1)
  • Context3D::setProgramConstantsFromMatrix(programType:String, firstRegister:int, matrix:Matrix3D, transposedMatrix:Boolean = false)

以便分别编写一个 ActionScript Vector 或 Matrix3D。

所以,如果您需要将一个基本的旋转矩阵传入您的着色器,您需要运行以下代码:

复制代码
var m:Matrix3D = new Matrix3D();
m.appendRotation(getTimer()/50, Vector3D.Z_AXIS);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);

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

延伸阅读

本文向您介绍了着色器的概念和AGAL 着色语言。如果您希望构建基于Stage3D API 的ActionScript 3D 应用程序,必须创建一个着色器。尽管我们还没有构建完全有用的Stage3D 应用程序,但本文内容为使用Stage3D API 的能力奠定了基础。在本系列的下一篇文章中,我会将所有知识点衔接起来,向您展示如何构建一个使用Stage3D 呈现简单几何体的应用程序。

查看原文: What is AGAL

2011-11-10 06:081714

评论

发布
暂无评论
发现更多内容

深圳web前端培训费用多少?

小谷哥

字节Java大神精心编写的《Java开发者面试百宝书》,助你一臂之力!

收到请回复

Java 云计算 开源 架构 编程语言

【Go】go build失败,报方法undefined

非晓为骁

Go 编译 go build

史上最全大厂面试题复盘总结,全会进大厂拿35K没问题(Java岗)

收到请回复

Java 云计算 开源 架构 编程语言

什么是帮助中心?企业该怎样制作帮助中心页面?

Baklib

企业 帮助中心

【荣耀帐号服务】手把手教你快速上手快应用接入

荣耀开发者服务平台

数据库 前端 手机 服务器 honor

低代码平台包罗万象,企业应该如何做出抉择?

ToB行业头条

在武汉Java培训费用多少

小谷哥

谈一谈 build-scripts 架构设计

Java-fenn

Java

Java 异步编程 (5 种异步实现方式详解)

Java-fenn

Java

「番外篇」如何用Git平台账号登录建木CI with docker-compose.yml

Jianmu

DevOps 低代码 CI/CD gitops 无代码

为什么说企业需要关注客户体验?怎样去提升它?

Baklib

企业 客户体验

C++ 左值引用与 const 关键字

Java-fenn

Java

京东云无线宝产品部负责人张晓东 : 京东云无线宝与开源的亲密关系 | 《大神详解开源 BUFF 增益攻略》讲座回顾

Apache IoTDB

物联网 京东云 企业号九月金秋榜

大数据培训机构如何选择

小谷哥

Go 语言为什么建议定义零值可用的结构体?

Java-fenn

Java

mysql优化---如何搭建mysql的主从关系和mycat中间件

Java快了!

设计模式之备忘录模式

Java-fenn

Java

教你如何用CSS修改图片颜色

千锋IT教育

Java培训可以从事哪些工作

小谷哥

21个大厂Offer?这份“Java核心技能精讲”轻松收割

收到请回复

Java 云计算 开源 架构 编程语言

有关Redis你掌握好这22点,大厂面试基本稳了!

Java全栈架构师

数据库 程序员 后端 Java 面试 redis 底层原理

通过自动化单元测试的形式守护系统架构

京东科技开发者

系统架构 单元测试 代码评审 代码质量检测工具 Archunit

【CSM认证】11月1-4日在线工作日班 | 全国招生

ShineScrum捷行

项目管理 Scrum Scrum Master 敏捷项目管理

女生参加java培训前景如何

小谷哥

MySQL约束和事务知识归纳。

Java快了!

MySQL

面试官:说说Java并发运行中的一些安全问题

Java-fenn

Java

面试复盘 | 2022届 大疆秋招 测试开发 完整面经

Java-fenn

Java

C++ 中 Lambda 表达式的快速指南

Java-fenn

Java

建木持续集成平台v2.5.5发布

Jianmu

开源 DevOps 低代码 CI/CD 无代码

利用Python开发App实战

千锋IT教育

什么是AGAL_语言 & 开发_Marco Scabia_InfoQ精选文章