Importing Google Earth files dynamically into Papervision3D – Scaling & positioning


Loading Google Earth models into flash, dynamically. The files are loaded directly from the web and rescaled and positioned. And this is how it is done:

The Google 3D Warehouse has many 3D models and buildings and most of them available for free download. It would be relatively easy to download the files, and try how they work in Papervision. But I want to leave them on the server, and import them directly from the web.
The trouble is, they are all modeled in different dimensions. So it could happen that a simple house is 200 times the size of the Empire State Building. This means we have to get the dimensions of a model to be able to scale it appropriately.
Another problem with these models is, that they aren’t all modeled right at the center. So if you want to place them on screen you can’t simply move them to a certain point, they might still appear in completely different positions.

Let’s start by looking at different file formats. Papervision3D supports .dae files and now it also supports .kmz, which is what I will be working with.
If you haven’t tried loading models into Papervision I suggest starting with the Loading Complex Models tutorial first. Now what is the difference between a kmz and a .dae ? Well effectively the kmz is a compressed .dae including all material images. You can simply rename a kmz file to zip and see yourself. What Papervision does, it takes the kmz file and unzips it with nochump.
Using kmz files we can load files directly from the internet without downloading them first. In the warehouse advanced search you can search specifically for files that are available as kmz.
Something else to be aware of is the filesize. The filesize is always shown next to the download link. Try to get a low filesize. Everything over 1mb takes far to long to import or Flash will stop after 30 seconds.

Let’s start importing a file:

		private var view:BasicView;
		private var model:KMZ;

		public function Import():void {
			// Create and add a new View
			view = new BasicView(400, 300, true, false);
			addChild(view);
			loadKMZ("http://sketchup.google.com/3dwarehouse/download?mid=c4d51a0691a715f06faa554cf2cc4cd0&rtyp=ks&fn=carolands&ctyp=other&prevstart=36&ts=1272574263000");
		}

		private function loadKMZ(model_url:String):void {
		model = new KMZ();
		model.load(model_url);
		model.addEventListener(FileLoadEvent.LOAD_COMPLETE, colladacomplete);
		}

		private function colladacomplete(e:Event):void {
			// adding the model to the stage and render the scene
		view.scene.addChild(model);
                view.singleRender();
		}
		}

Now the model is loaded and added to the stage. However the size of the model depends on the original file. In order to scale the model we need to know the original size of it. There is no property that defines the size of a 3d model, so we need to calculate it.
That can be done by finding the highest and lowest values for the vertexes in x, y and z. To do this we need to loop through all children of the model. I found this script on another blog

private function parseMesh(obj:DisplayObject3D, pos:Number3D):void
{
if (obj.children)
{
for each( var child:* in obj.children )
{
var n:Number3D = new Number3D(
pos.x + obj.x,
pos.y + obj.y,
pos.z + obj.z);
parseMesh( child, n );
}
}

if (obj.geometry)
{
for each(var vertex:Vertex3D in obj.geometry.vertices)
{
var vx:Number = pos.x + vertex.x;
var vy:Number = pos.y + vertex.y;
var vz:Number = pos.z + vertex.z;

maxX = Math.max(maxX, vx);
minX = Math.min(minX, vx);
maxY = Math.max(maxY, vy);
minY = Math.min(minY, vy);
maxZ = Math.max(maxZ, vz);
minZ = Math.min(minZ, vz);

}
}
}

Now technically the difference between the x values should be the width and the difference between the y values should be the height. That however isn’t always the case. In many models the Up-axis is the Z axis. In Papervision the Up-axis is the Y axis. So we need to find out how the model is placed. Luckily this is defined inside the dae file and Papervision creates a property for our dae. So model.dae.yUp is a boolean that defines wether the y or z axis points upwards.
So now we can scale the model accordingly:

			if (model.dae.yUp == false) {

        	         model.scale = 1000 / sizeZ;
		}
	               else {
			model.scale = 1000 / sizeX; }

Now all models should be roughly the same height…Or are they? No! They might be the same height, but it doesn’t look like it. And that is because of the positioning. Because we have a 3dimensional space objects can also be positioned in z ( or y if the axis are layed out differenly), and that means that objects can be moved away or towards the viewpoint which will make them appear smaller or taller. So we need to position the Collada. And that brings us to a similar problem as for the size.
In Papervision space the model will sit at 0 0 0, but how is it modeled? Did the creator start at 0 0 0 and modeled only into positiv space? Or is the model centered at 0 0 0 ? Or maybe just centered in x and y and somewhere far off in z?
So again, we need to calculate the position of the model and we can use our Max values for that.
The easiest way is to move the model so the lower left corner closest to the camera, will sit at 0 0 0 and then we can move the model further from there. You have to move the dae and not the model.
Here I am moving the model to be centered in x as well.
Additionally I want the model to resize differently if the width is greater than the height. So If I have a really tall building it should be tall but wide ones shouldn’t be stretched to be just as tall.

So this is what the script looks like now:

parseMesh(model, new Number3D());

			var sizeX = maxX - minX;
			var sizeY = maxY - minY;
			var sizeZ = maxZ - minZ;

			var middleinx:int = ((minX + maxX)) / 2;

			if (model.dae.yUp == false) {
	                 model.dae.position = new Number3D( -middleinx, -minZ, -minY);
					 if ( sizeZ > sizeX) {
								model.scale = 1400 / sizeZ;
									}
					 else {
						model.scale = 2500 / sizeX

						}
					 		}
	               else {
					model.dae.position = new Number3D( -middleinx, -minY, -minZ);
						if (sizeY > sizeX) {
						model.scale = 1400 / sizeZ;
						}
						else {
						model.scale = 2500 / sizeX;
							}
				        }

Now we can position the model where I want:

model.position = new Number3D( 0 , -450, 0);

Finally I want to say: I have tried various different models from the warehouse and I have to say, some work and some don’t. Sometimes the texture doesn’t load properly. Sometimes Flash just crashes and for some the scaling method doesn’t work. This can be the case if for example the creator of the model accidently left some vertexes somwhere in space. But it might also be the case that the script is still not working properly. Please comment if you have optimization ideas or questions.

Download source files

Print Friendly

One Response to “Importing Google Earth files dynamically into Papervision3D – Scaling & positioning”

  • Trackback…

    [...]we find pleasure in showing my readers other places on the Internet, even though those URLs aren’t similar to mine, by hyperlinking them. Just below are a couple links worth visiting[...]…

Leave a Reply


four - = 2