stage3d的资料实在是太少了。 so~ dreamfairy 决定从directX 入手来学习stage3d. 毕竟彼此是师徒关系,所以API基本都一致,名字也无二。

d3dcube
和stage3d一样,要创建一个cube需要准备 顶点,顶点索引。 贴图还需要创建 Texture.
在directX中。 context3D 是以 IDirect3DDevice9 来存在的。

准备工作有以下几个类.
cube.h 申明了cube的顶点和索引信息,以及 IDirect3DDevice9 的引用
cube.cpp 对Cube进行填充顶点,索引,以及绘制
texCube.cpp 负责具体的渲染循环,包括矩阵,相机,创建贴图等。
vertex.h 顶点坐标类,保存了顶点坐标,以及UV贴图坐标

代码如下:
Continue reading

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

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

趁着2月结束前把starling版的洛克恶魔城放出来.
赶上过年狠狠的补了几部电视剧,加上年后生病了一周,所以完成度不高,原版的发射子弹,血条,受伤,死亡,BOSS战都没有实现. 不过想了解starling的部分基本都了解了.
直接放demo吧, 顺便加上了残影效果,原版是使用Filter来绘制的,不过有些bug就不放出了.

下个月要做的东西已经想好了,starling + away3d 的ARPG

Continue reading

DreamFairy正在把前年的 苍白的茧大冒险 移植到starling上.
之前的游戏在这里 点我进入

一些一般性常识就不提了,直接记录我遇到的问题

1.创建starling后, 要么设置 starling.start() 要么在 某个render中调用 starling.nextfame(); 否则所有的监听都会失效. 比如 Event.TRIGGERED

2.创建一个MovieClip后 必须使用 Starling.juggler.add 加载后,才会播放帧. 移除MovieClip 后从 juggler移除,然后执行dispose ,它的事件会自动移除

3.在用之前的洛克素材创建MovieClip的时候,发现每帧会出现拉伸和模糊. 原因是 MovieClip会根据其第一个Texture来设置其宽高, 而洛克的素材原本就是矢量的逐帧动画,每帧宽高不一样,导致部分帧被拉伸.

要解决模糊问题, 直接调用 Texture.fromBitmapData(bmd,false); 第二个参数设置为 false即可.
要解决拉伸问题. 我试过几种方法.
1) 遍历洛克的所有帧,取出最大宽和最大高,然后创建一个空的Texture插入 Texture数组. 待创建MovieClip后 将其移除. 结果画面仍然被拉伸, 虽然还没去看源码,但我估计是 MovieClip设置宽高依据的不是第一个 Texture的width 和 height 而是 colorBounds ,因此第一个空的Texuture因为没有任何像素而导致宽高失效.

2) 试着使用TexturePacker 但是这货要导出一张位图和一张xml配置表.这样导致项目的复杂度又高了…(其实是DreamFairy很懒,不舍得写混合loader,连greensock的queueloader都不舍得用, 更别说写一个 xml+png 打包成一个文件的 打包工具了)

3) 于是考虑着既然游戏的体积不大,就适当的浪费一下性能吧.
代码如下:
[cc lang=”actionscript” nowrap=”false”]
private function createIdelTexture() : void
{
var cls : Class = getDefinitionByName(“stand”) as Class;
var standMovie : flash.display.MovieClip = new cls();
var textureList : Vector. = new Vector.();
var bmd : BitmapData;
var maxWidth : Number = 0;
var maxHeight : Number = 0;
for(var i : int = 0; i <= standMovie.totalFrames; i++) { standMovie.gotoAndStop(i); if(standMovie.width > maxWidth) maxWidth = standMovie.width;
if(standMovie.height > maxHeight) maxHeight = standMovie.height;
}

for(var j : int = 0; j <= standMovie.totalFrames; j++) { standMovie.gotoAndStop(j); bmd = new BitmapData(maxWidth, maxHeight, true, 0); bmd.draw(standMovie); textureList.push(Texture.fromBitmapData(bmd,false)); } m_idelMovie = new starling.display.MovieClip(textureList); m_idelMovie.pivotX = m_idelMovie.width >> 1;
m_idelMovie.pivotY = m_idelMovie.height;
}
[/cc]

非常笨的方式,先循环一次,计算出最大宽高.
再循环一次,创建全部等大且为最大宽高的BitmapData.然后构建成Texture
最后设置中心点为洛克的脚下中央…

by the way… stage3d的 实时阴影部分的源码,很多大神明明写出来了,却不公开源码. 我懂得,这是潜规则. It’s ok 我也已经研究出来flare3d 创建实时投影的办法,虽然在我看来我的实现方式比较笨. 嘛嘛~既然是潜规则,你们不公开,那我也不公开.

之前的地址中的demo 没有出现模型, 估计是使用的 lib的问题, 导致load 模型解析失败. 本地是正常的说.
于是在这版直接嵌入了模型,同时加上骨骼绑定和第二摄像机.
地址: http://www.dreamfairy.cn/blog/work/flash/3d/everymounthgame01/bin-debug/FlareShadow.html

总结一下吧, 之前忘了总结了.
1.想模仿<天界>那样做一个2D的地图,于是试着创建一个 4000*4000的 plane 并贴上 4000*4000的位图, 显示的结果只有 2000*2000的位图被拉伸到 4000*4000了,翻阅资料后发现, 向GPU上传位图的时候,不支持超过2000的尺寸. 因此需要将位图切割并 创建4个 2000*2000的 plane进行组合.

2.在创建了水波效果后,试着创建了一个灯光,结果水波的贴图丢失了,无法渲染. 在错误日志中发现是寄存器不够用了. 于是找到水波的flsl文件,将不再使用的属性全部删除,给灯光shader留出位置. 所以对于创建的所有shader程序都要记得释放寄存器.

3.骨骼绑定,直接贴代码吧.
[cc lang=”actionscript3″ nowrap=”true”]
var skinnedMesh:Mesh3D = player.getChildByName( “astronaut”) as Mesh3D;
var weapon:Cube = new Cube( “weapon”, 10, .05, .05 );
weapon.rotateZ(90);
weapon.setPosition(0,-5,0);
weapon.addComponent( new BoneController( skinnedMesh, “Bip01 L Finger2” ) );
scene.addChild(weapon);
[/cc]
new BoneController 是一个自定义类,非官方API 借口是 IComponent. 内容如下.
在3d max中,选取模型后 该模型的名字为 astronaut. 所有的骨骼都在这个容器里. 因此先 getChildByName获得容器. 再通过 skinnedMesh.modifier.root.getChildByName( boneName ); 获取到骨骼, 返回的是一个 Pivot3D类型. 然后将这个我们定制的 weapon 添加到该骨骼上.

4.贴图更换,也是直接上代码.
var curSkin : Shader3D = player.getMaterialByName(“head”) as Shader3D;
首先可以通过材质的名称获取到该材质
然后通过 curSkin.filters[0].texture = new Texture(要替换的bitmapdata贴图); 来改变该材质的贴图.

5.GUI 我试着制作一个3D的UI,但是时间成本太高了,没有快速的解决方案,于是只好使用 starling. 虽然 starling可以在构造函数中设定使用的 stage3D层级. 但是flare3D本身却没有这样的方法. 因此这样会导致 starling会跟 场景出现渲染层级的冲突. 解决方案只有调用 flare3d 的 postRender 来延迟 flare3D的渲染,先调用 starling.nextFrame()来保证 GUI在最前.

6.flsl 是个好东西,把agal code 封装层 pixel bender的语法了,类似C++这样的高级语言, 使我很容易编写出自己想要的效果. 但是 real time shadow 一直很难实现, 会的人不多,但他们也都不肯轻易放出实现方法,原因我懂的. 那就让我自己研究吧.

记得前年暑假的时候,做过一个山寨恶魔城的游戏. 嘛~下个月就做 采用starling来复刻的版本吧~

之前看某国外博客的时候,发现博主每月都会出个游戏,虽然不是很好玩的样子,但是都很有技术性的说.
于是DreamFairy也决定照着这么干了.

这是这个月的demo
里面使用了换肤,灯光,碰撞检测(地面),天空盒

在制作的时候,遇到一件很棘手的事情… 在给场景添加了灯光之后,之前渲染的水波效果就突然丢失贴图了. 于是跟踪了错误后发现,丢失贴图并不是在构造动态材质的时候出的错,而是才设置材质的时候出错. 出错信息是寄存器溢出. 于是才想到这坑爹的 像素着色器只有坑爹的8个寄存器. 于是在所有的 着色器的运行完毕后,将所有用不到的参数全部删除.这下在正常了.

以下是截图, 游戏地址是这里.. 略大 慢慢等. http://www.dreamfairy.cn/blog/work/flash/3d/everymounthgame01/bin-release/FlareShadow.html

最近手头在做深度排序的优化.
于是做了下面一个实验
在场景上创建 2000 个对象. 然后使用传统的深度排序算法,全排.
[cc lang=”actionscript3″ nowrap=”false”]
private function checkCollsion() : void
{
_rects.sort(sortFun);

var rect : Rect;
for(var i : int = 0; i < _rects.length; i ++){ rect = _rects[i] as Rect; if(_container.getChildAt(i) != rect){ _container.setChildIndex(rect,i); } } } private function sortFun(p1 : DisplayObject, p2 : DisplayObject) : int { return p1.y > p2 .y ? 1 : -1;
}
[/cc]
结果帧数降到了6帧.

于是考虑使用四叉树来做.
在收集资料的时候发现了一篇 javsScript 实现的四叉树

改写成AS后的代码为
Continue reading

很久没来博客写东西了,也真心明白为嘛很多技术博客的文章时间跨度都很大了。
果然,当兴趣成为工作的一部分后,也就没有了以往的激情了。当然还有另一个原因,那就是手头上写的新东西都是项目的商业机密了,不能随便公开的说。

话说,dreamfairy最近实现了一套剧情系统给项目用呢,包含了游戏中即时演算和可视化编辑器两部分,编辑器甚至可以独立出游戏载入剧本文件直接播放编辑呢。想想如果结合下之前写的触发器和地图编辑器的话,差不多可以实现当年星际争霸1战役编辑器的水平了。像星际争霸2那种可自定义函数略有差距,不过自我感觉还是碉堡!

等项目上线了,就丢几个裁图上来。不过没有源码噢。话说年后也丢个正式的3D玩意上来。