/** * @see http://b-o-w.jp/blog/2008/12/14/fluffy_fur_rendering/ * テクスチャ一色にして毛がなびくの少なくしてみた */ package { 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.utils.getTimer; [SWF(width=465,height=465,frameRate=60,backgroundColor=0xFFFFFF)] public class Fur extends Sprite { private const FUR_DEPTH:uint = 10; 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 textures:Array = []; private var view:Matrix3D = new Matrix3D(); public function Fur() { x = y = 465 / 2; createGeometry(10, 6); projection.fieldOfView = 60; textures.push(new BitmapData(512, 512, false, 0xCCAA66)); for (var i:uint=1; i<FUR_DEPTH; i++) { textures.push(new Texture(i / FUR_DEPTH * 1.2 + 0.5, 1 - i / FUR_DEPTH)); } addEventListener(Event.ENTER_FRAME, enterFrame); } private function createGeometry(xDiv:uint, yDiv:uint):void { 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, cy, sx * sy); uvtData.push(xr, yr, 0); if (y < yDiv) { var i1:uint = y * (xDiv + 1) + x; var i2:uint = y * (xDiv + 1) + ((x + 1) % (xDiv + 1)); var i3:uint = (y + 1) * (xDiv + 1) + x; var i4:uint = (y + 1) * (xDiv + 1) + ((x + 1) % (xDiv + 1)); indices.push(i1, i2, i3, i3, i2, i4); } } } } private function enterFrame(event:Event):void { var count:Number = getTimer() / 1000 * 60; graphics.clear(); for (var i:uint=0; i<FUR_DEPTH; i++) { var scale:Number = 200 + i * 7; view.identity(); view.appendScale(scale, scale, scale); view.appendRotation(Math.cos(count * 0.0045) * 120, Vector3D.X_AXIS); view.appendRotation(Math.cos(count * 0.0081) * 120, Vector3D.Y_AXIS); view.appendTranslation(0, 0, 850); view.append(projection.toMatrix3D()); Utils3D.projectVectors(view, vertices, projected, uvtData); graphics.beginBitmapFill(textures[i], null, false, true); graphics.drawTriangles(projected, indices, uvtData, TriangleCulling.POSITIVE); count -= 1.5; } } } } import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.geom.ColorTransform; class Texture extends BitmapData { private static var noiseBitmap:BitmapData = createNoiseBitmap(); private static function createNoiseBitmap():BitmapData { var noiseBitmap:BitmapData = new BitmapData(512, 512, false); noiseBitmap.noise(0, 0, 255, BitmapDataChannel.BLUE, false); var palette:Array = []; for (var i:uint=0; i<256; i++) { palette[i] = Math.max(0, Math.pow(i / 0xFF * 1.7 - 0.7, 0.1) * 0xFF); } noiseBitmap.paletteMap(noiseBitmap, noiseBitmap.rect, noiseBitmap.rect.topLeft, null, null, palette); return noiseBitmap; } public function Texture(colorMultiplier:Number, alphaMultiplier:Number) { super(512, 512, true, 0xFF009900); //perlinNoise(64, 64, 1, 0, true, true); copyChannel(noiseBitmap, rect, rect.topLeft, BitmapDataChannel.BLUE, BitmapDataChannel.ALPHA); colorTransform(rect, new ColorTransform(colorMultiplier, colorMultiplier, colorMultiplier, alphaMultiplier)); } } Fur