前回のエントリーから続き。

前回は基準値とオブジェクトの距離からのぼかしの算出を行ったが、今回はカメラとオブジェクトの距離の算出による被写界深度。

こちらのほうがより自然っぽい。


カメラとの距離からピントが合う距離(FOCUS_POS)を引くことで、被写界深度表現の適用量(deg)を出すことができる。


まずカメラからの距離の算出として焦点距離が必要になる。


■焦点距離

カメラとオブジェクトの3次元内での距離の算出は2次元で使用する「Math . sqrt」にz軸を加えるだけで算出できる


式は関数化して戻り値として使用してそこからフォーカスの値を使用する


private function DistancePoint(obj:DisplayObject3D):Number {
var vecX:Number = obj.sceneX - camera.x;
var vecY:Number = obj.sceneY - camera.y;
var vecZ:Number = obj.sceneZ - camera.z;
return Math.sqrt((vecX * vecX) + (vecY * vecY) + (vecZ * vecZ));
}



■被写界深度表現の適用量

カメラとオブジェクトの距離からフォーカス値を引いた値を絶対値で計算。


var deg:Number=Math.abs(DistancePoint(obj) - フォーカス値) ;


■適応量を偶数補正

ここらへんはよく分からないけどぼかしなど「BlurX」「BlurY」の値は「2のべき乗」にするのが鉄則なのかな??

つまり偶数補正によって自然にするってこと??


var blur:int=Math.min(64 , deg * 0.02 << 1);


var blurfilter:BlurFilter=new BlurFilter(blur,blur,1);



■明度のコントロール

明度を対象にするとより自然になるってことなんで。ColorMatrixFilterをフィルタを使用


var blight:Number=deg/6; //ぼかしの適用量に調整値で割る(割らないと奥行きにいると真っ白になってしまう)

var blightnessArr:Array =
[
1, 0, 0, 0, blightness,
0, 1, 0, 0, blightness,
0, 0, 1, 0, blightness,
0, 0, 0, 1, 0
];
var blightnessFilter:ColorMatrixFilter = new ColorMatrixFilter(blightnessArr);




とこんな感じらしい。ちなみに上記のスクリプトはENTER_FRAME内


private function enterframeHandler(e:Event):void {
// 被写界深度フィルタの適用
for (var i:int = 0; i < list.length; i++) {
var p:DisplayObject3D = list[i] as DisplayObject3D;

// カメラとの距離の算出
var deg:Number = Math.abs(calcPointDistanceFromCamera(p) - FOCUS_POS);

// ぼかしの適用値
var blurVal:int = Math.min(64, deg * .012 << 1); // 偶数調整
var blurFilter:BlurFilter = new BlurFilter(blurVal, blurVal, 1);

// 明度の適用値
var blightness:Number = deg /8;
var blightnessArr:Array =
[
1, 0, 0, 0, blightness,
0, 1, 0, 0, blightness,
0, 0, 1, 0, blightness,
0, 0, 0, 1, 0
];
var blightnessFilter:ColorMatrixFilter = new ColorMatrixFilter(blightnessArr);

// フィルタ適用
p.filters = [blurFilter, blightnessFilter];
}

// Rendering
render.renderScene(scene, camera, vp);
}

/**
* カメラからの距離を算出します
* @param obj 計測対象のオブジェクト
* @return カメラからの距離(3D空間内のピクセル値)
*/
private function calcPointDistanceFromCamera(obj:DisplayObject3D):Number {
var vecX:Number = obj.sceneX - camera.x;
var vecY:Number = obj.sceneY - camera.y;
var vecZ:Number = obj.sceneZ - camera.z;
return Math.sqrt((vecX * vecX) + (vecY * vecY) + (vecZ * vecZ));
}


そもそも被写界深度とはよりリアルさを追求するためのものと個人的に思っているので、

今後はこのままのロジックを使用すれば良さそう