Away3D Surface Tracking tutorial

Flash, Tutorials

reader1

This tutorial shows you how “read” the height of an Elevation mesh in order to place or move objects on it’s surface using the Away3D 2.0 library or higher.

We assume here you already know how the elevation class works, see the tutorial
How to create an elevation for more details on the Elevation class.

A word on the concept and how it works
The ElevationReader class manages surface tracking using exactly the same parameters as the Elevation class. For obvious reasons it must use the same elevation source BitmapData as well. Both classes share the same principles of color measurement, but this class does not generate any 3d objects. The ElevationReader class generates its own version of the elevation mesh but in a BitmapData form, a smooth shaded interpretation of the mesh based on the source passed to the ElevationReader class. Between each point defined on x – x1 and y – y1, the class draws gradients between the color values along the x and y axes.

At runtime, you are able to return the height from a given x and y coordinate, allowing an optional offset if you wish your object/camera to be higher than the actual surface level (usually the case). Depending on how your mesh is oriented, the returned number can be used to set the x,y or z properties of your object.

The reason a separate smoothed gradient BitmapData is used (instead of the original source BitmapData) is simple – say for the purpose of this tutorial you wanted to make an elevation from a source.jpg image containing some noisy pixels in between the resolution you passed to the Elevation class. The color channel values at coordinates between those points will not be an exact reflection of the mesh elevation. ElevationReader saves you the time-consuming task of making the smoothed map yourself.

Since the surface reading is pixel based, the higher the source resolution the better the reading. Try to have a source size as close as possible to the mesh size. In the case of very rough terrains, the constructor allows you to pass a smoothing integer which averages the current surface calculations with the previous calculation – the higher the integer the slower the reaction time in surface height. This value is useful when an object needs to move slowly across a low resolution terrain.watch full film Brooklyn 2015

reader2

The above demo shows you the gradient. Both meshes are the same elevation, but the top one is textured using the smoothed result generated by the ElevationReader. You can see here that the lower the elevation, the darker the color (the internal color channel being used by the class is the red one).

ElevationReader.generate method properties
– sourceBmd:BitmapData – This is the same source BitmapData the Elevation class uses.
– channel:String – Specifies the color channel as: r, g, b or a. The default is r.
– subdivisionX:int – Specifies the gap between pixels to be read along the x axis, the default is 10.
– subdivisionY:int – Specifies the gap between pixels to be read along the y axis, the default is 10.
– factorX:Number – Specifies the scale along the x axis, the default is 1.
– factorY:Number – Specifies the scale along the y axis, the default is 1.
– elevate:Number – Specifies the scale along the z axis (the elevation multiplier), the default is 0.5.

ElevationReader public methods
– get source():BitmapData – returns the generated smoothed BitmapData object
– getLevel(x:Number, y:Number offset:Number = 0):Number – the most useful value, returns the height value of the surface at the given coordinates x and y, adding an optional extra offset.

How to implement
You’ll need to import 2 classes from the extrusions package

import away3d.extrusions.Elevation;
import away3d.extrusions.ElevationReader;

The code shown below is used by the the demo at top of this tutorial:

private function prepareWorld():void
{
	//the scale along x axis
	var factorW:Number = 8;
	
	//the scale along y axis
	var factorH:Number = 8;
	
	//the elevation scale along z axis
	var factorD:Number = 3.5;
	
	//the precision for the x and y on the source
	var precisionX:Number = 20;
	var precisionY:Number = 20;
	
	//make a new instance of the reader
	elevationreader = new ElevationReader(0);
	
	//we pass exactly same settings as for the Elevation class
	elevationreader.traceLevels(elevatesource_bmd,
	                            "r",
	                            precisionX,
	                            precisionY,
	                            factorW,
	                            factorH,
	                            factorD);
	
	//make a material
	var mat:IMaterial = new BitmapMaterial(colorsource_bmd , {smooth:false, debug:false});
	
	//you can reuse the smooth data if you want to test
	var source_elevation:BitmapData = elevationreader.source;
	var elevate:Elevation = new Elevation();
	
	// now we generate the mesh, again using same params
	var points:Array = elevate.generate(source_elevation,
	                                    "r",
	                                    precisionX,
	                                    precisionY,
	                                    factorW,
	                                    factorH,
	                                    factorD)
	var extrude:SkinExtrude = new SkinExtrude(points, {material:mat,
	                                                   recenter:true,
	                                                   closepath:false,
	                                                   coverall:true,
	                                                   subdivision:1,
	                                                   bothsides:false,
	                                                   flip:false});
	extrude.rotationX = 90;
	extrude.x = extrude.z = 0;
	extrude.y = 400;
	(extrude as Mesh).pushback = true;
	this.scene.addChild(extrude);
	
	var matsphere:IMaterial = new BitmapMaterial(generateFromLib("spheretexture"));
	target = new Sphere ({material:matsphere,
	                      segmentsH:5,
	                      segmentsW:5,
	                      radius:50});
	target.pushfront = true;
	scene.addChild(target);
}

To update the y of the sphere at runtime, just pass the x and z coordinates of the sphere in the getLevel method to return the surface y. Note that thanks to the orientation of the mesh, the z value is negative in this case.

private function render(e:Event):void
{
	if(target.x > 2400){
		target.x = -2400;
		target.z = -1500 + Math.random()*3000;
	}else{
		target.x += 50;
	}
	target.rotationZ  -= 30;
	target.y = elevationreader.getLevel(target.x, -target.z, 20);
	view.render();
}