Main | 2005年12月 »

2005年11月30日

跳ね回る火の玉 - draw / applyFilter

drawの代表的な使い方として、オブジェクトの軌跡を描く使い方。徐々に消えていく処理はBlurFilterとColorMatrixFilterをapplyFilterを使って適用していますが、毎フレーム実行すると負荷が高いので、setIntervalを使って実行するレートを調整しています。
動きに関してはあまりにも適当なので、まだ未公開です。

import flash.filters.*;
import flash.display.*;
import flash.geom.*;

var bmp:BitmapData = new BitmapData(360, 240, true, 0);
var stage:MovieClip = this.createEmptyMovieClip("stage", 2);
stage.attachBitmap(bmp, 1);

var cs:MovieClip = this.createEmptyMovieClip("cs", 1);
var clr:ColorTransform = new ColorTransform(4,2,1,1,70,10,0,0);
var blur:BlurFilter  = new BlurFilter(5, 5, 2);
var matrix:Array = [
		.9, 0, 0, 0, 1,
		0, .9, 0, 0, 3,
		0, 0, .9, 0, 1,
		0, 0, 0, 1, 0
		];
var black:ColorMatrixFilter = new ColorMatrixFilter(matrix);

for(var i = 0; i < 18; i++){
	var ppt:Object = {_x:Math.random()*Stage.width, _y:Math.random()*Stage.height, _xscale:Math.random()*80+20, _yscale:_xscale};
	var m:MovieClip = cs.attachMovie("mc", "m"+i, i, ppt);
	var trans:Transform = new Transform(m);
	trans.colorTransform = clr;
	m.blendMode = "add";
	m.filters = [blur];
}

interval = setInterval(setFilter, 70);
this.onEnterFrame = function():Void {
	bmp.draw(cs);
}

function setFilter():Void {
	bmp.applyFilter(bmp, bmp.rectangle, new Point(0,0), black);
	bmp.applyFilter(bmp, bmp.rectangle, new Point(0,0), blur);
}

2005年11月25日

FLASHでペイント (1) エアブラシと消しゴム - copyPixels

copyPixelsでPhotoshopのようなエアブラシと消しゴムを再現。ビットマップの描画はdrawでも代替可能ですが、drawではビットマップをアルファに置き換えることができないので、消しゴムを再現するにはcopyPixelsを使う必要があります。

copy_pixels イメージ

サンプルではレイヤーのblendModeを変更できるようにしてますが、下のスクリプトは描画関係に絞って記述してあります。ライブラリ内に背景イメージ(下記では"himawari")とブラシのイメージ(同"air_circle35")を設置してスクリプトに書き出しておく必要があります。長いので分けて配置していますが、すべて1フレーム目に記述。

import flash.display.*;
import flash.geom.*;

var now_tool:String = "brush";

// --- ビットマップ作成

var img:BitmapData = BitmapData.loadBitmap("himawari");
var layer:BitmapData = new BitmapData(300, 220, true, 0); 
var brush_shape:BitmapData = BitmapData.loadBitmap("air_circle35");
var brush_src:BitmapData = new BitmapData(360, 240, true, 0xFF660000);

// --- ムービークリップ作成 & ビットマップ貼り付け

var bgmc:MovieClip = this.createEmptyMovieClip("bg_mc", 0);
var stage:MovieClip = this.createEmptyMovieClip("stage_mc", 1);
var brimg:MovieClip = this.createEmptyMovieClip("circle_mc", 2);

stage._x = bgmc._x = 50;
stage._y = 10;

stage.attachBitmap(layer, 1);
bgmc.attachBitmap(img, 1);
brimg.attachBitmap(brush_shape, 1);

次に、消しゴムを作成するため、

1. アルファマスク用に白の矩形ビットマップ(eraser_shape)を作成
2. ブラシのビットマップを読み込んだMC(brimg)をdrawでeraser_shapeに描画
3. copyChannelでブラシ部分を透明にして型抜き
4. copyPixelsで [アルファの結合(mergeAlpha)] パラメータをfalseに設定して対象自身(layer)をコピー

・・・の手順。(もう少しいい方法がありそうな気もしますが・・・。)

// --- 消しゴム作成

var eraser_shape:BitmapData = new BitmapData(brush_shape.width, brush_shape.height, true, 0xFFFFFFFF);
eraser_shape.draw(brimg);
eraser_shape.copyChannel(eraser_shape, eraser_shape.rectangle, new Point(0, 0), 1, 8);

brimg.removeMovieClip();

// --- ブラシを使う

function useBrush():Void {
	var offset:Point = new Point(stage._xmouse-brush_shape.width/2, stage._ymouse-brush_shape.height/2);
	var rect:Rectangle = new Rectangle(offset.x, offset.y, brush_shape.width, brush_shape.height);	
	layer.copyPixels(brush_src, rect, offset, brush_shape, new Point(0, 0), true);
	updateAfterEvent();
}

// --- 消しゴムを使う

function useEraser():Void {
	var offset:Point = new Point(stage._xmouse-eraser_shape.width/2, stage._ymouse-eraser_shape.height/2);
	var rect:Rectangle = new Rectangle(offset.x, offset.y, eraser_shape.width, eraser_shape.height);	
	layer.copyPixels(layer, rect, offset, eraser_shape, new Point(0, 0), false);
	updateAfterEvent();
}

// --- マウスイベント

this.onMouseDown = function():Void {
	if (stage.hitTest(this._xmouse, this._ymouse, true)) {
		switch (now_tool) {
			case "brush": 
			this.onMouseMove = useBrush;
			useBrush();
			break;
			
			case "eraser":
			this.onMouseMove = useEraser;
			useEraser();
			break;
		}
	}
}

this.onMouseUp = function():Void {
	delete this.onMouseMove;
}

// --- ボタン

brushBtn_mc.onPress = function ():Void {
	changeTool("brush");
}

eraserBtn_mc.onPress = function():Void {
	changeTool("eraser");
}

function changeTool(tool:String):Void {
	now_tool = tool;
}

BitmapDataの基本的な操作は以下を参照。
Flash 8 のイメージ API の概要(Macromedia - Developer Center)

2005年11月21日

流れる雲 - perlinNoise

BitmapDataクラスのperlinNoiseメソッドを使用することで、Photoshopでいう「雲模様」の効果を作ることができます。例では簡易的に雲を表現しましたが、他のフィルタと組み合わせることで、煙や炎などのリアルな表現もFlashのみで表現することが可能になります。

ステージ上にアルファを含んだグラデーションで塗った長方形"gmask"を配置し、アルファチャンネルを利用したマスクとして雲に対して適用しています。アルファチャンネルのマスクを利用するためには、マスクと対象のムービークリップのcacheAsBitmapをtrueにする必要があります。

import flash.display.*;
import flash.geom.*;

var w:Number = 360;
var h:Number = 150;
var octaves:Number = 3;

var bmp:BitmapData = new BitmapData(w, h, true, 0);
var mc:MovieClip = this.createEmptyMovieClip("mc", 1);
mc.attachBitmap(bmp, 1);
mc.blendMode = "hardlight";
mc._y = 90;

mc.cacheAsBitmap = true;
gmask.cacheAsBitmap = true;
mc.setMask(gmask);

var offset:Array = new Array();
var speed:Array = new Array();

for (var i:Number = 0; i < octaves; i++) {
	offset[i] = new Point(Math.random()*w, Math.random()*h);
	speed[i] = new Point(3, Math.random()*4-2);
}

var rdm:Number = Math.random()*1000;
var clr:ColorTransform = new ColorTransform(1.5, 1.5, 2, 1, 0, 0, 0, -30);

this.onEnterFrame = function():Void {
	for (i = 0; i < octaves; i++) {
		offset[i].x += speed[i].x;
		offset[i].y += speed[i].y;
	}
	bmp.perlinNoise(w/3, h/2, octaves, rdm, false, true, 0, true, offset);
	bmp.colorTransform(bmp.rectangle, clr);
};

CPU負荷が高い処理なので、あまり大きな描画領域には適用しない方が無難です。また、perlinNoiseのオクターブの数値(上ではoctaves)を減らすことで負荷を少し抑えられます。

2005年11月20日

FLASH内のイベントをトラッキングする

たまに「FLASHはアクセス解析できない」と言われることがあるんですが、ある程度FLASHやサーバーサイドに精通している人ならわかることですけど、特にFLASHだから不可能というわけではなく、むしろ一度仕組みを作ってしまえばHTMLよりも詳細なデータを取得することも可能になります。

既存の解析サービスではFLASH内のイベントを追跡できないものも多いですが、Googleが今月から無料で提供しているサービス「Google Analytics」を使えば、FLASH 側のイベント内にjavascriptを呼び出すコードを記述することで、クリックの動作はもちろん、ロールオーバーやマウスホイールなどの動作でさえ解析することが可能になるようです。変数の値も送信できるので、色々と活用できそうです。

btn.onRelease = function() {
	getURL("javascript:urchinTracker('/folder/file');");
}

詳細は以下参照。

Google Analytics - Flash イベントを追跡するにはどうすればよいですか。

2005年11月16日

有機的に動く光 - blendMode

今までAfterEffectsなどを使用しなければ表現できなかったような映像もFlashのみで可能になりました。

blendModeを"add"(加算)にすることと、動かすオブジェクトの色と背景色の色を上手く組み合わせることでこんな感じになります。

スクリプト自体は単純です。

import flash.filters.*;

var matrix:Array = [
		2, 1, 0, 0, 0,
		0, 1, 0, 0, 100,
		0, 0, 1, 0, 0,
		0, 0, 0, 1, 0
		];

var w:Number = 360;
var h:Number = 240;
var cmf:ColorMatrixFilter = new ColorMatrixFilter(matrix);
var blur:BlurFilter = new BlurFilter(50, 50, 2);
var cont:MovieClip = this.createEmptyMovieClip("cont_mc", 1);

for (var i:Number = 1; i <= 5; i++) {
	var ppt:Object = {_x:Math.random()*w, _y:Math.random()*h};
	var c:MovieClip = cont.attachMovie("circle", "c"+i, i, ppt);
	c.blendMode = "add";
	c.filters = [blur, cmf];
	c.onEnterFrame = rebound(0, w, 0, h);
}

function rebound(minX:Number, maxX:Number, minY:Number,maxY:Number):Function {
	var xp:Number = Math.random()*6-3;
	var yp:Number = Math.random()*6-3;
	return function():Void {
		if (this._x>=maxX || this._x<=minX) xp = -xp;
		if (this._y>=maxY || this._y<=minY) yp = -yp;
		this._x += xp;
		this._y += yp;
	};
}

blendModeはプロパティパネルからも設定可能ですが、グラフィックインスタンスには適用できません。アニメーターの人にとってはちょっと痛いところです。

2005年11月11日

キャッシュを有効にしてアニメーションを高速にする - cacheAsBitmap

Flashやillustratorで描いたベクターデータは拡大しても表示が乱れず、データのサイズも増えないというメリットがある一方、複雑なベクターコンテンツを含むムービークリップを動かそうとした場合、毎フレーム描画に計算を要するために、どうしてもスムーズに動かない問題がありました。

これまではこの問題を解決するために、一時的に_quality プロパティの値を"LOW"に変更したり、ベクター画像をビットマップに書き出して置き換えたりしていたわけですが、Flash8からはcacheAsBitmapプロパティをtrueに設定することで、ベクターで描かれたオブジェクトがビットマップとしてメモリにキャッシュされ、複雑なベクターデータも高速に動かすことが可能になりました。

上の例では複雑なベクターで描かれたムービークリップを同時に20個移動させています。「cacheAsBitmap」にチェックを入れると、それぞれの環境によって差はありますが、キャラクターが高速で動き出すと思います。右下のフレームレートの数値も格段に上昇し、ムービーの描画処理速度が向上していることがわかります。

function switchCache():Void {
    var mc:MovieClip;
    for (var i:Number = 0; i < 20; i++) {
        mc = this["mc"+i];
        mc.cacheAsBitmap = !mc.cacheAsBitmap;
    }
}

cachebtn.onRelease = function():Void {
    switchCache();
}

注意したいのは、拡大や回転するオブジェクトにcacheAsBitmapを適用すると、かえって動きが遅くなる可能性があるということです。有用なのは、静的な背景や移動だけの「変形しない」オブジェクトに限られます。詳しくは キャッシュを有効にする状況 (Flash 8 LiveDocs)を参考にするとよいでしょう。

ビットマップキャッシュは、ムービークリップやボタンのプロパティパネルの[ランタイムビットマップを有効にする]の欄にチェックを入れることでも有効にできます。また、ムービークリップにBevelFilterやColorMatrixFilterなどのBitmapFilterを適用することで、cacheAsBitmapは自動的にtrueに設定されます。

色を操作する 2 - ColorMatrixFilter

ColorMatrixFilter クラスを使用すると、モノクロ効果や色相回転など、幅広い効果を演出できます。4×5マトリックス(行列)を用いて計20の値を設定する必要があります。

特にアルファの値を上手く操作して背景のオブジェクトと重ねることで、面白い効果を作れそうです。

下記ではムービークリップ [mc] をモノクロに変換します。これ以外の設定値は上のFLASHを参考に。

import flash.filters.ColorMatrixFilter;

var matrix:Array = [
		1/3, 1/3, 1/3, 0, 0,
		1/3, 1/3, 1/3, 0, 0,
		1/3, 1/3, 1/3, 0, 0,
		0, 0, 0, 1, 0
		];

var clr:ColorMatrixFilter = new ColorMatrixFilter(matrix);
mc.filters = [clr];

また、フィルタパネルから [カラー調整] を選び、「明度」・「コントラスト」・「彩度」・「色相」の形式で同様の効果が可能になりますが、アルファ値の変更やカラー値ごとに細かい設定はできません。

カラー調整

2005年11月10日

色を操作する 1 - ColorTransform

カラー値の操作について、Flash Player8 からはColorクラスの使用は推奨されていません。
代わりに ColorTransformクラスを使用することになります。

たとえば、今までムービークリップmc にネガのような反転効果を与える場合、以下のように記述していました。

var clr:Color = new Color(mc);
var trans:Object = {ra:-100, rb:255, ga:-100, gb:255, ba:-100, bb:255, aa:100, ab:0};
clr.setTransform(trans);

これと同様の効果をColorTransformクラスを使用して記述すると下記のようになります。

import flash.geom.ColorTransform;
import flash.geom.Transform;

var trans:Transform = new Transform(mc);
var clr:ColorTransform = new ColorTransform(-1, -1, -1, 1, 255, 255, 255, 0);
trans.colorTransform = clr;

基本的にはプロパティパネルの[カラー]での[拡張効果]の操作と同じになります。

拡張効果

ColorTransformクラスでは、上図のダイアログボックスでいうと、左上から縦の順番に値を記述し、 %表記の部分を乗数で記述するため、100%を1と表します。

2005年11月09日

このブログについて

当面はデザイナー向けにFlash8の機能の実験・解説など。スクリプトについては、プロセスをできるだけシンプルに記述するつもりなので、オブジェクト指向的にはあまりよろしくないと思います。これが最善の方法ではないことをあらかじめご了承ください。

Flashも今年9月(※日本語版は10月)にバージョン8が発売されました。このバージョンアップでビットマップ操作をはじめとして、表現の可能性は確実に広がる一方で、非インタラクティブな映像においても、タイムラインでの作業のみでは、スクリプトを使用する場合とくらべて表現できる幅が制限されてきています。

プログラマー系Flash使いの間ではActionScript3.0で騒いでいたりしますが、多くのデザイナーにとっては、まずはFlash8の機能を使いこなすことが先決であると思いますので、期間限定的に個人的な研究も兼ねて実験ブログを始めることにしました。個人的な実験の場ですが、少しでも参考になれば幸いです。

著作権について

記述しているスクリプトやファイルについては、著作権は放棄しませんが、商用・私用問わずコピペして利用・改造する分には構いません。特に許可も必要ありません。ご自由に使っていただいて結構です。ただし、ソースの利用による損失や不利益には当方は一切責任を負いません。自己責任の上、お使いください。また、ソースやファイルそのものをそのままの形で、あるいは数値・変数名に修正を加えただけのようなものを無断で公開・再配布することは認めません。そんなとこです。