スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

--.--.-- | | スポンサー広告

レンズで部分拡大

DisplacementMapFilterで、レンズを通したように画像を拡大してみました。マウスを左側の画像の上に持っていくとその周辺がレンズで拡大されたように変形するハズです(うまくいかないときは一回クリックしてみてクダサイ)。




このフラッシュでは、入力したサイズ/曲率半径/焦点距離からマップ画像と表示用ムービークリップを生成し、サイズにしたがって元画像をクリッピングしたものにDisplacementMapFilterをかけてマス。
サイズで指定した値がレンズの直径なので、曲率半径はサイズの1/2以上の必要がありマス。

マップ画像ですが、下図のようなレンズを想定して算出しました。
レンズ
水色に塗ってある部分がレンズで、oがレンズの半径(サイズの1/2)、rが曲率半径、fが焦点距離デス。

マップ画像を作りたいので、ココから表示ピクセルと元ピクセルの位置のずれを算出していきます。
レンズの中心からyの距離での元画像とのずれy'は、

  x' / (f + x') = y' / y
なので、
  y' = y x' / (f + x')
となるハズです。
そんでx'は
  x' = sqrt(r^2 - y^2) - sqrt(r^2 - o^2)
のハズです。
なので元画像のピクセルは、表示位置からレンズの中心向かって
  y(sqrt(r^2 - y^2) - sqrt(r^2 - o^2)) / (f + sqrt(r^2 - y^2) - sqrt(r^2 - o^2))
ずれた位置にあるハズです。
上記のずれをd、表示ピクセルの座標を(x, y)、レンズの中心座標を(o, o)とすると、x方向、y方向のずれはx0, y0は、
  y0 = d(y - o)
x0 = d(x - o)
デス。たぶん。

コレを元に作成したマップ画像が、右側の画像デス。
あとは、onEnterFrameでマウスカーソルの位置から元画像を指定したサイズで切り取ってattachBitmapしてるダケです。

ActionScript自体は、
import flash.display.BitmapData;
import flash.filters.DisplacementMapFilter;
import flash.geom.Matrix;
// 位置、サイズ
var l:Number = test_mc._x;
var t:Number = test_mc._y;
var w:Number = test_mc._width;
var h:Number = test_mc._height;

// レンズの大きさ
var size:Number;
// 曲率半径
var r:Number;
// 焦点距離
var f:Number;

// マップ画像オフセット
var mapOffsetX:Number = w + 10;
var mapOffsetY:Number = 0;

// スケール調整値
var yAdj:Number = 1;
var xAdj:Number = 1;

// レンズムービークリップ
var lens_mc:MovieClip;

// マップムービークリップ
var map_mc:MovieClip;

// 設定ボタン
test_btn.onRelease = setupLens;

setupLens();

// レンズのセットアップ
function setupLens() {
size = Number(size_txt.text);
r = Number(r_txt.text);
f = Number(f_txt.text);
// マップ画像
var mapBitmap:BitmapData = createMapBitmap();

// マップ画像表示
if (map_mc) {
map_mc.removeMovieClip();
}
var depth:Number = _root.getNextHighestDepth();
map_mc = _root.createEmptyMovieClip("mask_" + depth, depth);
map_mc.attachBitmap(mapBitmap, 1);
map_mc._x = l + mapOffsetX;
map_mc._y = t + mapOffsetY;

// レンズムービークリップ
if (lens_mc) {
lens_mc.removeMovieClip();
}
depth = _root.getNextHighestDepth();
lens_mc = _root.createEmptyMovieClip("lens_" + depth, depth);

// フィルタ設定
var filter:DisplacementMapFilter
= new DisplacementMapFilter(mapBitmap,
new Point(),
4,
2,
Math.ceil(256 / xAdj),
Math.ceil(256 / yAdj));
lens_mc.filters = [filter];
}


// フレーム毎の処理
function onEnterFrame() {
// 対象ムービークリップ上にマウスカーソルがない場合は
// レンズは表示しない
if (_root._xmouse < test_mc._x
|| _root._xmouse > test_mc._x + test_mc._width
|| _root._ymouse < test_mc._y
|| _root._ymouse > test_mc._y + test_mc._height) {
lens_mc._visible = false;
Mouse.show();
return;
}
lens_mc._visible = true;
// レンズを動かす
lens_mc._x = _root._xmouse - size / 2;
lens_mc._y = _root._ymouse - size / 2;
// マウスカーソルの位置を中心にレンズ効果
var src:BitmapData = new BitmapData(size, size);
var matrix:Matrix = new Matrix();
matrix.tx = -(test_mc._xmouse - size / 2);
matrix.ty = -(test_mc._ymouse - size / 2);
src.draw(test_mc, matrix, new ColorTransform(),
"normal", new Rectangle(0, 0, size, size), false);
lens_mc.attachBitmap(src, 1);
Mouse.hide();
}


// DisplacementMapFilter用のビットマップを生成する
function createMapBitmap():BitmapData {
var bitmap:BitmapData
= new BitmapData(size, size, false, 0xFF008080);
var o:Number = size / 2;
var o2:Number = o * o;
var r2:Number = r * r;
// 調整値の設定
var maxY:Number = 0;
var maxX:Number = 0;
for (var y:Number = 0; y < size; y++) {
var dY:Number = y - o;
var dY2:Number = dY * dY;
for (var x:Number = 0; x < size; x++) {
var dX:Number = x - o;
var dR2:Number = dX * dX + dY2;
// ピクセルが、レンズムービークリップの内接円に
// 入っている場合のみ処理
if (dR2 < o2) {
// ずれ
var l:Number = Math.sqrt(r2 - dR2) - Math.sqrt(r2 - o2);
var d:Number = l / (f + l);
// 最大値設定
maxY = Math.max(maxY, Math.abs(dY * d));
maxX = Math.max(maxX, Math.abs(dX * d));
}
}
}
yAdj = 128 / (maxY + 1);
xAdj = 128 / (maxX + 1);
// ビットマップ生成
for (var y:Number = 0; y < size; y++) {
var dY:Number = y - o;
var dY2:Number = dY * dY;
for (var x:Number = 0; x < size; x++) {
var dX:Number = x - o;
var dR2:Number = dX * dX + dY2;
// ピクセルが、レンズムービークリップの内接円に
// 入っている場合のみ処理
if (dR2 < o2) {
// ずれ
var l:Number = Math.sqrt(r2 - dR2) - Math.sqrt(r2 - o2);
var d:Number = l / (f + l);
// ピクセルの色
var yC:Number = -Math.floor(dY * d * yAdj);
var xC:Number = -Math.floor(dX * d * xAdj);
var c:Number = 0xFF000000
+ (0x80 + yC) * 0x100
+ (0x80 + xC);
// ピクセルを描画する
bitmap.setPixel(x, y, c);
}
}
}
return bitmap;
}
こんなカンジです。

test_mcは、変形元画像のムービークリップです。
x、y方向のずれは0x80を中心に0x00~0xFFの範囲しか指定できないので、createMapBitmap()の最初のループで算出されるずれの最大値を探して、範囲内に収まるように調整してマス。

結果をみるとどうやらちゃんと表示されてるような気がしますが、計算があってるかは自信アリマセン。

2007/7/5このエントリのソースコードはFlash8用デス。Flash CS3で同じことするバージョンがFlash CS3でレンズにあります。
スポンサーサイト

テーマ:Flash - ジャンル:コンピュータ

2007.03.20 | | Comments(0) | Trackback(0) | Flash/ActionScript

コメント

コメントの投稿


秘密にする

«  | HOME |  »

プロフィール

HundredthMonkey

Author:HundredthMonkey
プログラマ。

ブロとも申請フォーム

この人とブロともになる

メールフォーム

名前:
メール:
件名:
本文:

ブログ内検索


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。