Forked from: makc3d's forked from: BumpMap diff:58 Shadow casting test shadow mapping test (warning: CPU killer) makc3d forked:0favorite:2lines:114license : see code comments modified : 2009-03-12 18:39:32 Embed Tweet package { import flash.display.*; import flash.events.*; import flash.filters.*; import flash.geom.*; import sandy.core.*; import sandy.core.data.*; import sandy.core.scenegraph.*; import sandy.primitive.*; import sandy.materials.*; import sandy.materials.attributes.*; import sandy.view.*; // shadow mapping test (warning: CPU killer) [SWF (width=465, height=465, backgroundColor=0, frameRate=10)] public class Test extends BasicView { private const S:int = 150; private const Q:int = 10; private const Y:Number = 30; private var angle:Number = 0; private var texture:BitmapData; private var hmap:BitmapData, lmap:BitmapData, tmap:BitmapData; private var blur:BlurFilter = new BlurFilter (2, 2, 2); private var stmp:Shape = new Shape; public function Test() { super (); init (465, 465); render (); // planes suck - use hexagonal grid instead var p:Plane3D = addHorizontalPlane (S, S, Q, new Point3D (0, -0.6 * S, 0)); texture = new BitmapData (S, S, false, 0); p.appearance = makeBitmapAppearance (texture); // engine light p.appearance.frontMaterial.attributes = new MaterialAttributes (new LightAttributes (false, 0.6)); p.appearance.lightingEnable = true; // build random terrain // this is not really smooth terrain, but whatever var r:Number = 0; for each (var v:Vertex in p.geometry.aVertex) { //r = 0.5 * (r + Math.random ()); v.y = Y * r; if (Math.random () < 0.1) v.y = Y / 2; } // update face normals for each (var face:Polygon in p.aPolygons) face.updateNormal (); // render terrain heightmap renderHeightMap (p, graphics, S); hmap = new BitmapData (S, S, false, 0); hmap.draw (this); // noisy texture tmap = new BitmapData (S, S, false, 0); tmap.noise (123, 200, 255, 7, true); tmap.draw (tmap, null, new ColorTransform (1, 0xEF / 255.0, 0x7F / 255.0)); // make light map lmap = new BitmapData (S, S, false, 0); var b:Bitmap = new Bitmap (lmap); b.x = S; addChild (b); // "sun" graphics.beginFill (0xFFEF7F); graphics.drawCircle (465 * 0.5, 465 * 0.5, 10); } override public function simpleRender(e:Event = null):void { // spin light (map coords) angle = mouseX / 100; var light:Point3D = new Point3D (Math.sin (angle), Math.cos (angle), 0.25); light.normalize (); // face light (real coords) camera.x = +2 * S * light.x; camera.y = +2 * S * light.z; camera.z = -2 * S * light.y; camera.lookAt (0, 0, 0); scene.light.setDirection (camera.x, -camera.y, camera.z); // re-build shadow map lmap.lock (); lmap.fillRect (lmap.rect, 0); var m:Number = 0; m1.identity (); while (m < 255) { m1.tx += light.x; m1.ty += light.y; m += 2; // TODO: m = f (light) stmp.graphics.clear (); stmp.graphics.beginBitmapFill (hmap, m1, true, true); stmp.graphics.drawRect (0, 0, S, S); stmp.graphics.endFill (); lmap.draw (stmp, null, new ColorTransform (1, 1, 1, 1, -m, -m, -m), BlendMode.LIGHTEN, null, true); } lmap.draw (hmap, null, null, BlendMode.DIFFERENCE); // transform into light map lmap.draw (lmap, null, new ColorTransform ( -10, -10, -10, 1, 255, 255, 255)); lmap.threshold (lmap, lmap.rect, lmap.rect.topLeft, "<", 0x808080, 0xFF404030, 0xFFFFFF); lmap.threshold (lmap, lmap.rect, lmap.rect.topLeft, ">", 0x808080, 0xFFFFFFFF, 0xFFFFFF); lmap.unlock (); lmap.applyFilter (lmap, lmap.rect, lmap.rect.topLeft, blur); texture.draw (tmap); texture.draw (lmap, null, null, BlendMode.MULTIPLY); super.simpleRender (e); } private function renderHeightMap (p:Plane3D, g:Graphics, s:int):void { for each (var t:Polygon in p.aPolygons) renderHeightMapElement (t, g, s); } private var m1:Matrix = new Matrix; private var m2:Matrix = new Matrix; private function renderHeightMapElement (t:Polygon, g:Graphics, s:int):void { var h0:Number = t.a.y / Y; var h1:Number = t.b.y / Y; var h2:Number = t.c.y / Y; var v0:Number = -100, v1:Number = 0, v2:Number = 100; var u0:Number = (h0 - 0.5) * (32768 * 0.05); var u1:Number = (h1 - 0.5) * (32768 * 0.05); var u2:Number = (h2 - 0.5) * (32768 * 0.05); var uv:UVCoord = UVCoord (t.aUVCoord [0]); m2.tx = uv.u * s; m2.ty = uv.v * s; if ( (int (u0 * 0.1) == int (u1 * 0.1)) && (int (u1 * 0.1) == int (u2 * 0.1)) ) { // solid color case g.beginFill ( 0x10101 * Math.round (0xFF * h0) ); } else { // gradient case if ((u2 - u1) * (u1 - u0) > 0) { var tmp:Number = v1; v1 = v2; v2 = tmp; } m1.a = u1 - u0; m1.b = v1 - v0; m1.c = u2 - u0; m1.d = v2 - v0; m1.tx = u0; m1.ty = v0; m1.invert (); uv = UVCoord (t.aUVCoord [1]); m2.a = uv.u * s - m2.tx; m2.b = uv.v * s - m2.ty; uv = UVCoord (t.aUVCoord [2]); m2.c = uv.u * s - m2.tx; m2.d = uv.v * s - m2.ty; m1.concat (m2); g.beginGradientFill ("linear", [0, 0xFFFFFF], [1, 1], [0, 255], m1); } g.moveTo (m2.tx, m2.ty); for each (uv in t.aUVCoord) g.lineTo (uv.u * s, uv.v * s); g.endFill (); } } } Code Fullscreen Preview Fullscreen keiso : 3d keim_at_Si : 3dRender 3d Render aUVCoord UVCoord texture Polygon Point3D aPolygons angle tx ty topLeft attributes LightAttributes light aVertex updateNormal addHorizontalPlane makeBitmapAppearance threshold appearance lightingEnable