Everyday Stage3D (四) AGAL的数据操作

上一篇教程中我们对AGAL中的基本概念进行了基本的讲解,可能你在学习的时候发现很多内容一知半解,不是非常透彻,没关系,随着教程的深入这些问问也会慢慢变为你常用的知识内容。这一边我们继续对AGAL的内容进行讲解。

我们还是使用原来的demo,因为这个demo简单而且对于目前要掌握的内容具备一定的说明性。我们已经知道了AGAL中各个寄存器的功能,以及使用方法。现在我们关心的是使用这些工具来对数据进行操作。而数据如何组织,如何进行操作则是本篇要讨论的问题。

我们还是从顶点开始。大家还记不记得你的代码中对于顶点的操作包含一个update这样的API?不错,这个API的功能是将你的数据上传之显存以供你后面的程序使用。但是请注意,顶点虽然上传至GPU,但是用不用则要看你的接口调用,如果你上传的数据没有使用过,那么恭喜你,你白白浪费了用户显卡的一点点显存。我们要解决的问题是如何有效而正确的是使用这些数据。前面我们介绍过va这个寄存器。实际上当你编写一段程序的时候,va肩负着数据读取的作用。我们用代码来进行说明。

this._vb.uploadFromVector( triangleData,0,triangleData.length/5 );

上面这行代码就是将我们triangleData顶点数据上载到GPU中。请注意,当你没有对_vb使用过dispose操作的时候,这些数据会随着你进程的寿命驻留在显存当中。所以,当你不需要使用到某些数据或者模型的时候,你可以使用下面这样的语句来为你的GPU清理出一些显存来。

this._vb.dispose();

我们再来回忆一下顶点操作的AGAL语句。

mov op, va0

如果你认真的学习本教程的话,你应该对这个va0产生疑问,为什么是va0而不是va或者va4之类的名称,这里我们就要引出另外一个问题,va 属性寄存器只有8个,也就是说你的AGAL中如果使用属性寄存器只能够出现一下8中情况va0,va1,va2,va3,va4,va5,va6,va7。如果你出现了这8个之外的操作,那么恭喜你,你的程序将成功的引发一个error!对于为什么是8个属性寄存器,官方给出的解释为考虑到就设备的兼容性。我们暂且不对这个问题进行深究,这就好比你问为什么一个人要有一个心脏而不是两个一样。那么为什么我们这段程序中要使用va0,而不是其他7个呢,请大家注意程序中的另外一句话。

this._context3d.setVertexBufferAt( 0, this._vb, 0, Context3DVertexBufferFormat.FLOAT_2 );

其实道理非常的简单,是我们人工的指定将顶点数据的前两个放到第一个寄存器va0中的。这个API中,第一个参数0标识的就是将数据传递至va0,如果我们把参数改变一下,改为:

this._context3d.setVertexBufferAt( 1, this._vb, 0, Context3DVertexBufferFormat.FLOAT_2 );

那么你的AGAL代码也相应的要变为

mov op, va1

我想这么解释的话大家就应该明白了。对于第二个参数不用过多解释,表示的是顶点数据本身。第三个参数的实参为0,这里表示数据偏移量,因为我们的数据格式为x,y,r,g,b,对于顶点我们只需要下标为0,1的x,y两个数据,所以我们从0开始取值。最后一个参数大家可以直接翻阅API文档,表示数据的长度,我们需要x,y两个数据,所以选择FLOAT_2。到目前为止,我们已经清楚的明白va0的数据是如何来的,同时我们也要明白这里的set操作只在你设置数据的时候执行一次即可。本篇讲解完成之后,我们会把优化修改后的代码共享给大家。

到目前位置我们还没有使用过vc,对于vc我们计划在后面的部分逐步设计到,因为vc的功能可以帮助我们优化扩展我们的程序,以便提高渲染性能。

到目前位置不知道到大家有没有对这段程序产生过什么疑问或者遗漏掉什么。如果你细心的话,你会发现,在Context3DVertexBufferFormat这个类中,我们最大的数量只有4,为什么呢?其实非常简单,因为每一个va中,我们最多能携带4个32位的浮点数。也就是说,你可以通过va0.x,va0.y,va0,z,va0.w来分别访问内部的四个数据。当然你也可以通过rgba来进行访问,这种方法我们在后面讲解。

对于顶点的说明暂且到这里,片段着色器其实操作方式相同。对于ft寄存器我们使用的数量同样有8个。具体的操作实践我们在后面的文章中会逐步讲解到。

最后分享代码:

package
{
	import com.adobe.utils.AGALMiniAssembler;

import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.MouseEvent;

public class stage3ddemo1 extends Sprite
{

	private var _stage3d:Stage3D;
	private var _context3d:Context3D;

	public function stage3ddemo1()
	{
		trace( "stage3D层数量:",stage.stage3Ds.length );

		if( stage.stage3Ds.length > 0 )
		{
			this._stage3d = stage.stage3Ds[0];
			this._stage3d.addEventListener(Event.CONTEXT3D_CREATE,created_handler);
			this._stage3d.addEventListener(ErrorEvent.ERROR, created_error_handler );
			this._stage3d.requestContext3D( Context3DRenderMode.AUTO );
		}
	}

	private function created_error_handler(evt:ErrorEvent):void
	{
		trace("GPU启动失败或设备丢失!");
	}

	private function created_handler (evt:Event):void
	{
		trace( "GPU设备类型:",this._stage3d.context3D.driverInfo );

		this._context3d = this._stage3d.context3D;
		this._context3d.configureBackBuffer( 300,300,0,true);

//		stage.addEventListener(MouseEvent.CLICK, click_handler );

		this.addTriangle();
		this.draw();
	}

	private var _vb:VertexBuffer3D;
	private var _ib:IndexBuffer3D;
	private var _pm:Program3D;

	private function addTriangle():void
	{

		//三角形顶点数据
		var triangleData:Vector.<Number> = Vector.<Number>([
		//	x, y, r, g, b
			0, 1, 0, 0, 1,
			1, 0, 0, 1, 0,
			0, 0, 1, 0, 0
		]);

		this._vb = this._context3d.createVertexBuffer( triangleData.length/5, 5 );
		this._vb.uploadFromVector( triangleData,0,triangleData.length/5 );
	//	this._vb.dispose();

		//三角形索引数据
		var indexData:Vector.<uint> = Vector.<uint>([
			0, 1, 2
		]);

		this._ib = this._context3d.createIndexBuffer( indexData.length );
		this._ib.uploadFromVector( indexData, 0, indexData.length );

		//AGAL
		var vagalcode:String = "mov op, va0

” + “mov v0, va1”; var vagal:AGALMiniAssembler = new AGALMiniAssembler(); vagal.assemble( Context3DProgramType.VERTEX, vagalcode );

		var fagalcode:String = "mov oc, v0";
		var fagal:AGALMiniAssembler = new AGALMiniAssembler();
		fagal.assemble( Context3DProgramType.FRAGMENT, fagalcode );

		this._pm = this._context3d.createProgram();

		this._context3d.setVertexBufferAt( 0, this._vb, 0, Context3DVertexBufferFormat.FLOAT_2 );
		this._context3d.setVertexBufferAt( 1, this._vb, 2, Context3DVertexBufferFormat.FLOAT_3 );
		this._context3d.setProgram( this._pm );

		this._pm.upload( vagal.agalcode, fagal.agalcode );
	}

	private function draw():void
	{
		this._context3d.clear( 0, 0, 0);
		this._context3d.drawTriangles( this._ib );
		this._context3d.present();
	}

	private function click_handler(evt:MouseEvent):void
	{
		this._context3d.dispose();
	}
}

}