Reading the height of a terrain surface with the ElevationReader class

When using a 3D object created with the SkinExtrusion class, it is very common to need to find the height of the surface at a given point. For example, you may want to ensure that a 3D object representing a car is positioned so that it appears above a SkinExtrusion 3D object, simulating the car driving across some terrain. The ElevationReader class can be used for this purpose. When it is created with the same height map supplied to an Elevation object, the getLevel() function returns the corresponding height of points returned by the Elevation generate() function. This value can then be used to position 3D objects relative to a SkinExtrusion 3D object.

The following ElevationReaderDemo application shares much of its code with the SkinExtrusionDemo application. Some additional code has been introduced to create a ElevationReader object, which we use to modify the height of a sphere as it moves randomly across the surface of a SkinExtrusion 3D object.

package  
{

  import away3d.core.utils.Cast;
  import away3d.extrusions.Elevation;
  import away3d.extrusions.ElevationReader;
  import away3d.extrusions.SkinExtrude;
  import away3d.materials.BitmapMaterial;
  import away3d.primitives.Sphere;
  import com.greensock.TweenLite;
  import flash.events.Event;
  import flash.geom.Vector3D;

  public class ElevationReaderDemo extends Away3DTemplate
  {
    [Embed(source="heightmap.jpg")]
    protected var Heightmap:Class;

    [Embed(source="terrain.jpg")]
    protected var Terrain:Class;

    protected var extrude:SkinExtrude;
    protected var sphere:Sphere;
    protected var elevationreader:ElevationReader;

    public function ElevationReaderDemo() 
    {
      super();
    }

    protected override function initScene():void
    {
      super.initScene();

      camera.position = new Vector3D(400, 200, 400);
      camera.lookAt(new Vector3D(0, 0, 0));

      var terrainMaterial:BitmapMaterial = 
        new BitmapMaterial(Cast.bitmap(Terrain));

      var elevation:Elevation = new Elevation();
      var verticies:Array =
        elevation.generate(
          Cast.bitmap(Heightmap), 
          "r", 
          16, 
          16, 
          1, 
          1, 
          0.25
        );

      extrude = new SkinExtrude(verticies, 
        {
          coverall: true, 
          material: terrainMaterial, 
          recenter:true,
          bothsides: true
        }
      );

      extrude.rotationX = 90;
      extrude.x = extrude.y = extrude.z = 0;

      scene.addChild(extrude);

The process of creating an ElevationReader object is very similar to creating an Elevation object. First a new instance of the ElevationReader class is instantiated.

      elevationreader = new ElevationReader();

We then call the traceLevels() function, supplying exactly the same parameters we supplied to the Elevation generate() function. It is important that the parameters passed to the generate() and traceLevels() functions are the same, because this ensures that the values returned by the getLevel() function below are consistent with the height of the SkinExtrude 3D object.

      elevationreader.traceLevels(
        Cast.bitmap(Heightmap), 
        "r", 
        16, 
        16, 
        1, 
        1,
        0.25
      );

We then create a sphere that we will move randomly across the surface of the terrain.

      sphere = new Sphere({radius: 10});

      scene.addChild(sphere);

Finally, we call the moveSphere() function to kick off the tweening operation.

      moveSphere();
    }

    override protected function onEnterFrame(event:Event):void 
    {
      super.onEnterFrame(event);

Every frame we adjust the height of the sphere to match the height of the terrain, which is determined by calling the getLevel() function.

We supply the position of the sphere along the X and Z axes as the first two parameters. This may seem confusing at first when you consider that these parameters are actually called x and y. The reason we supply the spheres position on the Z axis to the y parameter is because the SkinExtrude 3D object was rotated 90 degrees around the X axis. Unfortunately, the ElevationReader class does not have the same ability to be rotated, which means we need to manually translate the movement of the sphere along the Z axis in world space into vertical movement along the Y axis in the local space of the ElevationReader.

The third parameter is used to apply an offset to the height returned by the getLevel() function.

If you look back at the code used to create the SkinExtrude 3D object, you will notice that the recenter init object parameter is set to true. This has the effect of setting the origin of the SkinExtrude 3D object to its center, as opposed to one of its corners. This also means that the lowest point of the SkinExtrude 3D object (that is, the points that relate to the darkest areas on the corresponding height map) will be below this centre point, while the highest point will be above the centre.

We don't need to adjust for the centering of the SkinExtrude 3D object when supplying the x and y parameters to the getLevel() function, as these values are assumed to be centered. However, the value returned by the getLevel() function is always positive—it does not take into account the effect that the centering has on the relative height of the SkinExtrude 3D object. This is why we calculate the offset by first subtracting 255 * 0.25 * 0.5, which will adjust the returned value so it relates to the actual minimum height of the matching SkinExtrude 3D object (remember that the maximum height of the SkinExtrude 3D object is 255 units, which we scaled by 0.25, and then centered it, which dropped the position of the terrain by half its height). We then add the radius of the sphere to ensure the bottom of the sphere is above the SkinExtrude 3D object.

Tip

If the SkinExtrude recenter init object parameter was set to false, we would need to adjust the values supplied to the x and y parameters like so (where 128 is half the width and depth of the terrain):

sphere.y = elevationreader.getLevel(
sphere.x + 128, 
-sphere.z + 128, 
sphere.radius
);
      sphere.y = elevationreader.getLevel(
        sphere.x, 
        -sphere.z, 
        -255 * 0.25 * 0.5 + sphere.radius
      );
    }

The moveSphere() function is used to set up a recursive tweening operation that will move the sphere to a random position over the terrain.

    protected function moveSphere():void
    {
      TweenLite.to(sphere, 2, 
        {
          x: Math.random() * 256 - 128, 
          z: Math.random() * 256 - 128,

By setting the onComplete parameter to recursively call the moveSphere() function, we are ensuring that the sphere will continuously move to random points.

          onComplete: moveSphere
        }
      );
    }
  }
}

When this application is run, you will see that the sphere remains above the terrain as it moves across its surface.

Reading the height of a terrain surface with the ElevationReader class
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.223.169