每月一个游戏-03 包含了Starling水波滤镜 寻路 2D地图和3D模型

研究了2周的Starling ,期间看了几本关于Shader的书,感觉已经略懂了啊! 于是试着把水波AGAL移植进Starling的滤镜中,结果意料之外的顺利,在研究Starling的FragmentFilter的时候发现在其 设置纹理->绘制三角形->后紧跟的是清空纹理. 这个我之前完全没想到要这样做, 也许是优化? 反正不重写这个方法的话还会导致context3D丢失. 仔细想想的话,这货其实不能仅仅称为滤镜怎么简单,甚至可以扩展层uv动画工具类了的说,比如残影啊,地震抖动啊 等等…

话不多说,直接上demo. 地图层是starling 并附带上了水波滤镜, 在文章最后会开源. 然后中间层away3D. 顶层还是starling的UI层.
demo中调用了A*寻路,因为路径编辑器是花了5分钟定制写的…画的非常偷懒,如果人物移动的时候突然丢失context3D了,说明是寻路报错了.直接刷新就好了.

DEMO地址:http://www.dreamfairy.cn/blog/work/flash/3d/everymounthgame03/myRpg.html

水波滤镜代码:请将前一篇文章AGAL 笔记01中的 柏林噪音图配合使用 http://www.dreamfairy.cn/blog/?p=1316‎

package starling.filters
{
    import flash.display3D.Context3D;
    import flash.display3D.Context3DProgramType;
    import flash.display3D.Program3D;
    import flash.utils.getTimer;
   
    import starling.core.Starling;
    import starling.textures.Texture;

    /********************************************************
     * @Author:苍白的茧
     * @WebSite:http:www.dreamfairy.cn
     ********************************************************/

    public class WaveFilter extends FragmentFilter
    {
        public function WaveFilter(waveTexture : Texture)
        {
            m_waveTexture = waveTexture;
        }
       
        protected override function createPrograms():void
        {
            var vertexProgramCode:String =
                "m44 op, va0, vc0       n" +
                "mov v0, va1            n";
           
            var fragmengProgramCode : String =
                "mul ft0, v0, fc5.xn"+
                "add ft0,ft0,fc5.y n"+
                "mul ft1, v0, fc5.xn"+
                "add ft1,ft1,fc5.y n"+
                "tex ft2, ft0, fs1 <2d,linear,repeat>n"+
                "mul ft2, ft2, fc6.xn"+
                "sub ft2, ft2, fc6.yn"+
               
                "tex ft3, ft1, fs1 <2d,linear,repeat>n"+
                "mul ft3, ft3, fc6.xn"+
                "sub ft3, ft3, fc6.yn"+
               
                "add ft4, ft2, ft3n"+
                "nrm ft4.xyz, ft4n"+
                "mul ft4, ft4, fc5.wn"+
                "add ft5, v0,ft4n"+
                "tex ft1, ft5, fs0 <2d,linear,repeat>n" +
                "mov oc, ft1n";
           
            m_waveProgram = assembleAgal(fragmengProgramCode, vertexProgramCode);
        }
        public override function dispose():void
        {
            if(m_waveProgram)m_waveProgram.dispose();
            m_waveTexture.dispose();
            super.dispose();
        }
       
        protected override function activate(pass:int, context:Context3D, texture:starling.textures.Texture):void
        {
            // already set by super class:
            //
            // vertex constants 0-3: mvpMatrix (3D)
            // vertex attribute 0:   vertex position (FLOAT_2)
            // vertex attribute 1:   texture coordinates (FLOAT_2)
            // texture 0:            input texture
           
            context.setTextureAt(1,m_waveTexture.base);
            context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,4,Vector.<Number>( [ 0.3, 0.59, 0.11, 1] ) );
            context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,5,Vector.<Number>( [ 0.3, getTimer()*0.00005, 1, 0.1] ) );
            context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,6,Vector.<Number>( [ 2, 1, 1,1] ) );
            context.setProgram(m_waveProgram);
        }
       
        protected override function deactivate(pass:int, context:Context3D, texture:Texture):void
        {
            context.setTextureAt(1,null);
        }
       
        private var m_waveTexture : Texture;
        private var m_waveProgram : Program3D;
    }
}

3D图形学也研究了几周了,接下里开始专注模型的格式,解析,差值,优化,uv动画上了.
下个月的游戏就决定以模型为主了~

AGAL Note 01

花了一个晚上,终于把agal啃下来了,发现一点也不难 =.=
于是尝试的做了几个效果.

先是这个,位图左右缓动
AGAL Code

            var vertexShaderAssbler : AGALMiniAssembler = new AGALMiniAssembler();
            vertexShaderAssbler.assemble(Context3DProgramType.VERTEX,
                "m44 op, va0, vc0n" +
                "mov v1, va1n" +
                "mov v2, va2n"
                );
           
            var fragmentShaderAssbler : AGALMiniAssembler = new AGALMiniAssembler();
            fragmentShaderAssbler.assemble(Context3DProgramType.FRAGMENT,
                "mov ft5, fc0n" +
                "sin ft5.g, ft5.rn" +
                "add ft4, ft5.g, v1n" +
                "tex ft0, ft4, fs0<2d,repeat,miplinear>n" +
//              "mul ft1, v2, ft0n" +
                "mov oc, ft0n"
                );

Render Code

t += 0.1;
context3D.setTextureAt(0,myTexture);
context3D.setVertexBufferAt(0,vertexBuffer,0,Context3DVertexBufferFormat.FLOAT_3);
context3D.setVertexBufferAt(1,vertexBuffer,3,Context3DVertexBufferFormat.FLOAT_2);
context3D.setVertexBufferAt(2,vertexBuffer,8,Context3DVertexBufferFormat.FLOAT_4);
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,0,Vector.<Number>([t,0,0,0]));

原理就是从外部发送一个递增的常量,然后在像素渲染程序上对每一个像素进行sin运算,算出一个左右缓动值,然后以该值去取对应点像素,然后输出即可.
效果地址:点我进入

然后复杂一些水波效果
用的水波图是之前flare3d中使用的柏林噪音图

AGAL Code

            var fragmentShaderAssbler : AGALMiniAssembler = new AGALMiniAssembler();
            fragmentShaderAssbler.assemble(Context3DProgramType.FRAGMENT,
//              "mov ft5, fc0n" +
//              "sin ft5.g, ft5.rn" +
//              "add ft4, ft5.g, v1n" +
//              "tex ft0, ft4, fs0<2d,repeat,miplinear>n" +
//              "mul ft1, v2, ft0n" +
//              "mov oc, ft0n"
//             
                "mul ft0, v0, fc1.xn"+
                "add ft0,ft0,fc1.y n"+
                "mul ft1, v0, fc1.xn"+
                "add ft1,ft1,fc1.y n"+
                "tex ft2, ft0, fs1 <2d,linear,repeat>n"+
                "mul ft2, ft2, fc2.xn"+
                "sub ft2, ft2, fc2.yn"+
               
                "tex ft3, ft1, fs1 <2d,linear,repeat>n"+
                "mul ft3, ft3, fc2.xn"+
                "sub ft3, ft3, fc2.yn"+
               
                "add ft4, ft2, ft3n"+
                "nrm ft4.xyz, ft4n"+
                "mul ft4, ft4, fc1.wn"+
                "add ft5, v0,ft4n"+
                "tex ft1, ft5, fs0 <2d,linear,repeat>n" +
                "mov oc, ft1"
                );

效果图

效果地址:点我进入

关于UV坐标

今天重新细看了 Molehill Game Programming Beginner’s Guide . 我承认之前都是一味的敲代码,完全没去理解(或许是当初理解不能), 现在似乎相关知识都积累够了,也玩了几个3D引擎所以略知其原理了.

UV坐标就是 XYZ坐标的变种,作为2D贴图坐标不需要Z轴,又为了于三维坐标进行区分,因此改名为UV坐标.
UV坐标最大值1,最小值0 多了,少了都没有意义.

在 Molehill Game Programming Beginner’s Guide 中的 <第三章> 有绘制2个三角形构建一个屏幕并贴图的例子代码如下

meshVertexData = Vector.<Number>
  ( [
    //X,  Y,  Z,   U, V,   nX, nY, nZ    
     -3, -1,  1,   0, 0,   0,  0,  1,
      1, -1,  1,   1, 0,   0,  0,  1,
      1,  1,  1,   1, 1,   0,  0,  1,
     -1,  1,  1,   0, 1,   0,  0,  1
  ]);

;

贴图完毕后,结果图片是垂直翻转的.

f1

我猜测,对于位图来说其坐标系的0,0点在左上角,而molehill的uv坐标系0,0点在左下角,因此在贴图的时候导致垂直翻转了.
于是我进行uv坐标的反转,将左上和左下坐标对换,右上和右下坐标对换,结果成功的转换回正常情况了.

f2

既然我猜测没有错误,那么就可以进一步对图片进行水平翻转了.即将 左下和右下对换,左上和右上对换
f3

如此一来扩展一下,对图片的各种扭曲也是很轻松的.