http://www.youtube.com/watch?v=CW9imHbbljU
使用 FlarDetector 作成的地洞測試影片,加上在 3DS MAX 作的 miku 動畫、彩虹及程式中運算的 3D 彈跳球。
project source ...
http://code.google.com/p/flardetector/
2009年12月30日 星期三
2009年12月22日 星期二
FLARToolKit Multi Marker Detector & Cube type Marker 實作
ARis...
ARis 是日本一間公司出品的產品,應用了 ARToolKit 技術。
展示影片在這…
http://www.youtube.com/watch?v=yCCx7zANsGE
YouTube上可以找到更多類似的影片。
這邊是我用 FLARToolKit 自己作的 DEMO,當然,不止是能運用在這方面( 指宅男專用 ),像是商業產品的3D 展示也可以這樣用,在全像投影真正普及化實現之前,我想 AR 技術或許是最快實現類似體驗的方法吧? ( 配合 AR 眼鏡 )
DEMO VIDEO...
http://www.youtube.com/watch?v=W9s2ldmd9Vc
DEMO ONLINE...
http://www.asn.com.tw/flex/FlarMikuDemo/PV3DFlarTest.html
要線上執行需要列印出上列 Marker 檔,將其中的方塊組合起來,並且準備一台 Webcam,程式運行後再將 Webcam 對準方塊就會出現人偶嘍~(還有牛)!!!
Markers...
ARis Marker : http://www.asn.com.tw/flex/FlarMikuDemo/Data/ARisMarker.jpg
Cube Marker : http://www.asn.com.tw/flex/FlarMikuDemo/Data/CubeMarker.jpg
要自建 Marker 檔可以到…
http://flash.tarotaro.org/blog/2008/12/14/artoolkit-marker-generator-online-released/
======== 底下給有興趣寫 AR 程式的人作參考 ========
MultiMarker...
這個程式等於是 FLARToolKit 複數 Marker 的應用,在 FLARToolKit 中有個 FLARMultiMarkerDetector 的類別,是用來同時偵測多個 Marker 用的,MultiMarker 的偵測需要管理多個 Maeker 的 ARCode。
網路上有現成的多偵測點 Marker 管理函式庫 FLARManager…
這個 MultiMarker 管理類別功能蠻強大的,包含多點偵測、圖形二元化閥值最佳化、座標位置 smooth 及動態點預測…。
FlarDetetor...
不過我沒有實際去用 FLARManager,而是自己寫了個簡化版的 FlarDetetor,一樣是 MultiMarker Detect,還蠻好用的,我的 ARis 就是利用這個類別作出來的。
FlarDetetor 特色:
一、多個 Marker 同時偵測。
二、事件觸發 ( MARKER_ADDED、MARKER_UPDATED、MARKER_REMOVED )。
三、完全獨立的一個類別,低耦合,只用到原始的 FLARToolKit 類別。
四、俱備簡易 smooth 功能。
如何使用:
一、初始化,跟一般 FLARToolKit 應用程式一樣代入 FLARParam 跟 Webcam 的 Bitmapdata。
二、 建立 FlarObject 物件並載入 Marker 檔,然後加入 PV3D scene 中。
var cube:FlarCube = new FlarCube ();
cube.detector.loadCode( 'cube.pat',16,100 ); /// 注意後面二個 width 參數要與當初存 patern 時一致,否則測不出來唷。
三、最後只要在 PV3D Render 的時候 detect 即可自動分派事件。
FlarObject...
這個類別便是拿來裝你的 PV3D 子物件的容器,繼承自 FLARToolKit 的 FLARBaseNode 類別,並且有基本的一個 FlarDetector 及預設的事件反應,當 FlarDetector偵測到時便進行座標方位的轉換。
比較特別的地方在於我使用了一個 _pivot:DisplayObject3D 作為內容器,好方便底下延伸類別的座標軸轉換,所有子物件都放在 pivot中,就可以自由在程式控制相對位置跟方向,而不會受 Node Transform 的影響。
當然,其實 FlarDetector 是蠻低耦合的一個類別,你也可以直接使用 FlarDetector 在任何的場合,創造你自己的類別,也不一定要配合 PV3D 來使用,把 FlarDetector 當成一個單純的 Sensor 來使用即可。
FlarARisCube...
至於六面體 Marker 的偵測,網路上可以找到 Tarotaro 的 5 面立方體範例…
http://flash.tarotaro.org/blog/2009/04/06/cube-type-marker-in-flar/
他的演算法是將水平的四個面用二個 Marker 解決,一個偵測用,一個判斷面向用,再加上上面一個 Marker 總共三個,真聰明丫,詳細的演算法可以參考…
http://flash.tarotaro.org/blog/2009/06/10/about-cube-detection-algorithm/
但是可惜是這個方法只能作 5 面偵測,從底下往上看沒有(要幹嘛?!),而且水平的四個面的 Marker 必需有一定的規則,Marker 的設計要比較注意。
這 個函式庫我也沒實際去用,於是又寫了個 FlarARisCube 的類別,這個類別其實只是在一個類別中放了六個 FlarDetector,再在偵測到時轉換一下座標而己,只是在轉換座標時搞的有點暈頭轉向,我的方法是比較直接的方式,效能沒 Tarotaro 的好,只能說是比較容易實現的方法。
最後則是六面體方塊在上仰角度時,會有遮罩的效果,讓六面體看起來更直實(能遮到人偶),我是參考 FLARToolKit 的原作者 saqoosha 的這篇文章…
http://saqoosha.net/en/2009/01/08/1676/
文章是介紹地上打洞的效果,不過原理一樣 ( 地上打洞很酷丫,下回再來作 ^ ^ )。
Finally…
一連串的學習QQ",總算成功,出現人偶嘍~(還有牛)~呵呵呵。
Source Code...
原始程式下載:( 包含 papervision3d 及 flartoolkit )-原始版本
http://www.asn.com.tw/flex/FlarMikuDemo/FlarMikuDemo.zip
2009/12/22 - 最新的 source 改放在 google code,http://code.google.com/p/flardetector/
( 不包含 papervision3d 及 flartoolkit )
ARis 是日本一間公司出品的產品,應用了 ARToolKit 技術。
展示影片在這…
http://www.youtube.com/watch?v=yCCx7zANsGE
YouTube上可以找到更多類似的影片。
這邊是我用 FLARToolKit 自己作的 DEMO,當然,不止是能運用在這方面( 指宅男專用 ),像是商業產品的3D 展示也可以這樣用,在全像投影真正普及化實現之前,我想 AR 技術或許是最快實現類似體驗的方法吧? ( 配合 AR 眼鏡 )
DEMO VIDEO...
http://www.youtube.com/watch?v=W9s2ldmd9Vc
DEMO ONLINE...
http://www.asn.com.tw/flex/FlarMikuDemo/PV3DFlarTest.html
要線上執行需要列印出上列 Marker 檔,將其中的方塊組合起來,並且準備一台 Webcam,程式運行後再將 Webcam 對準方塊就會出現人偶嘍~(還有牛)!!!
Markers...
ARis Marker : http://www.asn.com.tw/flex/FlarMikuDemo/Data/ARisMarker.jpg
Cube Marker : http://www.asn.com.tw/flex/FlarMikuDemo/Data/CubeMarker.jpg
要自建 Marker 檔可以到…
http://flash.tarotaro.org/blog/2008/12/14/artoolkit-marker-generator-online-released/
======== 底下給有興趣寫 AR 程式的人作參考 ========
MultiMarker...
這個程式等於是 FLARToolKit 複數 Marker 的應用,在 FLARToolKit 中有個 FLARMultiMarkerDetector 的類別,是用來同時偵測多個 Marker 用的,MultiMarker 的偵測需要管理多個 Maeker 的 ARCode。
網路上有現成的多偵測點 Marker 管理函式庫 FLARManager…
這個 MultiMarker 管理類別功能蠻強大的,包含多點偵測、圖形二元化閥值最佳化、座標位置 smooth 及動態點預測…。
FlarDetetor...
不過我沒有實際去用 FLARManager,而是自己寫了個簡化版的 FlarDetetor,一樣是 MultiMarker Detect,還蠻好用的,我的 ARis 就是利用這個類別作出來的。
FlarDetetor 特色:
一、多個 Marker 同時偵測。
二、事件觸發 ( MARKER_ADDED、MARKER_UPDATED、MARKER_REMOVED )。
三、完全獨立的一個類別,低耦合,只用到原始的 FLARToolKit 類別。
四、俱備簡易 smooth 功能。
如何使用:
一、初始化,跟一般 FLARToolKit 應用程式一樣代入 FLARParam 跟 Webcam 的 Bitmapdata。
FlarDetector.init(_capture);
二、 建立 FlarObject 物件並載入 Marker 檔,然後加入 PV3D scene 中。
var cube:FlarCube = new FlarCube ();
cube.detector.loadCode( 'cube.pat',16,100 ); /// 注意後面二個 width 參數要與當初存 patern 時一致,否則測不出來唷。
this.scene.addChild( cube );
三、最後只要在 PV3D Render 的時候 detect 即可自動分派事件。
FlarDetector.detectMarkerLite();
FlarObject...
這個類別便是拿來裝你的 PV3D 子物件的容器,繼承自 FLARToolKit 的 FLARBaseNode 類別,並且有基本的一個 FlarDetector 及預設的事件反應,當 FlarDetector偵測到時便進行座標方位的轉換。
比較特別的地方在於我使用了一個 _pivot:DisplayObject3D 作為內容器,好方便底下延伸類別的座標軸轉換,所有子物件都放在 pivot中,就可以自由在程式控制相對位置跟方向,而不會受 Node Transform 的影響。
當然,其實 FlarDetector 是蠻低耦合的一個類別,你也可以直接使用 FlarDetector 在任何的場合,創造你自己的類別,也不一定要配合 PV3D 來使用,把 FlarDetector 當成一個單純的 Sensor 來使用即可。
FlarARisCube...
至於六面體 Marker 的偵測,網路上可以找到 Tarotaro 的 5 面立方體範例…
http://flash.tarotaro.org/blog/2009/04/06/cube-type-marker-in-flar/
他的演算法是將水平的四個面用二個 Marker 解決,一個偵測用,一個判斷面向用,再加上上面一個 Marker 總共三個,真聰明丫,詳細的演算法可以參考…
http://flash.tarotaro.org/blog/2009/06/10/about-cube-detection-algorithm/
但是可惜是這個方法只能作 5 面偵測,從底下往上看沒有(要幹嘛?!),而且水平的四個面的 Marker 必需有一定的規則,Marker 的設計要比較注意。
這 個函式庫我也沒實際去用,於是又寫了個 FlarARisCube 的類別,這個類別其實只是在一個類別中放了六個 FlarDetector,再在偵測到時轉換一下座標而己,只是在轉換座標時搞的有點暈頭轉向,我的方法是比較直接的方式,效能沒 Tarotaro 的好,只能說是比較容易實現的方法。
最後則是六面體方塊在上仰角度時,會有遮罩的效果,讓六面體看起來更直實(能遮到人偶),我是參考 FLARToolKit 的原作者 saqoosha 的這篇文章…
http://saqoosha.net/en/2009/01/08/1676/
文章是介紹地上打洞的效果,不過原理一樣 ( 地上打洞很酷丫,下回再來作 ^ ^ )。
Finally…
一連串的學習QQ",總算成功,出現人偶嘍~(還有牛)~呵呵呵。
Source Code...
原始程式下載:( 包含 papervision3d 及 flartoolkit )-原始版本
http://www.asn.com.tw/flex/FlarMikuDemo/FlarMikuDemo.zip
2009/12/22 - 最新的 source 改放在 google code,http://code.google.com/p/flardetector/
( 不包含 papervision3d 及 flartoolkit )
2009年12月6日 星期日
有趣的 FLARToolKIT
結合 webcam 產生像是虛擬+實境融合的效果(Augmented Reality)~
http://blog.papervision3d.org/2009/01/07/augmented-reality-with-flartoolkit/
網路上有一大堆很酷的作品唷。
FLARToolKit 是一位日本人將 ARToolKit 改寫成 AS3版本,再配合 3D 引擎 (如 Papervision3D ) 作成的。
主要的原理是利用事先製作好的圖像(marker)作為辨識它在現實環境中的 3D 位置、角度…等等的資料,再套用到螢幕這個 marker 所代表的 3D 物件,結合 webcam 畫面就造成這樣的視覺效果了。
底下是自己練習的成果影片…
http://www.youtube.com/watch?v=tyQWHQH28iM
可以想像一下整個房間貼滿 marker 或 全身穿上有 marker 的衣服會是怎樣的情景~^ ^,有很多發揮創意的空間。
線上 Demo 在這…
http://www.asn.com.tw/flex/PV3DFlar/PV3DFlar.html
*要使用線上 Demo 必須準備 webcam,再列印我使用的二種 marker,到這個網址後會提示啟用 webcam,再把 marker 對著 webcam 鏡頭晃,就會在螢幕上看到效果了。
*我的 marker 可以在這下載。
http://blog.papervision3d.org/2009/01/07/augmented-reality-with-flartoolkit/
網路上有一大堆很酷的作品唷。
FLARToolKit 是一位日本人將 ARToolKit 改寫成 AS3版本,再配合 3D 引擎 (如 Papervision3D ) 作成的。
主要的原理是利用事先製作好的圖像(marker)作為辨識它在現實環境中的 3D 位置、角度…等等的資料,再套用到螢幕這個 marker 所代表的 3D 物件,結合 webcam 畫面就造成這樣的視覺效果了。
底下是自己練習的成果影片…
http://www.youtube.com/watch?v=tyQWHQH28iM
可以想像一下整個房間貼滿 marker 或 全身穿上有 marker 的衣服會是怎樣的情景~^ ^,有很多發揮創意的空間。
線上 Demo 在這…
http://www.asn.com.tw/flex/PV3DFlar/PV3DFlar.html
*要使用線上 Demo 必須準備 webcam,再列印我使用的二種 marker,到這個網址後會提示啟用 webcam,再把 marker 對著 webcam 鏡頭晃,就會在螢幕上看到效果了。
*我的 marker 可以在這下載。
2009年11月29日 星期日
PV3D 練習 - Facebook 好友大頭照
DEMO:(需登入fb)
http://www.asn.com.tw/flex/20091129.htm
20110827更新連結…
http://www.vercenter.nknu.edu.tw/flex/FacebookFriends/LongfellowHelloFlex.html
在 facebook 上登入,讀取好友名單及大頭照,再將大頭照轉成 BitmapMaterial,用這個材質生成 PLANE,再置入 PV3D 場景中。
效果跟效能,並不是絕對的反比關係。
SOURCE:
package study
{
import game.FacebookAP;
import com.facebook.data.users.FacebookUser;
import flash.display.Bitmap;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import org.papervision3d.core.effects.view.ReflectionView;
import org.papervision3d.core.math.Quaternion;
import org.papervision3d.cameras.CameraType;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Plane;
public class study21 extends ReflectionView
{
private var currentQuat:Quaternion = new Quaternion();
private var targetQuat:Quaternion = new Quaternion();
private var slerp:Number = 0;
private var fbRadius:Number;
private var carousel:DisplayObject3D = new DisplayObject3D();
private var isMouseDown:Boolean;
private var fb:FacebookAP;
private var save_mouseX:Number;
private var save_rotationY:Number;
private static var planeWidth:Number = 50;
private static var planeHeight:Number = 50;
public function study21()
{
super(0,0,true,false,CameraType.FREE);
this.addEventListener(Event.ADDED_TO_STAGE, init0);
}
private function init0( event:Event ):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, init0);
fb = new FacebookAP();
fb.addEventListener( Event.COMPLETE, init1 );
fb.init();
}
private function init1( event:Event ):void
{
fb.removeEventListener( Event.COMPLETE, init1 );
opaqueBackground=0;
surfaceHeight = -5;
viewport.interactive=true;
viewportReflection.filters = [new BlurFilter(3,3,3)];
setReflectionColor(.7, .7, .7);
fbRadius = ( fb.friends.length * (planeWidth+planeWidth/2) )/(2*Math.PI);
camera.target = carousel;
camera.position = carousel.position;
camera.y = planeHeight/2;
camera.moveBackward( fbRadius+150 );
for( var i:int=0; i
{
var user:FacebookUser = fb.friends.getItemAt(i) as FacebookUser;
var lc:LoaderContext = new LoaderContext(true);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onLoadBitmap );
if( user.pic_square == "" )
loader.load(new URLRequest( "images/q_silhouette.gif" ), lc );
else
loader.load(new URLRequest( user.pic_square ), lc);
}
scene.addChild(carousel);
this.addEventListener(Event.ENTER_FRAME, onENTER_FRAME );
this.stage.addEventListener( MouseEvent.MOUSE_DOWN, onMOUSE_DOWN );
this.stage.addEventListener( MouseEvent.MOUSE_UP, onMOUSE_UP );
}
private function onLoadBitmap( event:Event ):void
{
var bodyMaterial:BitmapMaterial = new BitmapMaterial( Bitmap(LoaderInfo(event.target).content).bitmapData );
bodyMaterial.interactive=true;
bodyMaterial.doubleSided=true
var plane:DisplayObject3D = new Plane( bodyMaterial,planeWidth,planeHeight,1,1 );
plane.rotationY = ( 360 / fb.friends.length ) * carousel.numChildren;
plane.moveForward( fbRadius );
plane.y = planeHeight/2;
carousel.addChild(plane);
}
private function onMOUSE_DOWN(e:Event):void
{
isMouseDown = true;
save_mouseX = this.stage.mouseX;
save_rotationY = carousel.rotationY;
}
private function onMOUSE_UP(e:Event):void
{
isMouseDown = false;
}
private function onENTER_FRAME(e:Event):void
{
if( isMouseDown )
{
carousel.rotationY = save_rotationY + (180/Math.PI)*Math.atan((save_mouseX-this.stage.mouseX)/(fbRadius+150));
} else {
carousel.rotationY -= ( this.stage.mouseX - this.stage.stageWidth/2 )/200;
slerp += (1 - slerp) * .05;
var quat:Quaternion = Quaternion.slerp( currentQuat, targetQuat, slerp );
carousel.transform = quat.matrix;
}
singleRender();
}
}
}
http://www.asn.com.tw/flex/20091129.htm
20110827更新連結…
http://www.vercenter.nknu.edu.tw/flex/FacebookFriends/LongfellowHelloFlex.html
在 facebook 上登入,讀取好友名單及大頭照,再將大頭照轉成 BitmapMaterial,用這個材質生成 PLANE,再置入 PV3D 場景中。
效果跟效能,並不是絕對的反比關係。
SOURCE:
package study
{
import game.FacebookAP;
import com.facebook.data.users.FacebookUser;
import flash.display.Bitmap;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import org.papervision3d.core.effects.view.ReflectionView;
import org.papervision3d.core.math.Quaternion;
import org.papervision3d.cameras.CameraType;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Plane;
public class study21 extends ReflectionView
{
private var currentQuat:Quaternion = new Quaternion();
private var targetQuat:Quaternion = new Quaternion();
private var slerp:Number = 0;
private var fbRadius:Number;
private var carousel:DisplayObject3D = new DisplayObject3D();
private var isMouseDown:Boolean;
private var fb:FacebookAP;
private var save_mouseX:Number;
private var save_rotationY:Number;
private static var planeWidth:Number = 50;
private static var planeHeight:Number = 50;
public function study21()
{
super(0,0,true,false,CameraType.FREE);
this.addEventListener(Event.ADDED_TO_STAGE, init0);
}
private function init0( event:Event ):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, init0);
fb = new FacebookAP();
fb.addEventListener( Event.COMPLETE, init1 );
fb.init();
}
private function init1( event:Event ):void
{
fb.removeEventListener( Event.COMPLETE, init1 );
opaqueBackground=0;
surfaceHeight = -5;
viewport.interactive=true;
viewportReflection.filters = [new BlurFilter(3,3,3)];
setReflectionColor(.7, .7, .7);
fbRadius = ( fb.friends.length * (planeWidth+planeWidth/2) )/(2*Math.PI);
camera.target = carousel;
camera.position = carousel.position;
camera.y = planeHeight/2;
camera.moveBackward( fbRadius+150 );
for( var i:int=0; i
{
var user:FacebookUser = fb.friends.getItemAt(i) as FacebookUser;
var lc:LoaderContext = new LoaderContext(true);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onLoadBitmap );
if( user.pic_square == "" )
loader.load(new URLRequest( "images/q_silhouette.gif" ), lc );
else
loader.load(new URLRequest( user.pic_square ), lc);
}
scene.addChild(carousel);
this.addEventListener(Event.ENTER_FRAME, onENTER_FRAME );
this.stage.addEventListener( MouseEvent.MOUSE_DOWN, onMOUSE_DOWN );
this.stage.addEventListener( MouseEvent.MOUSE_UP, onMOUSE_UP );
}
private function onLoadBitmap( event:Event ):void
{
var bodyMaterial:BitmapMaterial = new BitmapMaterial( Bitmap(LoaderInfo(event.target).content).bitmapData );
bodyMaterial.interactive=true;
bodyMaterial.doubleSided=true
var plane:DisplayObject3D = new Plane( bodyMaterial,planeWidth,planeHeight,1,1 );
plane.rotationY = ( 360 / fb.friends.length ) * carousel.numChildren;
plane.moveForward( fbRadius );
plane.y = planeHeight/2;
carousel.addChild(plane);
}
private function onMOUSE_DOWN(e:Event):void
{
isMouseDown = true;
save_mouseX = this.stage.mouseX;
save_rotationY = carousel.rotationY;
}
private function onMOUSE_UP(e:Event):void
{
isMouseDown = false;
}
private function onENTER_FRAME(e:Event):void
{
if( isMouseDown )
{
carousel.rotationY = save_rotationY + (180/Math.PI)*Math.atan((save_mouseX-this.stage.mouseX)/(fbRadius+150));
} else {
carousel.rotationY -= ( this.stage.mouseX - this.stage.stageWidth/2 )/200;
slerp += (1 - slerp) * .05;
var quat:Quaternion = Quaternion.slerp( currentQuat, targetQuat, slerp );
carousel.transform = quat.matrix;
}
singleRender();
}
}
}
2009年11月27日 星期五
PV3D 練習 - 加入影片
現在可以邊開車邊看電視了 ^ ^"
http://www.asn.com.tw/flex/cardrive/CarDriver4.html
20110827連結更新…
http://www.vercenter.nknu.edu.tw/flex/CarDriver/CarDriver.html
不過所使用的影片檔是伺服端的 flv 檔,若要使用外部的連結(如 youtube),則會有 security domain 的問題,還要再研究。
幾個問題要注意…
一、DAE 物件有可能是很多個小物件組成的,在 3DS 裡會有不同的名稱及材質名稱,若需要讓 DAE 物件能產生事件 ( 譬如這個例子中液晶電視的畫面會接收滑鼠按下的事件來停止、撥放影片 ),必須從讀入的 DAE 物件中抽取出子物件 ( getChildByName ),再把這個子物件加上 InteractiveScene3DEvent (材質亦需事先設定好 interactive = true,才能正確接收到事件。
二、同樣是 DAE 物件,由於物件的建立順序是先建立 DisplayObject3D 再 LOAD 進模型及上材質,因此在 Render 的時候要特別注意,別在還沒 FileLoadEvent.LOAD_COMPLETE 之前就先調用子物件 ( 例如本例中的車承軸及車輪 ),否則會誤用 NULL 物件。 解決的辦法是確認全部 LOAD 完再 startRendering 或者在每次使用前作 NULL check。
三、材質使用貼圖 bitmap 時要特別小心原 bitmap 的檔案大小也會嚴重影響到 render 的效能 ( 例如被我消去的草坪 = =",跟原本很大張的木箱圖 )。
PV3D 的效能確實不是很理想,但想必隨著 ADOBE 日後支援 3D 硬體 GPU 加速 (希望早點實現 ),PV3D (或其它 WEB 3D 引擎 ) 應該也會更讚才是,在此之前,先把效率最優化的技巧學好吧~ ^ ^
另外順便介紹一個超驚人的 Web 3D 引擎 UNITY,底下是官網 DEMO…
http://unity3d.com/gallery/live-demos/tropical-paradise
需要安裝個小小元件才能看到,不過效果驚人。
http://www.asn.com.tw/flex/cardrive/CarDriver4.html
20110827連結更新…
http://www.vercenter.nknu.edu.tw/flex/CarDriver/CarDriver.html
不過所使用的影片檔是伺服端的 flv 檔,若要使用外部的連結(如 youtube),則會有 security domain 的問題,還要再研究。
幾個問題要注意…
一、DAE 物件有可能是很多個小物件組成的,在 3DS 裡會有不同的名稱及材質名稱,若需要讓 DAE 物件能產生事件 ( 譬如這個例子中液晶電視的畫面會接收滑鼠按下的事件來停止、撥放影片 ),必須從讀入的 DAE 物件中抽取出子物件 ( getChildByName ),再把這個子物件加上 InteractiveScene3DEvent (材質亦需事先設定好 interactive = true,才能正確接收到事件。
二、同樣是 DAE 物件,由於物件的建立順序是先建立 DisplayObject3D 再 LOAD 進模型及上材質,因此在 Render 的時候要特別注意,別在還沒 FileLoadEvent.LOAD_COMPLETE 之前就先調用子物件 ( 例如本例中的車承軸及車輪 ),否則會誤用 NULL 物件。 解決的辦法是確認全部 LOAD 完再 startRendering 或者在每次使用前作 NULL check。
三、材質使用貼圖 bitmap 時要特別小心原 bitmap 的檔案大小也會嚴重影響到 render 的效能 ( 例如被我消去的草坪 = =",跟原本很大張的木箱圖 )。
PV3D 的效能確實不是很理想,但想必隨著 ADOBE 日後支援 3D 硬體 GPU 加速 (希望早點實現 ),PV3D (或其它 WEB 3D 引擎 ) 應該也會更讚才是,在此之前,先把效率最優化的技巧學好吧~ ^ ^
另外順便介紹一個超驚人的 Web 3D 引擎 UNITY,底下是官網 DEMO…
http://unity3d.com/gallery/live-demos/tropical-paradise
需要安裝個小小元件才能看到,不過效果驚人。
2009年11月26日 星期四
PV3D 練習-幾種加入光影材質的方式
開車加入光影材質…
http://www.asn.com.tw/flex/cardrive/CarDriver3.html
幾種加入光影材質的方式…
在PV3D 裡面有所謂的 shadematerial,用來產生會按照光源反應出明暗變化的效果的材質,在使用上很方便,只需產生一個點光源,再利用它來 new 出一個 ShadeMaterial,再賦予物件使用。
最簡單的像是 org.papervision3d.materials.shadematerials 底下的 FlatShadeMaterial …
private function foo():void
{
var light:PointLight3D = new PointLight3D();
var shaderMaterial:FlatShadeMaterial = new FlatShadeMaterial( light, 0x123456, 0x000000 );
var plane:Plane = new Plane(shaderMaterial,500,500);
}
但有時會需要用貼圖的方式來生成物件的表面紋理,比較像真,這時要透過 shader 來重新製作俱備貼圖的 ShadedMaterial…
[Embed(source="assets/photo.jpg")]
private var bmpAsset:Class;
private function foo():void
{
var light:PointLight3D = new PointLight3D();
var yourBitmap:Bitmap = new bmpAsset() as Bitmap;
var bitmapMaterial:BitmapMaterial = new BitmapMaterial(yourBitmap.bitmapData);
var shader:FlatShader= new FlatShader( light, 0xffffff, 0x333333);
var shaderMaterial:ShadedMaterial = new ShadedMaterial(bitmapMaterial, shader);
plane = new Plane(shaderMaterial,500,500);
}
上面是靜態讀圖的作法,但是若是透過 BitmapFileMaterial 動態即時讀圖檔,卻會失敗…
private function foo():void
{
var fileMaterial:BitmapFileMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
/// after FileLoadEvent.LOAD_COMPLETE ....
var light:PointLight3D = new PointLight3D();
var shader:FlatShader = new FlatShader(light, 0xFFFFFF, 0x333333);
var shaderMaterial:ShadedMaterial = new ShadedMaterial(fileMaterial, shader);
var plane:Plane = new Plane(shaderMaterial,500,500);
}
因為 BitmapFileMaterial 並不是 BitmapMaterial 的子類別 ~"~,所以要稍微轉一下…
private function foo():void
{
var fileMaterial:BitmapFileMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
/// after FileLoadEvent.LOAD_COMPLETE ....
var light:PointLight3D = new PointLight3D();
var shader:FlatShader = new FlatShader(light, 0xFFFFFF, 0x333333);
var bitmapMaterial:BitmapMaterial = new BitmapMaterial( fileMaterial.bitmap );
var shaderMaterial:ShadedMaterial = new ShadedMaterial(bitmapMaterial, shader);
var plane:Plane = new Plane(shaderMaterial,500,500);
}
另外要注意,Cube 六面體若是要使用 ShadedMaterial 的話,六面都要 new 個新 shader 給它,否則會有三角形黑色塊產生 = =",很麻煩,而且跑起來非常秏效能。
org.papervision3d.materials.shader 底下還有很多種不同的 shader 可以使用,效果皆不同…
FlatShader
PhongShader
CellShader
EnvMapShader
GouraudShader
…
http://www.asn.com.tw/flex/cardrive/CarDriver3.html
幾種加入光影材質的方式…
在PV3D 裡面有所謂的 shadematerial,用來產生會按照光源反應出明暗變化的效果的材質,在使用上很方便,只需產生一個點光源,再利用它來 new 出一個 ShadeMaterial,再賦予物件使用。
最簡單的像是 org.papervision3d.materials.shadematerials 底下的 FlatShadeMaterial …
private function foo():void
{
var light:PointLight3D = new PointLight3D();
var shaderMaterial:FlatShadeMaterial = new FlatShadeMaterial( light, 0x123456, 0x000000 );
var plane:Plane = new Plane(shaderMaterial,500,500);
}
但有時會需要用貼圖的方式來生成物件的表面紋理,比較像真,這時要透過 shader 來重新製作俱備貼圖的 ShadedMaterial…
[Embed(source="assets/photo.jpg")]
private var bmpAsset:Class;
private function foo():void
{
var light:PointLight3D = new PointLight3D();
var yourBitmap:Bitmap = new bmpAsset() as Bitmap;
var bitmapMaterial:BitmapMaterial = new BitmapMaterial(yourBitmap.bitmapData);
var shader:FlatShader= new FlatShader( light, 0xffffff, 0x333333);
var shaderMaterial:ShadedMaterial = new ShadedMaterial(bitmapMaterial, shader);
plane = new Plane(shaderMaterial,500,500);
}
上面是靜態讀圖的作法,但是若是透過 BitmapFileMaterial 動態即時讀圖檔,卻會失敗…
private function foo():void
{
var fileMaterial:BitmapFileMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
/// after FileLoadEvent.LOAD_COMPLETE ....
var light:PointLight3D = new PointLight3D();
var shader:FlatShader = new FlatShader(light, 0xFFFFFF, 0x333333);
var shaderMaterial:ShadedMaterial = new ShadedMaterial(fileMaterial, shader);
var plane:Plane = new Plane(shaderMaterial,500,500);
}
因為 BitmapFileMaterial 並不是 BitmapMaterial 的子類別 ~"~,所以要稍微轉一下…
private function foo():void
{
var fileMaterial:BitmapFileMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
/// after FileLoadEvent.LOAD_COMPLETE ....
var light:PointLight3D = new PointLight3D();
var shader:FlatShader = new FlatShader(light, 0xFFFFFF, 0x333333);
var bitmapMaterial:BitmapMaterial = new BitmapMaterial( fileMaterial.bitmap );
var shaderMaterial:ShadedMaterial = new ShadedMaterial(bitmapMaterial, shader);
var plane:Plane = new Plane(shaderMaterial,500,500);
}
另外要注意,Cube 六面體若是要使用 ShadedMaterial 的話,六面都要 new 個新 shader 給它,否則會有三角形黑色塊產生 = =",很麻煩,而且跑起來非常秏效能。
org.papervision3d.materials.shader 底下還有很多種不同的 shader 可以使用,效果皆不同…
FlatShader
PhongShader
CellShader
EnvMapShader
GouraudShader
…
2009年11月24日 星期二
多圖 BitmapFileMaterial 讀取方式
上次提到了 BitmapFileMaterial load 的時候使用一個 array,利用事件傳遞的方式來檢測什麼時候所有的圖片讀取完畢,好進行下一個有前後相依的步驟。
結果,今天 trace 了一下 BitmapFileMaterial 這個類別,發現原來它早就有把類似的機制作在裡面了,在BitmapFileMaterial.as 的這行…
static public var callback :Function;
於是,要讀取一連串的圖檔就變的更容易了…
public function init():void
{
BitmapFileMaterial.callback = loadComplete;
floorMaterial = new BitmapFileMaterial("assets/grassTexture.jpg");
bodyMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
wheelMaterial = new BitmapFileMaterial("assets/FocusWheel.jpg");
boxMaterial = new BitmapFileMaterial("assets/box.jpg");
}
private function loadComplete():void
{
BitmapFileMaterial.callback = null;
///......
}
雖然如此,但使用上也要特別小心,因為 BitmapFileMaterial.callback 是 public static 的,意即所有其它程序也是有可能在你讀取一堆圖檔的時候,使用同樣的方式設定了 callback 的函式,那就會出錯嘍(潛藏的BUG)。
結果,今天 trace 了一下 BitmapFileMaterial 這個類別,發現原來它早就有把類似的機制作在裡面了,在BitmapFileMaterial.as 的這行…
static public var callback :Function;
於是,要讀取一連串的圖檔就變的更容易了…
public function init():void
{
BitmapFileMaterial.callback = loadComplete;
floorMaterial = new BitmapFileMaterial("assets/grassTexture.jpg");
bodyMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
wheelMaterial = new BitmapFileMaterial("assets/FocusWheel.jpg");
boxMaterial = new BitmapFileMaterial("assets/box.jpg");
}
private function loadComplete():void
{
BitmapFileMaterial.callback = null;
///......
}
雖然如此,但使用上也要特別小心,因為 BitmapFileMaterial.callback 是 public static 的,意即所有其它程序也是有可能在你讀取一堆圖檔的時候,使用同樣的方式設定了 callback 的函式,那就會出錯嘍(潛藏的BUG)。
2009年11月23日 星期一
PV3D 防止破圖的幾種方法
一、使用 QuadrantRenderEngine…
新版的 PV3D 可以使用 QuadrantRenderEngine 代替原來的 BasicRenderEngine
renderer = new QuadrantRenderEngine(QuadrantRenderEngine.ALL_FILTERS);
但是效能很差,可能還需要細部的參數設定。
二、自己手動作 ViewportLayer…
viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;
objViewportLayer = new ViewportLayer(viewport, null);
objViewportLayer.layerIndex = 1;
viewport.containerSprite.addLayer(objViewportLayer);
objViewportLayer.addDisplayObject3D(YOUR_OBJECT, true);
同一層的物件依然存在破圖的問題,並且,上層物件絕對會遮蓋住下層物件,所以在分配上要自己作好控制,效能很好。
三、在近距離的情況下,多邊形會被省略不畫而導致的缺面…
renderer.clipping = new FrustumClipping(FrustumClipping.BOTTOM);
新版的 PV3D 可以使用 QuadrantRenderEngine 代替原來的 BasicRenderEngine
renderer = new QuadrantRenderEngine(QuadrantRenderEngine.ALL_FILTERS);
但是效能很差,可能還需要細部的參數設定。
二、自己手動作 ViewportLayer…
viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;
objViewportLayer = new ViewportLayer(viewport, null);
objViewportLayer.layerIndex = 1;
viewport.containerSprite.addLayer(objViewportLayer);
objViewportLayer.addDisplayObject3D(YOUR_OBJECT, true);
同一層的物件依然存在破圖的問題,並且,上層物件絕對會遮蓋住下層物件,所以在分配上要自己作好控制,效能很好。
三、在近距離的情況下,多邊形會被省略不畫而導致的缺面…
renderer.clipping = new FrustumClipping(FrustumClipping.BOTTOM);
2009年11月21日 星期六
PV3D 練習 - 開車
開車兜兜風…
http://www.asn.com.tw/flex/cardrive/cardrive.html
http://www.asn.com.tw/flex/cardrive/cardrive2.html with BOX2D
程式參考…
http://pv3d.org/2009/01/23/springcamera3d-and-driving-a-car/
重點在 driveCar() 及 updateCar() 兩個函式。
汽車控制幾乎都使用原作的,看別人的程式可以學到很多,沒想到原來不難,缺的大概就是經驗跟創意。
另一個重點是汽車的模型,在建模的時候就要先規畫好,要能配合程式運作,包括物件軸心、面向、四個輪子的軸心跟方向、子物件的名稱…。
圖檔及資源的讀取部份改寫如下…
使用一個陣列 push 所有需要讀取資源的 loader,並加入事件監聽,在收到完成的事件後再移出陣例,最後判斷是否己全數讀取完成,再進行其它的初始化工作。
private var loadAssets:Array = new Array();
private function initAssets():void
{
removeEventListener(Event.ADDED_TO_STAGE, initAssets);
floorMaterial = new BitmapFileMaterial("assets/grassTexture.jpg");
floorMaterial.addEventListener(FileLoadEvent.LOAD_COMPLETE,onLoadAssets);
loadAssets.push(floorMaterial);
bodyMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
bodyMaterial.addEventListener(FileLoadEvent.LOAD_COMPLETE,onLoadAssets);
loadAssets.push(bodyMaterial);
wheelMaterial = new BitmapFileMaterial("assets/FocusWheel.jpg");
wheelMaterial.addEventListener(FileLoadEvent.LOAD_COMPLETE,onLoadAssets);
loadAssets.push(wheelMaterial);
}
private function onLoadAssets(e:FileLoadEvent):void
{
var idx:Number = loadAssets.indexOf(e.target);
if( idx != -1 )
{
if( e.target is BitmapFileMaterial )
(e.target as BitmapFileMaterial).removeEventListener(FileLoadEvent.LOAD_COMPLETE,onLoadAssets);
loadAssets.splice( idx, 1 );
if( loadAssets.length == 0 )
initOther();
}
}
http://www.asn.com.tw/flex/cardrive/cardrive.html
http://www.asn.com.tw/flex/cardrive/cardrive2.html with BOX2D
程式參考…
http://pv3d.org/2009/01/23/springcamera3d-and-driving-a-car/
重點在 driveCar() 及 updateCar() 兩個函式。
汽車控制幾乎都使用原作的,看別人的程式可以學到很多,沒想到原來不難,缺的大概就是經驗跟創意。
另一個重點是汽車的模型,在建模的時候就要先規畫好,要能配合程式運作,包括物件軸心、面向、四個輪子的軸心跟方向、子物件的名稱…。
圖檔及資源的讀取部份改寫如下…
使用一個陣列 push 所有需要讀取資源的 loader,並加入事件監聽,在收到完成的事件後再移出陣例,最後判斷是否己全數讀取完成,再進行其它的初始化工作。
private var loadAssets:Array = new Array();
private function initAssets():void
{
removeEventListener(Event.ADDED_TO_STAGE, initAssets);
floorMaterial = new BitmapFileMaterial("assets/grassTexture.jpg");
floorMaterial.addEventListener(FileLoadEvent.LOAD_COMPLETE,onLoadAssets);
loadAssets.push(floorMaterial);
bodyMaterial = new BitmapFileMaterial("assets/FocusBody.jpg");
bodyMaterial.addEventListener(FileLoadEvent.LOAD_COMPLETE,onLoadAssets);
loadAssets.push(bodyMaterial);
wheelMaterial = new BitmapFileMaterial("assets/FocusWheel.jpg");
wheelMaterial.addEventListener(FileLoadEvent.LOAD_COMPLETE,onLoadAssets);
loadAssets.push(wheelMaterial);
}
private function onLoadAssets(e:FileLoadEvent):void
{
var idx:Number = loadAssets.indexOf(e.target);
if( idx != -1 )
{
if( e.target is BitmapFileMaterial )
(e.target as BitmapFileMaterial).removeEventListener(FileLoadEvent.LOAD_COMPLETE,onLoadAssets);
loadAssets.splice( idx, 1 );
if( loadAssets.length == 0 )
initOther();
}
}
2009年11月20日 星期五
PV3D DAEMC2 練習
2009年11月11日 星期三
Paper Vision 3D 正確 destory 物件的方法
由於 AS3 有 garbage collection 的機制,這樣的機制有好有壞,但千萬別以為有 garbage collection 就不用去在意 memory 的議題,因為不管 garbage collection 運作的原理是什麼,它總還是有一套運作的規則,不去依循這個規則的話,仍然會造成 memory leaks。
garbage collection 主要的扮演角色的是在程式背後的「管理程式」,記錄、管理使用者(這裡指程式設計師) 記憶體的使用狀況,它底層的意義就是在記錄某段記憶體是不是有物件(指標、參考…)指向它,若沒的話,便能進行釋放。
可以想像的到,一個環狀的參考一定會造成 garbage collection 的困擾,因此,在具備 garbage collection 的系統下寫程式,有些地方便要特別注意,才不會造成問題。
以前在 C++,常常會使用指標將自己 allocate 到的 memory 記錄下來,以便在物件 destroy 時一併釋放,但在 garbage collection 系統,這樣的習慣卻會造成「過多的」或「意外的」參考到了沒用到的記憶體,反而造成 garbage collection 無法正確運作。
因此在寫 AS3 時,儘量在要用到時才去 new 一個物件,而不需要在初始化時就把一切 new 出來放在私有變數裡去作準備,當然,這也不是通則,期待更好的 garbage collection 系統出現。
回歸正題,Paper Vision 3D 物件的創建跟刪除便出現了類似上述的問題,當你用「動態」的產生物件 (譬如 sphere 或 cube) 時,由於物件需要參考到 Material 材質,而材質又會記錄著使用這個 Material 的物件 list,於是當你刪除物件( 從 scene 移除並設為 null ) 卻發現 garbage collection 起不了作用,memory 依然被佔用住,這樣的 memory leaks 造成的後果會非常嚴重,memory 用量會不斷攀升,最後效能直線下降。
在 Paper Vision 3D 團隊還沒修正這段(bug?)或 改用更好的作法之前…
解決方法:
private function destory3DObject():void
{
var objArray:Array = new Array();
var obj:DisplayObject3D;
for each ( obj in this.scene.objects )
objArray.push(obj);
for ( obj=objArray.pop(); obj; obj=objArray.pop() )
{
var mmArray:Array = new Array();
var mm:MaterialObject3D;
for each ( mm in obj.materials )
mmArray.push(mm);
for ( mm=mmArray.pop(); mm; mm=mmArray.pop() )
{
mm.interactive = false;
mm.unregisterObject(obj);
obj.materials.removeMaterial(mm);
mm.destroy();
}
obj.materials = null;
//obj.material.animated = false;
obj.material.interactive = false;
obj.material.unregisterObject(obj);
this.scene.removeChild( obj );
obj.material.destroy()
obj.material = null;
}
}
每個步驟的先後順序很重要,次序相反有可能還是沒清楚跟 garbage collection 系統交待好你不要這段 memory 了,你會發現,最後參考到這段 memory 的會是區域變數 var obj,如此才能保證在離開 scope 後沒有任何參考指標與該物件有關聯。
這個函式是一次清除所有的 DisplayObject3D物件,若只想清除物定物件,那可以使用 array 來裝你的 DisplayObject3D 物件即可,程式雷同。
所以其實 garbage collection 好壞見仁見智吧,好像只不過換了方式去管理你創出來的物件/記憶體罷了,恐怕還是需要瞭解黑箱下的作業方式,才能真正去掌握你所有的資源。
garbage collection 主要的扮演角色的是在程式背後的「管理程式」,記錄、管理使用者(這裡指程式設計師) 記憶體的使用狀況,它底層的意義就是在記錄某段記憶體是不是有物件(指標、參考…)指向它,若沒的話,便能進行釋放。
可以想像的到,一個環狀的參考一定會造成 garbage collection 的困擾,因此,在具備 garbage collection 的系統下寫程式,有些地方便要特別注意,才不會造成問題。
以前在 C++,常常會使用指標將自己 allocate 到的 memory 記錄下來,以便在物件 destroy 時一併釋放,但在 garbage collection 系統,這樣的習慣卻會造成「過多的」或「意外的」參考到了沒用到的記憶體,反而造成 garbage collection 無法正確運作。
因此在寫 AS3 時,儘量在要用到時才去 new 一個物件,而不需要在初始化時就把一切 new 出來放在私有變數裡去作準備,當然,這也不是通則,期待更好的 garbage collection 系統出現。
回歸正題,Paper Vision 3D 物件的創建跟刪除便出現了類似上述的問題,當你用「動態」的產生物件 (譬如 sphere 或 cube) 時,由於物件需要參考到 Material 材質,而材質又會記錄著使用這個 Material 的物件 list,於是當你刪除物件( 從 scene 移除並設為 null ) 卻發現 garbage collection 起不了作用,memory 依然被佔用住,這樣的 memory leaks 造成的後果會非常嚴重,memory 用量會不斷攀升,最後效能直線下降。
在 Paper Vision 3D 團隊還沒修正這段(bug?)或 改用更好的作法之前…
解決方法:
private function destory3DObject():void
{
var objArray:Array = new Array();
var obj:DisplayObject3D;
for each ( obj in this.scene.objects )
objArray.push(obj);
for ( obj=objArray.pop(); obj; obj=objArray.pop() )
{
var mmArray:Array = new Array();
var mm:MaterialObject3D;
for each ( mm in obj.materials )
mmArray.push(mm);
for ( mm=mmArray.pop(); mm; mm=mmArray.pop() )
{
mm.interactive = false;
mm.unregisterObject(obj);
obj.materials.removeMaterial(mm);
mm.destroy();
}
obj.materials = null;
//obj.material.animated = false;
obj.material.interactive = false;
obj.material.unregisterObject(obj);
this.scene.removeChild( obj );
obj.material.destroy()
obj.material = null;
}
}
每個步驟的先後順序很重要,次序相反有可能還是沒清楚跟 garbage collection 系統交待好你不要這段 memory 了,你會發現,最後參考到這段 memory 的會是區域變數 var obj,如此才能保證在離開 scope 後沒有任何參考指標與該物件有關聯。
這個函式是一次清除所有的 DisplayObject3D物件,若只想清除物定物件,那可以使用 array 來裝你的 DisplayObject3D 物件即可,程式雷同。
所以其實 garbage collection 好壞見仁見智吧,好像只不過換了方式去管理你創出來的物件/記憶體罷了,恐怕還是需要瞭解黑箱下的作業方式,才能真正去掌握你所有的資源。
2009年11月10日 星期二
BOX2D + PV3D 物理運動模擬-線上測試盒
網址 :http://www.asn.com.tw/flex/box2dpv3d_world.htm
使用方法,在 creat 頁,填上整個 world 的 XML 描述檔,再按 creat 即可建立一個新的物理模擬世界,按 sample world 有範例可以參考。
說明:
這個程式是依據 boristhebrave Box2DWith 的 Box2D XML loader
線上建立 Box2D 物件,同時轉換成 PV3D 物件對應( 目前支援 CUBE、SPHERE )
支援 TAG 如下…(細節請參考 boristhebrave 的 b2XML.as 文件說明)
world
body
circle
box
distance
prismatic
revolute
gear
<body userData="PV3D" position="200 100" id="head">
<circle radius="15" density="1" friction="0.4" restitution="0.3">
</body>
即是在XY座標(200,100)的位置建立一個半徑15的圓,其密度=1,摩擦力=0.4,反彈=0.3
其中 userData="PV3D" 代表要同時建立一個 PV3D 的對應3D物件-球。
更新…
2009/11/13-PV3D物件增加z軸初始及物件厚度的解析。(BOX適用)
語法:userData="PV3D,Z,DEPTH"
範例:userData="PV3D,50,20" - 在z軸50的位置上建立厚度20的PV3D物件(CUBE)
*實際碰撞處理仍為BOX2D引擎。
使用方法,在 creat 頁,填上整個 world 的 XML 描述檔,再按 creat 即可建立一個新的物理模擬世界,按 sample world 有範例可以參考。
說明:
這個程式是依據 boristhebrave Box2DWith 的 Box2D XML loader
線上建立 Box2D 物件,同時轉換成 PV3D 物件對應( 目前支援 CUBE、SPHERE )
支援 TAG 如下…(細節請參考 boristhebrave 的 b2XML.as 文件說明)
world
body
circle
box
distance
prismatic
revolute
gear
<body userData="PV3D" position="200 100" id="head">
<circle radius="15" density="1" friction="0.4" restitution="0.3">
</body>
即是在XY座標(200,100)的位置建立一個半徑15的圓,其密度=1,摩擦力=0.4,反彈=0.3
其中 userData="PV3D" 代表要同時建立一個 PV3D 的對應3D物件-球。
更新…
2009/11/13-PV3D物件增加z軸初始及物件厚度的解析。(BOX適用)
語法:userData="PV3D,Z,DEPTH"
範例:userData="PV3D,50,20" - 在z軸50的位置上建立厚度20的PV3D物件(CUBE)
*實際碰撞處理仍為BOX2D引擎。
訂閱:
文章 (Atom)
VirtualBox 空間減肥
sdelete64 -z c: VBoxManage modifymedium disk "/Users/fellow/VirtualBox VMs/Win10/Win10.vdi" --compact *.vdi 路徑可以在 VirtualBox 儲...
-
https://github.com/ljean/modbus-tk/ install pip… sudo apt-get install python-pip install... download modbus_tk-x.x.x.tar.gz tar zxvf...
-
set0 bit 位元設0 set1 bit 位元設1 tog bit 位元0/1切換 swapc bit 位元與c切換 =================== call addr 呼叫副程式 goto addr 跳躍到標籤 icall [index] 呼叫指標指到的副程式 ig...
-
rails blog -d mysql 建立一個名為 blog 的網站app,使用 mysql cd blog 進去 gen 好的網站 config/database.yml 編輯資料庫設定 rake db:create 自動建立資料庫 ruby script/generate ...