Senin, Februari 07, 2011

FLARManager v1.1 (FLARToolkit + Away3D) + FlashDevelop = Multi Marker & Collada

Setelah menunggu 2 bulan sejak versi terakhirnya FLARManager v1.0.4 yang masih banyak bug (terutama sangat terasa pada fitur mirrorDisplay yang saat itu hanya mencerminkan video dari kamera saja tanpa mencerminkan objek 3D-nya), akhirnya di bulan Januari yang lalu kembali ada update menjadi FLARManager v.1.1.0. Pada FLARManager v1.1.0 ini ada perbedaan yang sangat mendasar dari versi-versi sebelumnya, yaitu diubahnya sebagian besar contoh kode untuk menampilkan objek 3D yang pada awalnya menggunakan engine Papervision3D menjadi menggunakan engine Away3D.


Berkaitan dengan pekerjaan saya tentang Augmented Reality yang salah satu fiturnya yaitu harus dapat menampilkan objek 3D yang berbeda-beda untuk tiap marker yang berbeda-beda pula, maka saya modifikasi file contoh standar yang awalnya hanya menampilkan satu objek COLLADA pada marker menggunakan FLARManager v1.1, FLARToolkit, dan Away3D (FLARManagerTutorial_Collada_Away3D.as). Metode untuk melakukannya saya adaptasikan dari kode milik lOOney dOOdle pada link ini yang masih menggunakan Papervision3D sebagai Flash 3D engine (dan FLARManager versi sebelumnya), sedemikian sehingga file hasil modifikasinya (MultiMarkerMultiCollada.as) menjadi seperti ini:

package examples {
 import away3d.animators.Animator;
 import away3d.animators.BonesAnimator;
 import away3d.containers.ObjectContainer3D;
 import away3d.containers.Scene3D;
 import away3d.containers.View3D;
 import away3d.core.utils.Cast;
 import away3d.events.Loader3DEvent;
 import away3d.lights.DirectionalLight3D;
 import away3d.loaders.AbstractParser;
 import away3d.loaders.Collada;
 import away3d.loaders.Loader3D;
 import away3d.loaders.utils.AnimationLibrary;
 import away3d.materials.BitmapMaterial;
 
 import com.transmote.flar.FLARManager;
 import com.transmote.flar.camera.FLARCamera_Away3D;
 import com.transmote.flar.camera.FLARCamera_PV3D;
 import com.transmote.flar.marker.FLARMarker;
 import com.transmote.flar.marker.FLARMarkerEvent;
 import com.transmote.flar.tracker.FLARToolkitManager;
 import com.transmote.flar.utils.geom.AwayGeomUtils;
 
 import flash.display.Sprite;
 import flash.events.Event;
 import flash.geom.Rectangle;
 import flash.geom.Vector3D;
 import flash.utils.getTimer;
 
 
 /**
  * This file (MultiMarkerMultiCollada.as) is modification of the standard
  * example file to display collada-formatted model using FLARManager v1.1,
  * FLARToolkit, and Away3D (FLARManagerTutorial_Collada_Away3D.as) authored 
  * by Eric Socolofsky (http://transmote.com/flar). The collada model used 
  * for this example (mario_testrun.dae) comes from Away3D's examples.
  * 
  * The method to display multiple colladas on multiple markers is derived
  * from a code to display multiple colladas on multiple markers using 
  * previous version of FLARManager, FLARToolkit, and Papervision3D
  * (http://www.looneydoodle.com/MultiMarkerMultiCollada.zip) authored by
  * Arunram Kalaiselvan aka lOOney dOOdle (http://www.looneydoodle.com/).
  * 
  * @author Fathah Noor Prawita
  * @url  http://blog.fathah.net
  */
 
 public class MultiMarkerMultiCollada extends Sprite {
  private var flarManager:FLARManager;
  
  private var view:View3D;
  private var camera3D:FLARCamera_Away3D;
  private var scene3D:Scene3D;
  private var light:DirectionalLight3D;
  
  private var activeMarker:FLARMarker;
  private var activeMarker1:FLARMarker;
  private var activeMarker2:FLARMarker;
  
  private var modelLoader:Loader3D;
  
  private var modelContainer:ObjectContainer3D;
  private var modelContainer1:ObjectContainer3D;
  private var modelContainer2:ObjectContainer3D;
  
  private var modelAnimator:BonesAnimator;
  private var modelAnimator1:BonesAnimator;
  private var modelAnimator2:BonesAnimator;
  
  // texture file for mario
  [Embed(source="../../resources/assets/mario_tex_red-blue.jpg")]
  private var MarioTextureRedBlue:Class;
  
  [Embed(source="../../resources/assets/mario_tex_green-red.jpg")]
  private var MarioTextureGreenRed:Class;
  
  [Embed(source="../../resources/assets/mario_tex_blue-green.jpg")]
  private var MarioTextureBlueGreen:Class;
  
  // collada file for mario
  [Embed(source="../../resources/assets/mario_testrun.dae",mimeType="application/octet-stream")]
  private var MarioDae:Class;
  
    
  public function MultiMarkerMultiCollada () {
   this.addEventListener(Event.ADDED_TO_STAGE, this.onAdded);
  }
  
  private function onAdded (evt:Event) :void {
   this.removeEventListener(Event.ADDED_TO_STAGE, this.onAdded);
   
   // pass the path to the FLARManager xml config file into the FLARManager constructor.
   // FLARManager creates and uses a FLARCameraSource by default.
   // the image from the first detected camera will be used for marker detection.
   // also pass an IFLARTrackerManager instance to communicate with a tracking library,
   // and a reference to the Stage (required by some trackers).
   this.flarManager = new FLARManager("../resources/flar/flarConfig.xml", new FLARToolkitManager(), this.stage);
   
   // to switch tracking engines, pass a different IFLARTrackerManager into FLARManager.
   // refer to this page for information on using different tracking engines:
   // http://words.transmote.com/wp/inside-flarmanager-tracking-engines/
   //   this.flarManager = new FLARManager("../resources/flar/flarConfig.xml", new FlareManager(), this.stage);
   //   this.flarManager = new FLARManager("../resources/flar/flarConfig.xml", new FlareNFTManager(), this.stage);
   
   // add FLARManager.flarSource to the display list to display the video capture.
   this.addChild(Sprite(this.flarManager.flarSource));
   
   // begin listening for FLARMarkerEvents.
   this.flarManager.addEventListener(FLARMarkerEvent.MARKER_ADDED, this.onMarkerAdded);
   this.flarManager.addEventListener(FLARMarkerEvent.MARKER_UPDATED, this.onMarkerUpdated);
   this.flarManager.addEventListener(FLARMarkerEvent.MARKER_REMOVED, this.onMarkerRemoved);
   
   // wait for FLARManager to initialize before setting up Away3D environment.
   this.flarManager.addEventListener(Event.INIT, this.onFlarManagerInited);
  }
  
  private function onFlarManagerInited (evt:Event) :void {
   this.flarManager.removeEventListener(Event.INIT, this.onFlarManagerInited);
   
   this.scene3D = new Scene3D();
   this.camera3D = new FLARCamera_Away3D(this.flarManager, new Rectangle(0, 0, this.stage.stageWidth, this.stage.stageHeight));
   this.view = new View3D({x:0.5*this.stage.stageWidth, y:0.5*this.stage.stageHeight, scene:this.scene3D, camera:this.camera3D});
   this.addChild(this.view);
   
   this.light = new DirectionalLight3D();
   this.light.direction = new Vector3D(500, -300, 200);
   this.scene3D.addLight(light);
   
   
   //--------------------------------------3D-Model----
   var collada:Collada = new Collada();
   collada.scaling = 10;
   var model:ObjectContainer3D = collada.parseGeometry(MarioDae) as ObjectContainer3D;
   model.materialLibrary.getMaterial("FF_FF_FF_mario1").material = new BitmapMaterial(Cast.bitmap(MarioTextureRedBlue));
   model.mouseEnabled = false;
   model.rotationX = 90;
   this.modelAnimator = model.animationLibrary.getAnimation("default").animator as BonesAnimator;
   
   // create a container for the model, that will accept matrix transformations.
   this.modelContainer = new ObjectContainer3D();
   this.modelContainer.addChild(model);
   this.modelContainer.visible = false;
   this.scene3D.addChild(this.modelContainer);
   
   
   //--------------------------------------3D-Model----
   var collada1:Collada = new Collada();
   collada1.scaling = 10;
   var model1:ObjectContainer3D = collada1.parseGeometry(MarioDae) as ObjectContainer3D;
   model1.materialLibrary.getMaterial("FF_FF_FF_mario1").material = new BitmapMaterial(Cast.bitmap(MarioTextureGreenRed));
   model1.mouseEnabled = false;
   model1.rotationX = 90;
   this.modelAnimator1 = model1.animationLibrary.getAnimation("default").animator as BonesAnimator;
   
   // create a container for the model, that will accept matrix transformations.
   this.modelContainer1 = new ObjectContainer3D();
   this.modelContainer1.addChild(model1);
   this.modelContainer1.visible = false;
   this.scene3D.addChild(this.modelContainer1);
   
   
   //--------------------------------------3D-Model----
   var collada2:Collada = new Collada();
   collada2.scaling = 10;
   var model2:ObjectContainer3D = collada2.parseGeometry(MarioDae) as ObjectContainer3D;
   model2.materialLibrary.getMaterial("FF_FF_FF_mario1").material = new BitmapMaterial(Cast.bitmap(MarioTextureBlueGreen));
   model2.mouseEnabled = false;
   model2.rotationX = 90;
   this.modelAnimator2 = model2.animationLibrary.getAnimation("default").animator as BonesAnimator;
   
   // create a container for the model, that will accept matrix transformations.
   this.modelContainer2 = new ObjectContainer3D();
   this.modelContainer2.addChild(model2);
   this.modelContainer2.visible = false;
   this.scene3D.addChild(this.modelContainer2);
   
   
   
   this.addEventListener(Event.ENTER_FRAME, this.onEnterFrame);
  }
  
  private function onMarkerAdded (evt:FLARMarkerEvent) :void {
   trace("[" + evt.marker.patternId + "] added");
   
   if (evt.marker.patternId == 0) {
    markerAdded(0);
    this.activeMarker = evt.marker;
   }
   
   if (evt.marker.patternId == 1) {
    markerAdded(1);
    this.activeMarker1 = evt.marker;
   }
   
   if (evt.marker.patternId == 2) {
    markerAdded(2);
    this.activeMarker2 = evt.marker;
   }
  }
  
  private function onMarkerUpdated (evt:FLARMarkerEvent) :void {
   trace("[" + evt.marker.patternId + "] updated");
   
   if (evt.marker.patternId == 0) {
    markerAdded(0);
    this.activeMarker = evt.marker;
   }
   
   if (evt.marker.patternId == 1) {
    markerAdded(1);
    this.activeMarker1 = evt.marker;
   }
   
   if (evt.marker.patternId == 2) {
    markerAdded(2);
    this.activeMarker2 = evt.marker;
   }
  }
  
  private function onMarkerRemoved (evt:FLARMarkerEvent) :void {
   trace("[" + evt.marker.patternId + "] removed");
   
   if (evt.marker.patternId == 0) {
    markerRemoved(0);
   }
   
   if (evt.marker.patternId == 1) {
    markerRemoved(1);
   }
   
   if (evt.marker.patternId == 2) {
    markerRemoved(2);
   }
   
   this.activeMarker = null;
   this.activeMarker1 = null;
   this.activeMarker2 = null;
  }
  
  private function onEnterFrame (evt:Event) :void {
   // apply the FLARToolkit transformation matrix to the Cube.
   if (this.activeMarker) {
    this.modelContainer.transform = AwayGeomUtils.convertMatrixToAwayMatrix(this.activeMarker.transformMatrix);
   }
   
   if (this.activeMarker1) {
    this.modelContainer1.transform = AwayGeomUtils.convertMatrixToAwayMatrix(this.activeMarker1.transformMatrix);
   }
   
   if (this.activeMarker2) {
    this.modelContainer2.transform = AwayGeomUtils.convertMatrixToAwayMatrix(this.activeMarker2.transformMatrix);
   }
   
   // update the animation and Away3D view.
   if (this.modelAnimator) {
    this.modelAnimator.update(getTimer() * .005);
   }
   
   if (this.modelAnimator1) {
    this.modelAnimator1.update(getTimer() * .005);
   }
   
   if (this.modelAnimator2) {
    this.modelAnimator2.update(getTimer() * .005);
   }
   this.view.render();
  }
  
  private function markerAdded(markerId:int):void {
   switch(markerId) {
    case 0: {
     if (modelContainer.visible == false) {
      modelContainer.visible = true;
      break;
     } else {
      break;
     }
    }
    case 1: {
     if (modelContainer1.visible == false) {
      modelContainer1.visible = true;
      break;
     } else {
      break;
     }
    }
    case 2: {
     if (modelContainer2.visible == false) {
      modelContainer2.visible = true;
      break;
     } else {
      break;
     }
    }
   }
  }
  
  private function markerRemoved(markerId:int):void {
   switch(markerId) {
    case 0: {
     if (modelContainer.visible == true) {
      modelContainer.visible = false;
      break;
     } else {
      break;
     }
    }
    case 1: {
     if (modelContainer1.visible == true) {
      modelContainer1.visible = false;
      break;
     } else {
      break;
     }
    }
    case 2: {
     if (modelContainer2.visible == true) {
      modelContainer2.visible = false;
      break;
     } else {
      break;
     }
    }
   }
  }
 }
}

Untuk langsung mencobanya, silakan print marker-1, marker-2, dan marker3, kemudian buka link ini. Jika Flash meminta izin untuk mengakses webcam, tekan "Allow" saja. Arahkan marker yang tadi telah diprint ke depan webcam.

Bagi yang biasa menggunakan FlashDevelop, file proyeknya dapat dapat didownload di link ini. Semoga bermanfaat.

[UPDATE 2013-04-24] Karena ternyata banyak yang menanyakan ke saya via YM dan Facebook tentang bagaimana mengubah (misalnya) skala dari si model 3D jika kita menekan suatu tombol pada keyboard, maka saya update sedikit file proyeknya untuk menambahkan fungsi tersebut. Silakan download di link ini. Cara menggunakan contoh ini yaitu dengan mengarahkan marker pertama pada webcam, sehingga akan memunculkan model 3D berupa Mario berbaju merah. Kemudian tekan tombol panah kanan/kiri pada keyboard untuk memperbesar/memperkecil ukurannya.

220 komentar:

«Terlama   ‹Lebih tua   201 – 220 dari 220
Fathah Noor mengatakan...

@Fivtatianti Hendajani: pertanyaannya agak kurang jelas, mungkin bisa disertai link ke video contohnya.

ardi yulianto rakasiwi mengatakan...

mas cara buat tambahin audio di project ini gimana ya?

Fathah Noor mengatakan...

1. di Flash CS Pro import audio yang mau digunakan, biasanya format yang didukung adalah MP3 atau WAV.

2. beri linkage name dari tiap audio tersebut. nantinya, audio yang diekspor akan bertipe Sound.

3. publish SWC.

4. di FlashDevelop, klik kanan pada SWC hasil eksport tadi dan pilih "add to library".

5. pelajari cara menggunakan Sound dan SoundChannel.
misal audioSound adalah nama variable dari instance Sound(), dan audioChannel adalah nama variable dari instance SoundChannel().

6. nantinya tiap kali suatu marker terdeteksi (sebanyak beberapa frame berurutan), jalankan audio dengan cara audioChannel = audioSound.play();

7. dan tiap kali marker tersebut tidak terdeteksi lagi (sebanyak beberapa frame berurutan), stop audio dengan cara audioChannel.stop();

ardi yulianto rakasiwi mengatakan...

ok mas saya coba
thank you

Fiqih Firdaus mengatakan...

Maaf nih mas ane mau tanya
1. ane pak flash develop tapi begitu ane kasih model yang ukuran besar sekitar 5 Mb dia g mau di test project keluarnya beginian :
"[Fault] exception, information=Error: Error #1502: A script has executed for longer than the default timeout period of 15 seconds."


2.File Collada Ane Material ID nya banyak bgt..???apa harus di masukkan semua ?

Terima Kasih sebelumnya

Fiqih Firdaus mengatakan...

oh ya ada 1 lagi yang mau ane tanyain mas

cara membuat texture itu gimana gan?

Fathah Noor mengatakan...

@Fiqih Firdaus: pertanyaan 1 dan 2 bisa dijawab sekaligus, kemungkinan karena file Colladanya diembed. Coba diubah scriptnya sehingga file Collada diload ketika aplikasi sedang jalan (bukan diembed di awal). Collada yang saya gunakan di proyek ini rata-rata berukuran 5 s/d belasan MB lancar-lancar saja :)

detil cara membuat tekstur saya kurang tau karena biasanya teman saya (3D modeller) yang bikin ;)

adit samudra mengatakan...

mas fahtah, saya mau tanya

AR yang dibuat dengan flashbuilder, yang jalan di .air apakah bisa dieksport ke dalam project flash yang berbasis .swf?

kalo bisa gimana caranya ya mas.:)

Fathah Noor mengatakan...

@adit samudra: pada dasarnya AIR project itu adalah file SWF yang di-repackage menjadi AIR agar dapat menjalankan fungsi-fungsi khusus tertentu. Coba saja cek di folder bin (atau sejenisnya) pasti ada file SWF dan tetap dapat dieksekusi seperti biasa, asalkan tidak ada fungsi-fungsi khusus yang dia butuhkan ketika dijalankan sebagai aplikasi AIR.

Beti Yunita mengatakan...

selamat malam maz fathah.
saya mau tanya maz.
saya ada projek,pake flash.ukuran file dae'nya 3 Mb,tp dy ga mau jalan.
output'nya spti ini:
"Error: Error #1502: A script has executed for longer than the default timeout period of 15 seconds.
at org.libspark.flartoolkit.core::FLARCode/loadARPatt()
at ARAppBase/::_onLoadCode()
at flash.events::EventDispatcher/flash.events:EventDispatcher::dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.net::URLLoader/flash.net:URLLoader::onComplete()"


coding action scriptnya spti ini:
package {
import flash.events.Event;
import org.papervision3d.objects.parsers.DAE;
[SWF(width=640, height=480, backgroundColor=0x808080, frameRate=30)];


public class amikom extends PV3DARApp {
private var _bisa;DAE;
public function amikom() {
addEventListener(Event.INIT, _onInit);
init('Data/camera_para.dat','Data/bisa.pat');
}
private function _onInit(e:Event):void {
_bisa = new DAE();
_bisa.load('model/bisa.dae');//untuk membaca file pd folder model
_bisa.scale = 1;//Skala 3D-nya
_bisa.rotationX = 90;//Rotasinya
_markerNode.addChild(_bisa);
}
}
}


mohon pencerahannya maz :)
saya msh newbie dg AR.

Fathah Noor mengatakan...

@Beti Yunita: Wah infonya agak kurang komplit yha, tapi kalo saya coba tebak mungkin detil errornya seperti di link ini. Troubleshootingnya, coba buka file DAE di text editor, dan pastikan path ke teskturnya sudah benar (cek juga file tesktur ada di tempatnya)

sai0506 mengatakan...

selamat malam mas,
mau nanya, apa bisa membuat augmented reality dengan animasi 2D ?

Fathah Noor mengatakan...

@sai0506: bisa, dibuat dalam bentuk video saja, nanti tinggal dipasangkan sebagai tekstur di suatu plane

Global mengatakan...

Maaf mas saya mau tanya, saya kan baru mau belajar....saya pakai flarmanager dan disitu udah ada default kan.....script udah kebaca tuh....waktu saya run udah kebaca kamera nya....tp waktu saya kasi marker....koq ga ada object yang tampil ya....knp ya kira2......

Fathah Noor mengatakan...

Global: pake marker yang mana? biasanya default yang udah nempel ke model 3D itu marker patt001

Global mengatakan...

saya pakai FLARManager_v1_1_0......kan saya udah ikutin step yang dari website :http://belajar-ar.blogspot.com/2012/06/tutorial-augmented-reality-dengan.html
harusnya keluar gambar itu yah....tapi saya ga bisa keluar gambar apa2....kenapa ya....saya bingung mau lanjut belajar tapi ini aja ga keluar2.....

Fathah Noor mengatakan...

Global: wah sori, belum kebayang kenapa bisa gitu. mestinya klo mengikuti step-by-step di sana langsung muncul. tapi bisa coba pake source yang ada di blog saya. cukup simple, install FlashDevelop, download project file di blog ini, buka menggunakan FlashDevelop :)

Syarifah Fauziah mengatakan...

salam mas,,mau tanya kalo seumpama bikin AR semacam fitting room sederhana gitu gimana ya,yg ada virtual buttonnya kalo pake flash develop apa bisa?
makasih sebelumnya...:-)

Fathah Noor mengatakan...
Komentar ini telah dihapus oleh pengarang.
Fathah Noor mengatakan...

@Syarifah Fauziah: Pertama-tama perlu diingat bahwa FlashDevelop adalah IDE (Integrated Development Environment) saja, bukan logic core untuk pengembangan aplikasinya. Mirip dengan Eclipse jika kita membuat aplikasi JAVA.
asal ada SDK yang sesuai, atau script yang dibuat sendiri, ya pasti bisa.



Fitting roomnya sesederhana apa? Coba sertakan contoh YouTube-nya. Soalnya mau lihat apakah ingin dapat mendeteksi bagian-bagian tubuh dan baju virtualnya dapat mengikuti gerakan user, atau user harus membawa marker, atau user tidak membawa apa-apa, dsb.



Nb: mungkin seperti Zugara?

«Terlama ‹Lebih tua   201 – 220 dari 220   Lebih baru› Terbaru»
Google+