package com.dafishinsea.tutorials.normalmap { import flash.display.BitmapData; import flash.display.Sprite; import flash.display.TriangleCulling; import flash.events.Event; import flash.geom.Matrix3D; import flash.geom.PerspectiveProjection; import flash.geom.Utils3D; import flash.geom.Vector3D; import flash.text.TextField; /** * procedural model of a Pumpkin to demonstrate use of normal map */ [SWF(backgroundColor="0x000000", width="800", height="600", frameRate="20")] public class NormalMap1 extends Sprite { private var vertices:Vector.; private var projectedVerts:Vector.; private var numverts:int; private var indices:Vector.; private var uvts:Vector.; private var texture:BitmapData; private var perspective:PerspectiveProjection; private var projMatrix:Matrix3D; private var sphereRadius:Number; private var sphereCenter:Vector3D; private var rows:int;//number of times the sphere is sliced to form segments private var cols:int; private const PI:Number = Math.PI;//half revolution in radians private const HALFPI:Number = Math.PI/2;//1/4 revolution in radians private const TWOPI:Number = 2*Math.PI;//full revolution in radians private var canvas:Sprite; private var r:Number = 0; //the number of segments = num slices - 1 //this is the same as lines of longitude //thus there are twice as many as horizontal slices public function NormalMap1() { init(); createMesh(); addEventListener(Event.ENTER_FRAME, onEnterFrame); addEventListener(Event.RENDER, render); //render(); } private function onEnterFrame(event:Event):void { r = r + 0.2; prerender(); stage.invalidate(); } /** * initialize common properties */ private function init():void { perspective = root.transform.perspectiveProjection; texture = new BitmapData(800,800,false,0xCCCCCC); sphereRadius = 100; //sphereCenter = new Vector3D(stage.stageWidth/2, stage.stageHeight/2, 200); cols = 40; rows = 20; numverts = (cols+1)*(rows+1); vertices = new Vector.(numverts*3);//x,y,z for each vertex projectedVerts = new Vector.(numverts*3); uvts = new Vector.(numverts*3); indices = new Vector.(); //we need to work around the fact that Utils3D.projectVectors disregards the projection center //of the projectionMatrix it is passed .. it always projects around 0,0 //so we must render things on a canvas centered on stage canvas = new Sprite(); canvas.x = stage.stageWidth/2; canvas.y = stage.stageHeight/2; addChild(canvas); } /** * create the mesh of the Sphere */ private function createMesh():void { var lon_incr:Number = TWOPI/cols; var lat_incr = PI/rows; var lon:Number = 0;//angle of rotation around the y axis, *in radians* var lat:Number = 0;//angle of rotation around the x axis var x:Number, y:Number, z:Number; var vnum:int = 0; var ind:int = 0; //a full rotation is PI radians for(var h:int = 0; h <= rows; ++h) { y = sphereRadius*Math.cos(lat);//need to shift angle downwards by 1/4 rev for(var v:int = 0; v <= cols; ++v) { x = sphereRadius*Math.cos(lon)*Math.sin(lat); z = sphereRadius*Math.sin(lon)*Math.sin(lat);//seen from above, z = y //add vertex triplet vertices[vnum] = x; vertices[vnum+1] = y; vertices[vnum+2] = z; vnum+=3; //add indices if(h < rows && v < cols){ indices.push(ind, ind+1, ind + cols+1); indices.push(ind + cols+1, ind+1, ind + cols + 2); } ind+=1; lon += lon_incr; } lat += lat_incr; } } /** * prerender the sphere -- project vertices using rotated matrix */ private function prerender():void { projMatrix = perspective.toMatrix3D(); projMatrix.prependTranslation(0,0,400); projMatrix.prependRotation(r, new Vector3D(0,1,0)); Utils3D.projectVectors(projMatrix, vertices, projectedVerts,uvts); } /** * render */ private function render(event:Event):void { canvas.graphics.clear(); canvas.graphics.beginFill(0xFFFFFF); canvas.graphics.lineStyle(1,0xcccccc,1); canvas.graphics.drawTriangles(projectedVerts, indices, null /* uvts */, TriangleCulling.POSITIVE); canvas.graphics.endFill(); } } }