2011年3月11日星期五

【測試】Flash3D API(Molehill)Jiglib物理引擎範例

此範例是參考Jiglib物理引擎改寫,
方向鍵可以控制車輛移動,
空白鍵停止。
車輛的材質還有反光效果。

demo

2011年3月10日星期四

【測試】Flash3D API(Molehill) MD2模型範例

寫了一個簡單範例demo,
現在Flash 3D API(Molehill)提供硬體支援,
跑起來順暢多了,
點擊滑鼠可以改變角色狀態。


demo

2011年3月9日星期三

【教學】Flash 3D API(Molehill) Texture

Flash 3D API(Molehill)目前一些知名的3D引擎已有支援,
像Alternativa3D、Away3D、Flare 3D 等,
透過這些現有引擎建立3D專案非常方便。
不過為了瞭解Flash 3D API的基本運作模式,
還是研究了一下,此範例就是延續DrawMesh範例,
Mesh由頂點著色改為貼上貼圖,
原本頂點緩衝內的顏色rgb值改為UV貼圖座標。

程式碼如下:

package
{
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;

import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DRenderMode;
import flash.events.Event;
import flash.geom.Rectangle;
import flash.display3D.VertexBuffer3D;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.textures.Texture;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.net.URLRequest;
import flash.display.Loader;

import MonitorKit;

/**
* ...Flash 3D API(Molehill) 貼圖範例
* @author Max
*/
public class Flash3D_Texture extends Sprite
{
private var sta3D:Stage3D;
private var con3D:Context3D;
private var vertexBuffer:VertexBuffer3D;
private var indexBuffer:IndexBuffer3D;

private var perspection:PerspectiveMatrix3D;
private var modelProjection:Matrix3D;
private var modelView:Matrix3D;

private var texture:Texture;
private var loaderObj:Loader;
private var shaderpg3d:Program3D;

public function Flash3D_Texture()
{
addEventListener(Event.ADDED_TO_STAGE, onAddtoStage);
}

private function onAddtoStage(event:Event):void
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;

sta3D = stage.stage3Ds[0];
sta3D.addEventListener(Event.CONTEXT3D_CREATE, onCreateContext3D);
sta3D.requestContext3D(Context3DRenderMode.AUTO);

var FPS:MonitorKit = new MonitorKit(MonitorKit.MKMODE_TL);
addChild(FPS);
}

private function onCreateContext3D(event:Event):void
{
con3D = sta3D.context3D;
con3D.enableErrorChecking = true;
initTexture();
}

private function initTexture():void
{
loaderObj = new Loader();
loaderObj.contentLoaderInfo.addEventListener(Event.COMPLETE,
onLoaderBmpComple);
loaderObj.load(new URLRequest("pic.jpg"));
}

private function onLoaderBmpComple(event:Event):void
{
var tmploaderBmp:Bitmap = event.target.content as Bitmap;
texture = con3D.createTexture( 256, 256,
Context3DTextureFormat.BGRA, false);
texture.uploadFromBitmapData(tmploaderBmp.bitmapData,0);
initMesh();
}

private function initMesh():void
{
var vertexShader:Array =["dp4 op.x, va0, vc0",
"dp4 op.y, va0, vc1",
"dp4 op.z, va0, vc2",
"dp4 op.w, va0, vc3",
"mov v0, va1.xyzw"];
var vertexAssembler:AGALMiniAssembler = new AGALMiniAssembler();
vertexAssembler.assemble(flash.display3D.Context3DProgramType.VERTEX,
vertexShader.join("\n"));

var fragmentShader:Array =["mov ft0, v0\n",
"tex ft1, ft0, fs1 <2d,clamp,linear>\n",
"mov oc, ft1\n"];
var fragmentAssembler:AGALMiniAssembler = new AGALMiniAssembler();
fragmentAssembler.assemble(flash.display3D.Context3DProgramType.FRAGMENT,
fragmentShader.join("\n"));

shaderpg3d = con3D.createProgram();
shaderpg3d.upload(vertexAssembler.agalcode, fragmentAssembler.agalcode);

indexBuffer = con3D.createIndexBuffer(6);
indexBuffer.uploadFromVector(Vector.([0, 1, 2, 0, 2, 3]), 0, 6);

vertexBuffer = con3D.createVertexBuffer(4, 4);
vertexBuffer.uploadFromVector(Vector.([-1.0, 1.0,0.0,1.0,
-1.0,-1.0,0.0,0.0,
1.0,-1.0,1.0,0.0,
1.0, 1.0,1.0,1.0]),0,4);

con3D.setVertexBufferAt( 0, vertexBuffer, 0,
Context3DVertexBufferFormat.FLOAT_2);
con3D.setVertexBufferAt( 1, vertexBuffer, 2,
Context3DVertexBufferFormat.FLOAT_2);
con3D.setTextureAt(1, texture);

addEventListener(Event.ENTER_FRAME, on3DRender);
stage.addEventListener(Event.RESIZE, onResizeStage);
onResizeStage();
}

private function drawMesh():void
{
con3D.setProgram(shaderpg3d);

modelView = new Matrix3D();
modelView.identity();
modelView.position = new Vector3D(0, 0, 2, 1);
modelView.appendScale(1, -1, 1);

perspection = new PerspectiveMatrix3D();
perspection.identity();
perspection.perspectiveLH(5.5, 4, 1, 100);

modelProjection = new Matrix3D();
modelProjection.identity();
modelProjection.position = new Vector3D(0, 0, 0, 1);
modelProjection.appendRotation(stage.mouseX/4,
new Vector3D(0, 1, 0, 1),null);
modelProjection.append(modelView);
modelProjection.append(perspection);

con3D.setCulling("none");
con3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,
0,modelProjection,true);
con3D.drawTriangles(indexBuffer, 0, 2);
}

private function onResizeStage(event:Event=null):void
{
con3D.configureBackBuffer(stage.stageWidth, stage.stageHeight,2,true);
sta3D.viewPort = new Rectangle(0,0,stage.stageWidth,stage.stageHeight);
on3DRender();
}

private function on3DRender(event:Event=null):void
{
con3D.clear(0.0, 0.0, 0.5, 1.0);
drawMesh();
con3D.present();
}
}
}

執行結果:

demo

2011年3月8日星期二

【教學】Flash 3D API(Molehill) DrawSquareMesh

這是DrawTriangleMesh範例的延伸,
也就是再增加一個頂點,
四個頂點組成兩個三角面,
其繪製的方式一樣。

程式碼如下:

package
{
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;

import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Rectangle;
import flash.geom.Vector3D;

public class Flash3D_DrawMesh extends Sprite
{
private var sta3D:Stage3D;
private var con3D:Context3D;

private var indexBuffer:IndexBuffer3D;
private var perspection:PerspectiveMatrix3D;
private var modelProjection:Matrix3D;
private var modelView:Matrix3D;

private var ro:Number = 5;

public function Flash3D_DrawMesh()
{
addEventListener(Event.ADDED_TO_STAGE, onAddtoStage);
}

public function onAddtoStage(event:Event):void
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.frameRate = 30;

sta3D = stage.stage3Ds[0];
sta3D.addEventListener(Event.CONTEXT3D_CREATE,onCreateContext3D);
sta3D.requestContext3D(Context3DRenderMode.AUTO);

var FPS:MonitorKit = new MonitorKit(MonitorKit.MKMODE_TL);
addChild(FPS);
}

public function onCreateContext3D(event:Event):void
{
con3D = sta3D.context3D;
con3D.enableErrorChecking = true;

initMesh();

addEventListener(Event.ENTER_FRAME,on3DRender);
stage.addEventListener(Event.RESIZE,onResizeStage);
onResizeStage();
}

public function onResizeStage(event:Event = null):void
{
con3D.configureBackBuffer(stage.stageWidth,stage.stageHeight,2,true);
sta3D.viewPort = new Rectangle(0,0,stage.stageWidth,stage.stageHeight);
on3DRender();
}

public function initMesh():void
{
var vertexAssembler:AGALMiniAssembler = new AGALMiniAssembler();
vertexAssembler.assemble(Context3DProgramType.VERTEX,"m44 op,va0,vc \n"+
"mov v0,va1");

var fragmentAssembler:AGALMiniAssembler = new AGALMiniAssembler();
fragmentAssembler.assemble(Context3DProgramType.FRAGMENT,"mov oc,v0");

var vertexBuffer:VertexBuffer3D = con3D.createVertexBuffer(4,6);
vertexBuffer.uploadFromVector(Vector.([-1, 1,0,1,0,0,
-1,-1,0,1,1,0,
1,-1,0,1,0,1,
1, 1,0,1,0,0]),0,4);

con3D.setVertexBufferAt(0,vertexBuffer,0,
Context3DVertexBufferFormat.FLOAT_3);
con3D.setVertexBufferAt(1,vertexBuffer,3,
Context3DVertexBufferFormat.FLOAT_3);

indexBuffer= con3D.createIndexBuffer(6);
indexBuffer.uploadFromVector(Vector.([0,1,2,0,2,3]),0,6);

var program:Program3D = con3D.createProgram();
program.upload(vertexAssembler.agalcode,fragmentAssembler.agalcode);
con3D.setProgram(program);

modelView = new Matrix3D();
modelView.identity();

perspection = new PerspectiveMatrix3D();
perspection.identity();
perspection.perspectiveLH(5.5, 4, 1, 10000);

modelProjection = new Matrix3D();
}

private function drawMesh():void
{
modelView.position = new Vector3D(0,0,1.5,1);
modelView.appendRotation(ro,Vector3D.Z_AXIS, null);

modelProjection.identity();
modelProjection.append(modelView);
modelProjection.append(perspection);

con3D.setCulling("front");
con3D.setProgramConstantsFromMatrix( Context3DProgramType.VERTEX,
0,modelProjection,true);
con3D.drawTriangles(indexBuffer,0,2);
}

private function on3DRender(event:Event=null):void
{
con3D.clear(0.0, 0.0, 0.5, 1.0);
drawMesh();
con3D.present();
}
}
}



demo

2011年3月7日星期一

【教學】Flash 3D API(Molehill) DrawTriangleMesh

利用先前範例所建立的基本框架,
新增initMesh()函式,運用頂點緩衝與索引緩衝建立三角面,
再透過AGALMiniAssembler來填上顏色,
最後DrawMesh()把結果畫上。


程式碼如下:

package
{
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;

import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Rectangle;
import flash.geom.Vector3D;

public class Flash3D_DrawTriangle extends Sprite
{
private var sta3D:Stage3D;
private var con3D:Context3D;

private var vertexBuffer:VertexBuffer3D;
private var indexBuffer:IndexBuffer3D;

private var modelView:Matrix3D;
private var modelProjection:Matrix3D;
private var perspection:PerspectiveMatrix3D;

private var ro:Number = 5;
private var pos:Vector3D;

public function Flash3D_DrawTriangle()
{
addEventListener(Event.ADDED_TO_STAGE, onAddtoStage);
}

public function onAddtoStage(event:Event):void
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.frameRate = 30;

sta3D = stage.stage3Ds[0];
sta3D.addEventListener(Event.CONTEXT3D_CREATE, onCreateContext3D);
sta3D.requestContext3D(Context3DRenderMode.AUTO);

var FPS:MonitorKit = new MonitorKit(MonitorKit.MKMODE_TL);
addChild(FPS);
}

public function onCreateContext3D(event:Event):void
{
con3D = sta3D.context3D;
con3D.enableErrorChecking = true;

initMesh();

addEventListener(Event.ENTER_FRAME, on3DRender);
stage.addEventListener(Event.RESIZE, onResizeStage);
onResizeStage();
}

public function onResizeStage(event:Event = null):void
{
con3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 2, true);
sta3D.viewPort = new Rectangle(0,0,stage.stageWidth, stage.stageHeight);
on3DRender();
}

public function initMesh():void
{
var vertexAssembler:AGALMiniAssembler = new AGALMiniAssembler();
vertexAssembler.assemble(Context3DProgramType.VERTEX,"m44 op,va0,vc0 \n"+
"mov v0,va1");

var fragmentAssembler:AGALMiniAssembler = new AGALMiniAssembler();
fragmentAssembler.assemble(Context3DProgramType.FRAGMENT,"mov oc,v0");

vertexBuffer = con3D.createVertexBuffer(3,6);
vertexBuffer.uploadFromVector(Vector.([ 0, 1,0,1,0,0,
-1,-1,0,0,1,0,
1,-1,0,0,0,1,]),0, 3);

con3D.setVertexBufferAt(0,vertexBuffer,0,
Context3DVertexBufferFormat.FLOAT_3);
con3D.setVertexBufferAt(1,vertexBuffer,3,
Context3DVertexBufferFormat.FLOAT_3);

indexBuffer = con3D.createIndexBuffer(3);
indexBuffer.uploadFromVector(Vector.([0,1,2]),0,3);

var program:Program3D = con3D.createProgram();
program.upload(vertexAssembler.agalcode,fragmentAssembler.agalcode);
con3D.setProgram(program);

modelView = new Matrix3D();
modelView.identity();
pos = new Vector3D(0,0,2,1);

perspection = new PerspectiveMatrix3D();
perspection.identity();
perspection.perspectiveLH(2.8,2,1,10000);
}

public function DrawMesh():void
{
modelView.position = pos;
modelView.appendRotation(ro,Vector3D.Y_AXIS, null);

modelProjection = new Matrix3D();
modelProjection.identity();
modelProjection.append(modelView);
modelProjection.append(perspection);

con3D.setCulling("none");
con3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,
0,modelProjection,true);
con3D.drawTriangles(indexBuffer,0,-1);
}

public function on3DRender(event:Event):void
{
con3D.clear(0.0, 0.0, 0.5, 1.0);
DrawMesh();
con3D.present();
}
}
}


執行結果:

demo

2011年3月6日星期日

【教學】Flash 3D API(Molehill) 基本框架建立

Molehill 3D前陣子很多人在討論,
最近也研究了一下,發現3D環境都是大同小異,
所以寫了一個3D的基本框架測試範例,
使用到 Flex SDK Hero(版本19784),
Flash Player 11.0.0.58 Incubator,
本範例開發工具使用FlashDevelop,
也可以使用Adobe Flash Builder 4或Flash CS5。



程式碼如下:


package
{
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DRenderMode;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.Rectangle;

import MonitorKit;

/**
* ...Flash 3D Framework
* @author Max
*/
public class Flash3D_Framework extends Sprite
{
private var sta3D:Stage3D;
private var con3D:Context3D;

public function Flash3D_Framework():void
{
addEventListener(Event.ADDED_TO_STAGE, onAddtoStage);
}

public function onAddtoStage(event:Event):void
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;

sta3D = stage.stage3Ds[0];
sta3D.addEventListener(Event.CONTEXT3D_CREATE, onCreateContext3D);
sta3D.requestContext3D(Context3DRenderMode.AUTO);
// 設定FPS
var FPS:MonitorKit = new MonitorKit(MonitorKit.MKMODE_TL);
addChild(FPS);
}

public function onCreateContext3D(event:Event):void
{
con3D = sta3D.context3D;
con3D.enableErrorChecking = true;

addEventListener(Event.ENTER_FRAME, on3DRender);
stage.addEventListener(Event.RESIZE, onResizeStage);
onResizeStage();
}

public function onResizeStage(event:Event = null):void
{
// 設定背景緩衝
con3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 2, true);
// 讓成像大小等於stage的大小
sta3D.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
on3DRender();
}
// 3D渲染
public function on3DRender(event:Event = null):void
{
// 設定3D背景色(rgba)
con3D.clear(0.0, 0.0, 0.5, 1.0);
// ...
// 要繪製3D的處理可以加在這...
// ...
con3D.present();
}
}
}


執行結果: