package { import flash.display.BlendMode; import flash.display.TriangleCulling; import flash.display.Sprite; import flash.display.Shape; import flash.display.Stage; import flash.display.BitmapData; import flash.display.Bitmap; import flash.events.Event; import flash.geom.PerspectiveProjection; import flash.geom.Matrix3D; import flash.geom.Vector3D; import flash.geom.Utils3D; public class GlobeRenderingTest extends Sprite { [Embed(source="world_map_small.jpg")] // texture private var MappingTexture:Class; [Embed(source="gradientGlobe.jpg")] // shading private var GradientBitmap:Class; protected var shape:Shape; protected var shading:Shape; protected var vertices:Vector.; // x,y,z -coordinates protected var vertexNormals:Vector.; // normals for each coordinate protected var indices:Vector.; // triangle mesh protected var uvtData:Vector.;// texture mapping u,v,t-coordinates protected var uvtShadingData:Vector.; // u,v,t-coordinates for shading protected var projectedVerts:Vector.;// x,y-screen coordinates protected var bitmapData:BitmapData; protected var gradientBitmapData:BitmapData; private var i:int; protected var lightDirection:Vector3D = new Vector3D(0.6,0.,0.80); protected var lightMovement:Matrix3D; protected var perspective:PerspectiveProjection; protected var projectionMatrix:Matrix3D; protected var rotAngle:Number = -115.0; public function GlobeRenderingTest():void { init(); } protected function init():void { bitmapData = new MappingTexture().bitmapData; gradientBitmapData = new GradientBitmap().bitmapData; // spr, the container for projected world map: addChild(shape= new Shape()); // the container for shading: addChild(shading = new Shape()); shading.blendMode = BlendMode.HARDLIGHT; // middle of the stage: shading.x= shape.x= stage.stageWidth>>1; shading.y= shape.y= stage.stageHeight>>1; perspective= new PerspectiveProjection(); perspective.fieldOfView = 35.0; // camera angle, in degrees vertices = new Vector.(); projectedVerts = new Vector.(); uvtData = new Vector.(); uvtShadingData = new Vector.(); var radius:Number = 1.0; var j:int, ix:Number = 0.0, iy:Number = 0.0; // u and v-divisions on the sphere: var n:int = 32, m:int = 16; vertexNormals= new Vector.(); for (i=0 ; i!=n; i++) { ix= i/(n-1)*Math.PI*2.0; for (j=0 ; j!=m; j++) { iy= (j/(m-1)-0.5)*Math.PI; // polar coordinate: var vc:Vector3D = new Vector3D( Math.cos(iy)*Math.cos(ix), Math.sin(iy), Math.cos(iy)*Math.sin(ix) ); // in case a sphere the normal is so easy: vertexNormals.push(vc); // the coordinate, scaled by radius vertices.push( radius*vc.x, 1.05*radius*vc.y, radius*vc.z); // t=0.0, counted by projectVectors: uvtData.push( i/(n-1),j/(m-1), 0.0); uvtShadingData.push(i/(n-1),j/(m-1), 0.0); // initialize also the size of this array projectedVerts.push(0.0,0.0); } } // the triangle mesh: indices= new Vector.(); var ii:int =0; for (i=0 ; i!=n-1; i++) { for (j=0 ; j!=m-1; j++) { indices.push( ii,ii+m+1,ii+1, ii+m,ii+m+1,ii++); } ii++; } var tmp:Number; // normalize the lightDirection lightDirection.x *= (tmp = 1.0/lightDirection.length); lightDirection.y *= tmp; lightDirection.z *= tmp; // animate the light by rotating around some arbitrary axis: lightMovement = new Matrix3D(); lightMovement.prependRotation(2.1,new Vector3D(0.5,0.8,0.1)); // lightMovement.appendScale(20.0,20.0,20.0); addEventListener(Event.ENTER_FRAME, update); } protected function update(e:Event =null):void { projectionMatrix = perspective.toMatrix3D(); // controls the viewpoint: projectionMatrix.prependTranslation(0.0,0.0,7.0); // rotate the globe: projectionMatrix.prependRotation( rotAngle+=1.7 ,new Vector3D(0.24,0.96,0.0)); Utils3D.projectVectors(projectionMatrix, vertices, projectedVerts, uvtData); /* // in case of a sphere and with no need for z-sorting // this routine has been commented out // // sorting in z var minz:Number; for each (var tr in triangles) { tr.z = uvtData[3*tr.index0+2]; if ((minz=uvtData[3*tr.index1+2])0; i-=3) uvtShadingData[i]=uvtData[i]; var nrml:Vector3D; i=-3; for each (nrml in vertexNormals) { // dotProduct returns the cosine of the angle between // lightDirection and mesh normal, // this value in range -1.0..1.0 is mapped to 0.0..1.0 as u-coordinate uvtShadingData[i+=3] = 0.5+0.5*nrml.dotProduct(lightDirection); } } } }