[Flash 11]

Fevrier 2014

2D lighting with normal map, take 2

My first experiment with normal map and colorm matrix

Here another try, without ColorMatrixFilter (click on the swf then you can use space bar to remove the Color )

[swfobj src=”https://yopsolo.fr/ressources/medusa.swf” alt=”Animation Flash” width=”512″ height=”512″ class=”flashObject” AllowScriptAccess=”always” allowfullscreen=”true” bgcolor=”#ffffff” required_player_version=”11″]


Assets used for this demo :

Another build of the previous scene using this technique
Click on the swf then you can use space bar to remove the Color and dbl click to go fullscreen.

[swfobj src=”https://yopsolo.fr/ressources/LightningCPU2.swf” alt=”Animation Flash” width=”640″ height=”360″ class=”flashObject” AllowScriptAccess=”always” allowfullscreen=”true” bgcolor=”#ffffff” required_player_version=”11″]

Assets used for this demo :


package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageDisplayState;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.geom.Vector3D;
	import flash.ui.Keyboard;
	import flash.ui.Mouse;
	
	/**
	 * ...
	 * @author YopSolo
	 */
	public class Main extends Sprite
	{
		[Embed(source="assets/diff.png")]
		private const DiffuseClass:Class;
		[Embed(source = "assets/norm.png")]
		private const NormClass:Class;
		[Embed(source = "assets/lum.png")]
		private const LumClass:Class		
		
		private var normalMap:BitmapData;
		private var lightMap:BitmapData;
		private var dat:BitmapData;
		
		// ---------------------
		
		private const WIDTH:int = 1280;
		private const HEIGHT:int = 720;
		
		private var light:Vector3D;
		private var lightDst:int = 96;
		private var norm:Vector.;
		private var Nm:Vector3D = new Vector3D();
		private var Nl:Vector3D = new Vector3D();
		
		private const LIMIT:int = 128;
		private var power:int = 10000;
		private var diffuse:Bitmap;
		
		public function Main():void
		{
			if (stage)
				init();
			else
				addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			
			// config stage
			stage.align = StageAlign.TOP_LEFT;
			//stage.scaleMode = StageScaleMode.NO_SCALE;
			//stage.quality = StageQuality.LOW;
			stage.stageFocusRect = false;
			stage.tabChildren = false;
			
			light = new Vector3D(0, 0, lightDst);
			norm = new Vector.(WIDTH * HEIGHT, true); // wow such a big vector :D
			
			// diffuse
			diffuse = new DiffuseClass();
			addChild(diffuse);
			
			// normal map
			normalMap = (new NormClass() as Bitmap).bitmapData;
			
			// self light map
			lightMap = (new LumClass() as Bitmap).bitmapData;
			
			// my lightning
			dat = new BitmapData(normalMap.width, normalMap.height, false, 0x0);
			var bmp:Bitmap = new Bitmap(dat);
			bmp.blendMode = BlendMode.MULTIPLY;
			addChild(bmp);
			
			// filling my vector
			var xx:int = 0;
			var yy:int = 0;
			var coul:Number;
			var idx:int = 0;
			while (xx < WIDTH)
			{
				yy = 0;
				while (yy < HEIGHT)
				{
					coul = normalMap.getPixel(xx, yy);
					idx = (xx + (yy * WIDTH));
					norm[idx] = new Vector3D((-128 + ((coul >> 16) & 0xFF)), (-128 + ((coul >> 8) & 0xFF)), (-128 + (coul & 0xFF)));
					norm[idx].normalize();
					++yy;
				}
				;
				++xx;
			}
			
			Mouse.hide();
			
			stage.doubleClickEnabled = true;
			stage.addEventListener(MouseEvent.DOUBLE_CLICK, _onClickFullScreen);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, update);
			stage.addEventListener(KeyboardEvent.KEY_UP, _onSpaceBar);
		}
		
		private function _onSpaceBar(e:KeyboardEvent):void
		{
			if (e.keyCode == Keyboard.SPACE)
			{
				diffuse.visible = !diffuse.visible;
			}
		}
		
		private function _onClickFullScreen(e:MouseEvent):void
		{
			stage.fullScreenSourceRect = new Rectangle(0, 0, 1280, 760);
			stage.displayState = StageDisplayState.FULL_SCREEN;
		}
		
		private function update(e:MouseEvent):void
		{
			e.updateAfterEvent();
			e.stopImmediatePropagation();
			
			// --
			light.x = mouseX;
			light.y = mouseY;
			
			// --
			var xxMin:int = mouseX - LIMIT;
			if (xxMin < 0)
			{
				xxMin = 0;
			}
			var yyMin:int = 0;
			yyMin = mouseY - LIMIT;
			// --
			var xxMax:int = mouseX + LIMIT;
			if (xxMax > WIDTH)
			{
				xxMax = WIDTH;
			}
			var yyMax:int = mouseY + LIMIT;
			if (yyMax > HEIGHT)
			{
				yyMax = HEIGHT;
			}
			// --
			var len:Number;
			var c:uint;
			
			// --
			dat.fillRect(dat.rect, 0x444444);
Nl = new Vector3D();
			while (xxMin < xxMax)
			{
				yyMin = mouseY - LIMIT;
				if (yyMin < 0)
				{
					yyMin = 0;
				}
				while (yyMin < yyMax)
				{
					Nm = norm[(xxMin + (yyMin * WIDTH))];
					Nl.x = (xxMin - light.x);Nl.y = (yyMin - light.y);Nl.z = -(light.z);				len = Nl.length;
					Nl.normalize();
					c = ((power * (1 - Nm.dotProduct(Nl))) / len);
					if (c > 0xFF)
						c = 0xFF;
					dat.setPixel(xxMin, yyMin, (((c << 16) | (c << 8)) | c));
					++yyMin;
				}
				++xxMin;
			}
			
			// self illum
			dat.draw(lightMap, null, null, BlendMode.ADD);
		}
	
	}

}