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; } } } flash on 2009-12-9