stage3D成像的具体流程一般我们分为:准备阶段和在每一帧中的渲染阶段
一、准备阶段:
1、初始化stage3D
2、对舞台进行一些简单的设置
3、准备模型数据(通过数组形式存储)
- 准备存放顶点信息的数组
- 准备存放顶点的索引数组
4、把模型数据上传给显卡(通过顶索引缓冲IndexBuffer3D和顶点信息缓冲VertexBuffer3D上传)
5、把纹理上传给显卡
6、创建着色器
- 创建顶点着色器
- 创建片段着色器
- 合并着色器提交给显卡
7、准备摄像机
8、启动主循环进行对模型数据在每一帧中的渲染
二、渲染阶段
1、清空缓冲区
2、给着色器传入参数,调用着色器
- 调整模型的transform
- 把主矩阵传给顶点着色器的vc0(主矩阵即为存放包括模型矩阵、摄像机矩阵、视场矩阵,vc0为顶点着色器的常量寄存器,编号自己取)
- 将顶点位置和大小等信息传给顶点着色器的特殊寄存器va0
- 将顶点的颜色信息(rgba)传给顶点着色器的特殊寄存器的va1
- 将顶点的UV信息传给顶点着色器的特殊寄存器的va2
- 将模型的颜色的指定的信息传给片段着色器的常量寄存器的fc0
- 将材质上传给片段着色器的特殊寄存器fs0
3、画三角形
4、准备下一个缓冲区
以上步骤代码实现如下:(黄色背景的为准备阶段的操作、红色背景的为渲染阶段的操作)
需注意在传入的图片的大小必须是2的幂次
package { import com.adobe.utils.AGALMiniAssembler; import com.adobe.utils.PerspectiveMatrix3D; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.display.Stage3D; import flash.display3D.Context3D; 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.Matrix; import flash.geom.Matrix3D; import flash.geom.Vector3D; public class Stage3DTest002_Texture extends Sprite { //纹理所需的图片 [Embed(source="Delicious.png")]private var Img1:Class; [Embed(source="meinv.jpg")]private var Img2:Class; /******核心3D引擎*********/ private var context3D:Context3D; /******模型数据**********/ private var vertexIndexData:Vector.<uint>; private var vertexData:Vector.<Number>; /******顶点索引的缓冲(通过这个东西上传给GPU)**********/ private var indexBuffer:IndexBuffer3D; private var vertexBuffer:VertexBuffer3D; /**定义自己的着色器*/ private var shaderProgram:Program3D; /**摄像机所需的矩阵**/ private var modelMatrix:Matrix3D = new Matrix3D();//用于描述模型的变化transform private var viewMatrix:Matrix3D = new Matrix3D();//用于描述摄像机的transform private var vohMatrix:PerspectiveMatrix3D = new PerspectiveMatrix3D();//视场矩阵 private var mainMatrix:Matrix3D = new Matrix3D();//上述三个矩阵的合并 /**********颜色***************/ private var col:Vector.<Number> = new Vector.<Number>(); /************纹理************/ private var texture1:Texture; private var texture2:Texture; public function Stage3DTest002_Texture() { /*******************************************1初始化stage3D*********************************************************************/ var stage3D:Stage3D = stage.stage3Ds[0]; stage3D.addEventListener(Event.CONTEXT3D_CREATE,onContext3DCreated); stage3D.requestContext3D(); } protected function onContext3DCreated(event:Event):void { //3D引擎创建完成 //进行相关的设置 /********************************************2进行一些简单的设置******************************************************************/ var stage3D:Stage3D = event.target as Stage3D; //或得context3D,因为所有实际功能,比如上传、渲染全部都是调用的context3D的方法 context3D = stage3D.context3D; //启用错误检查(以牺牲效率为代价,在控制台打印出AGAL的运行信息) context3D.enableErrorChecking = true; //开启一块缓冲区 context3D.configureBackBuffer(stage.stageWidth,stage.stageHeight,1);// /********************************************3准备模型数据************************************************************************/ initData(); /********************************************4把模型数据上传给显卡******************************************************************/ indexBuffer = context3D.createIndexBuffer(vertexIndexData.length); indexBuffer.uploadFromVector(vertexIndexData,0,vertexIndexData.length); vertexBuffer = context3D.createVertexBuffer(vertexData.length / 9,9); vertexBuffer.uploadFromVector(vertexData,0,vertexData.length /9); /********************************************5把纹理上传***************************************************************************/ texture1 = uploadTexture(new Img1()); texture2 = uploadTexture(new Img2()); /*********************************************6创建着色器**************************************************************************/ initShader(); /**********************************************7准备摄像机**************************************************************************/ initCamear(); //设定颜色 col.push(1,1,1,1);//红色 modelMatrix.appendRotation(-90,Vector3D.Z_AXIS); /***********************************************8启动渲染循环***********************************************************************/ stage.addEventListener(Event.ENTER_FRAME , update); } /**上传纹理*/ private function uploadTexture(img:Bitmap):Texture { var texture:Texture = context3D.createTexture(img.width,img.height,Context3DTextureFormat.BGRA,true); //上传纹理 texture.uploadFromBitmapData(img.bitmapData); //mip映射 var w:int = img.width; var h:int = img.height; var level:int = 0; var matrix:Matrix = new Matrix(); //创建一个bitmapData来绘制每个级别的mip映射像素 var bmd:BitmapData = new BitmapData(w,h,true,0); while(w > 1 && h > 1){ bmd.draw(img,matrix,null,null,null,true); texture.uploadFromBitmapData(bmd,level); trace(bmd.width+" "+bmd.height+" "+level); w >>= 1; h >>= 1; matrix.scale(0.5,0.5); level++; //清空,然后创建一个原来的一半大小的bitmapdata bmd.dispose(); bmd = new BitmapData(w,h,true,0); } return texture; } protected function update(event:Event):void { /********************************************1清空当前的缓冲区***************************************************************/ context3D.clear(); /********************************************2给着色器传入参数,调用着色器****************************************************/ context3D.setProgram(shaderProgram);//指定着色器,(着色器可能有多个,一个负责。。。,另一个负责..) this.mainMatrix.identity();//单位化此矩阵,去掉所有的transform信息,转化为单位矩阵 mainMatrix.append(this.modelMatrix); mainMatrix.append(this.viewMatrix); mainMatrix.append(this.vohMatrix); //让图形动起来 modelMatrix.appendRotation(1,Vector3D.Z_AXIS); modelMatrix.appendRotation(1,Vector3D.Y_AXIS); modelMatrix.appendRotation(1,Vector3D.X_AXIS); //把这个矩阵传给顶点着色器的vc0(第0个常量寄存器) context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,0,mainMatrix,true); //va0传值.给顶点着色器的第0个传入定点数据 context3D.setVertexBufferAt(0,vertexBuffer,0,Context3DVertexBufferFormat.FLOAT_3); //给顶点着色器的第1个va寄存器 context3D.setVertexBufferAt(1,this.vertexBuffer,5,Context3DVertexBufferFormat.FLOAT_4); //给顶点着色器的第2个va寄存器传入UV值 context3D.setVertexBufferAt(2,vertexBuffer,3,Context3DVertexBufferFormat.FLOAT_2); //给片段着色器的fc0传值 col.splice(0,4); col.push(Math.random(),Math.random(),Math.random(),Math.random()); context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,0,col); //上传纹理fs0 context3D.setTextureAt(0,texture1); //上传纹理fs1 context3D.setTextureAt(1,texture2); /*************************************************3画三角形*********************************************************************/ context3D.drawTriangles(indexBuffer,0,vertexIndexData.length/3); /*************************************************4准备下一个缓冲区**************************************************************/ context3D.present(); } /** * 初始化摄像机 * */ private function initCamear():void { //让摄像机向后移 viewMatrix.appendTranslation(0,0,-10); //利用voh对场景进行裁剪 vohMatrix.perspectiveFieldOfViewRH(Math.PI/4,stage.stageWidth/stage.stageHeight,0.01,100); } /** * 创建一个简单的着色器 * 1.创建顶点着色器 * 2.创建片段着色器 * 3.合并为一个着色器提交给显卡 * */ private function initShader():void { /**汇编语言 * 操作码 目标寄存器,源寄存器,.......源寄存器 * 常用操作码:mov nul add sub sin cos * 特殊操作码:m33 m44 m34(矩阵乘法) tex(纹理采样) * */ //1.创建顶点着色器 var vertaxShader:AGALMiniAssembler = new AGALMiniAssembler(); vertaxShader.assemble( Context3DProgramType.VERTEX, "m44 op,va0,vc0 "+ //"m44 vt0,va0,vc0"+ //"mov op,vt0 "这两句就相当于下面一句 //让第0个va着色器和第0个vc着色器进行m44运算(4*4矩阵乘法 ) //va寄存器:传入顶点的位置 //vc寄存器:传入一些全局变量,比如矩阵 //op顶点寄存器的最终目的地 "mov v0,va1 "+ "mov v1,va2" ); //顶点着色器,每个顶点都会执行一次,也就是说,在每次执行时,va0就是当前正在处理的这个顶点的位置 //1.创建片段着色器 var fragmentShader:AGALMiniAssembler = new AGALMiniAssembler(); fragmentShader.assemble( Context3DProgramType.FRAGMENT, "tex ft0,v1,fs0<2d,repeat> "+ //添加纹理 "mul ft1,v1,fc0 "+ "tex ft2,ft1,fs1 "+ "mul ft3,ft0,fc0 "+ "mul oc,ft2,ft3" ); //片段着色器为每个像素都执行一次 //合并为一个着色器提交给显卡 shaderProgram = context3D.createProgram(); shaderProgram.upload(vertaxShader.agalcode , fragmentShader.agalcode); } /** * 准备模型数据 * 包含两个部分,定点数据和定点索引数据,在实际开发中,这些数据是来自于3Dmax工具到处 * */ private function initData():void { //存放顶点的数据 vertexData = new Vector.<Number>(); vertexData.push( //x y z u v r g b a /** * 三角形 * */ // 1 ,1 ,0, 1 ,0, 0, 0 ,0 ,1, //0 // -1,1 ,0, 0 ,0, 0, 0 ,0 ,0, //1 // -1,-1,0, 0 ,1, 0, 0 ,0 ,0 //2 /**正方形*/ -3 , 5 , 0, 0 , 0, 1 , 0 , 0 , 1, //0 5 , 3 , 0, 0 , 1, 0 , 1 , 0 , 1, //1 5 ,-3 , 0, 1 , 1, 0 , 0 , 1 , 1, //2 -3 ,-5 , 0, 1 , 0, 0 , 0 , 1 , 1 //3 /**正方体*/ // -1 , 1 , -1, 1 , 0, 1 , 0 , 0 , 1, //0 // 1 , 1 , -1, 0 , 0, 0 , 1 , 0 , 0, //1 // -1 ,-1 , -1, 0 , 1, 0 , 0 , 1 , 0, //2 // 1 ,-1 , -1, 1 , 1, 0 , 0 , 0 , 0, //3 // 1 , -1 , 1, 1 , 0, 0 , 0 , 0 , 1, //4 // 1 , 1 , 1, 0 , 0, 0 , 0 , 0 , 0, //5 // -1 , 1 , 1, 0 , 1, 0 , 0 , 0 , 0, //6 // -1 ,-1 , 1, 1 , 1, 0 , 0 , 0 , 0 //7 ); //存放索引 vertexIndexData = new Vector.<uint>(); // vertexIndexData.push(0,1,2); vertexIndexData.push( /**正方形**/ 0 , 1 , 2, 0 , 2 , 3 /**正方体*/ // 0 , 1 , 3, // 0 , 3 , 2, // 1 , 3 , 4, // 1 , 4 , 5, // 1 , 0 , 6, // 1 , 6 , 5, // 4 , 5 , 6, // 4 , 6 , 7, // 0 , 2 , 7, // 0 , 7 , 6, // 2 , 3 , 4, // 2 , 4 , 7 ); } } }