Archive for the ‘Code Demos’ Category

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 Away3D dev list, 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.

Reflection in AS3

Source code + Flash Develop project

Inspired by this tutorial on reflections in AS3 at adobe devnet, I decided to play with reflections in Actionscript3. As usual I can never follow a tutorial or step by step process without constantly trying to tweak it.

In my process of tweaking I found a slight short coming in the example given. While it does a fantastic job of handling standard DisplayObjects, I found that things get a little messed up when you add filters to these objects. Notice how the edges of the first image are cut off and sharp, whereas the the second image that accounts for the filters’ impact on DisplayObjects’ dimensions looks smooth:

Reflections cut-off

Filters cut-off

Reflections cut-off

Filters complete

In my efforts to remedy this problem I came across a very useful function for BitmapData called generateFilterRect(). Given a Rectangle and a BitmapFilter this function will return the Rectangle that would actually encompass the DisplayObject along with its filter. With a simple bit of iteration we can traverse an object’s list of filters and determine what the max dimensions will be. Here’s the function I added to take care of it:

  private function _createReflectionBitmapData(obj:Sprite):BitmapData {
      var filterRect:Rectangle;
      var width:Number = obj.width;
      var height:Number = obj.height;
      var bmd:BitmapData = new BitmapData(width, height, true, 0xffffff);
      var matrix:Matrix = new Matrix();
 
      // filters can cause a display object to render outside of its rectangle
      for each (var filter:BitmapFilter in obj.filters) {
        filterRect = bmd.generateFilterRect(bmd.rect, filter);
        width = filterRect.width > width ? filterRect.width : width;
        height = filterRect.height > height ? filterRect.height : height;
      }
 
      // create, invert, and position relfection bitmapdata
      bmd = new BitmapData(width, height, true, 0xffffff);
      matrix.createBox(1, -1, 0, (width - obj.width)/2, height - (height - obj.height)/2);
      bmd.draw(obj, matrix);
 
      return bmd;
    }

The end result is BitmapData that contains our inverted DisplayObject, now properly sized and positioned. We can now pass this into a Bitmap object and continue on with the code in the tutorial mentioned at the beginning of this post. Or… you can use my stripped down and less functional version to get a simple view of how reflections are achieved in AS3:

package
{
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.DisplayObject;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.filters.BitmapFilter;
  import flash.filters.GlowFilter;
  import flash.geom.Matrix;
  import flash.geom.Rectangle;
 
  /**
   * ...
   * @author Tony Lukasavage - SavageLook.com
   */
  public class Main extends Sprite
  {
    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);
 
      // create main glow circle
      var obj:Sprite = new Sprite();
      var matrix:Matrix = new Matrix();
      var radius:Number = 100;
      matrix.createGradientBox(radius*2, radius*2, Math.PI / 2);
      obj.graphics.beginGradientFill("linear", [0x888888, 0xffffff], [1, 1], [0, 255], matrix);
      obj.graphics.drawCircle(radius, radius, radius);
      obj.graphics.endFill();
      obj.x = stage.stageWidth / 2 - radius;
      obj.y = stage.stageHeight / 2 - radius*1.5;
      obj.filters = [new GlowFilter(0xffffff, 1, 20, 20, 2, 1)];
      this.addChild(obj);
 
      // create reflection
      var bmd:BitmapData = _createReflectionBitmapData(obj);
      var bitmapReflect:Bitmap = new Bitmap(bmd);
      bitmapReflect.x = stage.stageWidth / 2 - bitmapReflect.width/2;
      bitmapReflect.y = obj.y + radius*2;
      this.addChild(bitmapReflect);
 
      // create gradient for reflection
      var grad:Sprite = new Sprite();
      matrix.createGradientBox(bitmapReflect.width, bitmapReflect.height / 2, Math.PI / 2, 0, 0);
      grad.graphics.beginGradientFill("linear", [0xffffff, 0xffffff], [1, 0], [0, 255], matrix);
      grad.graphics.drawRect(0, 0, bitmapReflect.width, bitmapReflect.height);
      grad.x = bitmapReflect.x;
      grad.y = bitmapReflect.y;
      grad.cacheAsBitmap = true;
      bitmapReflect.cacheAsBitmap = true;
      bitmapReflect.mask = grad;
      this.addChild(grad);
    }
 
    private function _createReflectionBitmapData(obj:Sprite):BitmapData {
      var filterRect:Rectangle;
      var width:Number = obj.width;
      var height:Number = obj.height;
      var bmd:BitmapData = new BitmapData(width, height, true, 0xffffff);
      var matrix:Matrix = new Matrix();
 
      // filters can cause a display object to render outside of its rectangle
      for each (var filter:BitmapFilter in obj.filters) {
        filterRect = bmd.generateFilterRect(bmd.rect, filter);
        width = filterRect.width > width ? filterRect.width : width;
        height = filterRect.height > height ? filterRect.height : height;
      }
 
      // create, invert, and position relfection bitmapdata
      bmd = new BitmapData(width, height, true, 0xffffff);
      matrix.createBox(1, -1, 0, (width - obj.width)/2, height - (height - obj.height)/2);
      bmd.draw(obj, matrix);
 
      return bmd;
    }
  }
}

And thats the basics. If you want an in depth description of each step and how they are performed, I will again refer you to the terrific tutorial by Ben Pritchard. In the meantime, enjoy your new found knowledge and start putting it to use. Everyone else is. Seriously. Like every image anymore has a reflection under it. This is really starting to irk my “swim against the current” side. Oh well, nothing a glass of Jack can’t cure.

Is everyone doing this in Away3D? No? Well you can add me to the list soon ;)

Box2DFlashAS3 v2.1a HelloWorld

Box2D demo

Box2D demo

Click the image above for the demo.
Click here or right click on the demo to view the source code.

Inspired by this clip of Box2D running on Android, I decided to dive into this 2D physics engine I have heard so much about.  While the version of Box2D I used is the AS3 version called Box2DFlashAS3, the original version is written in C++.  Basically it very simply lets you apply 2D physics to your objects, or “bodies,” in AS3.

Most of the examples and tutorials I saw were lacking 2 things:

  1. A way to apply sprites to my “bodies” without the use of a flash project (FLA) file.
  2. Code that was compatible with the latest version of Box2DFlashAS3, v2.1a at the time of this post.

So to resolve that situation, or to account for my search engine deficiency, I present the HelloWorld example from the Box2DFlashAS3 2.1a distribution modified to be pure AS3:

package{
package {
  /*
   * Tony Lukasavage - SavageLook.com - 8/18/2010
   * Box2DFlashAS3 2.1a HelloWorld example, minus the need for an accompanying FLA
   *
   * This the basic Box2DFlashAS3 HelloWorld.as file from the source distribution
   * with some adjustments made so that you do not need an FLA file to compile and
   * run the code.  A simple bonus for us pure AS3 guys.  Also a few minor modifications
   * are made to account for changes between version 2.0 and 2.1, like adding a type
   * for body definitions.  Finally, I threw in an click handler to toggle between
   * normal and debug drawing.
   *
   */
 
  import Box2D.Collision.*;
  import Box2D.Collision.Shapes.*;
  import Box2D.Common.Math.*;
  import Box2D.Dynamics.*;
 
  import __AS3__.vec.Vector;
 
  import com.adobe.viewsource.ViewSource;
 
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.geom.Matrix;
  import flash.text.TextField;
  import flash.text.TextFormat;
 
  [SWF(width="800", height="600", frameRate="30")]
  public class box2d extends Sprite
  {
    private var _world:b2World;
    private var _velocityIterations:int = 10;
    private var _positionIterations:int = 10;
    private var _timeStep:Number = 1.0 / 30.0;
    private var _showDebug:Boolean = true;
    private var _debugSprite:Sprite;
    private var _bodySprites:Vector. = new Vector.();
 
    // Box2D uses meters for measurement, AS3 uses pixels.  1 meter = 30 pixels
    public var _worldRatio:int = 30;
 
    public function box2d()
    {
      // Add event for main loop
      addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
      stage.addEventListener(MouseEvent.CLICK, onClick );
 
      // add background gradient
      var bg:Sprite = new Sprite();
      var matrix:Matrix = new Matrix();
      matrix.createGradientBox(stage.stageWidth, stage.stageHeight, Math.PI/2, 0, 0);
      bg.graphics.beginGradientFill("linear", [0x9999ff, 0xffffff], [1, 1], [0, 255], matrix);
      bg.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
      bg.graphics.endFill();
      addChild(bg);
 
      // Define the gravity vector
      var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
 
      // Allow bodies to sleep
      var doSleep:Boolean = true;
 
      // Construct a world object
      _world = new b2World(gravity, doSleep);
 
      // set debug draw
      var debugDraw:b2DebugDraw = new b2DebugDraw();
      _debugSprite = new Sprite();
      addChild(_debugSprite);
      debugDraw.SetSprite(_debugSprite);
      debugDraw.SetDrawScale(_worldRatio);
      debugDraw.SetFillAlpha(0.5);
      debugDraw.SetLineThickness(2);
      debugDraw.SetAlpha(1);
      debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
      _world.SetDebugDraw(debugDraw);
 
      // Vars used to create bodies
      var body:b2Body;
      var bodyDef:b2BodyDef;
      var boxShape:b2PolygonShape;
      var circleShape:b2CircleShape;
 
      // Adding sprite variable for dynamically creating body userData
      var sprite:Sprite;
      var groundHeight:int = 60;
 
      sprite = new Sprite();
      sprite.graphics.lineStyle(1);
      sprite.graphics.beginFill(0x444444);
      sprite.graphics.drawRect(-stage.stageWidth/2, -groundHeight/2, stage.stageWidth, groundHeight);
      sprite.graphics.endFill();
 
      bodyDef = new b2BodyDef();
      bodyDef.type = b2Body.b2_staticBody;
      bodyDef.position.Set(stage.stageWidth / _worldRatio / 2, (stage.stageHeight - sprite.height/2) / _worldRatio);
      bodyDef.userData = sprite;
      addChild(bodyDef.userData);
 
      boxShape = new b2PolygonShape();
      boxShape.SetAsBox(sprite.width/_worldRatio/2, sprite.height/_worldRatio/2);
 
      var fixtureDef:b2FixtureDef = new b2FixtureDef();
      fixtureDef.shape = boxShape;
      fixtureDef.friction = 0.3;
      fixtureDef.density = 0; // static bodies require zero density
 
      body = _world.CreateBody(bodyDef);
      body.CreateFixture(fixtureDef);
 
      // Add some objects
      for (var i:int = 1; i < 20; i++) {
        // create generic body definition
        bodyDef = new b2BodyDef();
        bodyDef.type = b2Body.b2_dynamicBody;
        bodyDef.position.x = Math.random() * 15 + 5;
        bodyDef.position.y = Math.random() * 10;
        var rX:Number = Math.random() + 0.5;
        var rY:Number = Math.random() + 1;
        var spriteX:Number = rX * 30 * 2;
        var spriteY:Number = rY * 30 * 2;
 
        // Box
        if (Math.random() < 0.5) {
          sprite = new Sprite();
          sprite.graphics.lineStyle(1);
          sprite.graphics.beginFill(0xff6666);
          sprite.graphics.drawRect(-spriteX/2, -spriteY/2, spriteX, spriteY);
          sprite.graphics.endFill();
          bodyDef.userData = sprite;
 
          boxShape = new b2PolygonShape();
          boxShape.SetAsBox(rX, rY);
 
          fixtureDef.shape = boxShape;
          fixtureDef.density = 1.0;
          fixtureDef.friction = 0.5;
          fixtureDef.restitution = 0.2;
 
          body = _world.CreateBody(bodyDef);
          body.CreateFixture(fixtureDef);
        }
        // Circle
        else {
          sprite = new Sprite();
          sprite.graphics.lineStyle(1);
          sprite.graphics.beginFill(0x44ff44);
          sprite.graphics.drawCircle(0, 0, spriteX/2);
          sprite.graphics.endFill();
          bodyDef.userData = sprite;
 
          circleShape = new b2CircleShape(rX);
 
          fixtureDef.shape = circleShape;
          fixtureDef.density = 1.0;
          fixtureDef.friction = 0.5;
          fixtureDef.restitution = 0.2;
 
          body = _world.CreateBody(bodyDef);
          body.CreateFixture(fixtureDef);
        }
 
        _bodySprites.push(bodyDef.userData as Sprite);
        addChild(bodyDef.userData);
      }
 
      // enable view source
      ViewSource.addMenuItem(this, "srcview/index.html");
      var text:TextField = new TextField();
      text.text = "Right click to view source";
      text.setTextFormat(new TextFormat("arial", 14, 0, true));
      text.x = 20;
      text.y = 20;
      text.width = 200;
      addChild(text);
    }
 
    public function onClick(e:MouseEvent):void {
      _showDebug = !_showDebug;
      if (!_showDebug) {
        _debugSprite.graphics.clear();
      }
      for each (var sprite:Sprite in _bodySprites) {
        sprite.visible = !_showDebug;
      }
    }
 
    public function Update(e:Event):void{
      _world.Step(_timeStep, _velocityIterations, _positionIterations);
      if (_showDebug) {
        _world.DrawDebugData();
      }
 
      // Go through body list and update sprite positions/rotations
      for (var bb:b2Body = _world.GetBodyList(); bb; bb = bb.GetNext()){
        if (bb.GetUserData() is Sprite){
          var sprite:Sprite = bb.GetUserData() as Sprite;
          sprite.x = bb.GetPosition().x * 30;
          sprite.y = bb.GetPosition().y * 30;
          sprite.rotation = bb.GetAngle() * (180/Math.PI);
        }
      }
    }
  }
}

Very cool stuff that adds lots of possibilities to your Flash projects.  I can’t wait to start playing with the more complex aspects like joints, buoyancy and breakable bodies.  More intensely awesome demos sure to follow.

Webcam Video in Actionscript3

Webcam test in AS3

Click the above picture for the webcam demo (webcam required).
Right click on the demo, or click here for the source code.

This is a pretty simple demo compared to some of my other stuff, but it’s a key point for a lot of them.  Knowing how to use the webcam independently of an existing library can open up lots of options beside augmented reality.  For that reason, I present this small demo showing off how easy it is to do so in Actionscript3.

Here’s a slightly modified excerpt from the full source code that is the meat and potatoes of the demo:

var camera:Camera = Camera.getCamera();
camera.setQuality(0,100);
camera.setMode(800,600,60,true);
 
var video:Video = new Video(800,600);
video.attachCamera(camera);
addChild(video);

As you can see, its as simple as creating a Camera object, attaching it to a Video object and adding the Video object to the main sprite.  The demo will show you how to manipulate image quality, camera frame rate, and viewport size.  For more details on all the properties and methods of each, check out the ASDocs on Camera and Video.

What can you do with this besides making yet another video chat application?  I don’t know about you, but I’m planning an Away3DLite project that will involve multiple levels of “reflection” based on the images from the webcam.  It will be awesome.  Now I just need to figure out how I’m going to do it.  Details…

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: 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 video demo from my prior blog post.  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.