LogoLogo
  • Home
  • Projects
  • About
  • Contact

JiblibFlash + Augmented Reality (Take Three)

Devon O. · May 26, 2009 · Actionscript, Flash · 13 comments
2

Well here’s one more take. Now there’s two levels – you’ll bounce back and forth between them as you get through each maze. I made everything a bit smaller which improves cpu usage and also makes it easier to see. Also (hopefully) fixed it so that it will be viewable on Macs (Don’t know why Apple makes it so difficult to target the default webcam of a Mac, but man, what a pain). Once again, the marker can be found here.

Get Adobe Flash player

I’m still not happy with how the movement is accomplished. It takes a whole lot of mucking around to get a good movement based on the AR transformation system, but it works. Mostly…

While not as clean as I normally like my code, it’s all posted below, if you’d like to try it out.. You’ll have to supply your own materials as well as flartoolkit, papervision3d, and jiglib libraries, but other than that, it’s all there. Enjoy

The two maze levels and their interface:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package  {
    
    import org.papervision3d.materials.utils.MaterialsList;
    
    /**
     * Maze Level Interface
     * @author Devon O Wolfgang
     */
    public interface ILevel {
        function get wallList():MaterialsList;
        function get map():Array;
    }
    
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package  {
    
    import org.papervision3d.materials.BitmapMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
    
    /**
     * First maze level with brick wall
     * @author Devon O Wolfgang
     */
    public class Level1Maze implements ILevel {
        
        [Embed(source = "../assets/wall.jpg")] private static const WallClass:Class;
        
        private var _wallMaterial:BitmapMaterial = new BitmapMaterial(new WallClass().bitmapData);
        
        private var _wallList:MaterialsList;
        
        private var _map:Array = [     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                                    [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                                    [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                                    [1, 1, 1, 1, 1, 0, 0, 0, 0, 1],
                                    [1, 1, 0, 0, 1, 0, 0, 0, 0, 1],
                                    [1, 1, 0, 0, 1, 0, 0, 1, 1, 1],
                                    [1, 1, 0, 0, 1, 0, 0, 1, 1, 1],
                                    [1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
                                    [1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
                                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
                                    ];
        
        public function Level1Maze() {
            buildMaterialList();
        }
        
        private function buildMaterialList():void {
            _wallList = new MaterialsList( { all:_wallMaterial } );
        }
        
        public function get wallList():MaterialsList { return _wallList; }
        
        public function get map():Array { return _map; }
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package  {
    
    import org.papervision3d.materials.BitmapMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
    
    /**
     * Second level maze of hedges
     * @author Devon O Wolfgang
     */
    public class Level2Maze implements ILevel {
        
        [Embed(source = "../assets/hedge.jpg")] private static const WallClass:Class;
        
        private var _wallMaterial:BitmapMaterial = new BitmapMaterial(new WallClass().bitmapData);
        
        private var _wallList:MaterialsList;
        
        private var _map:Array = [     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                                    [1, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                                    [1, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                                    [1, 0, 0, 1, 1, 0, 0, 0, 0, 1],
                                    [1, 0, 0, 1, 1, 0, 0, 0, 0, 1],
                                    [1, 0, 0, 1, 1, 1, 1, 0, 0, 1],
                                    [1, 0, 0, 1, 1, 1, 1, 0, 0, 1],
                                    [1, 0, 0, 0, 0, 0, 1, 0, 0, 1],
                                    [1, 0, 0, 0, 0, 0, 1, 0, 0, 1],
                                    [1, 0, 0, 1, 1, 1, 1, 1, 1, 1]
                                    ];
        
        public function Level2Maze() {
            buildMaterialList();
        }
        
        private function buildMaterialList():void {
            _wallList = new MaterialsList( { all:_wallMaterial } );
        }
        
        public function get wallList():MaterialsList { return _wallList; }
        
        public function get map():Array { return _map; }
    }
}

Not perfectly decoupled, but the FlarObject handles most of the AR stuff, while the MazeScene handles the PV3d and Jiglib stuff.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package  {
    
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.system.Capabilities;
    import flash.utils.ByteArray;
    
    import org.papervision3d.core.render.IRenderEngine;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.view.Viewport3D;
    
    import org.libspark.flartoolkit.core.FLARCode;
    import org.libspark.flartoolkit.core.param.FLARParam;
    import org.libspark.flartoolkit.core.raster.rgb.FLARRgbRaster_BitmapData;
    import org.libspark.flartoolkit.core.transmat.FLARTransMatResult;
    import org.libspark.flartoolkit.detector.FLARSingleMarkerDetector;
    import org.libspark.flartoolkit.pv3d.FLARBaseNode;
    import org.libspark.flartoolkit.pv3d.FLARCamera3D;
    
    /**
     * Manages most FLAR goings on
     * @author Devon O. Wolfgang
     */
    public class FlarObject extends Sprite {
        
        [Embed (source="pat1.pat", mimeType="application/octet-stream")]
        private var Pattern:Class;
        
        [Embed (source="camera_para.dat", mimeType="application/octet-stream")]
        private var Params:Class;
        
        private var _fparams:FLARParam;
        private var _fpattern:FLARCode;
        private var _raster:FLARRgbRaster_BitmapData;
        private var _detector:FLARSingleMarkerDetector;
        private var _transformObject:FLARTransMatResult;
        private var _virtualcam:FLARCamera3D;
        
        private var _vid:Video;
        private var _webcam:Camera;
        private var _bmd:BitmapData;
        
        private var _renderEngine:IRenderEngine;
        private var _scene:Scene3D;
        private var _viewport:Viewport3D;
        private var _flarContainer:FLARBaseNode;
        
        private var _mazescene:MazeScene;
        
        private var _doRender:Boolean = false;
        
        public function FlarObject(videowidth:int = 640, videoheight:int = 480) {
            initFlar();
            initVideo(videowidth, videoheight);
            initBitmap();
            initCamera();
        }
        
        private function initFlar():void {
            _fparams = new FLARParam();
            _fparams.loadARParam(new Params() as ByteArray);
            
            _fpattern = new FLARCode(16, 16);
            _fpattern.loadARPatt(new Pattern());
            
            _transformObject = new FLARTransMatResult();
        }
        
        private function initVideo(vw:int, vh:int):void {
            _vid = new Video(vw, vh);
            
            // find default camera on Mac
            var camIndex:int = 0;
            for ( var i : int = 0 ; i < Camera.names.length ; i++ ) {
                if ( Camera.names[ i ] == "USB Video Class Video" ) {
                    camIndex = i;
                    break;
                }
            }
            _webcam = Camera.getCamera(String(camIndex));
 
            _webcam.setMode(vw, vh, 31);
            _vid.attachCamera(_webcam);
            addChild(_vid);
        }
        
        private function initBitmap():void {
            _bmd = new BitmapData(_vid.width, _vid.height);
            _bmd.draw(_vid);
            _raster = new FLARRgbRaster_BitmapData(_bmd);
            _detector = new FLARSingleMarkerDetector(_fparams, _fpattern, 80);
        }
        
        private function initCamera():void {
            _virtualcam = new FLARCamera3D(_fparams);
        }
        
        private function renderHandler(event:Event):void {
            _bmd.draw(_vid);
            try {
                if (_detector.detectMarkerLite(_raster, 80) && _detector.getConfidence() > .45) {
                    _viewport.visible = true;
                    _detector.getTransformMatrix(_transformObject);
                    _flarContainer.setTransformMatrix(_transformObject);
                    
                    _mazescene.moveBall( _transformObject );
                    
                    _renderEngine.renderScene(_scene, _virtualcam, _viewport);
                    
                } else {
                    _viewport.visible = false;
                }
            } catch (err:Error) {
                // do nothing
            }
        }
        
        public function startRendering():void {
            if (_mazescene != null && !willTrigger(Event.ENTER_FRAME)) {
                _viewport.visible = true;
                addEventListener(Event.ENTER_FRAME, renderHandler);
                _doRender = true;
            } else {
                throw new Error("MazeScene must be set before rendering can begin!");
            }
        }
        
        public function stopRendering():void {
            _viewport.visible = false;
            removeEventListener(Event.ENTER_FRAME, renderHandler);
            _doRender = false;
        }
        
        public function set mazescene(value:MazeScene):void {
            _mazescene = value;
            _renderEngine = _mazescene.engine;
            _scene = _mazescene.scene;
            _viewport = _mazescene.viewport;
            _flarContainer = _mazescene.flarContainer;
            addChild(_viewport);
        }
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package  {
    
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import jiglib.cof.JConfig;
    import jiglib.geometry.JSphere;
    import jiglib.math.JNumber3D;
    import jiglib.physics.PhysicsSystem;
    import jiglib.plugin.papervision3d.Papervision3DPhysics;
    import jiglib.plugin.papervision3d.Pv3dMesh;
    import org.libspark.flartoolkit.core.transmat.FLARTransMatResult;
    import org.papervision3d.core.math.Matrix3D;
    import org.papervision3d.core.math.Number3D;
    import org.papervision3d.materials.BitmapMaterial;
    
    import jiglib.geometry.JBox;
 
    import org.papervision3d.cameras.Camera3D;
    import org.papervision3d.lights.PointLight3D;
    import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.objects.primitives.Plane;
    import org.papervision3d.objects.primitives.Sphere;
    import org.papervision3d.render.BasicRenderEngine;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.view.layer.util.ViewportLayerSortMode;
    import org.papervision3d.view.layer.ViewportLayer;
    import org.papervision3d.view.Viewport3D;
    
    
    import org.libspark.flartoolkit.pv3d.FLARBaseNode;
    
    import org.papervision3d.Papervision3D;
    import org.papervision3d.core.render.IRenderEngine;
    import org.papervision3d.render.BasicRenderEngine;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.view.Viewport3D;
    
    /**
     * Manages pv3d/jiglib shenanigans
     * @author Devon O. Wolfgang
     */
    public class MazeScene extends EventDispatcher {
        
        [Embed(source = "../assets/metal1.jpg")] private static const BallClass:Class;
        
        private var _scene:Scene3D;
        private var _viewport:Viewport3D;
        private var _engine:BasicRenderEngine;
        
        private var _flarContainer:FLARBaseNode;
        
        private var _physics:Papervision3DPhysics;
        
        private var _ground:JBox;
        private var _world:DisplayObject3D;
        private var _ball:JSphere;
        private var _visibleBall:Sphere;
        
        private var _cellsize:int = 12;
        
        private var _level:ILevel;
        
        private var _physicsWalls:Array = [];
        private var _visibleWalls:Array = [];
        private var _vplObjects:ViewportLayer;
        
        public function MazeScene(videowidth:int = 640, videoheight:int = 480) {
            // no tracing
            Papervision3D.PAPERLOGGER.unregisterLogger(Papervision3D.PAPERLOGGER.traceLogger);
            initScene(videowidth, videoheight);
        }
        
        private function initScene(vw:int, vh:int):void {            
            _viewport = new Viewport3D(vw, vh, false, false, true, true);
            _engine = new BasicRenderEngine();
            _flarContainer = new FLARBaseNode();
            _scene = new Scene3D();
            _scene.addChild(_flarContainer);
            
            _physics = new Papervision3DPhysics(_scene, 2);
            _physics.engine.setSolverType("ACCUMULATED");
            PhysicsSystem.getInstance().setGravity(new JNumber3D(0, 0, -5));
        }
        
        public function buildMaze():void {
            
            _vplObjects = new ViewportLayer(_viewport, null);
            _vplObjects.layerIndex = 1;
            _vplObjects.sortMode = ViewportLayerSortMode.Z_SORT;
            _viewport.containerSprite.addLayer(_vplObjects);
            
            var light:PointLight3D = new PointLight3D();
            light.x = 0; light.y = 300; light.z = 0;
            
            var groundMat:FlatShadeMaterial = new FlatShadeMaterial(light, 0x999999);
            var matList:MaterialsList = new MaterialsList( { all:groundMat } );
            var groundPlane:Cube = new Cube(matList, 125, 2, 125);
            
            _ground = new JBox(new Pv3dMesh(groundPlane), 125, 2, 125);
            _ground.material.restitution = 1.5;
            _ground.material.friction = 2;
            _ground.movable = false;
            _physics.addBody(_ground);
            
            // create walls
            
            var w:int = _level.map[0].length;
            var h:int = _level.map.length;
            
            for (var i:int = 0; i < h; i++) {
                for (var j:int = 0; j < w; j++) {
                    if (_level.map[i][j] == 1) {
                        var c:Cube = new Cube(_level.wallList, _cellsize, _cellsize, _cellsize, 1, 1, 1);
                        _flarContainer.addChild(c);
                        _vplObjects.addDisplayObject3D(c);
                        _visibleWalls.push(c);
                        
                        var wall:JBox = new JBox(new Pv3dMesh(c), _cellsize, _cellsize, _cellsize);
                        wall.moveTo(new JNumber3D(((j * _cellsize) - 65) + (_cellsize * .5),      ((i * _cellsize) - 65) + (_cellsize * .5),     _cellsize * .6));
                        wall.movable = false;
                        _physicsWalls.push(wall);
                        _physics.addBody(wall);
                    }
                }
            }
            
            var ballMat:BitmapMaterial = new BitmapMaterial(new BallClass().bitmapData);
            _visibleBall = new Sphere(ballMat, 6);
            _flarContainer.addChild(_visibleBall);
            _vplObjects.addDisplayObject3D(_visibleBall);
            
            _ball = new JSphere(new Pv3dMesh(_visibleBall), 6);
            _ball.mass = 10;
            resetBall();
            _physics.addBody(_ball);
        }
        
        private function destroy():void {
            var len:int = _visibleWalls.length;
            for (var i:int = 0; i < len; i++) {
                _flarContainer.removeChild(_visibleWalls[i]);
                _vplObjects.removeDisplayObject3D(_visibleWalls[i]);
                _physics.removeBody(_physicsWalls[i]);
            }
            _physicsWalls = [];
            _visibleWalls = [];
            
            _physics.removeBody(_ball);
            _physics.removeBody(_ground);
            if (_visibleBall != null) {
                _vplObjects.removeDisplayObject3D(_visibleBall);
                _flarContainer.removeChild(_visibleBall);
            }
        }
        
        private function resetBall():void {
            _ball.moveTo(new JNumber3D(40, 40, 25));
        }
        
        public function moveBall(trans:FLARTransMatResult):void {
            var mat:Matrix3D = new Matrix3D();
            mat.n11 =  trans.m01; mat.n12 =  trans.m00; mat.n13 =  trans.m02; mat.n14 =  trans.m03;
            mat.n21 = -trans.m11; mat.n22 = -trans.m10; mat.n23 = -trans.m12; mat.n24 = -trans.m13;
            mat.n31 =  trans.m21; mat.n32 =  trans.m20; mat.n33 =  trans.m22; mat.n34 =  trans.m23;
            var objRot:Number3D = Matrix3D.matrix2euler(mat);
            trace(objRot.x);
            if(_ball.z < 10 && _ball.z > 4)
                // too much kludge to get this working well. Experiment with these numbers and see what's good for you
                _ball.addWorldForce(new JNumber3D((-objRot.z + 100) * .15, ((objRot.x - 120) * -2 ) , 0), _ball.currentState.position);
                
            _physics.step();
            if (_ball.z < -30) dispatchEvent(new Event("nextLevel"));
        }
        
        public function get scene():Scene3D { return _scene; }
        
        public function get viewport():Viewport3D { return _viewport; }
        
        public function get engine():IRenderEngine { return _engine; }
        
        public function get flarContainer():FLARBaseNode { return _flarContainer; }
        
        public function get level():ILevel { return _level; }
        
        public function set level(value:ILevel):void {
            _level = value;
            destroy();
            buildMaze();
        }
    }
}

And finally the Main class to tie it all together:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package {
    
    import flash.display.Sprite;
    import flash.events.Event;
    
    /**
     * Augmented Reality with Jiglib Maze game
     * @author Devon O. Wolfgang
     */
    public class Main extends Sprite {
        
        private var _flarObject:FlarObject;
        private var _mazeScene:MazeScene;
        private var _levels:Array;
        private var _currentLevel:int = 0;
        
        // game always starts with ball falling. Give it 2 tries
        private var _firstTry:Boolean = true;
        
        public function Main():void {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            
            _levels = [ new Level1Maze(), new Level2Maze() ];
            
            initGame();
        }
        
        private function initGame():void {
            _flarObject = new FlarObject();
            _mazeScene = new MazeScene();
            _mazeScene.addEventListener("nextLevel", changeLevel);
            _mazeScene.level = _levels[_currentLevel];
            _flarObject.mazescene = _mazeScene;
            addChild(_flarObject);
            _flarObject.startRendering();
        }
        
        private function changeLevel(event:Event):void {
            if (_firstTry) {
                _firstTry = false;
            } else {
                _flarObject.stopRendering();
                _currentLevel++;
                if (_currentLevel > _levels.length-1) _currentLevel = 0;
                _mazeScene.level = _levels[_currentLevel];
                _flarObject.startRendering();
            }
        }
    }
    
}

Have fun…

EDIT:
I cleaned up the code a tad more uploaded the entire project. Anyone wanting to play around with this can download the whole kit and kaboodle here. Let me know if you discover anything interesting.

  Facebook   Pinterest   Twitter   Google+
augmented realityjiglib
  • Spirography
    November 08, 2009 · 3 comments
    2249
    5
    Read more
  • Warp Filter for Starling
    May 26, 2013 · 5 comments
    5564
    19
    Read more
  • Some Photographic Shaders
    September 13, 2014 · 12 comments
    6787
    46
    Read more
13 Comments:
  1. Great work!
    I am also trying the jiglib, however, I found the RigidBody cannot really rotate in all axis in one time like PV3D, have you encountered similar problems?

    CW · May 27, 2009
  2. I have noticed that (if I understand what you’re saying). It would be nice to have a physics “container object”, sort of like a generic DisplayObject3d that you could attach multiple Rigid Bodies to then animate them all as one. Of course there may be and I just haven’t dug far enough into the system. And of course I may have no idea what you’re talking about…

    Devon O. · May 27, 2009
  3. Hello,

    I wanted to play with your example, but i cannot complie because of the missing Embed sources. Any chance that you post a zipped package?
    Many thanks for the experiment!

    Best Regards!

    Andras Csizmadia · May 27, 2009
  4. Hey Andras, all the files are now downloadable. Have at…

    Devon O. · May 29, 2009
  5. hi,

    i encountered the same problem as you with the rigidbodys. i hoped you could give me a solution to the container problem. i would like to rotate all my rigidbodys as one big piece like DisplayObject3d.
    any idea please?

    thanks in advance

    Sergio Maruqes Dias · September 17, 2009
  6. Hi,

    When the marker is tilted to a certain angle, the ball just roll over the wall entirely. Any idea why?

    Benjamin · January 11, 2010
  7. I have a error like this :
    1067: Implicit coercion of a value of type jiglib.plugin.papervision3d:Pv3dMesh to an unrelated type jiglib.physics:PhysicsSystem.

    1067: Implicit coercion of a value of type Number to an unrelated type jiglib.physics:PhysicsSystem.

    1067: Implicit coercion of a value of type Number to an unrelated type jiglib.plugin:ISkin3D.

    can you help me?

    Ncuzz · January 27, 2010
  8. Hi Devon!

    Great example. I’m trying to do something, but I have a problem, apparently you also have ..

    The problem occurs when i turn the marker, what happens is that when you add force anyway this will target in the original direction of the marker, as if taken with respect to the marker force locally, and not from the new point of view.

    I’ve been playing with mathematical equations to reverse the signs as I turn the marker, but anyway I have not had good results.

    I leave a small picture (excuse the poor drawing in paint) http://yfrog.com/4jdibujocctp of what happens and how it should happen. Hopefully you can help, and thank you very much again for this excellent example.

    ps: Sorry my bad english :P

    Ryo007 · March 08, 2010
  9. Where can we play this game?… using flash professional 5.5?

    about the flartoolkit, papaervision3d, jiglib libraries,

    I only have the toolkit and the ppvd but i dont have the jiglib.. where can i exactly download the jilib libraries because i cant find it in jiglibflash website.

    Also, i downloaded the ar_maze.zip file, does all the files included, like the codes? because i cant find it.

    Sorry sir if i have many questions. i just want to learn how to make this. I’m just a newbie for Augmented reality. I hope you can help me and teach me step by step procedure…

    Thank you very much…

    Jolly Matthew · August 06, 2011
  10. Great Work

    but

    Is there any way to modify the game? like, changing the wall into something better…and adding 1 or more maze level?..

    PS:Im not doing any copyright..i just want to modify it so i can practice doing it..and i still use your name while doing this…

    John Bush · August 19, 2011
  11. May i know where can i find the pat1.pat file? please

    John Bush · September 03, 2011
  12. Mr. Wolfgang how can I flip it horizontally? Thanks in advance. Godbless!

    Thomas Richardson · October 02, 2011

Leave a Comment! Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Devon O. Wolfgang

AIR | Unity3D | AR/VR

Unity Certified Developer

Technical Reviewer of “The Essential Guide to Flash CS4 AIR Development” and “Starling Game Development Essentials”

Reviewer of “The Starling Handbook”

Unity Engineer at Touch Press.

Categories
  • Actionscript (95)
  • AIR (16)
  • Flash (99)
  • Games (7)
  • Liberty (13)
  • Life (53)
  • Shaders (20)
  • Unity3D (21)
Recent Comments
  • MainDepth on Unity Ripple or Shock Wave Effect
  • Devon O. on Unity Ripple or Shock Wave Effect
  • Feral_Pug on Unity Ripple or Shock Wave Effect
  • bavvireal on Unity3D Endless Runner Part I – Curved Worlds
  • Danielius Vargonas on Custom Post Processing with the LWRP
Archives
  • December 2020 (1)
  • December 2019 (1)
  • September 2019 (1)
  • February 2019 (2)
  • December 2018 (1)
  • July 2018 (1)
  • June 2018 (1)
  • May 2018 (2)
  • January 2018 (1)
  • December 2017 (2)
  • October 2017 (1)
  • September 2017 (2)
  • January 2017 (1)
  • July 2016 (1)
  • December 2015 (2)
  • March 2015 (1)
  • September 2014 (1)
  • January 2014 (1)
  • August 2013 (1)
  • July 2013 (1)
  • May 2013 (1)
  • March 2013 (2)
  • December 2012 (1)
  • November 2012 (1)
  • September 2012 (3)
  • June 2012 (2)
  • May 2012 (1)
  • April 2012 (1)
  • December 2011 (2)
  • October 2011 (3)
  • September 2011 (1)
  • August 2011 (1)
  • July 2011 (1)
  • May 2011 (2)
  • April 2011 (2)
  • March 2011 (1)
  • February 2011 (1)
  • January 2011 (2)
  • December 2010 (3)
  • October 2010 (5)
  • September 2010 (1)
  • July 2010 (2)
  • May 2010 (5)
  • April 2010 (2)
  • March 2010 (7)
  • February 2010 (5)
  • January 2010 (5)
  • December 2009 (3)
  • November 2009 (1)
  • October 2009 (5)
  • September 2009 (5)
  • August 2009 (1)
  • July 2009 (1)
  • June 2009 (2)
  • May 2009 (6)
  • April 2009 (4)
  • March 2009 (2)
  • February 2009 (4)
  • January 2009 (1)
  • December 2008 (5)
  • November 2008 (2)
  • September 2008 (1)
  • August 2008 (6)
  • July 2008 (6)
  • June 2008 (9)
  • May 2008 (4)
  • April 2008 (3)
  • March 2008 (4)
  • February 2008 (9)
  • January 2008 (7)
  • December 2007 (6)
Copyright © 2021 Devon O. Wolfgang