Away3D the right timing

Flash

bees

A new computer is great, but the day I upgraded to a MacBook Pro, a little issue became obvious… I was using a G5 and a G4 to make my demos (and still do), not because I love pain, but because if you dev only on new machines, you can be sure your client will call you and accuse you of smelting his CPU…

The day I ran the demo shown above, it was clear (and hilarious) that the code I wrote one day before on the G4 was running a bit faster on the new mac… In this case, the bees were flying like crazy. So I’ve written a little class to correct this, and with a surprisingly short and easy code, a time based animation can ensure that your 3D runs the same on every machine. And these days, the power gap between machines can be huge. In this demo, the time base runs exact the same on my G5, G4 and on the macbook pro. Only the smoothness and fps are (very) different, since the bees need to cover greater distances on updates on the G4 than on the faster mac. This is especially visible when you have increases for properties in your code like position, (obj.x += value) or rotations…. and this demo is just full of those!

Here the version not timebased (obj.y += value)
and here
the version where the animations are timebased (obj.y += tb.increase(value) )

The lucky ones like me with both fast and a slow machines will be able to see the difference very quickly. For the people having a machine as powerful as a G5, they will see no differences since this is the machine that I’ve used for the speed base… For the ones who wanna keep doing 3D for clients with older machines, this handy little class will soon land in the Away3D trunk.

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();
}

Away3D Fog filter tutorial

Flash, Tutorials

fog1Watch Full Movie Online Streaming Online and Download

This tutorial shows you how to use the fog filter using the Away3D 2.0 library or higher.

A little word on the fog filter,
The simulation of a saturated atmosphere created by the fog filter is not only there to enhance the graphical look of a scene, it’s also a very good way of improving the rendering performance of your project. At it’s heart, the fog filtering processes a depth filter as well. In other words, according to your fog filter maxZ property, all faces at a distance greater than this value are not processed by the renderer. The fog filter reaches a 100% alpha value at this given depth value, which equates to a solid 100% color. Note that a ZDepth filter class is also available if you do not wish to use the fog but benefit from the depth filtering.

FogFilter properties

– minZ the nearest distance from the camera, this value represents where the fog should start

– maxZ the furthest distance from the camera, this value represents where the fog should end

– subdivisions the fog is composed of a series of layers inserted in the view between the rendered triangles – this property sets the number of layers. The alpha values set internally are graduated according to this value.

– material at this time of development the fog filter supports only solid colors like the ColorMaterial class. This is where you set your color information
by default the filter has a white color set.

How to implement the fog filter into your code

	//create a new material
	var fogMaterial:ColorMaterial = new ColorMaterial(0xBCC687);

	//create a new fogfilter using the material
	var fog:FogFilter = new FogFilter({minZ:6500,
						maxZ:13200,
						subdivisions:20,
						material:fogMaterial});

	//create a renderer using the filter
	var basicrenderer:IRenderer = new BasicRenderer(fog);

	//create a view using the renderer
	_view = new View3D({scene:new Scene3D(),
				renderer:basicrenderer});

	_view.x = stage.stageWidth / 2;
	_view.y = stage.stageHeight / 2;
	addChild(_view);

The images below should give you an idea of the way it works

fog2
In this case if this elevation were to be 1000×1000, minZ would be set at 200, and the maxZ at 900

fog3
Here it could be something like minZ 400 and maxZ 550

fog4
And here we would have something like minZ 10 and maxZ 500

this images above are displaying a subdivision of 7. Feel free to experiment with more layers, since the look and feel is highly dependent on the way the layers blend with each other, the amount of faces in between, and their respective sizes on screen.

Away3D Lathe tutorial

Flash, Tutorials

lathe

This tutorial shows you how to use the Lathe class using the Away3D 1.9.4 library or higher. The class is located in the extrusions package.

A word about the Lathe class
The Lathe class allows you to generate a mesh at runtime from an array of Number3Ds rotated around a given axis. With it, you can generate simple shapes like a cylinder, or more visually complex ones like a bottle, glass, vase or spring. It also offers the ideal solution to generating a panoramic skyline where the mesh needs to take up only a portion of the screen, but creates a 360° environment.
As well as a great diversity of properties, generation can be easily automated allowing you to create shapes from an xml definition file, DB, webservice etc. Since you do not need to load geometry definition files, loading time of your project is reduced when using the lathe.

The class contains a lot of properties that allow you to get many different results from simple changes in the constructor.

The properties:
– axis:String – the axis around which the lathe rotates.
– rotations:Number – the number of rotations used. Note that integers (whole rotations) are not necessary. The minimum possible value is 0.1.
– subdivision:int – how many segments define the geometry, the default is 2.
– offsetradius:int – offsets all points from the rotation axis, the default is set to 0.
– scaling:Number – global scale for the produced object, the default is set to 1.
– materials:Object – multiple materials (see below for details).
– material:IMaterial – a single material defined on your model.
– omit:String – string that defines which part of the geometry can be ignored during the building process: possible values include “front, back, top, bottom, left, right”, the default is set to “”. Note that this is only applicable if the thickness is greater than 0.
– tweek:Object – object containing cumulative offset values to generate spring like shapes (see below for more details).
– thickness:Number – the thickness of the produced shape, non-zero values create an evenly distributed inner and outer side from the central values of the rotated vertices, the default is set to 0.
– coverall:Boolean – true if the texture is stretched over the entire geometry, otherwise it is repeated per segment, the default is set to true.
– recenter:Boolean – true if the generated object has its pivot point set at the center of it’s geometry, otherwise it is defined as the first Number3D passed to the constructor, the default is set to false.
– flip:Boolean – true if the faces generated require reversing, the default is set to false.

Below is a graphical representation of a resulting Lathe object with color-coded property representations.

tweek1
Click to enlarge

material and materials properties:
To apply a single material to the lathe class the property material:IMaterial is used like any other primitive, which will cover the whole geometry by default or per-segment if the coverall property is set to false.

In cases where the thickness option is used, you can apply multiple materials on the same lathe object: defined as front, back, top, bottom, left, right and defaultmaterial in the materials object. For example:

var oMat:Object = {front:material1,
                   back:material2,
                   left:material2,
                   defaultmaterial:anothermat};

can be passed to the init object like so:

var lathe = new Lathe(points, {materials:oMat})

Note that the object property defaultmaterial takes the place of the omitted definitions for top, bottom, right and up. This can be used, for instance, if you were creating a lathe object for a plate. You would use a porcelain texture everywhere except on the front where you would add some extra colors defined in a “front” material.

How to implement the Lathe class into your code
The first thing you need to do is import the Lathe and Number3D classes into your project class. The Number3D class is required to define the “profile points” you want to rotate around the given axis.

import away3d.extrusions.Lathe;
import away3d.core.math.Number3D;

The following example represents a lathe definition for a simple glass shape.

private function generateLatheObject():void
{
	var aPoints = new Array();
	aPoints.push(new Number3D(280, 250, 0));
	aPoints.push(new Number3D(250, 0, 0));
	aPoints.push(new Number3D(0, 0, 0));

	var mat:BitmapMaterial = new BitmapMaterial(myBitmapData); 
	var lathe:Lathe = new Lathe(aPoints, {material:mat,
                                          axis:"y",
                                          rotations:1,
                                          subdivision:10,
                                          coverall:true,
                                          recenter:true});
	scene.addChild(lathe);
}

if finer definition is required, you can increase the value of the “subdivisions” property, and add more Number3Ds to the profile points array. This would display the same shape on screen, but with many more faces.

var aPoints = new Array();
aPoints.push(new Number3D(280, 250, 0));
aPoints.push(new Number3D(265, 125, 0));
aPoints.push(new Number3D(250, 0, 0));
aPoints.push(new Number3D(125, 0, 0));
aPoints.push(new Number3D(0, 0, 0));

To add thickness, just pass thickness:value in the init object

The tweek object:
If you pass a tweek object to the init object, tweek:{x:Number,y:Number,z:Number,radius:Number} you can influence the circular way vertices are generated. The defined x, y and z values add a cumulative offset to the points as they are rotated, in the x, y and z directions respectively. The radius value adds a cumulative offset radially from the central axis of the lathe.

A few examples using the tweek object.

Here same as above, we define a profile from an array of Number3Ds, in this case forming a flipped “C” shape.

var aPoints = new Array();
aPoints.push(new Number3D(100, 300, 0));
aPoints.push(new Number3D(200, 200, 0));
aPoints.push(new Number3D(200, 100, 0));
aPoints.push(new Number3D(100, 0, 0));

tweek1

var lathe:Lathe = new Lathe(aPoints, {material:mat, 
                                      axis:"y",
                                      rotations:3,
                                      subdivision:40,
                                      scaling:1,
                                      coverall:true,
                                      recenter:false
                                      tweek:{x:0,
                                             y:10,
                                             z:0,
                                             radius:400},
                                      bothsides:true});

tweek2

var lathe:Lathe = new Lathe(aPoints, {material:mat,
                                      axis:"y",
                                      rotations:6,
                                      offset:-400,
                                      subdivision:60,
                                      scaling:1,
                                      coverall:true,
                                      recenter:false
                                      tweek:{x:0,
                                             y:1.5,
                                             z:0,
                                             radius:100},
                                      bothsides:true});

tweek3

var lathe:Lathe = new Lathe(aPoints, {material:mat,
                                      axis:"y",
                                      rotations:1.5,
                                      subdivision:60,
                                      scaling:1,
                                      coverall:true,
                                      recenter:false,
                                      tweek:{x:0,
                                             y:5,
                                             z:0,
                                             radius:0},
                                      bothsides:true});