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();
}
}
}


執行結果:

2010年11月17日星期三

【教學】Director 3D與PhysX 物理引擎

CasetMember視窗:


Lingo程式代碼:
----------Movie Script:"main"

global pDirPhyz -- 物理引擎
global pTimeStep -- 影響時間
global pSubSteps -- 計算動力係數
global resSphere -- 球的模型資源
global modSphere -- 球的模型
global resBox -- 方塊的模型資源
global modBox -- 方塊模型
global resFloor -- 地板模型資源
global modFloor -- 地板模型

on startmovie

--W3D
member("Scene3D").resetworld()

-------------------------------------
--建立球體模型
resSphere = member("Scene3D").newModelResource("SphereRes",#sphere,#front)
resSphere.radius = 10
resSphere.resolution = 6

modSphere = member("Scene3D").newModel("SphereRes")
modSphere.resource = resSphere
modSphere.transform.position = vector(50,100,-20)
modSphere.addmodifier(#meshdeform)


-------------------------------------
--建立方塊模型
resBox = member("Scene3D").newModelResource("BoxRes",#Box,#front)
resBox.height = 5
resBox.width = 100
resBox.length = 100
resBox.lengthVertices = 5
resBox.widthVertices = 5
resBox.heightVertices = 2

modBox = member("Scene3D").newModel("BoxRes")
modBox.resource = resBox
modBox.transform.position = vector(20,0,-20)
modBox.transform.rotation = vector(10,10,20)
modBox.addmodifier(#meshdeform)

-----------------------------------------
--建立地板模型
resFloor = member("Scene3D").newModelResource("FloorRes",#Box,#front)
resFloor.height = 5
resFloor.width = 200
resFloor.length = 200
resFloor.lengthVertices = 5
resFloor.widthVertices = 5
resFloor.heightVertices = 2

modFloor = member("Scene3D").newModel("FloorRes")
modFloor.resource = resFloor
modFloor.transform.position = vector(0,-70,0)
modFloor.transform.rotation = vector(0,0,0)
modFloor.addmodifier(#meshdeform)

------------------------------------------
--物理引擎
pDirPhyz = member("physX")
pTimeStep = 0.2
pSubSteps = 10

--初始引擎
pDirPhyz.Init(member("Scene3D"), vector(1,1,1),#equal, pTimeStep, pSubSteps )
pDirPhyz.gravity = vector(0,-9.8,0)
pDirPhyz.contacttolerance = 0.2
pDirPhyz.friction = 0.2
pDirPhyz.lineardamping = 0.4
pDirPhyz.angulardamping = 0.4
pDirPhyz.restitution = 0.9

--引擎套用到球模型
rb_ball=pDirPhyz.createRigidBody(modSphere.name,modSphere.name,#sphere,#dynamic)
rb_ball.mass = 100

--引擎套用到方塊模型
rb_box=pDirPhyz.createRigidBody(modBox.name,modBox.name,#Box,#static )
rb_box.mass = 100

--引擎套用到地板模型
rb_floor=pDirPhyz.createRigidBody(modFloor.name,modFloor.name,#Box,#static )
rb_floor.mass = 100

end

on endSprite me
if (pDirPhyz.isInitialized = 1) then
pDirPhyz.destroy()
end if
end


----------Frame Script:"loop"

global pDirPhyz -- 物理引擎
global pTimeStep -- 影響時間
global pSubSteps -- 計算動力係數

on exitFrame
pDirPhyz.simulate()

go to the frame
end


Score視窗:



執行結果:

demo