Google Map Wormhole in Gumbo Air (Flex 4)


I’m working on a huge Google map project for a seminar I’m doing next Tuesday, (and given that I have much time on my hands – right!), I could not resist creating this Google Map wormhole. The animation is created by iterating the map coordinates (longitude and latitude forward), and uses the Tunnel class developed by Petri Leskinen on Pixelero

I don’t iterate uvtData as is done on Pixelero, but longitude and latitude coordinates of the Google map. The change is picked up by drawing the iterated movie into a bitmapdata object and throwing that on to the Tunnel class.

It’s actually map data coming at you (not just a jpeg being recycled).


Google Wormhole in Gumbo


Air Source Files Click Here


Bringing Google map data into CS4 or Papervision3D is really easy, as discussed in an earlier post (Google Map on a Papervision Primitive) . In this case, I use Gumbo (Flex 4) not Papervision3D. Gumbo performs better than Papervision3D and does not distort button positions on standard Google control buttons (as Papervision3D does) – hurray!!!

Here are the steps required to get your Google map Wormhole working!

Step 1: Create a movie clip to add your Google map to;,0,300,300);

Step 2: Add the Google map to your movie


Step 3: Create a bitmapdata and draw your movie into it

_bmpd=new BitmapData(300,300, false);

Step 4: Instantiate the Tunnel class (adding in the bitmapdata material) and add the tunnel to a canvas container on your Flex stage.

tunnel = new Tunnel(_bmpd, 800.0, 600.0, 32, 32);

Step 5: Redraw the movie and iterate Latitude and Longitude coordinates in the onEnterFrame animation loop.



To see the complete code click the more button below

Google Map Air Wormhole Code

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:WindowedApplication xmlns:mx=”; layout=”absolute”>
<maps:Map xmlns:maps=”*”
id=”map” mapevent_mapready=”TunnelDemo(event)”
width=”100%” height=”100%”


import flash.display.*;
import flash.geom.*;
import mx.core.Application;


import Tunnel;

private var tunnel:Tunnel;
public var movie:MovieClip = new MovieClip();
public var movieParent:MovieClip = new MovieClip();
private var _bmpd:BitmapData;

private var count:Number = 0.0;
private var myLat:Number=40.736072;
private var myLng:Number=-73.992062;

public function TunnelDemo(event:Event):void { LatLng(myLat,myLng), 14, MapType.HYBRID_MAP_TYPE);;,0,300,300)

_bmpd=new BitmapData(300,300, false);


tunnel = new Tunnel(_bmpd, 800.0, 600.0, 20, 20);


addEventListener(Event.ENTER_FRAME, update);


private function update(e:Event):void {

count += 0.03;
var sin:Number = Math.sin(count);

// move forward


//tunnel.step(0.01,0.01*sin); LatLng(myLat,myLng));

// bend the tunnel
tunnel.xBending = 0.02*(sin-Math.cos(2.5*count));
tunnel.yBending = 0.01*(Math.sin(2.5*count)+sin);


<mx:Canvas x=”400″ y=”300″ width=”800″ height=”600″ id=”mapHolder”>

Tunnel class developed by Petri Leskinen

// OldSchool Tunnel-class for Flash 10
// Petri Leskinen, leskinen[dot]petri[at]
// August 2008, Espoo, Finland

// update September 2nd 2008
// added PerspectiveProjection, Utils3D etc.

package {

import flash.display.Sprite;
import flash.display.BitmapData;
import flash.display.GraphicsPathCommand;
import flash.display.TriangleCulling;
import flash.geom.Vector3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Matrix3D;
import flash.geom.Utils3D;

public class Tunnel extends Sprite {

public var n:int =20; // divisions in z-depth
public var m:int =20; // circular tube is in fact a regular m-polygon
public var w:Number = 800;
public var h:Number = 600;

public var xBending:Number = 0.02;
public var yBending:Number = -0.03;

public var bitmapData:BitmapData = new BitmapData(1,1,true,0xFFFFFFFF);

private var msk:Sprite;
private var radius:Number;
private var vertices:Vector.<Number>;
private var indices:Vector.<int>;
private var uvtData:Vector.<Number>;
private var coords3D:Vector.<Number>;

private var projectedVerts:Vector.<Number>;
private var bendedVerts:Vector.<Number>;

private var projectionMatrix:Matrix3D;

private var i:int;
private var j:int;

private static const doublePi:Number = 2.0*Math.PI; // 6.28…

public function Tunnel(bmp:BitmapData, _w:Number = 800, _h:Number = 600,
_n:int =20, _m:int=20) {

bitmapData = bmp;
this.w = _w;
this.h = _h;
this.n = _n;
this.m = _m;

// minor radius of a polygon
// r = R cos(PI/m);
radius = 0.5*Math.sqrt(w*w+h*h) / Math.cos(Math.PI/(m-1));

var perspective:PerspectiveProjection= new PerspectiveProjection();
perspective.fieldOfView = 70.0; // camera angle, in degrees
projectionMatrix = perspective.toMatrix3D();

// Defining the correct radius for the cone,
// so that it fills the rectangle (w,h) on the screen
// point (1,0,1) must not be closer to the center that half the diameter
var check3D:Vector3D = Utils3D.projectVector(
new Vector3D(1.0,0.0,1.0)
radius /= check3D.x;



private function init():void {

vertices = new Vector.<Number>();
indices = new Vector.<int>();
uvtData = new Vector.<Number>();
coords3D = new Vector.<Number>();

var x:Number;
var y:Number;
var z:Number;
var w:Number =0.0;
var a:Number;
var tmp:Number;

for (i=0 ; i!=n; i++) {
// z starts from the farest end of the tunnel
// so there’s no need for sorting the 3d-faces in depth
z = n-i;

tmp = radius*i/(n-1.0);
for (j=0; j!=m; j++) {
// x,y coordinates, initialize vector size
vertices.push(0.0, 0.0);

// Texture mapping coordinates
// u and v; between 0,0 and 1,1
// w for correcting the perspective projection
// (here w=0.0, only to allocate the vector,
// where rendered the correct w-values
// are counted by Utils3D.projectVectors )
uvtData.push(i/(n-1.0),j/(m-1.0), w);

// coords3D: precount the xyz-coordinates
// of a cone looking up the z-axis
// with radius of ‘radius’ at bottom, 0.0 at top.
// No bending or projection yet
a = j/(m-1.0)*doublePi;
x = Math.sin(a) *tmp;
y = -Math.cos(a) *tmp;


// indices for two triangles, CCW
// ii—–ii+1
// |\ |
// | \ |
// | \ |
// | \|
// ii+n—ii+n+1

var ii:int =0;
for (i=0 ; i!=n-1; i++) {
for (j=0 ; j!=m-1; j++) {

projectedVerts = new Vector.<Number>(vertices.length);
bendedVerts = new Vector.<Number>(coords3D.length);


// ‘moving’ in tunnel is done by altering the uv-coordinates of the projection
// ‘we’ don’t move forward, bitmap moves towards the origin
// that’s why it’s a subtraction for x
// adding to y rotates around the axis
// usual values for addX seem very small,
// remember that addX = 1.0/bitmapData.width moves 1 pixel forward
public function step(addX:Number, addY:Number=0.0):void {
for (i=0; i<uvtData.length; i+=2) {
uvtData[i++] -= addX;
uvtData[i] += addY;
// each loop i increases by 3 because skiping over the t-coordinate

public function update():void {

// when the map’s updated, the mesh info, e.g uvtData and indices
// remain the same, only vertices will be updated

var z:Number;
var fz:Number;

for (i=0; i<coords3D.length; i++) {
// Bending is done by adding x- and y-coordinates with
// a parabola with zero values at bottom and top of the cylinder
// x’ = x + f(z)
// y’ = y + g(z)
z = coords3D[i+2];
fz = (z-1.0)*(z-n);

// x-coordinate
bendedVerts[i]= coords3D[i++] + xBending*fz;
// y-coordinate
bendedVerts[i]= coords3D[i++] + yBending*fz;
// and z
bendedVerts[i]= z;

// projection to 2D
Utils3D.projectVectors(projectionMatrix, bendedVerts,
projectedVerts, uvtData);

// drawing …
with ( {
beginBitmapFill(this.bitmapData ,
null, // no matrix
true, // = repeat, important for ‘moving’ the bitmap
true); // = smooth


private function addMask():void {
// circular tube is in fact a regular m-polygon
// mask crops that to a rectangle
msk = new Sprite();,0×00,1.0);,1.0);,-h/2,w,h);;
this.mask = msk;


3 Responses to Google Map Wormhole in Gumbo Air (Flex 4)

  1. […] > Google Map Wormhole in Gumbo Air (Flex 4) « Professional Papervision3D Book […]

  2. larry says:

    I am confused about Gumbo vs. PaperVision3D.
    Has Adobe created a commercially supported alternative to open source PV3D in Flex 4?

    Sorry if I got it wrong. I’m a total newbie to PV3D, and still very new to Flex.

    Thanks for all the great code and YouTube videos!


    • Mike Lively says:

      I think that Adobe got caught with its pants down when PV3D came along, and have turned the tables with the release of Flash Player 10. Now PV3D is playing catchup and are in the process of creating PapervisionX a version of Papervision that takes advantage of the Flash 10 player.

      So yes, it’s a very dynamic process…welcome to the business…

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: