Archive for the ‘Away3D’ Category

Reflection in Away3D, Take 2

Reflection in Away3D

About 13 seconds after I finished my last “Reflections in Away3D” demo I thought up a much better way to do it. I guess that’s what happens when you apply loosely applicable code (see “Reflection in AS3″) to a new scenario. This method, while a bit more resource intensive, is MUCH more functional. Instead of doing a simple Bitmap inversion with a gradient mask and locking the view to only 2 out of 3 planes at a time, I use Away3D Plane objects and multiple views/cameras to create real-time reflections.  This is a 3D engine after all.

The revision I’m presenting here is just a proof of concept. In the near future I hope to release a class that encapsulates reflections much like SimpleShadow in Away3D. You’ll recognize SimpleShadow from the my Away3D shadows demo, which was written by the bad-ass Away3D dev and Prefab creator Fabrice Closier. Inspiration for this code definitely comes from his motivational work.  The reflections aren’t perfect, the overlapping isn’t perfect, but it does help to add a little more dimension to the scene.

UPDATE: Normally I would release the source code, but in my ignorance and zeal to get this done I totally missed the Away3D ReflectivePlane class.  It is designed to do exactly what this plane does using a lot more math, but only one additional camera/view per reflective plane.  It also does realistic reflections relative to the position of the viewing camera.  In other words, way better than what I was offering!

Li's ReflectivePlane Demo

Li's ReflectivePlane Demo

The only problem with ReflectivePlane is that it was designed a few Away3D revisions back and now has some intermittent initialization glitches.  It seemed to me to be better for the Away3d community that I try to recruit ReflectivePlane’s author, Alejandro Santander (AKA, “Li”), to help troubleshoot the problems rather than muddy the waters by adding another solution to an already solved scenario.  When we have a resolution to this problem, I’ll be sure to let you know… in the form of a demo WITH source code this time!

JigLib Flash and Away3D

Away3D and Jiglib Flash

→ Click the above image or here to play the demo
View the source code

The Overview

Toying around with JigLib Flash in Away3D today was both interesting and sobering. For those who don’t know, JigLib is a 3D physics engine, and JigLib Flash is the AS3 port of it. While my expectations weren’t too high since this is complex mathematical processing in Flash, I was hoping for a little more. Don’t get me wrong, though, there’s some very cool potential here.  Be sure to check the tutorials and demos added by people who didn’t give up quite as quickly as me: JigLib Flash demos and tutorials.  I particularly enjoyed some of the car physics demos using this library.

I was setting out to do a basic Jenga-like game. Its just a tower of zig zagging blocks, 3 blocks to a row, 18 rows total. It quickly became evident that this just wasn’t going to happen. After about 4 rows of blocks the frame rate dropped down into single digits and there was tons of “jitter” among the blocks in the scene. I assume the jitter has to do with the fact that Flash can’t process the collisions fast enough and Jiglib is trying to correct rigid body penetrations. I did A LOT of tinkering with the settings, which are a group of static settings that manipulate how the physics is calculated, but couldn’t make it work for me. In the end, I think JigLib Flash just needs a lot of work on “stacking” and rigid bodies with many simultaneous points of contact.

Framerate Fail

Framerate Fail

OK, now that I’ve had my purge of frustration, let me at least talk about a half decent example of Away3D and JigLib running very well together. In the demo at the top of this post I just have a whole bunch of spheres falling into a box with JigLib taking care of the collisions. It works very well and even maintains a good frame rate. So good in fact that I even took the time to add some simple shadows to the falling spheres.

The Code

full source code (download link at bottom)
jiglib_away3d.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*"
                    creationComplete="init();" frameRate="60" height="600" width="800" 
                    viewSourceURL="srcview/index.html">
    <mx:Script>
        [CDATA[
                import away3d.primitives.Plane;
                import away3d.core.base.Mesh;
                import __AS3__.vec.Vector;
                import away3d.materials.BitmapMaterial;
                import jiglib.physics.RigidBody;
                import jiglib.plugin.away3d.*;
                import mx.core.UIComponent;
                import away3d.primitives.Sphere;
                import away3d.core.math.Number3D;
                import away3d.core.utils.Cast;
 
                private var _physics:Away3DPhysics;
                private var _shadows:Vector.<Plane> = new Vector.<Plane>();
                private var _bodies:Vector.<RigidBody> = new Vector.<RigidBody>();
                [Embed("shadow.png")] private var pngShadow:Class;
                [Embed("water.jpg")] private var jpgPaper:Class;
 
                private function init():void {
                        if (stage) {
                                        initAway3D();
                                } else {
                                        this.addEventListener(Event.ADDED_TO_STAGE, function(e:Event):void { initAway3D(); });
                                }     
                }     
 
                private function initAway3D():void {
                        stage.quality = flash.display.StageQuality.LOW;
                        stage.scaleMode = StageScaleMode.NO_SCALE;
                        _drawBackground();
 
                        // prepare physics
                        var walls:Vector.<RigidBody> = new Vector.<RigidBody>();
                        _physics = new Away3DPhysics(away3dMain.view, 5);
                        walls.push(_physics.createCube({width:1000, height:10, depth:1000}));
                        walls.push(_physics.createCube({width:10, height:1000, depth:1000}));
                        walls.push(_physics.createCube({width:1000, height:1000, depth:10}));
                        walls.push(_physics.createCube({width:10, height:1000, depth:1000}));
 
                        var sprite:Sprite = new Sprite();
                        var matrix:Matrix = new Matrix();
                        matrix.createGradientBox(512,512,0,0,0);
                        sprite.graphics.beginGradientFill("radial", [0xdddddd,0x000000], [1,1], [0,255], matrix);
                        sprite.graphics.drawRect(0,0,512,512);
                        sprite.graphics.endFill();
                        var bmd:BitmapData = new BitmapData(512,512,false);
                        bmd.draw(sprite);
                        var mat:BitmapMaterial = new BitmapMaterial(bmd);
 
                        for (var j:uint = 0; j < walls.length; j++) {
                                var body:RigidBody = walls[j];
                                var mesh:Mesh = Away3dMesh(body.skin).mesh;
                                body.movable = false;
                                        mesh.material = mat;
                                        mesh.ownCanvas = true;
                                        mesh.pushback = true;
 
                                        switch(j) {
                                                case 1:
                                                        body.x = 505;
                                                        body.y = 495;
                                                        break;
                                                case 2:
                                                        body.z = 505;
                                                        body.y = 495;
                                                        break;
                                                case 3:
                                                        body.x = -505;
                                                        body.y = 495;
                                                        break;
                                        }
                        }
 
                                var paper:BitmapMaterial = new BitmapMaterial(Cast.bitmap(jpgPaper));
                                for (var i:int = 0; i < 20; i++) {
                                        var sphere:RigidBody = _physics.createSphere({radius:30, segmentsW:6, segmentsH:6});
                                        _bodies.push(sphere);
                                        sphere.x = 100 - Math.random() * 200;
                                        sphere.y = 700 + Math.random() * 3000;
                                        sphere.z = 200 - Math.random() * 100;
                                        sphere.material.restitution = 1; 
 
                                        // This is how to access the engine specific mesh/do3d
                                        _physics.getMesh(sphere).material = paper;
 
                                        var plane:Plane = new Plane({material:new BitmapMaterial(Cast.bitmap(pngShadow)), height:80, width:80, bothsides:true});
                                        plane.ownCanvas = true;
                                        plane.pushback = true;
                                        plane.filters = [new BlurFilter(8,8)];
                                        plane.blendMode = BlendMode.SUBTRACT;
                                        away3dMain.view.scene.addChild(plane);
                                        _shadows.push(plane);
                                }
 
                                // create away3d scene
                                away3dMain.title = "SavageLook.com -- Away3D JigLib Demo";
                                away3dMain.camera.position = new Number3D(0, 700, -1500);
                                away3dMain.camera.lookAt(new Number3D(0,0,0));
 
                                // assign pre and post render functions
                                away3dMain.preRender = function():void { 
                                        for (var k:uint = 0; k < _shadows.length; k++) {
                                                if (_shadows[k].x > 505 || _shadows[k].x < -505 || _shadows[k].z > 505 || _shadows[k].z < -505 || _bodies[k].y < -10) {
                                                        _shadows[k].visible = false;
                                                } else {
                                                        _shadows[k].x = _bodies[k].x;
                                                        _shadows[k].z = _bodies[k].z;
                                                }
                                        }
                                        _physics.step(); 
                                };
                                away3dMain.postRender = function():void { trace("postRender"); };
                }
 
                private function _drawBackground():void {
                        var sprite:Sprite = new Sprite();
                        var ui:UIComponent = new UIComponent();
                        var matrix:Matrix = new Matrix();
 
                        matrix.createGradientBox(this.width, this.height, Math.PI/2, 0, 0);
                        sprite.graphics.beginGradientFill("linear", [0x888888, 0xffffff], [1,1], [0,255], matrix);
                        sprite.graphics.drawRect(0, 0, this.width, this.height);
                        sprite.graphics.endFill();
                        ui.addChild(sprite);
                        this.addChildAt(ui, 0);
                }
        ]]>
    mx:Script>
        <local:AwayUIC id="away3dMain"  x="0" y="0" height="600" width="800"/>
mx:Application>

AwayUIC.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:UIComponent xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">
        <mx:Script>
                [CDATA[
                        import away3d.debug.AwayStats;
                        import away3d.core.math.Number3D;
                        import away3d.cameras.TargetCamera3D;
            import away3d.containers.View3D;
            import away3d.core.render.Renderer;
 
            public var view:View3D;
            public var camera:TargetCamera3D;
            public var doRender:Boolean;
            private var _title:String;
            private var _link:String;
            private var _titleText:TextField;
 
            public var preRender:Function = null;
            public var postRender:Function = null;
 
            override protected function createChildren():void {
                super.createChildren();
                doRender = true;
 
                // setup camera
                camera = new TargetCamera3D();
                camera.position = new Number3D(0, 0, -1000);
                                camera.lookAt(new Number3D(0,0,0));
 
                // setup view
                view = new View3D({camera:camera, renderer:Renderer.BASIC});
                view.x = this.unscaledWidth/2;
                view.y = this.unscaledHeight/2;
                this.addChild(view);
 
                // add stats and title
                var stats:AwayStats = new AwayStats(view);
                this.addChild(stats);
                _title = "SavageLook.com";
                _link = "https://savagelook.com/blog";
                _setText();
 
                this.addEventListener(Event.ENTER_FRAME, function(e:Event):void { _render(); });
            }
 
            private function _setText():void {
                if (_titleText == null) {
                        _titleText = new TextField();
                        this.addChild(_titleText);
                }
 
                _titleText.text = _title;
                _titleText.setTextFormat(new TextFormat("arial", 14, 0xffffff, false, false, false, _link));
                _titleText.x = 150;
                _titleText.y = 10;
                _titleText.width = _titleText.textWidth * 1.1;
                _titleText.filters = [new DropShadowFilter()];
            }
 
            public function get link():String {
                return _link;
            }
 
            public function set link(value:String):void {
                _link = value;
                _setText();
            }
 
            public function get title():String {
                return _title;
            }
 
            public function set title(value:String):void {
                _title = value;
                _setText();
            }
 
            override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
                super.updateDisplayList(unscaledWidth, unscaledHeight);
                view.x = unscaledWidth/2;
                view.y = unscaledHeight/2;
 
                if (view.stage) {
                        _render();
                }
            }
 
            private function _render():void {
                if (doRender) {
                        if (preRender != null) {
                                preRender();
                        }
                        view.render();
                        if (postRender != null) {
                                postRender();
                        }
                }
            }
        ]]>
        mx:Script>
mx:UIComponent>

The Summary

My hasty opinion in this case is that JigLib is fun to play with, but don’t get excited about doing anything super complex… yet.  I follow a few of the developers and contributors and they are constantly working on it.  They even just recently added support for Away3dLite so you can use all that quick rendering goodness along with it.  I fully intend to follow this project closely as it matures.

Reflection in Away3D

Reflection in Away3D

Click here or the image above for the reflection demo
View the source code
→ Download the source code

I alluded to a desire to implement reflections in Away3D in my prior post on reflections in AS3. Well here it is. It wasn’t quite as easy of a translation as I thought it would be, but with lots of digging through the , as well as spotting a good example at geepers.co.uk, I managed to get a basic demo up and running.

While there’s a good bit of code that goes into this demo, the secret sauce is right here:

  // must render before making the following calls
  _view.render();
 
  // find 2d bounding box of sphere
  _drawn = (_view.session.getContainer(_view) as DisplayObjectContainer).getChildAt(0);
  _bounds = _drawn.getRect(this);

What this code does is give us the DisplayObject that contains our 3D object within the given view. We are also able to determine the bounds of the DisplayObject and its 2 dimensional position within the view. With this information we are able to effectively create a snapshot of the visible 3d object. From there we need to create BitmapData that is the inverse of the DisplayObject. To do that we apply the appropriate matrix (invert the y scale) to the DisplayObject when it is drawn to BitmapData. After that we assign the BitmapData to the display Bitmap and then position it according to the bounds of the DisplayObject.

  // redraw reflection
  _bmd = new BitmapData(_drawn.width, _drawn.height, true, 0x00ffffff);
  _matrix.createBox(_xscale, -_yscale, 0, _drawn.width/2, _drawn.height * _yscale / 2);
  _bmd.draw(_drawn, _matrix);
  _bitmapReflect.bitmapData = _bmd;
  _bitmapReflect.x = _bounds.x;
  _bitmapReflect.y = stage.stageHeight / 2 + _distance;

Finally we create an alpha gradient mask that will be applied to the Bitmap in order to give it that cool, fading reflection look.

  // redraw gradient mask for reflection
  _matrix.createGradientBox(_bitmapReflect.width, _bitmapReflect.height * _yscale / 2, Math.PI / 2, 0, 0);
  _bitmapReflectGradient.graphics.clear();
  _bitmapReflectGradient.graphics.beginGradientFill("linear", [0xffffff, 0xffffff], [0.9, 0], [0, 255], _matrix);
  _bitmapReflectGradient.graphics.drawRect(0, 0, _bitmapReflect.width, _bitmapReflect.height);
  _bitmapReflectGradient.graphics.endFill();
  _bitmapReflectGradient.x = _bitmapReflect.x;
  _bitmapReflectGradient.y = _bitmapReflect.y;

And there you go, reflections in Away3D. There are a number of limitations to this method, though:

  • It can only draw reflections of objects currently visible in the view.  In fact, there should be a check on the
    (_view.session.getContainer(_view) as DisplayObjectContainer).getChildAt(0)
    call to make sure that the view contains any children.
  • The reflection is drawn of the entire view, not just the object in question.  That’s why this works best with only one object in the view.  You can use multiple views to get reflections for multiple objects.
  • This example only does reflections of the view as its manipulated along the X & Y planes.  Moving the object along the Z plane will not effect the reflection properly.  I’m sure a method utilizing planes could do better.

If those limitations don’t bother you, then go to town. If they do, be patient. I’m working on another idea for reflection in Away3D that will be a lot more flexible, though more complex and processor intensive.

Remember how my previous blog post on shadows (of course you do) showed how you can easily enhance the 3D feel of your site? Of course you do. Now you can add reflections to that repetoire. It’s all about subtle changes to give your work a more polished look and feel. Have fun and let me know if you create reflections this way, or if you have an implementation of your own.

Away3dLite: Bitmaps and BlendModes

I finally took some time away from Away3D… and dove into Away3DLite!  Away3dLite is quite simply your choice when you need performance over functionality.  It strips a lot of the heavier features from Away3D and leverages improvements in Flash Player 10 directly.  For this reason it’s only compatible with Flash Player 10 (sorry 2.x users).  Away3dLite in the right hands, though, is no slouch in the visual flair department.

In this demo I take a JPG, slice and dice it up into cubes, apply a color material to each cube that is the “color average” of a chunk of BitmapData, then let you change the background color and blend mode to get some interesting visual effects.  The demo below has almost 5000 faces and 400 color materials, which would likely bring Away3D down to a crawl in terms of frame rate.  With Away3dLite, though, I’m currently getting a steady ~27 frame per second!  Great performance and cool effects all rolled into one great package.

You can right click and “view source” on the demo to get a look at exactly what I did, but there’s one section of code in particular I’d like to point out here.  In Away3D, if you want to apply Flash filters and blending, you needed to do the following:

var object:Cube = new Cube();
object.ownCanvas = true;
object.filters = [new GlowFilter()];
object.blendmode = BlendMode.ADD;
view.scene.addChild(object);

In Away3DLite, things are slightly different.  In Away3DLite, objects don’t have their own canvas by default, I assume as a performance boost.  To give your objects a canvas and achieve the same as the above code, you have to create your own canvas in the layer property of Object3D and add it to the view, like this:

var object:Cube6 = new Cube6();
object.layer = new Sprite();
object.layer.filters = [new GlowFilter()];
object.layer.blendmode = BlendMode.ADD;
view.addChild(cube.layer);
view.scene.addChild(cube);

Hopefully this saves somebody switching from Away3D to Away3DLite a few minutes (or hours).

Featured Away3dLite Code:

  • flash.display.BitmapData.getPixel()
  • flash.display.BlendMode
  • away3dlite.primitives.Cube6
  • away3dlite.core.base.Object3D.layer

3DS in Away3D

I’m starting to cook up a few game ideas with some friends of mine and I wanted to get a sense of what Away3D could really do.  To start, I made this very basic example of Away3D loading a fairly high poly 3DS file with minimal animation.  More specifically, it’s a rotating, 2880 poly, torus knot with a wire frame material.  While Away3D isn’t really made to handle models with this many polys, it gives me an idea of how it will handle a total polycount of about 3000.

Featured Away3D code: Max3DS.load() and WireColorMaterial

Click the image above to access the example.  You can right click on the example and click “view source” to,  you guessed it, view the source.

Away3D: SimpleShadow and Simple Shadows

SimpleShadow vs. shadow image (click for demo)

Click the above picture for a demo.  Right click on the demo to view source. Be sure to pay close attention to the apply() and positionPlane() methods of SimpleShadow.

You want to quickly add perspective and depth to a scene?  Look no further than shadows.  Shadows can make a minimalistic scene look fantastic.  Take a look at the website of Peter Kapelyan, one of the Away3D’s developers, and you’ll see what I mean.  Luckily, in Away3D they are easily available in more than one form.  Note, though, that shadows in Away3D are not actually created by light sources as this would be extermely expensive in terms of performance.

The above demo shows Away3D’s built-in SimpleShadow class (left) vs. a shadow created simply by adding a plane with a shadow BitmapMaterial (right).  Both are pretty easy to do, and both have their pros and cons:

SimpleShadow BitmapMaterial method
Built into Away3D X
Shadow conforms to object shape X (specific to object)
Fast Performance X
Shadow handles rotation X (only on one axis)
Handles translation X X
Handles scaling X (needs to be added)
Handles distance X (needs to be added)

“Shadow conforms to object shape” means that no matter what type of 3D object you are applying the SimpleShadow to, the shadow will accurately represent its overall shape.  With the BitmapMaterial method the shadow image must be created specifically for a particular 3D object to maintain an accurate representation.  So for a cube you need to create a square shadow image, for a sphere you need to create a circle shadow, and so on.

By “needs to be added” I mean that there’s no reason this functionality could not be added to the BitmapMaterial method. The reason its not there now is the reason that SimpleShadow won’t perform as well as the BitmapMaterial method. All those extra calculations and shadow redrawing are what will slow down a scene that has one too many SimpleShadows.

Peter Kapelyan's site, flashten.com, using SimpleShadow

Away3D MultiMario example using BitmapMaterial method

The clear winner might appear to be SimpleShadow, but if functionality always won over performance we wouldn’t have a need for Away3DLite.  In general, if you have a scene with only a few shadows and you would like those shadows to appear realistic relative to the object casting them, use SimpleShadow.  If performance is the main concern, like in a scene with many objects casting a shadow, the BitmapMaterial method would likely suit you best.

These are the 2 methods I’ve seen for creating shadows in Away3D, but there may be others.  If you find any, let me know.  Otherwise, enjoy!

UPDATE: I conversed with SimpleShadow’s creator, Fabrice Closier, and he was confused as to why I said SimpleShadow’s performance was slower.  I should clarify that SimpleShadow is slower only when the shadow needs to be redrawn frequently with the apply() method.  In a still scene or when the shadows in the scene do not often need to be redrawn, the performance should be very similar to that of the BitmapMaterial method.

Away3D: SavageLook.com 1.0

Originally this project was the main page for savagelook.com, but I decided it to shuffle to “projects” on my blog.  While it is was a very cool showcase of the things I had learned so far using Away3D, Flint particles, FLARToolkit, FLARManager, TweenMax & TimelineMax, its not really practical for a main interface… yet.  Here’s the things I learned in this initial undertaking that I plan to apply to all future projects involving Away3D(Lite), particularly when the average user is the target audience:

  • Performance ALWAYS has to be on your mind.  There’s nothing more annoying to users than low frame rates.  Many of my next points relate directly to this.
  • Use Renderer.BASIC as your view’s renderer whenever feasible.  You will take an immediate performance hit trying to use the smarter z-sorting renderers (CORRECT_Z_ORDER or INTERSECTING_OBJECTS)
  • Control the size of the view.  While a resizeable view that fills the browser seem great, you can take a nasty performance hit on high resolutions.  For example, this project runs like a champ with a standard 800×600 or 1024×768 resolution.  When I jump it up to  1680×1050, though, things start to get a little choppy.
  • 3D particles are a whore on resources.  Fake 3D effects with 2D whenever possible.  You can literally get 100x (or more) particles in 2D and maintain the same frame rate as 3D.
  • Use simultaneous tweens judiciously.  There were noticeable slow downs in my intro animations when more than one tween was operating at a time.
  • Learn your z-sorting and plan it from the beginning.  I can’t tell you how much time I wasted restructuring my scene and code because I didn’t take the time to learn Frustum clipping, ownCanvas, pushback, pushfront, and screenZoffset before starting.
  • Interactivity and camera motion impacts performance. Static scenes will allow for far more polys at a good frame rate than dynamic ones.  Keeping the camera static or using mouseEnabled = false on your objects may help.
  • Users expect 2D dialogs and text. Use them whenever feasible to convey information to the user.
  • Make sure you clean up your unused objects.  ”scene.removeChild(obj)” and “obj = null” should become your best friend.
  • Reuse objects and materials whenever possible.  Its a lot easier and less expensive to toggle the visibility of a relatively simple object rather than destroy and recreate it every time.
  • Only render when you need to.  When I use 2D layout for the “Bio” section, I stop rendering the covered 3D scene to help performance.
  • Use texture baking or similar techniques to fake lighting.  Real-time lighting, while cool, chews up a lot of resources.  If it isn’t critical, fake it.
  • Materials with alphas process slower.
  • When all else fails, hit the . It may not have the fastest responses, but there’s no better place to get help and guidance.

I’m sure there’s lots more I picked up in the process, but that’s a pretty good assessment.  Hopefully this helps anyone getting started on their own Away3D projects.

I don’t have any specific plans to make version 2.0 of the savagelook.com 3D interface, but I’ve got a few ideas rolling around in my head.  The key factors will be simplicity, speed, more pseudo-3D effects using 2D, and use of Away3DLite.  I’m hoping to really represent Away3D next time.

Away3D: Carousel Gallery

At the request of one of my readers (a list that is probably about 12 people long), here is a demo and source code for the carousel gallery included in the 3d version of savagelook.com shown in my last blog post.  It’s a customizable ring of planes that can display any type of away3d material, in this case BitmapMaterials.  You simply need to pass in an array of materials during initialization and the CarouselGallery handles the rest.

This example uses a simple rotation in the render loop, but my 3d savagelook.com example uses mouse interaction to make it cycle.  You could even add left and right arrows if you wanted to have it move one image in those respective directions.  You could achieve this by simply rotating along the Y axis by a number of degress equal to 360 divided by the number of planes in the carousel.

I hope anyone else who wanders tot his site finds it useful or inspirational for their own work.  Oh, and the time to completion for the first code request I received was about a day and half.  So if you have any ideas or requests for me, feel free to send them along in a comment or email and I’ll get to them as soon as possible.  People’s feedback is what keeps me active and on my toes with this stuff.

Away3DLite + Augmented Reality = Free Camaro!

As promised the demo above includes bare bones source code (right click to view source)  for getting FLARManager up and running with Away3dLite.  And for a limited time, it comes with your very own Camaro!  99% of the credit goes to Eric Socolofsky as the code is just a trimmed down version of his example code included in FLARManager.  The model has been provided free by the modeler “Race Tracks” at turbosquid.  In order to use this demo, you need to do the following:

  • Download and print this marker
  • Turn on your webcam and point it at yourself.
  • Start the demo, point the printed marker at the webcam, and enjoy!

If the above steps aren’t clear, check out the .  For those out there constantly evaluating how far we can push the performance of away3dlite, you might like to know that the model consists of right around 1000 faces.  1000+ faces along with the video processing of patterns and I’m still maintaining right around 30 FPS.  Not bad at all.

The Many Forms of Away3D Text

Click here for the source code or click on the demo above then right click and select “view source.”
Also, here’s a link to the FLA for CS5 that can be used to publish the SWF that will contain your target font.  Simply open the FLA in Flash Pro, change the font of the “test” text on the stage, click “Embed” in the character panel to make sure the right font is set, and then publish your SWF.  The resulting SWF will contain your ready-to-be-embedded font.  If the following steps weren’t goos enough, let me know.  If I get a complaint or two I’ll put up a screenshot walkthrough for the whole process.

Text comes in many forms in Away3D and they all have their own advantages and disadvantages.  Here’s a quick run down of the various methods I know for generating text in Away3D, which are all displayed in the demo above.

PNG + BitmapMaterial + Plane
With this method, you take a PNG (or any other image format Away3D handles) image file containing the text you would like to display, create a BitmapMaterial from it and apply the BitmapMatierial to a Plane.

Pros: Fast rendering
Cons: Static text, quality depends on image resolution, text is flat

Textfield + MovieClip + MovieMaterial + Plane
Here we create a Textfield with our text and add it to a MovieClip.  We then create a MovieMaterial from the MovieClip and apply it to a plane as in the last example.

Pros: Fast rendering, dynamic text
Cons: Text is still flat

TextField + Sprite + BitmapMaterial + Plane
Almost identical to the last example, except this time we create BitmapMaterial from a Sprite.

Pros: Faster rendering, dynamic text
Cons: Text is still flat

TextField3D
We use the TextField3D class in conjunction with wumedia.vector.VectorText.extractFont() and a specially created SWF file that contains the embedded font we want to use in our example.

Pros: Vector quality text, dynamic text
Cons: Text is still flat, can only use embedded font

TextField3D + TextExtrusion
We expand on the last example by using the TextExtrusion class with the TextField.  This creates a 3 dimensional outline of our vector text finally giving us some depth.

Pros: Vector quality text, dynamic text, 3 dimensional
Cons: Can only use embedded font, fonts have arbitrary “winding” when drawn so determining which side of the text is the “back side” is tricky and can screw up shading materials.

3DS Model (high and low poly)
You can always forgo the ins and outs of dynamic text and do it yourself in the modeling program of your choice.  In this case I used 3DS Max 2010 to create low and high(er) poly text.

Pros: Full control over appearance of text
Cons: Text is totally static

So there’s the list of methods I’m aware of.  You got any more?  See anything glaringly stupid above?  Let me know either way.