Molehill初探

  关注flash的同学肯定都知道Adobe推出了新的基于硬件加速的API Molehill。它可以在60Hz左右的高分辨率显示器下全屏渲染近百万的Z缓冲三角形。就算你的显卡不兼容,也会通过一个叫SwiftShader软件来利用CPU进行渲染。

  我们熟悉的2D显示列表位于Molehill的Stage3D上面,而Stage3D又位于StageVideo上面。实际上3D内容可以通过bitmapdata呈现在2D显示列表中。

  下图表示了Molehill的基本架构

  

  

  下面的代码在Stage3D中创建了一个三角形,从中我们可以略微熟悉一下这套API的用法

package
	
{
	import com.adobe.utils.AGALMiniAssembler;
	
	import flash.display.Sprite;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.display3D.Context3D;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DTriangleFace;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.Program3D;
	import flash.display3D.VertexBuffer3D;
	import flash.events.Event;
	import flash.geom.Matrix3D;
	import flash.geom.Rectangle;
	
	[SWF(width="980", height="570", frameRate="60")]
	public class MoleHillTest extends Sprite
	{
		//Context3D 是渲染发生的地方,它和Stage3D的关系就像bitmapdata和bitmap的关系
		private var context3d:Context3D;
	
		//VertexBuffer3D将存储顶点数据
		private var vertexBuffer:VertexBuffer3D;
	
		//这里定义顶点的渲染顺序
		private var indexBuffer:IndexBuffer3D;

		//Program3D是用来包含两个着色器的
		private var program:Program3D;

		//这是一个矩阵,我们的顶点着色器将使用它来修改顶点的位置
		private var model:Matrix3D=new Matrix3D();
		
		public function MoleHillTest()
		{
		
			//监听flash什么时候给我们返回一个Context3D对象,因为当你请求Context3D的时候,flash不一定会马上回应
			stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onGotContext);
			//请求一个Context3D对象
			stage.stage3Ds[0].requestContext3D();
			
		}
		protected function onGotContext(ev:Event):void
		{
			//获得Stage3D对象,它将给我们Context3D
			var stage3d:Stage3D=Stage3D(ev.currentTarget);
			//我们获得了Context3d
			context3d=stage3d.context3D;
			//如果没有获得,那我们就跳出函数
			trace(context3d)
			if(context3d==null)
				return;
			//当发生问题的时候,我们可以获得error信息。请在正式发布的时候设为false以提高性能
			context3d.enableErrorChecking=true;
			//基本上,你可以看成是 new BitmapData(980, 570),表示渲染的大小。而4表示反锯齿的强度,可以设置的值为0,2,4,16.
			context3d.configureBackBuffer(980, 570, 4, true);
			//这里是说当三角形没有对着我们的时候,就不要渲染它,还有可能的值是Context3DTriangleFace.FRONT,Context3DTriangleFace.FRONT_AND_BACK,Context3DTriangleFace.NONE。
			context3d.setCulling(Context3DTriangleFace.BACK);
			//创建一个顶点缓冲,我们将有3个顶点(三角形),每个顶点包含6个元素,分别表示
			//x坐标,y坐标,z坐标,红色,绿色,蓝色。
			vertexBuffer=context3d.createVertexBuffer(3, 6);
			//为顶点创建一个索引缓冲来为三角形排序,我们有一个三角形,因此这里有3个顶点,因此有3个索引
			indexBuffer=context3d.createIndexBuffer(3);
			//顶点数据包含每个顶点的位置信息以及颜色信息
			//x==-1表示屏幕的左边
			//x==1表示屏幕的右边
			//x==0表示屏幕的中央
			//y也是同样的道理。1,0,-1分别表示屏幕的上中下
			//颜色值在0-1之间,比如1,0,0表示纯红色
			//下面的数据描述了一个三角形,它左下角的顶点是红色,中间上面的顶点是绿色,右下角的顶点是蓝色
			var vertexData:Vector.<Number>=Vector.<Number>(
				[
					-1, -1, 0,  255/255, 0, 0, //<- 1st vertex x,y,z,r,g,b
					0, 1, 0,  0, 255/255, 0, //<- 2nd vertex x,y,z,r,g,b
					1, -1, 0,  0, 0, 255/255 //<- 3rd vertex x,y,z,r,g,b
				]
			);
			//这个是我们渲染顶点的顺序,0是第一个顶点,1是第二个,2是第三个。
			var indexData:Vector.<uint>=Vector.<uint>([0, 1, 2]);
			//将我们的顶点数据传递给顶点缓冲
			vertexBuffer.uploadFromVector(vertexData, 0, 3);
			//将我们表示顺序的索引值传递给顶点缓冲
			indexBuffer.uploadFromVector(indexData, 0, 3);
			//AGAL(Adobe Graphics Assembly Language)是Adobe开发的图形汇编语言,可以操控机器硬件比如可编程显卡
			//AGALMiniAssembler是Adobe官方提供的编译器类,它通过字符串指令来获得一个AGAL二进制流,再通过context3D上传给显卡的编程管线。最后由显卡来处理顶点以及片段的运算
			//在此我们创顶点和片段两个‘编译器’,来处理顶点和片段
			var agalVertex:AGALMiniAssembler=new AGALMiniAssembler();
			var agalFragment:AGALMiniAssembler=new AGALMiniAssembler();
			//m44 op, va0, vc0 表示应用一个4x4矩阵到我们的顶点并输出到屏幕
			//mov v0, va1 表示取出我们顶点的颜色值,并传给片段着色器
			var agalVertexSource:String="m44 op, va0, vc0\n" +
				"mov v0, va1\n";
	
			//将我们的颜色输出到屏幕
			var agalFragmentSource:String="mov oc, v0\n";
			//编译AGAL源字符串,这个过程中将产生一个ByteArray供着色器使用
			agalVertex.assemble(Context3DProgramType.VERTEX, agalVertexSource);
			agalFragment.assemble(Context3DProgramType.FRAGMENT, agalFragmentSource);

			//创建一个Program3D来使用我们的着色器,包括顶点着色器和片段着色器,Program3D是显卡管线上的程序
			program=context3d.createProgram();

			//传递编译过的着色器给我们的Program3D使用
			program.upload(agalVertex.agalcode, agalFragment.agalcode);
			
			//定时触发渲染
			addEventListener(Event.ENTER_FRAME, onRenderLoop);
		}
		
		protected function onRenderLoop(event:Event):void
		{
			
			//清除颜色和透明度
			context3d.clear(0.5, 0.5, 0.5, 1);

			//设置会渲染到屏幕上的Program3D
			context3d.setProgram(program);
		
			//现在我们为顶点缓冲定义两个属性val0和val1,val0表示位置,val1表示颜色
			//第一个参数是属性的id,0代表位置val0,1代表颜色val1;第二个参数vertextBuffer提供了运算对象;第三个参数表示该属性要从什么位置开始取值;第四个参数可以理解为取几个值
			context3d.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
			//颜色值是从3开始的,所以从3取值,如果使用的是带alpha的颜色值,可能最后一个参数就该使用 Context3DVertexBufferFormat.FLOAT_4
			context3d.setVertexBufferAt(1, vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_3);
			
			//重设矩阵
			model.identity();

			//将三角形在x,y,z上各缩放0.5倍;你还可以通过model.appendScale,model.appendTranslation来旋转和移动三角形
			model.appendScale(0.5, 0.5, 0.5);
		
			//通过矩阵定义一个常量
			context3d.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, model);
	
			//将三角形绘制到屏幕,0表示起始位置,1表示我们只画一个三角形
			context3d.drawTriangles(indexBuffer, 0, 1);
		
			//将三角形显示到屏幕上
			context3d.present();
		}
	}
}    

  其中最核心的是Context3D,它是一个三维空间的处理环境,负责创建并处理三维对象的各个要素比如顶点、片段、透视等,并将处理的结果使用AGAL(Adobe Graphics Assembly Language)传递给显卡进行运算,运算结果最终被传给CPU并呈现在舞台上。

  如果你对上面的代码感到疑惑和陌生,这很正常,毕竟这套API是为底层3D开发者准备的,幸好大家所熟知的ActionScript 3D第三方框架如Alternativa3D, Away3s, Flare3D都开始支持Molehill了,因此对于AS开发者来说,我们可以在更高的层次去开发3D应用而不用去过多了解底层的实现。同时还有人开发了一些东西让Stage3D来加速2D图形的渲染,比如M2D框架。

  最后,如果你想测试上面的代码,请配置好你的运行环境使其能支持molehill,具体的配置方法请google ‘Molehill配置’。

posted on 2011-08-19 16:03  Dongxue.xie  阅读(1343)  评论(0编辑  收藏  举报

导航