2天时间,聊今年最热的 Agent、上下文工程、AI 产品创新等话题。2025 年最后一场~ 了解详情
写点什么

什么是 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:082415

评论

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

人脸活体检测初识

六月的雨在InfoQ

人脸活体检测 三周年连更 人脸数据库 人脸辨识度

Spring Boot 整合 Redis 基于 Stream 消息队列 实现异步秒杀下单

区块链基础设施 NFTScan 新增支持 Aptos 网络

NFT Research

区块链+ NFT

裸辞底气!GitHub飙升“java面试笔记2023” 了解下八股文天花板

Java你猿哥

Java 面试 Spring Boot ssm 八股文

阿里限量的性能调优+微服务+高并发设计,真的太香了!

Java 微服务架构 系统设计 性能调优 亿级并发

聊聊 IP packet 的 TTL 与 tcp segment 的 MSL

明哥的IT随笔

TCP/IP TTL MSL

阿里新一代微服务,内部大佬手抄的笔记+脑图不容错过,全是精华

Java 架构 微服务 Spring Cloud Aliababa

ChatGPT 会在三年内终结编程吗?| 社区征文

神木鼎

三周年征文

Apifox WebSocket 调试功能你会用了吗?

Apifox

程序员 接口 websocket API API 调试

Apache Flink ML 2.2.0 发布公告

阿里云大数据AI技术

大数据 算法 企业号 4 月 PK 榜

Spring Boot 整合 Redis 基于 Stream 消息队列 实现异步秒杀下单

Java你猿哥

Java redis stream ssm 消息队列

阿里技术官神作!大厂亿级流量性能调优学习手册,堪称保姆级教学

Java 性能优化 性能调优

运维报表有哪些内容?有什么用?

行云管家

运维 报表 IT运维 容器化部署

【FAQ】关于JavaScript版本的华为地图服务Map的点击事件与Marker的点击事件存在冲突的解决方案

HarmonyOS SDK

HMS Core

本铯智能科技是家怎样的共享电动车厂家?

共享电单车厂家

共享电动车厂家 共享电单车厂商 本铯智能科技 本铯智能电动车厂家

合合信息新推出反光消除技术,助力手写文字识别更精准

合合技术团队

人工智能 文字识别 扫描全能王 反光去除

亿级日活业务稳如磐石,华为云CodeArts PerfTest发布

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 企业号 4 月 PK 榜

与全球开发者创新共赢,全球首个“开发者村” 正式落成

极客天地

ByteHouse云数仓版查询性能优化和MySQL生态完善

NineData

数据库 架构 字节跳动 Clickhouse bytehouse

一文详解多模态认知智能

华为云开发者联盟

人工智能 华为云 AIGC 华为云开发者联盟 企业号 4 月 PK 榜

逆天!腾讯大神纯手撸“架构师速成手册”Github狂获4.5kstar

Java你猿哥

Java 架构 ssm 架构设计 架构师

从源码全面解析LinkedBlockingQueue的来龙去脉

那些关于DIP器件不得不说的坑

华秋PCB

插件 DIP 元器件 PCB PCB设计

YARN 远程代码执行(RCE)安全漏洞问题分析与解决方案

明哥的IT随笔

大数据 YARN 数据安全 RCE

读书笔记丨远程服务调用和RESTful,如何分析和抉择?

华为云开发者联盟

开发 华为云 华为云开发者联盟 企业号 4 月 PK 榜 远程服务调用

蚂蚁安全科技 Nydus 镜像加速实践

SOFAStack

开源 镜像 镜像安全 OCI Nydus

eBPF的发展演进---从石器时代到成为神(二)

统信软件

Linux Kenel 内核 Linux内核

从此脱离CRUD!Github热榜第三架构师速成手册成功颠覆了我的认知

Java你猿哥

架构 ssm 架构设计 架构师 微服务实战

HashData认证云原生数据仓库管理工程师培训报名开启!

酷克数据HashData

堡垒机英文是什么?有哪些品牌?

行云管家

网络安全 堡垒机

聊聊 Zookeeper 的 4lw 与信息安全

明哥的IT随笔

zookeeper 数据安全

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