[Augmented Reality] Jak stworzyć własną rzeczywistość?
Po dłuższej przerwie, związanej z sesją egzaminacyjną na uczelni, postanowiłem napisać nowy artykuł. Będzie on dotyczył niezwykłej technologii tworzenia własnej rzeczywistości - rozszerzonej rzeczywistości (ang. augmented reality).
Jak zapewne zauważyłeś/aś, w jednym z poprzednich postów zamieściłem filmik mojego autorstwa pokazującego próbkę możliwości tej technologii. Dzisiaj będę chciał przedstawić sposób na to, jak w łatwy i przystępny sposób zrobić taki efekt.
Ważne jest to, aby posiadać kamerę internetową, bo inaczej efekt nie będzie mógł zadziałać.
Muszę dodać, że jeśli znasz się na tworzeniu modeli trójwymiarowych i animacji trójwymiarowych, to będzie można stworzyć zdecydowanie lepsze efekty niż to co zostanie pokazane w tym artykule.
Na początek, muszę powiedzieć kilka słów odnośnie narzędzi jakich będziemy potrzebować. Jako że, efekt rozszerzonej rzeczywistości będę uzyskiwał za pomocą języka ActionScript, to potrzebujemy:
- Programy: darmowy FlashDevelop lub płatny Adobe Flex Builder
- bibliotekę PaperVision3D do generowania obiektów 3D
- bibliotekę FLARTOOLKIT do generowania rozszerzonej rzeczywistości
Muszę dodać, że jeśli studiujesz na jakiejś uczelni, to możesz się postarać o darmową, studencką wersję Adobe Flex Buildera.
Należy pamiętać, aby dołożyć ścieżki do pobranych bibliotek w wybranym przez ciebie programie.
Jeśli będziesz mieć z tym problem, to napisz w komentarzach. Postaram się ci pomóc z tym problemem.
Biblioteka FLARTOOLKIT dostarcza nam kilka gotowych przykładów do wygenerowania. My natomiast będziemy modyfikować przykład o nazwie "Multiple SimpleCube", aby osiągnąć nasz efekt dwóch kostek o różnym wyglądzie i zachowaniu.
Na początek otwieramy plik o nazwie FLARTK_Example_Multiple_SimpleCube_PV3D.as. W nim musimy znaleźć linijkę z funkcją init. Podmienimy zawartość tej funkcji na następującą:
this.captureWidth = 320; this.captureHeight = 240; this.canvasWidth = 800; this.canvasHeight = 600; this.cameraParamFile = '../resources/Data/camera_para.dat'; this.markerPatternList = new Vector.<flarcode>(); this.markerPatternFileList = new Vector.<string>(); //tutaj definiujemy wzorce markerów, na bazie których będą się wyświetlały efekty this.markerPatternFileList.push('../resources/Data/1.pat', '../resources/Data/2.pat', '../resources/Data/3.pat'); this.codeWidthList = new Vector.<number>(); this.codeWidthList.push( 80, 80); this.paramLoad(); for (var i:int=0; i<markerpatternfilelist .length; i++) { } |
Następnym krokiem będzie modyfikacja funkcji createObject:
var wmat:WireframeMaterial = new WireframeMaterial(_lightColor, 1, 2); var _plane:Plane = new Plane(wmat, 80, 80); // 80mm x 80mm _plane.rotationX = 0; var light:PointLight3D = new PointLight3D(); light.x = 0; light.y = 1000; light.z = -1000; _container = new DisplayObject3D(); _container.addChild(_plane); //tutaj definiujemy materiały z których będzie się składać kostka //pierwsza kostka będzie miała na sobie obrazki jpg if (_num == 1) { var front :BitmapFileMaterial = new BitmapFileMaterial("../bin/loga/legia.jpg"); var back :BitmapFileMaterial = new BitmapFileMaterial("../bin/loga/korona.jpg"); var left :BitmapFileMaterial = new BitmapFileMaterial("../bin/loga/wisla.jpg"); var right :BitmapFileMaterial = new BitmapFileMaterial("../bin/loga/ruch.jpg"); var top :BitmapFileMaterial = new BitmapFileMaterial("../bin/loga/jaga.jpg"); var bottom :BitmapFileMaterial = new BitmapFileMaterial("../bin/loga/lech.jpg"); var materialsList:MaterialsList = new MaterialsList(); materialsList.addMaterial(front, "front"); materialsList.addMaterial(right, "right"); materialsList.addMaterial(back, "back"); materialsList.addMaterial(left, "left"); materialsList.addMaterial(bottom, "bottom"); materialsList.addMaterial(top, "top"); //tutaj definiujemy nową kostkę i listę materiałów oraz zachowanie kostki _cube0 = new Cube(materialsList, 80, 80, 80, 9, 9, 9); _cube0.y = 0; _cube0.x = 0; _cube0.z = 40; _cube0.roll( -90); _container.addChild(_cube0); } //kostka numer 2. Będzie się składała z kolorów. Kolory są zapisane w postaci heksadecymalnej (16-stkowej) else if (_num == 2) { var col1:ColorMaterial = new ColorMaterial(0x454545); var col2:ColorMaterial = new ColorMaterial(0xb30000); var col3:ColorMaterial = new ColorMaterial(0x463d21); var col4:ColorMaterial = new ColorMaterial(0xff3de4); var col5:ColorMaterial = new ColorMaterial(0xaa36fd); var col6:ColorMaterial = new ColorMaterial(0x9e9d45); var materialsList2:MaterialsList = new MaterialsList(); materialsList2.addMaterial(col1,"front"); materialsList2.addMaterial(col2,"right"); materialsList2.addMaterial(col3,"back"); materialsList2.addMaterial(col4,"left"); materialsList2.addMaterial(col5,"bottom"); materialsList2.addMaterial(col6,"top"); //budowa drugiej kostki. Cube(lista materiałów, wysokość, szerokość, długość, dokładność, dokładność, dokładność) //dokładność odpowiada za jakość wyświetlanych tekstur _cube = new Cube(materialsList2, 40, 40, 40, 9, 9, 9); _cube.y = 0; _cube.x = 100; _cube.z = 0; _cube.roll( -90); _container.addChild(_cube); } else { return null; } return _container; |
Trzecim krokiem jest zmodyfikowanie funkcji start:
this.markerNodeList[0].addChild(this.createObject(0xFF0000, 0x660000, 1)); this.markerNodeList[1].addChild(this.createObject(0x0000FF, 0x000066, 2)); this.addEventListener(Event.ENTER_FRAME, this.run); |
Czwartą funkcją, którą będziemy modyfikować będzie funkcja run:
this.capture.bitmapData.draw(this.video); var detectedNumber:int = 0; //wykrywanie markerów try { detectedNumber = this.detector.detectMarkerLite(this.raster, this._threshold); } catch (e:Error) {} var i:int=0; for (i = 0; i < this.markerPatternList.length; i++) { this.markerList[i].isPrevDetect = this.markerList[i].isDetect; this.markerList[i].isDetect = false; this.markerList[i].confidence = 0.0; } for (i = 0; i < detectedNumber; i++) { if (this.detector.getConfidence(i) > 0.5) { var detectMarkerID:int = this.detector.getARCodeIndex(i); var congidence:Number = this.detector.getConfidence(i); if (this.markerList[detectMarkerID].confidence < congidence) { this.markerList[detectMarkerID].confidence = congidence; this.detector.getTransformMatrix(i, this.markerList[detectMarkerID].resultMat); this.markerList[detectMarkerID].isDetect = true; } } } for (i = 0; i < this.markerPatternList.length; i++) { var markerData:MarkerData = this.markerList[i]; if (markerData.isDetect && markerData.isPrevDetect) { this.markerNodeList[i].setTransformMatrix(markerData.resultMat); } else if (markerData.isDetect) { this.markerNodeList[i].setTransformMatrix(markerData.resultMat); this.markerNodeList[i].visible = true; } else { this.markerNodeList[i].visible = false; var th:int = this._threshold_detect.analyzeRaster(this.raster); this._threshold = (this._threshold + th) / 2; } } this.renderer.render(); //interakcja z markerami //tutaj jest sprawdzanie czy markery są widzialne i ustawiona jest akcja w zależności od tego czy są 2 markery widzialne czy tylko 1 z nich //dla każdej sytuacji jest inne zachowanie if (this.markerNodeList[0].visible) { _cube0.roll(10); } if (this.markerNodeList[0].visible && this.markerNodeList[1].visible ) { _cube0.yaw(5); var kierunek:Number3D = new Number3D(0, 10, 0); _cube.translate(10, kierunek); } if(this.markerNodeList[1].visible) { _cube.pitch(10); } |
Ostatnią rzeczą jaką będziemy zmieniać w kodzie, to zmiana przykładu który będzie aktualnie wyświetlany.
Tego możemy dokonać w pliku Main.as. Gdzie musimy odkomentować (usuwamy //)
this.addChild(new FLARTK_Example_Multiple_SimpleCube_PV3D()); |
To tyle jeśli chodzi o kod programu. Teraz wystarczy wydrukować markery i uruchomić nasz kod w programie w którym go edytowaliśmy. Akceptujemy uruchomienie kamery internetowej i prezentujemy markery do kamery internetowej. Wtedy powinien się pojawić nasz efekt.
Pliki z tego artykułu są dostępne tutaj: augmented reality demo.