好久没有写教程神马的了,最近比较忙的说。
回到正题,最近打算在游戏中创建一个3D模型,由于游戏是Starling 2D游戏,因此打算把模型丢到UI里,3D模型出现在2D游戏里的话一定是高端大气上档次!
之前老外写的教程都是 Starling 和 Away3D 杂交, 但是仅仅在UI上摆一个3D模型就整合一个Away3D 实在是大材小用,也可以说是浪费性能, 索性自己来写一个。
先上个图。
一切以兼容为主, 实现一个类 DisplayObject3D 继承自 Starling 的显示对象 DisplayObject
之后override 其的 render 方法
[cc lang=”actionscript3″]
public override function render(support:RenderSupport, parentAlpha:Number):void
[/cc]
do you see that? ?这里我们能获取到一个 ?RenderSupport.
这可是一个好东西, 我们能从中获取到 mvpMatrix 即 模型视图投影矩阵, 有3d 和 2d 2个版本。
然后,我们可以从 Starling.current.context 获取到 GPU的 API模组, 有了这些东西,想干啥都行了。
接下来开始干正事
[cc lang=”actionscript3″]
public function DisplayObject3D(modelData : ByteArray = null)
{
if(null == modelData) return;
init(modelData);
}
public function init(modelData : ByteArray) : void
{
m_context = Starling.current.context;
m_modelData = modelData;
m_meshList = new Vector.<Md5Mesh>();
createTexture();
m_md5MeshParser = new MD5MeshParser();
m_md5MeshParser.addEventListener(Event.COMPLETE, onMeshLoaded);
m_md5MeshParser.load(m_modelData);
registerPrograms(m_context);
}
[/cc]
我们首先在构造函数中传入一个 modelData 其内容是 md5 模型的 二进制文件了,本子就是一堆字符串, 之后在 init中对字符串进行解析,解析出其中的 顶点,索引等等
m_md5MeshParser ?的下载地址在之前的 git上
[cc lang=”actionscript3″]
private function createTexture() : void
{
var len : int = m_textureCache.length;
for(var i : int = 0; i < len; i++){
var data : Bitmap = m_textureCache.shift();
var t : Texture = m_context.createTexture(data.width,data.height,Context3DTextureFormat.BGRA,false);
t.uploadFromBitmapData(data.bitmapData);
m_textureCache.push(t);
}
}
[/cc]
之后我们要将模型用到的图片转换成纹理,可以用 Starling 的 Texture.FromBitmap, 但是本人偷懒,就自己随便写个了。
[cc lang=”actionscript3″]
private static function registerPrograms(context : Context3D) : void
{
var assembler : AGALMiniAssembler = new AGALMiniAssembler();
var vertexProgramCode : String;
var fragmentProgramCode : String;
// this is the input data we’ll pass to the shaders:
//
// va0 -> position
// va1 -> color
// va2 -> texCoords
// vc0 -> alpha
// vc1 -> mvpMatrix
// fs0 -> texture
vertexProgramCode =
“m44 op va0 vc0n” +
“mov v0 va1n”;
fragmentProgramCode =
“tex ft0 v0 fs0<2d,linear,repeat>n”+
“mov oc ft0 n”;
m_program = context.createProgram();
m_program.upload(assembler.assemble(Context3DProgramType.VERTEX,vertexProgramCode),
assembler.assemble(Context3DProgramType.FRAGMENT,fragmentProgramCode));
}
[/cc]
Starling 的所有 program3D 都是有缓存的,=。= 还是因为我懒,也不缓存了。 又由于 DisplayObject3D 是可能有多个的,因此这里使用静态方法来创建这个?program3D
最后是就是 具体的 render 方法了
[cc lang=”actionscript3″]
public override function render(support:RenderSupport, parentAlpha:Number):void
{
m_context.setCulling(Context3DTriangleFace.BACK);
m_context.setDepthTest(true, Context3DCompareMode.LESS);
if(m_meshNum)
{
if(null == m_proj)updateViewToClip();
if (m_context == null) throw new MissingContextError();
renderCuston(m_context,support);
}
m_context.setCulling(Context3DTriangleFace.NONE);
m_context.setDepthTest(false, Context3DCompareMode.ALWAYS);
}
[/cc]
由于 Starling 是一个2D框架,默认是关闭三角面剔除以及深度测试的,因此我们在绘制三角形前先将这两个选项打开,待渲染完毕后再将其关闭的说。
最后的最后,如果发现模型的前后像素出现错位的情况,请打开 Starling.as
找到?configureBackBuffer 函数
将??var methodArgs:Array = [width, height, antiAlias, false]; 的第4个参数, 改为 true, 由于Starling 不需要深度和模板所以默认关闭了,这里要将其打开,使深度可写
最后的最后放上这个md5扩展的git 地址