【CG】ズームレンズ(焦点距離を変更する)スライダーを実装しよう(UE4)

Pocket
email this

 写真展を見ているだけならまあいいのですが、カメラ設定を色々いじれるようにしてカメラマン気分に浸りたくなってきちゃうのは、性ですよねー。仕方がない。
 露光は自動でしょうがないかなとは思うけど、焦点距離やF値くらいはいじらせて下さい、と!
 ということで、カメラの焦点距離を変えるスライダーを画面上に実装して、いろいろ楽しんでみようではありませんか。


やってみよう

 まず、焦点距離と画角(以下FOV)の関係を見てみましょう。Wikipediaの画角を見るとその答えが載っています。
 さて勉強がてら自力で求めてみましょう。35mm判とは、横36mm×縦24mmフォーマットのことですから、ごにょごにょ計算すると以下のように求まります。

 グラフを作ってみるとこんな感じになります。
%e7%84%a6%e7%82%b9%e8%b7%9d%e9%9b%a2%e3%82%92%e5%a4%89%e6%9b%b4%e3%81%99%e3%82%8b%e3%82%b9%e3%83%a9%e3%82%a4%e3%83%80%e3%83%bc%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%97%e3%82%88%e3%81%86-1

 画角(α)は、上記の3ついずれかの寸法(d)と実効焦点距離(ƒ)とすると、
    α = 2 × arctan(d/2f) [rad]
つまり
    α = 2 × arctan(d/2f) × 180/π [deg]
で求められることも載っていますね。
 「えーこんな式をブループリントでやるのー?」とか思うでしょうが、UE4にはカーブというナイスなアセットがあります。

【参考】求め方(50mmレンズの場合)
興味がある方は以下ご参照。作ってみました。こういうことを言ってます。

センサーからレンズまでの距離が焦点距離ですが、センサーの半分の長さとで三角形を作ります。この三角から視野角が求められます。CGや光学でarctan()を多用するのはこの2値が分かっているけどFOVが分からんケースが多いからですね。

これを見て分かることは、例えば「焦点距離の値が大きいレンズ(=超望遠レンズ等)は小型化できない」ということ。やれないことはなくて、焦点距離fは縮めた分、センサーの幅dを小さくすれば視野角は維持できます。
じゃあセンサーを小さくする? と言われても、高解像度かつ超小型センサーというのは、今なら製造技術はあっても価格やら画質やらの兼ね合いで作る意味があんまりないのかも。ミラーレンズとかもありますが、光学の式から色々自分で考えてみるってのも面白いです。
余談になりました。




1.焦点距離・視野角の関係をカーブに落とし込む

 ということで早速カーブを作ってみましょう。コンテンツブラウザで[新規作成]→[その他]→[カーブ]がありますので選択。
 スライダーが0.0~1.0の範囲なので、
    カーブ①:この範囲がいくつの焦点距離に相当するのかということと、
    カーブ②:焦点距離から視野角FOVを求めるという2つのグラフを起こします。
これらは別にひとまとめでもいいです。2つに分けておけばカーブ①の方を変更すればスライダーのレンジを変更できますね。

 スライダーの範囲を『スライダー値=0.0の時、焦点距離=14mm』。『スライダー値1.0の時、焦点距離=200mm』とします。300mmはいいや。
 スライダー値(X)と焦点距離(Y)の関係は以下のように表しました。X=0.0のときY=14.0を返し、X=1.0のときY=200.0を返します。

 焦点距離(X)と視野角FOV(Y)の関係は以下のように表しました。X=14.0のときY=104.25を返します。こちらのカーブは線形補間しています。補完された値が正確なのか否かは気にしません、それっぽい挙動をすればいいです。




2.ウィジェットを作る

 画面にどう表示するかをデザインします。とりあえずこんなんでいいでしょう。
    ・ユーザは、スライダーをいじれます。
    ・焦点距離の値はスライダーに連動して更新されます。




3.ブループリントで制御を作る

 テキストはGetText_FocalLength()関数の処理と連動するようにします。

 スライダーの実装はこんな感じ。float型変数 slider_val 値と連動するようにしておきます。

 GetTextFocalLength()関数の中身はfloat型変数 focalLength_val を返してあげるだけです。




3-1.初期値の割り当て

 ウィジェットのグラフです。EventConstruct()関数で各変数に初期値をセットしておいてあげます。とりあえずスライダー値=0.0をセットします。
    slider_val   スライダーの値 
    focallength_val 焦点距離の値
    fov_val     視野角の値
    FOVSliderCurve  スライダー値 から 焦点距離値 を算出するカーブ。
    focallengthCurve 焦点距離値 から 視野角値 を算出するカーブ。
 このノードにより、プレイ時に以下のように初期値が決まります。
    slider_val   0.0
    focallength_val 14.0
    fov_val     104.25





3-2.スライダー移動時の制御

 次にスライダーが動かされたときの挙動を作りましょう。値が変更されたらイベントが起こるようにします。デザイナー画面で、スライダーの詳細に「OnValueChanged()」があるので追加します。
 イベントと一緒にスライダー値が来ますので、まずは素直にslider_valにセットし → 焦点距離値 → 視野角値 の順を更新します。

 最後にイベントディスパッチャでSliderEvent()を作成して、レベルブループリントにイベントを通知するようにします。
 ここからはレベルブループリントに移動。プレイ時にSliderEvent()とカスタムイベントのEventFOVSliderChanged()を作ってバインドします。

 あとは、ウィジェット側のSliderEvent()が呼ばれたときに何をしたいかをレベルブループリントの方に書きます。
 メインカメラの視野角を変えたいだけですので、下図のようなシンプルなノードでOKというわけですね。



完成

 いかがでしょうか。グーだね。
 次回はフォーカスとF値を調整するGUIも実装してみましょう。やろうとすればオートフォーカスも可能です。




画像提供

・Kamui Solano氏


コメントを残す