Beautifl - Flash Gallery

Thumbnail : flash on 2009-12-9
flash on 2009-12-9
psyark 2009-12-09 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

package {
	import flash.display.*;
	import flash.events.Event;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.*;
	import flash.system.Capabilities;
	import flash.utils.getTimer;
	
	[SWF(width=465,height=465,frameRate=60,backgroundColor=0x000000)]
	/**
	 * バンプマップのテスト
	 */
	public class Test30 extends Sprite {
		private static const SEA_HEIGHT:uint = 0x70;
		private var vertices:Vector.<Number>  = new Vector.<Number>(0, false);
		private var projected:Vector.<Number> = new Vector.<Number>(0, false);
		private var indices:Vector.<int>      = new Vector.<int>(0, false);
		private var uvtData:Vector.<Number>   = new Vector.<Number>(0, false);
		private var projection:PerspectiveProjection = new PerspectiveProjection();
		private var heightMap:BitmapData;
		private var normalMap:BitmapData;
		private var texture:BitmapData;
		private var tmp1:BitmapData = new BitmapData(512, 512, false, 0);
		private var tmp2:BitmapData = new BitmapData(512, 512, false, 0);
		private var world:Matrix3D = new Matrix3D();
		private var viewport:Shape = new Shape();
		
		/**
		 * 
		 */
		public function Test30() {
			createGeometry();
			heightMap = createHeightMap(512, 512);
			//heightMap.fillRect(new Rectangle(0, 0, 512, 256), 0xFF000000);
			normalMap = createNormalMap(heightMap, 25);
			texture = createTexture(heightMap);
			
			addChild(new Bitmap(createSpace(465, 465)));
			viewport.x = viewport.y = 465 / 2;
			addChild(viewport);
			projection.fieldOfView = 60;
			
			addEventListener(Event.ENTER_FRAME, enterFrame);
			
			show(new Bitmap(heightMap), {width:115, height:115, x:30, y:30});
			show(new Bitmap(normalMap), {width:115, height:115, x:30, y:175});
			show(new Bitmap(texture), {width:115, height:115, x:30, y:320});
			show(new Bitmap(tmp1), {width:115, height:115, x:320, y:30});
			show(new Bitmap(tmp2), {width:115, height:115, x:320, y:175});
			
			function show(item:DisplayObject, param:Object):void {
				for (var i:String in param) {
					item[i] = param[i];
				}
				addChild(item);
			}
		}
		
		/**
		 * ハイトマップを作成
		 */
		private static function createHeightMap(width:uint, height:uint):BitmapData {
			var heightMap:BitmapData = new BitmapData(width, height, false, 0);
			heightMap.perlinNoise(80, 120, 10, Math.random() * 100, true, true, 0, true);
			heightMap.colorTransform(heightMap.rect, new ColorTransform(1.5, 1.5, 1.5, 1, -0x40, -0x40, -0x40));
			return heightMap;
		}
		
		/**
		 * ハイトマップからノーマルマップを作成
		 */
		private static function createNormalMap(heightMap:BitmapData, multiplier:Number):BitmapData {
			var normalMap:BitmapData = new BitmapData(heightMap.width, heightMap.height, false);
			var vec:Vector3D = new Vector3D();
			var mtx:Matrix3D = new Matrix3D();
			for (var y:int=0; y<heightMap.height; y++) {
				for (var x:int=0; x<heightMap.width; x++) {
					var height:uint = heightMap.getPixel(x, y) & 0xFF;
					if (height >= SEA_HEIGHT) {
						vec.x = (height - (heightMap.getPixel((x + 1) % heightMap.width, y) & 0xFF)) / 0xFF * multiplier;
						vec.y = (height - (heightMap.getPixel(x, (y + 1) % heightMap.height) & 0xFF)) / 0xFF * multiplier;
					} else {
						vec.x = vec.y = 0;
					}
					vec.y *= -1;
					vec.z = 0;
					if (vec.lengthSquared > 1) {
						vec.normalize();
					} else {
						vec.z = Math.sqrt(1 - vec.lengthSquared);
					}
					mtx.identity();
					mtx.appendRotation(y / heightMap.height * 180 - 90, Vector3D.X_AXIS);
					mtx.appendRotation(x / heightMap.width * 360, Vector3D.Y_AXIS);
					vec = mtx.transformVector(vec);
					normalMap.setPixel(x, y,
						(vec.x * 0x7F + 0x80) << 16 |
						(vec.y * 0x7F + 0x80) << 8 |
						(vec.z * 0x7F + 0x80)
					);
				}
			}
			return normalMap;
		}
		
		/**
		 * ハイトマップからテクスチャを作成
		 */
		private static function createTexture(heightMap:BitmapData):BitmapData {
			var texture:BitmapData = new BitmapData(heightMap.width, heightMap.height, false, 0x229900);
			var paletteR:Array = [];
			var paletteG:Array = [];
			var paletteB:Array = [];
			var r:Number;
			for (var i:uint=0; i<256; i++) {
				if (i >= SEA_HEIGHT) {
					r = (i - SEA_HEIGHT) / (256 - SEA_HEIGHT);
					if (r > 0.7) {
						paletteR[i] = (0x99 + 0x66 * (r - 0.7) / (1 - 0.7)) << 16;
						paletteG[i] = (0x66 + 0x99 * (r - 0.7) / (1 - 0.7)) << 8;
						paletteB[i] = (0x00 + 0xFF * (r - 0.7) / (1 - 0.7));
					} else if (r > 0.15) {
						paletteR[i] = (0x00 + 0x99 * (r - 0.15) / (0.7 - 0.15)) << 16;
						paletteG[i] = (0xCC - 0x66 * (r - 0.15) / (0.7 - 0.15)) << 8;
						paletteB[i] = (0x00 + 0x00 * (r - 0.15) / (0.7 - 0.15));
					} else {
						paletteR[i] = (0xCC - 0xCC * r / 0.15) << 16;
						paletteG[i] = (0x99 + 0x33 * r / 0.15) << 8;
						paletteB[i] = (0x33 - 0x33 * r / 0.15);
					}
				} else {
					r = i / SEA_HEIGHT;
					paletteR[i] = 0;
					paletteG[i] = Math.pow(r, 5) * 0x66 << 8;
					paletteB[i] = (r * 0.5 + 0.5) * 0xFF;
				}
			}
			texture.paletteMap(heightMap, texture.rect, texture.rect.topLeft, paletteR, paletteG, paletteB);
			return texture;
		}
		
		private function createGeometry():void {
			var radius:Number = 300;
			var xDiv:uint = 24;
			var yDiv:uint = 16;
			for (var y:uint=0; y<=yDiv; y++) {
				var yr:Number = y / yDiv;
				var cy:Number = Math.cos(yr * Math.PI);
				var sy:Number = Math.sin(yr * Math.PI);
				for (var x:uint=0; x<=xDiv; x++) {
					var xr:Number = x / xDiv;
					var cx:Number = Math.cos(xr * Math.PI * 2);
					var sx:Number = Math.sin(xr * Math.PI * 2);
					vertices.push(cx * sy * radius, -cy * radius, sx * sy * radius);
					uvtData.push(xr, yr, 0);
					if (x < xDiv && y < yDiv) {
						var i1:uint =  y      * (xDiv + 1) + x;
						var i2:uint = (y + 1) * (xDiv + 1) + x;
						indices.push(i1, i2, i1 + 1, i1 + 1, i2, i2 + 1);
					}
				}
			}
		}
		
		private function enterFrame(event:Event):void {
			var light:Vector3D = new Vector3D();
			light.x = +viewport.mouseX / (465 / 2) / Math.SQRT2;
			light.y = -viewport.mouseY / (465 / 2) / Math.SQRT2;
			light.z = Math.sqrt(1 - light.x * light.x - light.y * light.y);
			world.identity();
			world.appendRotation(getTimer() * -0.02, Vector3D.Y_AXIS);
			light = world.transformVector(light);
			world.appendRotation(23.4, Vector3D.Z_AXIS);
			world.appendRotation(60, Vector3D.Y_AXIS);
			world.appendTranslation(0, 0, 900);
			world.append(projection.toMatrix3D());
			Utils3D.projectVectors(world, vertices, projected, uvtData);
			var lighting:ColorMatrixFilter = new ColorMatrixFilter([
				2 * light.x, 2 * light.y, 2 * light.z, 0, (light.x + light.y + light.z) * -0xFF,
				2 * light.x, 2 * light.y, 2 * light.z, 0, (light.x + light.y + light.z) * -0xFF,
				2 * light.x, 2 * light.y, 2 * light.z, 0, (light.x + light.y + light.z) * -0xFF,
				0,           0,           0,           1, 0
			]);
			tmp1.applyFilter(normalMap, normalMap.rect, normalMap.rect.topLeft, lighting);
			tmp2.copyPixels(texture, texture.rect, texture.rect.topLeft);
			tmp2.draw(tmp1, null, null, BlendMode.MULTIPLY);
			viewport.graphics.clear();
			viewport.graphics.beginBitmapFill(tmp2, null, false, true);
			viewport.graphics.drawTriangles(projected, indices, uvtData, TriangleCulling.POSITIVE);
		}
		
		private static function createSpace(width:uint, height:uint):BitmapData {
			var space:BitmapData = new BitmapData(width, height, false);
			space.noise(Math.random() * 256, 0, 255, 7, true);
			var a:Number = 20.4;
			var b:Number = 0xFF * -20;
			space.colorTransform(space.rect, new ColorTransform(a, a, a, 1, b, b, b));
			return space;
		}
	}
}