home > 投稿 > 某ウル○○Qみたいなエフェクト
2006/12/28

某ウル○○Qみたいなエフェクト


displacementMapフィルターを使って某ウル○○Qのようなエフェクトを作りました。
これまた結構前に(flash8が出たころ)作ったものなんですが
日の目を見てなかったので晒しときます。

当初、例の音が付いてたのですが、都合によりカットです(笑)

[[flash here]]

テキストは書き換えられます(日本語しか埋め込んでません)
テキスト以外の部分を左右にドラッグすると巻き戻し、早送りが出来ます。


以下、解説です。

displacementMapフィルターは本来画像を画像に作用させて
レンズのゆがみのような画像効果を得るための物なのですが、
フィルタ画像の各ドットのRGB要素の値によって
対象画像のドットを上下左右に移動するというな実装をされているため、
逆に移動したいドットの距離からRGB値を計算で割り出して
フィルタ画像を作ってやれば狙った形に画像をゆがませることが出来ます。

そんな事をわざわざするのは面倒くさくてややこしいのですが、
setPixel()で1ドットづつ描画するのに比べて
フィルタの処理は段違いに速いので、自分の場合、
ハデで大きな範囲が動く演出を作る時には、この技を多用してます。
(そのようにdisplacementMapフィルターを使う人はけっこういるようです。)

このウル○○Qエフェクトの場合は、左右別々に渦を巻く変形を
させるためのフィルタ画像を128枚ずつ用意しています。
画像一覧

最初はActionScript2でフィルタ画像も毎フレームリアルタイムで作成していたのですが
setPixel()メソッドは遅いので、アニメーション自体も遅くなってしまいました。
なので、このサンプルの場合は、vb(.NET)を使って事前にフィルタ画像を256枚作成し
それをflash8に素材として読み込みました。
(仕組み上、ロスレス圧縮で書き出さないと、意図しないRGB値となり、とんでもない画面になります…。)

ActionScript3なら全部リアルタイム演算でいけるかもしれません。
(いやそもそもフィルタなんぞ使わないでも、いい速度がでるのかも…)

flaとasダウンロード


◆asソース
毎フレームdisplacementMapフィルターを適用させています

import flash.display.*;
import flash.geom.*;
import flash.filters.*;
//
var self = this;
var mc:MovieClip;
var width = 80;//フィルタのサイズ
var height = 120;//フィルタのサイズ
var multiple:Number = 2;//フィルタの倍率
var noMoveCol:Number = 128 + (128<<8);//フィルタがかからない色(緑:横方向、青:縦方向)
var mapBitmap:BitmapData = new BitmapData(480,360,false,noMoveCol);
var displacementMap:DisplacementMapFilter = new DisplacementMapFilter(mapBitmap, new Point(0,0), 4, 2, 256*multiple, 256*multiple,"clamp");
var blurFilter:BlurFilter = new BlurFilter(2,2);
var workBitmapL:BitmapData;
var workBitmapR:BitmapData;
//フィルタの変形用
var offsetX = 0;
var offsetY = 0;
var rect1:Rectangle = new Rectangle(0,0,320,240);
var rect2:Rectangle = new Rectangle(0,0,320,240);
var matrix1:Matrix = new flash.geom.Matrix();
var matrix2:Matrix = new flash.geom.Matrix();
matrix1.scale(multiple,multiple);
matrix2.scale(multiple,multiple);
matrix1.translate(offsetX,offsetY);
matrix2.translate(160+offsetX,offsetY);
var ctr:ColorTransform = new ColorTransform();
//アニメパターン番号
var maxAnimNum:Number = 128;
var j:Number = maxAnimNum;//カウンタ
//他、演出用
var bDrag:Boolean = false;
var bt:Button;
//var sn:Sound;
/**
 * 初期化
 */
function init(){
	var fArr:Array = mc.filters;
	fArr.unshift(blurFilter);
	fArr.unshift(displacementMap);
	mc.filters = fArr;
	this.onEnterFrame = animation;
	animation();
	this.stop();
}
/**
 * ライブラリのビットマップを返す
 * @param   アニメパターン番号
 * @param   rl 右か左か("r"||"l")
 * @return  ビットマップデータ
 */
function getBitmaps(i:Number,rl:String):BitmapData{
	var bmp:BitmapData = BitmapData.loadBitmap("qBitmap"+i+"_"+rl+".png");
	return bmp;
}
/**
 * マイフレームのアニメーション処理
 */
function animation(){
	//左右にドラッグできる
	if(bDrag){
		j = Math.min(maxAnimNum-1,Math.floor(_xmouse/(320/maxAnimNum)));
	}
	workBitmapL.dispose();
	workBitmapR.dispose();
	workBitmapL = getBitmaps(j,"l");
	workBitmapR = getBitmaps(j,"r");
	mapBitmap.draw(workBitmapL,matrix1,ctr,"normal",rect,false);
	mapBitmap.draw(workBitmapR,matrix2,ctr,"normal",rect,false);
	if(--j <=0){
		j=0;
	}
	//アルファをいじるとフィルタ設定しなおさなくても描画が更新する
	mc._alpha = (mc._alpha==100)? 101: 100;
	tf.text= "frame "+j;
}
//ドラッグ処理
bt.onPress = function(){
	self.bDrag = true;
}
bt.onRelease = bt.onReleaseOutside = function(){
	self.bDrag = false;
	self.playSound();
}
init();


◆画像128枚x左右2セット作成のVisualBasic.NETのソース
初めて(で最後)のVB。専門外のため適当です。専門でも適当ですが…。

Imports System.Drawing.Bitmap
Imports System.Drawing.Imaging
'Option Strict On
Public Class Form1
    Private _width As Integer = 80
    Private _height As Integer = 120
    Private _files As Integer = 128
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim image1 As New Bitmap(_width, _height)
        Dim image2 As New Bitmap(_width, _height)
        Dim count As Integer = _files - 1
        Dim x, y As Integer
        Dim theta As Double = 0.0
        _initBar()
        Dim newColor As Color
        While count >= 0
            For x = 0 To image1.Width - 1
                For y = 0 To image1.Height - 1
                    newColor = _getCol(x, y, count, +1)
                    image1.SetPixel(x, y, newColor)
                    newColor = _getCol(x, y, count, -1)
                    image2.SetPixel(x, y, newColor)
                Next
            Next
            PictureBox1.Image = image1
            PictureBox2.Image = image2
            PictureBox1.Refresh()
            PictureBox2.Refresh()
            saveImage(count, image1, "l")
            saveImage(count, image2, "r")
            _setBar(_files - count)
            count = count - 1
        End While
        ProgressBar1.Value = 0
    End Sub
    Private Sub _initBar()
        ProgressBar1.Minimum = 0
        ProgressBar1.Maximum = _files
        ProgressBar1.Step = 1
    End Sub
    Private Sub _setBar(ByVal num As Integer)
        ProgressBar1.Value = num
    End Sub
    Private Sub saveImage(ByVal count As Integer, ByVal image As Bitmap, ByVal lr As String)
        Dim filename As String = TextBox1.Text & CStr(count) & "_" & lr & ".png"
        image.Save(filename, ImageFormat.Png)
        Console.WriteLine(filename + "を書き出し")
    End Sub
    Private Function _getCol(ByVal x As Integer, ByVal y As Integer, ByVal i As Integer, ByVal dir As Double) As Color
        Dim red As Double = 0
        Dim green As Double = 0
        Dim blue As Double = 0
        Dim speed As Double = 1.0
        Dim cx As Double = _width * 0.5
        Dim cy As Double = _height * 0.5
        Dim dx As Double = (x - cx)
        Dim dy As Double = (y - cy)
        Dim nx As Double
        Dim ny As Double
        Dim r As Double = Math.Sqrt(dx * dx + dy * dy)
        Dim theta As Double
        Dim bAll As Boolean = True
        Dim newColor As Color
        If r = 0 Then
            r = 0.1
        End If
		Dim rRatio As Double = Math.Max(0,0.07*speed*i*(1 - (Math.Sqrt(r/(cY*1.1))) ))
        Dim bInSide As Boolean = (r < cx And r < cy)
        If (Not bAll) And (Not bInSide) Then
            newColor = Color.FromArgb(0, 128, 128)
        Else
            theta = Math.Atan2(-dy, dx)
            nx = (cx + Math.Cos(theta - dir * rRatio) * r) - x
            ny = (cy - Math.Sin(theta - dir * rRatio) * r) - y
            blue = Math.Max(0, Math.Min(nx + 128, 255))
            green = Math.Max(0, Math.Min(ny + 128, 255))
            newColor = Color.FromArgb(CInt(red), CInt(green), CInt(blue))
        End If
        Return newColor
    End Function

End Class


Qぽいビットマップ変形の考え方の図
(左右の真ん中部分に切れめが見えるのでもうちょっと力を入れてなじませたいところ)

トラックバックURL

http://faces2.bascule.co.jp/mt/mt-tb.cgi/521

コメント一覧

かっこいいす! ボケがかかって、昔風な感じが再現されてていいですね。
どうも。 ボケはブラーフィルターという高等テクです!

コメントを投稿

(コメントには承認が必要になることがあります。承認されるまではコメントは表示されません。)