リフラクションマッピング
DisplacementMapFilter と ConvolutionFilter使えば,
屈折マッピングも余裕で出来たりする.
ホントすげーよ,ActionScript3のビットマップ操作系関数.
このC++ライブラリが欲しい.
[10/4追記:ソース貼るの忘れてた]
以下ソースコード.
ライセンスはPublic Domainです.
//---------------------------------------- // 2D metaball + reflaction map // written by keim +Si+ // licence: PD //---------------------------------------- package { import flash.display.*; import flash.events.*; import flash.geom.*; import flash.filters.*; import flash.utils.*; import flash.text.*; [SWF(width="240", height="240", backgroundColor="#406080", frameRate=30)] public class main_ref extends Sprite { static public var base:BitmapData; // base image static private var temp:BitmapData; // tempolaly static private var bump:BitmapData; // bump image static private var alph:BitmapData; // alpha image static private var pixels:BitmapData; // displaying image static private var screen:Bitmap; // displaying image static private var balls:Array; // meta-balls array static private var ptBallsCenter:Point = new Point(); // balls center position static private var matFace:Matrix = new Matrix(); // face matrix static private var convx:ConvolutionFilter; // convolution filter for x differencial static private var convy:ConvolutionFilter; // convolution filter for y differencial static private var disp:DisplacementMapFilter; // displacement filter for refraction static private var conv:ConvolutionFilter; // convolution filter for lighting static private var colt:ColorTransform; // color matrix for cutout static private var color:ColorTransform; // color matrix for coloring static private var face:BitmapData; // face image static private var floor:BitmapData; // floor image public function main_ref() { var i:int; // bitmaps base = new BitmapData(240, 240, false, 0x000000); temp = new BitmapData(240, 240, false, 0x000000); bump = new BitmapData(240, 240, false, 0x000000); alph = new BitmapData(240, 240, true, 0x000000); pixels = new BitmapData(240, 240, false, 0x000000); screen = new Bitmap(pixels); // create filter instance colt = new ColorTransform(32,32,32,1,-1280,-1280,-1280,0); conv = new ConvolutionFilter(3, 3, [1,0,0,0,0,0,0,0,-1], 0.4, 128); convx = new ConvolutionFilter(3, 3, [0,0,0,-1,0,1,0,0,0], 0.2, 128); convy = new ConvolutionFilter(3, 3, [0,-1,0,0,0,0,0,1,0], 0.2, 128); disp = new DisplacementMapFilter(bump, bump.rect.topLeft, BitmapDataChannel.RED, BitmapDataChannel.GREEN, 40, 40); color = new ColorTransform(1,1,1,1,0,0,0,0); // draw meta-ball gradation ball.pat = new BitmapData(ball.R*2,ball.R*2,false,0); var shp:Shape = new Shape(); var mtx:Matrix = new Matrix(); mtx.createGradientBox(ball.R*2,ball.R*2,0,0); shp.graphics.beginGradientFill(GradientType.RADIAL, [0x808080,0x000000], [1,1], [0,255], mtx); shp.graphics.drawRect(0,0,ball.R*2,ball.R*2); shp.graphics.endFill(); base.draw(shp); base.draw(shp, null, null, BlendMode.MULTIPLY); var blr:BlurFilter = new BlurFilter(4, 4, 4); ball.pat.applyFilter(base, ball.pat.rect, ball.pat.rect.topLeft, blr); // draw face face = new BitmapData(48, 16, true, 0x00000000); var tf:TextField = new TextField(); tf.width = 48; tf.height = 16; tf.defaultTextFormat = new TextFormat("MS Gothic", 12, 0x000000, null, null, null, null, null, TextFormatAlign.CENTER); tf.text = "o゚ω゚o"; face.draw(tf); // draw floor floor = new BitmapData(240, 240, false, 0xffffff); shp.graphics.clear(); shp.graphics.lineStyle(2, 0x000000); for (i=0; i<4; i++) { shp.graphics.moveTo(i*60+30, 0); shp.graphics.lineTo(i*60+30, 240); shp.graphics.moveTo(0, i*60+30); shp.graphics.lineTo(240, i*60+30); } floor.draw(shp); temp .applyFilter(floor, floor.rect, floor.rect.topLeft, blr); floor.applyFilter(temp, temp.rect, temp.rect.topLeft, new ConvolutionFilter(3, 3, [-0.5,-0.5,0,-0.5,0,0.5,0,0.5,0.5], 0.5, 128)); floor.draw(shp,null,new ColorTransform(1,1,1,0.4,0,0,0,0)); temp.fillRect(temp.rect, 0x8090e0); floor.draw(temp, null, null, BlendMode.OVERLAY); // create ball instance balls = new Array(16); for (i=0; i<balls.length; i++) { balls[i] = new ball(); } // set sprite/event addChild(screen); stage.quality = StageQuality.HIGH; stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; stage.doubleClickEnabled = true; stage.addEventListener(Event.ENTER_FRAME, _onEnterFrame); stage.addEventListener(MouseEvent.MOUSE_DOWN, _onMouseDown); stage.addEventListener(MouseEvent.MOUSE_UP, _onMouseUp); stage.addEventListener(MouseEvent.DOUBLE_CLICK, _onDoubleClick); } private function _onEnterFrame(event:Event) : void { var i:int, j:int; // measure start //var start:int = getTimer(); for (var l:int=0; l<100; l++) { // execute ball.mouseX = mouseX; ball.mouseY = mouseY; for (i=0; i<balls.length; i++) { ball(balls[i]).gravity(); } for (i=0; i<balls.length-1; i++) for (j=i+1; j<balls.length; j++) { ball(balls[i]).interact(ball(balls[j])); } for (i=0; i<balls.length; i++) { ball(balls[i]).run(); } calcBallCenter(); // draw balls base.fillRect(pixels.rect,0x000000); for (i=0; i<balls.length; i++) { ball(balls[i]).draw(base); } // refraction temp.applyFilter(base, base.rect, base.rect.topLeft, convx); bump.applyFilter(base, base.rect, base.rect.topLeft, convy); bump.copyChannel(temp, temp.rect, temp.rect.topLeft, BitmapDataChannel.RED, BitmapDataChannel.RED); temp.applyFilter(floor, floor.rect, floor.rect.topLeft, disp); alph.copyPixels(temp, temp.rect, temp.rect.topLeft); // lighting temp.applyFilter(base, base.rect, base.rect.topLeft, conv); alph.draw(temp,null,null,BlendMode.HARDLIGHT); // cutout temp.copyPixels(base, base.rect, base.rect.topLeft); temp.colorTransform(temp.rect, colt); alph.copyChannel(temp, temp.rect, temp.rect.topLeft, BitmapDataChannel.RED, BitmapDataChannel.ALPHA); // draw pixels.copyPixels(floor, floor.rect, floor.rect.topLeft); pixels.copyPixels(alph, alph.rect, alph.rect.topLeft); drawFace(); // measure end //} trace(getTimer() - start); } private function _onMouseDown(event:MouseEvent) : void { for (var i:int=0; i<balls.length; i++) { ball(balls[i]).check_hold(event.localX, event.localY); } } private function _onMouseUp(event:MouseEvent) : void { for (var i:int=0; i<balls.length; i++) { ball(balls[i]).hold = false; } } private function _onDoubleClick(event:MouseEvent) : void { for (var i:int=0; i<balls.length; i++) { ball(balls[i]).blast(); } } private function calcBallCenter() : void { ptBallsCenter.x = 0; ptBallsCenter.y = 0; for (var i:int=0; i<balls.length; i++) { ptBallsCenter.offset(balls[i].x, balls[i].y); } var dv:Number=1/balls.length; ptBallsCenter.x *= dv; ptBallsCenter.y *= dv; } private function drawFace() : void { matFace.identity(); matFace.translate(-24, -8); matFace.rotate(Math.atan2(balls[0].y-ptBallsCenter.y, balls[0].x-ptBallsCenter.x)); matFace.translate(ptBallsCenter.x, ptBallsCenter.y); pixels.draw(face, matFace, null, null, null, true); } } } import flash.display.*; import flash.geom.*; class ball { ...same as id:keim_at_Si:20070928... }