Hatena::ブログ(Diary)

プログラミングとかそんなの このページをアンテナに追加 RSSフィード

カレンダー
2004 | 08 | 09 | 10 | 11 | 12 |
2007 | 09 | 10 | 11 |
2008 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
2011 | 12 |

2011-12-23 ブログを移転して再開しました このエントリーを含むブックマーク

移転しました。移転先はこちら

2008-10-26 メタボールにチャンレジしてみたよ(2)

[][] メタボールにチャンレジしてみたよ(2)

前回に引き続き、メタボールを使った表現にチャレンジしてみました。

今回は、壁面で反射するパーティクルをメタボールレンダリングしてみました。多少見栄えを良くするためにBlurFilterとGlowFilterをかけています。

ソースコードこちらから。

2008-10-23 メタボールにチャレンジしてみたよ

[][]メタボールチャレンジしてみたよ

Tweenerを使って動きを作っていくとシャキーンという感じの動きを簡単に作れるのですが、

慣れてくると少し有機的な動きを取り入れてみたいという衝動に駆られます。

ということで、今回は「メタボール」に挑戦してみました。

メタボールって言葉自体はあまり馴染みがないかもしれませんが、ボールが滑らかにくっついたり離れたりするデモを見た事ある人は結構いるのではないかと思います。

あのレンダリング手法をメタボールと言います。

今回チャレンジしたのは2Dメタボールです。3Dは実装が大変そうなのでやめました。

参考にしたのは、mysketch.blog 炎の作成(1):メタボールの作成という記事です。

というか実装の方針は、ほとんどそのままです。

作成したサンプルではマウスを追跡するボールを時間差で動かしています。ボール自体は中心から外側に向かってアルファ値を滑らかに変化させており、このボールをメタボールとして描画しています。

描画の方法はいたって単純で、アルファ閾値以下の場合は白、閾値以上の場合は黒に色の置き換えをするだけです。この置き換えは、BitmapDataのpaletteMap()で実現できます。

今回は、メタボールの基本的な実装方法を確認しただけで終わりましたが次回以降では、メタボールを使って少し凝った表現を何か作ってみたいと思います。

ソースコード

参考

2008-09-07 BitmapDataを使ったモザイクエフェクト

[][] BitmapDataを使ったモザイクエフェクト

最近仕事忙殺されていて、趣味プログラムを全然書いてなかったので久しぶりに書いてみました。

作ってみたのは、スライドショーに使えそうなモザイクエフェクトです。

モザイクは、画像の拡大縮小によって実現しています。

まず、画像を縮小コピーします。縮小コピーするとその縮小率に応じて元画像より画素が減ります。これを元の大きさに拡大すると減った分の画素が縮小した時に残った画素で埋められるためモザイク状の画像になります。

ソースコード

以下、コードです。Main.asスライドショー本体で、MozaicEffect.asモザイクエフェクトのコードです。

//Main.as
package {
	import flash.display.*;
	import flash.geom.*;
	import flash.events.*;
	import flash.utils.*;
	import flash.ui.*;

	[SWF(width="600", height="600", backgroundColor="#000000", frameRate="30")]
	public class Main extends Sprite {
		[Embed(source="sample1.png")]
		public var Sample1:Class;

		[Embed(source="sample2.png")]
		public var Sample2:Class;

		private var currentBitmap:Bitmap;
		private var imageList:Array;
		private var currentIndex:int;
		private var showEffect:MozaicEffect;
		private var hideEffect:MozaicEffect;
		public function Main() {
			stage.addEventListener(KeyboardEvent.KEY_DOWN, handlerKeydown);
			stage.addEventListener(MouseEvent.CLICK,  handlerClick);

			initImageList();
			currentBitmap = new Bitmap();
			addChild(currentBitmap);

			// init effects
			hideEffect = new MozaicEffect();
			hideEffect.useTimer = false;
			showEffect = new MozaicEffect();
			showEffect.reverse = true;
			showEffect.useTimer = false;

			// show the first image
			showNextImage();
		}

		private function initImageList():void {
			imageList = [new Sample1(), new Sample2()];
			currentIndex = -1;
		}

		private function showNextImage():void {
			var prev:BitmapData = currentImageData;
			currentIndex = (currentIndex + 1) % imageList.length;
			var next:BitmapData = currentImageData;

			var self:Main = this;
			showEffect.source = next;
			showEffect.addEventListener(Event.COMPLETE, function(e:Event):void {
				self.currentBitmap.bitmapData = next;
				if ( self.contains(hideEffect) ) {
					self.removeChild(hideEffect);
				}
				if ( self.contains(showEffect) ) {
					self.removeChild(showEffect);
				}
			});

			if ( prev != null ) {
				hideEffect.source = prev;
				addChild(hideEffect);
				hideEffect.addEventListener(Event.COMPLETE, function(e:Event):void {
					self.addChild(showEffect);
					showEffect.play();
				});
				hideEffect.play();
			}
			else {
				addChild(showEffect);
				showEffect.play();
			}
		}

		private function get currentImageData():BitmapData {
			if ( 0 <= currentIndex && currentIndex < imageList.length ) {
				return imageList[currentIndex].bitmapData;
			}
			return null;
		}

		private function handlerKeydown(e:KeyboardEvent):void {
			if ( e.keyCode == Keyboard.SPACE ) {
				showNextImage();
			}
		}

		private function handlerClick(e:MouseEvent):void {
			showNextImage();
		}
	}
}
// MozaicEffect.as
package {
	import flash.events.*;
	import flash.display.*;
	import flash.geom.*;
	import flash.utils.*;

	public class MozaicEffect extends Sprite {
		public var endCount:int;
		public var reverse:Boolean;
		public var interval:uint;
		public var useTimer:Boolean;

		private var counter:int;
		private var _bgColor:uint;
		private var _source:BitmapData;
		private var buffer:Bitmap;
		private var timer:Timer;
		public function MozaicEffect() {
			endCount = 12;
			counter = 0;
			reverse = false;
			bgColor = 0x000000;

			useTimer = true;
			interval = 100;
		}

		public function play():void {
			if ( source != null ) {
				counter = 0;
				var bmpData:BitmapData = new BitmapData(source.width, source.height, false, 0x000000);
				if ( !reverse ) {
					bmpData.copyPixels(source, new Rectangle(0, 0, source.width, source.height), new Point(0, 0));
				}
				buffer = new Bitmap(bmpData);
				addChild(buffer);
				if ( useTimer ) {
					timer = new Timer(interval, 0);
					timer.addEventListener(TimerEvent.TIMER, updateDisplay);
					timer.start();
				}
				else {
					addEventListener(Event.ENTER_FRAME, updateDisplay);
				}
			}
		}

		public function stop():void {
			if ( hasEventListener(Event.ENTER_FRAME) ) {
				removeEventListener(Event.ENTER_FRAME, updateDisplay);
			}
			if ( useTimer ) {
				timer.removeEventListener(TimerEvent.TIMER, updateDisplay);
				timer.stop();
			}
		}

		public function get bgColor():uint {
			return _bgColor;
		}

		public function set bgColor(color:uint):void {
			color = _bgColor;
		}

		public function get source():BitmapData {
			return _source;
		}

		public function set source(data:BitmapData):void {
			_source = data;
		}

		private function mozaic(src:BitmapData, scale:uint):void {
			var mtrx:Matrix = new Matrix();
			mtrx.scale(1.0 / (scale * scale), 1.0 / (scale * scale));
			var half:BitmapData = new BitmapData(src.width / scale, src.height / scale, false, 0x000000);
			half.draw(src, mtrx);
			var double:uint = scale * scale;
			mtrx.scale(double * double, double * double);
			src.draw(half, mtrx);
			half.dispose();
		}

		private function updateDisplay(e:Event):void {
			var bmpData:BitmapData = buffer.bitmapData;
			if ( counter > endCount ) {
				stop();
				if ( !reverse ) {
					bmpData.fillRect(new Rectangle(0, 0, source.width, source.height), bgColor);
				}
				var event:Event = new Event(Event.COMPLETE);
				dispatchEvent(event);
			}
			else {
				bmpData.copyPixels(source, new Rectangle(0, 0, source.width, source.height), new Point(0, 0));
				if ( reverse ) {
					mozaic(bmpData, endCount - counter + 1);
				}
				else {
					mozaic(bmpData, counter + 1);
				}
			}
			counter++;
		}
	}
}

2008-08-25 AdvancedDataGridのヘッダに表示される縦線を消す方法

[][] AdvancedDataGridのヘッダに表示される縦線を消す方法

AdvancedDataGridのデフォルト設定だと、ヘッダがイケテなくて困った人は多いと思います。

とくに、並び替え機能が不要なときにsorter領域の縦線が消したくなった人は多いと思います。

普通に考えると、sortableColumnsというプロパティをfalseに設定する、もしくはAdvancedDataGridColumnのsortableプロパティをfalseにすれば並び替えができなくなる代わりに縦線は消えるだろうと思います。しかし、この縦線は並び替えを無効にしても残ります。

では、どうすれば良いのか?

ここでのやり取りを追ってみると、AdvancedDataGridのsortExpertModeプロパティを「true」にすれば良いらしいことがわかります。確かに、これを設定すると、

という感じで縦線が消えます。ちなみに、このプロパティをtrueにするとctrl(macではcommand)キーで複数列の並び替えが出来るようになります。つまりAdobe的には、(ctrl押しながらクリック出来る人) = (エキスパート)ということなんでしょうね。

以下余談です。

つい最近Flex Builder3を入手したのでFlexを触り始めました。起動がもっさりするのが気になりますが概ね快適です。

Flexを触り始めて思ったのが、色々とできそうなんだけど具体的にどうやればいいのかを調べるのが非常に面倒だと感じました。

特に日本語情報源が乏しく、嵌まった場合にWEBを検索してもあまり有益な情報を得られないのが初心者にはつらい気がします。(FxUGが頼みの綱って感じですね)

というわけで、これからはFlexのTips的な記事も少しずつ書いていきたいなと思います。

サンプルコード

<?xml version="1.0"?>
<!-- charts/AxisRendererStrokes.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
	<mx:Script>
		<![CDATA[
			[Bindable]
			private var dataList:Array = [
				{col1: 100, col2:200, col3:500},
				{col1: 100, col2:200, col3:400},
				{col1: 200, col2:200, col3:300},
				{col1: 200, col2:200, col3:200},
				{col1: 300, col2:200, col3:100}
			];
		]]>
	</mx:Script>
	<mx:AdvancedDataGrid designViewDataType="flat" sortableColumns="false" sortExpertMode="true" dataProvider="{dataList}" id="adg1">
		<mx:columns>
			<mx:AdvancedDataGridColumn headerText="列 1" dataField="col1"/>
			<mx:AdvancedDataGridColumn headerText="列 2" dataField="col2"/>
			<mx:AdvancedDataGridColumn headerText="列 3" dataField="col3"/>
		</mx:columns>
	</mx:AdvancedDataGrid>
</mx:Application>

参考