研究了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?

[cc lang=”actionscript3″ nowrap=”false”]
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.( [ 0.3, 0.59, 0.11, 1] ) );
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,5,Vector.( [ 0.3, getTimer()*0.00005, 1, 0.1] ) );
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,6,Vector.( [ 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;
}
}
[/cc]

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

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

先是这个,位图左右缓动
AGAL Code
[cc lang=”actionscript3″ nowrap=”false”]
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”
);
[/cc]
Render Code
[cc lang = “actionscript3″ nowrap=”false”]
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.([t,0,0,0]));
[/cc]

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

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

AGAL Code
[cc lang=”actionscript3″ nowrap=”false”]
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”
);
[/cc]

效果图

效果地址:点我进入

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

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

在 Molehill Game Programming Beginner’s Guide 中的 <第三章> 有绘制2个三角形构建一个屏幕并贴图的例子代码如下
[cc lang=”actionscript3″ nowrap=”false”]
meshVertexData = Vector.
( [
//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
]);
[/cc];

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

f1

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

f2

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

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