通过AGAL在stage3D中做出水纹波动的效果

在了解了stage3D的使用以及AGAL的用法后,用一个简单的AGAL实现水纹波动的效果。当然我们还可也通过调整AGAL的算法,实现各种不同的效果!

核心部分代码如下:在创建片段着色器时使用不同的AGAL算法实现。

//1.创建片段着色器
var fragmentShader:AGALMiniAssembler = new AGALMiniAssembler();
fragmentShader.assemble(
    Context3DProgramType.FRAGMENT,
    "tex ft0,v1,fs0<2d,miplinear,clamp>\n"+  //添加纹理0,通过纹理的方式将桥梁着色器V从顶点着色器获得的UV信息与片段着色器的特殊寄存器fs0(存的材质信息)
                                             //交给片段着色器的临时寄存器ft0
    "add ft1,v1,fc0\n"+                      //通过相加的方式,将v1寄存器中的信息与常量寄存器fc获得的颜色齐心交给临时寄存器ft1
    "tex ft2,ft1,fs1<2d,miplinear,repeat>\n"+//通过材质的方式将ft1与存放另一个材质信息的fs1寄存器获得信息交给临时寄存器ft2
    "add ft3,ft0,v0\n"+                      //通过相加的方式将ft0与从顶点寄存器获得的颜色矩阵信息交给临时寄存器ft3
    "mul oc,ft2,ft3"                         //两个纹理混合,通过相乘的方式将临时寄存器ft2与临时寄存器ft3上的信息交给输出寄存器oc,得到想要的结果。
   );

 

效果如下:

QQ截图20131107220039

***********************************************************************************************************

完整代码如下:

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;
    [SWF(width="500",height="300")]
    public class Stage3DTest002_Texture002 extends Sprite
    {
        //纹理所需的图片
        [Embed(source="reflections.jpg")]private var Img1:Class;
        [Embed(source="波纹.png")]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;
        /**********控制纹理颜色的常量矩阵*****************************/
        private var temp:Number = 0.01;
        public function Stage3DTest002_Texture002()
        {
            /*******************初始化stage3D*************************/
            var stage3D:Stage3D = stage.stage3Ds[0];
            stage3D.addEventListener(Event.CONTEXT3D_CREATE,onContext3DCreated);
            stage3D.requestContext3D();
        }
        
        protected function onContext3DCreated(event:Event):void
        {
            //3D引擎创建完成
            /***********进行相关的设置*********/
            //进行一些简单的设置
            var stage3D:Stage3D = event.target as Stage3D;
            //或得context3D,因为所有实际功能,比如上传、渲染全部都是调用的context3D的方法
            context3D = stage3D.context3D;
            //启用错误检查(以牺牲效率为代价,在控制台打印出AGAL的运行信息)
            context3D.enableErrorChecking = true;
            //开启一块缓冲区
            context3D.configureBackBuffer(stage.stageWidth,stage.stageHeight,1);//
            //准备模型数据
            initData();
            //把模型数据上传给显卡
            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);
            //把纹理上传(略过)
            texture1 = uploadTexture(new Img1());
            texture2 = uploadTexture(new Img2());
            //创建着色器
            initShader();
            
            //准备摄像机
            initCamear();            
            //设定颜色
            col.push(0,0,0,1);
            modelMatrix.appendRotation(-90,Vector3D.Z_AXIS);
            //启动渲染循环
            stage.addEventListener(Event.ENTER_FRAME , update);
        }
        
        /**上传纹理*/
        private function uploadTexture(img:Bitmap):Texture
        {
            var w:int = 512;
            var h:int = 512;
            //创建一个纹理对象
            var texture:Texture = context3D.createTexture(w,h,Context3DTextureFormat.BGRA,false);
            //上传mip映射(从2的n次幂到1,上传一套纹理)
            var level:int = 0;
            var marix:Matrix = new Matrix();
            marix.identity();
            //创建一个bitmapdata来绘制每个级别的mip映射像素
            var bmd:BitmapData = new BitmapData(w,h,true,0);
            while(w>=1&&h>=1){
                
                bmd.draw(img,marix,null,null,null,true);
                texture.uploadFromBitmapData(bmd,level);
                trace(bmd.width+" "+bmd.height+" "+level);
                w>>=1;
                h>>=1;
                marix.scale(0.5,0.5);
                level++;
                //清空,然后创建一个原来的1/2大小的bitmapdata
                bmd.dispose();
                if(w>=1&&h>=1)
                    bmd = new BitmapData(w,h,true,0);
            }
            return texture;
        }
        
        protected function update(event:Event):void
        {
            //清空当前的缓冲区
            context3D.clear();
            /***给着色器传入参数,调用着色器***/
            context3D.setProgram(shaderProgram);//指定着色器,(着色器可能有多个,一个负责。。。,另一个负责..)
            
            this.mainMatrix.identity();//单位化此矩阵,去掉所有的transform信息,转化为单位矩阵
            mainMatrix.append(this.modelMatrix);
            mainMatrix.append(this.viewMatrix);
            mainMatrix.append(this.vohMatrix);
            
            //把这个矩阵传给顶点着色器的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,col.length);    
            col.push(0,-temp,0,0);            
            temp += 0.01;
            
            context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,0,col);
            //上传纹理fs0
            context3D.setTextureAt(0,texture1);
            //上传纹理fs1
            context3D.setTextureAt(1,texture2);
            //画三角形
            context3D.drawTriangles(indexBuffer,0,vertexIndexData.length/3);
            //准备下一个缓冲区
            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\n"+
                "mov v0,va1\n"+
                "mov v1,va2"
            );
            //顶点着色器,每个顶点都会执行一次,也就是说,在每次执行时,va0就是当前正在处理的这个顶点的位置
            //1.创建片段着色器
            var fragmentShader:AGALMiniAssembler = new AGALMiniAssembler();
            fragmentShader.assemble(
                Context3DProgramType.FRAGMENT,
                "tex ft0,v1,fs0<2d,miplinear,clamp>\n"+  //添加纹理
                "add ft1,v1,fc0\n"+
                "tex ft2,ft1,fs1<2d,miplinear,repeat>\n"+
                "add ft3,ft0,v0\n"+
                "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 
                /**正方形*/
                  -2 , 2 , 0,    0 , 0,   1 , 0 , 0 , 1,     //0
                   2 , 2 , 0,    0 , 1,   0 , 1 , 0 , 1,     //1
                   2 ,-2 , 0,    1 , 1,   0 , 0 , 1 , 1,     //2
                  -2 ,-2 , 0,    1 , 0,   1 , 1 , 1 , 1      //3
            );
            //存放索引
            vertexIndexData = new Vector.<uint>();
            vertexIndexData.push(
                /**正方形**/
                0 , 1 , 2,
                0 , 2 , 3
            );
        }
    }
}
posted @ 2013-11-07 22:04  重庆-崽崽  阅读(429)  评论(4编辑  收藏  举报