News:快速了解Stage3D的一个实例
来自Starling中文站
下面的这段代码出处在这里:
http://uh.9ria.com/link.php?url=http://bbs.9ria.com/viewthread.php?tid=108015
感谢原作者和译者。
为了方便像我这样的懒人,通过代码快速了解Stage3D,就把代码略微整理了一下,添加了注释,如下:
补充:参阅James Li的这篇教程,加深对Stage3D和AGAL的了解: http://www.adobe.com/cn/devnet/flash/articles/molehill_trangle.html
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.Context3DBlendFactor; import flash.display3D.Context3DCompareMode; import flash.display3D.Context3DProgramType; import flash.display3D.Context3DTextureFormat; import flash.display3D.Context3DVertexBufferFormat; import flash.display3D.IndexBuffer3D; import flash.display3D.Program3D; import flash.display3D.VertexBuffer3D; import flash.display3D.textures.Texture; import flash.events.Event; import flash.geom.Matrix3D; import flash.geom.Vector3D; import flash.utils.getTimer; import flash.display.BitmapData; /** * 这是一个快速演示Stage3D用法的测试类,使用一张图片作为纹理 */ [SWF(backgroundColor="#000000")] public class TestStage3D extends Sprite { /**Context3D实例*/ private var context3D:Context3D; /**用于向GPU提交顶点着色器和片段着色器的对象*/ private var program:Program3D; /**顶点缓冲*/ private var vertexbuffer:VertexBuffer3D /**顶点索引(确定三角形)*/ private var indexBuffer:IndexBuffer3D; /**图片*/ [Embed(source="assets/bird.png")] protected const birdTextureClass:Class; /**纹理*/ public static var texture:Texture; /**@private*/ public function TestStage3D() { super(); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; this.addEventListener(Event.ADDED_TO_STAGE,initApp); } /** * 初始化应用 * @param args */ private function initApp(...args):void { //有几个Stage3D实例可用.I got 4 trace(stage.stage3Ds.length); //得到Stage3D实例 var stage3D:Stage3D = stage.stage3Ds[0]; //请求Context3D stage3D.addEventListener(Event.CONTEXT3D_CREATE,initStage3D); stage3D.requestContext3D(); } /** * 当Context3D可用,进一步初始化 * @param event */ protected function initStage3D(event:Event):void { context3D = stage.stage3Ds[0].context3D; //输出加速类型,在Mac下输出'OpenGL' trace(context3D.driverInfo); //场景渲染大小为800乘以600像素,最小等级抗锯齿(第三个参数),并且为渲染表面创建深度和模版缓冲(第四个参数) context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 2, true); //设置混合模式 context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA); //关闭深度测试,PNG透明背景必须 context3D.setDepthTest(false, Context3DCompareMode.NOT_EQUAL); //设置纹理 var birdBmd:BitmapData = (new birdTextureClass()).bitmapData; texture = context3D.createTexture(birdBmd.width, birdBmd.height, Context3DTextureFormat.BGRA, false); texture.uploadFromBitmapData(birdBmd); context3D.setTextureAt(0, texture); // 先把矩形的4个顶点定义出来,每个点有5个属性:x, y, z, u, v // x,y,z 是坐标系数值(-1到1),uv是坐标(0到1) var vertices:Vector.<Number> = Vector.<Number>([ -0.8,0.8,0, 0, 0, -0.8, -0.8, 0, 0, 1, 0.8, -0.8, 0, 1, 1, 0.8, 0.8, 0, 1, 0]); // 单纯的数组无法提交给GPU,必须用顶点缓冲进行包装 vertexbuffer = context3D.createVertexBuffer(4, 5); vertexbuffer.uploadFromVector(vertices, 0, 4); //Stage3D需要缓冲面,而一个三角形可以确定一个面,所以创建一个额外的数组,利用矩形的4个顶点,组成两个三角形,0,1,2是一个,2,3,0是另一个 var indices:Vector.<uint> = Vector.<uint>([ 0, 1, 2, 2, 3, 0]); //同样这个数组也需要包装,用IndexBuffer3D indexBuffer = context3D.createIndexBuffer(6); //两个三角形,6个顶点 indexBuffer.uploadFromVector(indices, 0, 6); //将数据置入缓冲区,0是起始索引,6是顶点数量 //由于Stage3D使用可编程管道,要将数据提交给显卡, //必须有顶点着色器和片段着色器,而这两个着色器需要AGAL编写(一种汇编语言) //AGALMiniAssembler是Adobe提高的AGAL编写辅助工具 var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();//顶点着色器 vertexShaderAssembler.assemble( Context3DProgramType.VERTEX, "m44 op, va0, vc0\n" + "mov v0, va1" ); var fragmentShaderAssembler : AGALMiniAssembler= new AGALMiniAssembler();//片段着色器 fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT, "tex ft0, v0, fs0 <2d>\n" + "mov oc, ft0" ); //Program3D类负责将AGAL编写的着色器提交给显卡 program = context3D.createProgram(); program.upload(vertexShaderAssembler.agalcode,fragmentShaderAssembler.agalcode); //开始呈现 //因为Stage3D是不透明的,这里将背景色设置为黑色 context3D.clear( 0, 0, 0, 1 ); //这里参照vertices的定义,每一个顶点定义的前三个是坐标(XYZ),所以用FLOAT_3 //我们将XYZ数据填入到va属性寄存器中,编号为0(即va0),偏移量为0 context3D.setVertexBufferAt (0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3); //同上理,UV信息是两位,所以用FLOAT_2,因为va0已经被使用了,所以我们va1中,偏移量为3(跳过XYZ) context3D.setVertexBufferAt(1, vertexbuffer, 3, Context3DVertexBufferFormat.FLOAT_2); //应用着色器 context3D.setProgram(program); //需要一个3维矩阵才能完成到2D屏幕的映射 var m:Matrix3D = new Matrix3D(); //把3维矩阵传递给着色器 context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true); //绘制三角形,you know,最后的矩形是两个三角形组成的 context3D.drawTriangles(indexBuffer); //绘制到屏幕 context3D.present(); } } }
整理: 郭少瑞(NeoGuo)