【UE5】チルトレンズの設計をしよう(1) ~必須となる「シャインプルーフの原理」~

Pocket
LinkedIn にシェア
LINEで送る

マーケットプレイスで販売中のシフトレンズカメラにもそろそろチルト機能をつけてあげたほうが良いかなと思って検討しつつ勉強中。
調査まもなく、なんということでしょう。レンズの傾きとフォーカス面の傾きの間には法則が存在し、公式があるというではありませんか。

引用元はこちらの論文。
チルトシフトレンズの被写界深度効果のCGによる再現(中根 智絵、馬場 雅志、日浦 慎作、浅田 尚紀) – CiNii

調べるとシャインプルーフの原理 (Scheimpflug principle)は、カタカナ表記だとシャインフルークとかシャインプリューフとか違いはありますがここではいったんWikipediaのカタカナ表記で示します。

誤解などあればご指摘ください。

チルトレンズ

ところでチルトレンズの作例と言うとこんな画が思い浮かぶと思いますが、ちなみにこれは結果的には似たような見た目ですけどもチルトレンズとは無関係です。F値(Aperture)を極端に小さくしたかのような表現をしているだけです。
こういうミニチュア風の画を手に入れることが目的であればブラーを誇大する実装で十分です。5分で終わりますしタイパも十分かと。

概要

普通の凸レンズでは、カメラセンサーの面、レンズの面、焦点が合う面がすべて並行になるのはわかっていますが、
さてレンズが傾くときに3面の間には何が起こるのか。カメラセンサーの面、レンズの面、焦点が合う面が一直線上に交わるというのです。これをシャインプルーフの原理と言うそうです。
すごいピンポイントな領域の話ですね。

通常のレンズ:

傾いたレンズ:焦点が合う面も傾く

導出

このルールがわかっていれば、焦点が合う面の傾きを求めること自体は簡単です。
レンズの傾きをΘL
求める合焦面の傾きをΘF
焦点距離をf、
レンズから焦点面までの距離をu
とします。このときセンサーの面から下に垂線を伸ばして3面が交わる地点までの距離をxと置いたとき、それぞれ2式が求まります。
  TanΘL = f / x  ・・・①
  TanΘF = (f + u) / x ・・・②

xについて①と②を1つの式にするとこうなります。
  f / TanΘL = (f + u) / TanΘF

TanΘFを求めるとこうなる。
  TanΘF = (f + u) / f * TanΘL

合焦面の傾きΘFが求まりました
  ΘF = Atan( (f + u) / f * TanΘL )

1. UE5へ実装するための検討

焦点面の傾く角度ΘFがわかりました、さてこれをUE5に対して実装したいと思っていますが、どうすればいいでしょう。

チルトレンズ機能というのは簡単に言うと「レンズの角度が変わることでピントが合うとされる平面の角度も変わる」ということなのですが、じゃあ、まずはどこに対して実装をしようかなという話になります。

ところでUnreal Engine Marketplaceで販売中のシフトレンズカメラはProjection Matrixを直接書き換えているのですが、だったらもちろんチルトレンズも同じProjection Matrixになにか影響を与えてやりたいと考えるわけですが、そうもいきません。
UE5に限らずCG全般はそうですが、ボケの表現というのはPost Processingで加工しているものですので、ボケ方が変化するチルトレンズを実装するのはPost Processingしかない。という結論になると考えられます。

ということでPost Processingに実装を考えていきましょう。

Post ProcessingにはPost Process Materialという設定項目があるのですが、これは一旦のレンダリング結果に対して加工が簡単にできたりするものになります。例えば画面全体に柄を加えたり、色を抜いたりとかってことがMaterial Editorの知識やコツがわかっていれば割と簡単に何でも加工が施せます。じゃあPost Process Materialでボケる部分を改変してやれば良いのではないかと考えます。
 

2. ボケを表現するための基本実装

ボケやブラーは知識が乏しいため、基本学習から始めて検討をしたためトータルで時間がかかりましたが要は
  ・自力でサンプリングするか
  ・ガウシアンブラー(Gaussian Blur)でいっちゃうか
という2択でした。最終的にはガウシアンブラーを採用しました。前者を取らなかった理由は2つで
  ①ノードがあまりにも複雑だったということ
  ①ブラーが弱くて気に入らなかったから
です。後者はカスタムシェーダー(Custom Shader)を使わざるを得ませんが
  ①1ノードで済みますし、
  ②ブラーの強さも調整できます。

ちなみにサンプリングする場合のブループリントです。地獄絵図。
地獄ブループリントはEpicフォーラムを参考にしました。
  Blur silhouette of mesh with material or post processing?? – Unreal Engine Forum
  Is this “the right way” to make a box blur material? – Unreal Engine Forum

一方でガウシアンブラーはこんな感じ。[Custom Shader]を使いますが1つでOKなのはうれしい。

[Code]の中身はUE Forumに載っていたものを利用させてもらいました。そのままコピペさせてもらうとUE5ではエラーが出るのでコンパイルエラーの内容に基づいて手直ししました。以下のCodeはUE5.2で動作確認がとれています。
  [Custom]シェーダーの[Code]
  Gaussian blur post processing material – Unreal Engine Forums

float3 res = 0;

float2 invSize = View.ViewSizeAndInvSize.zw;
uv = ViewportUVToSceneTextureUV(uv,14);
int TexIndex = 14;
float weights[] = { 0.01, 0.02, 0.04, 0.02, 0.01, 0.02, 0.04, 0.08, 0.04, 0.02, 0.04, 0.08, 0.16, 0.08, 0.04, 0.02, 0.04, 0.08, 0.04, 0.02, 0.01, 0.02, 0.04, 0.02, 0.01};

float offsets[] = { -4, -2, 0, 4, 2 };

if(Mask <= 0.01) return SceneTextureLookup(uv, TexIndex, false);

uv *= 0.5;
for (int i = 0; i < 5; ++i)
{
float v = uv.y + offsets[i] * invSize.y * Mask * BlurStrength;
int temp = i * 5;
for (int j = 0; j < 5; ++j)
{
float u = uv.x + offsets[j] * invSize.x * Mask * BlurStrength;
float2 uvShifted = uv + float2(u, v);
float weight = weights[temp + j];
float3 tex = SceneTextureLookup(uvShifted, TexIndex, false);
res += tex * weight;
}
}

return float4(res, 1);

3. 今のDepthを取得する

合焦面を得るには、まずは今の素直なDepth情報が元材料として必要です。
これは簡単でScene Depthノードで取得できます。

4. 正しい距離に基づくDepth情報を生成する

さてこれだけでは実は不十分で、Scene Depthというのは値が0~1の情報でしかありませんから、距離がわかりません。
例えば今見ている50%グレー色(Depth=0.5)の場所って、カメラからの距離が実際のところいくつなのか分からないんですよね。

ということでいったん[Camera Position]と[Absolute Position]の距離をとるノードを作ることでカメラからとある地点までの距離が単位:cmで正確に分かります。これを「測定A」と呼ぶことにします。
ただし、風景なんて被写体までの距離が2,000cmとかそれ以上になるわけですから、値をそのままDepthとして使うと全画面が真っ白になってしまいます。
そこで、とある係数で割ります。
カメラから被写体までの距離をFocus Distanceとしてパラメーターノードを作ってつないでおきます。

次に、Scene Depthに対してFocus Distanceノードを必ず使用することとして「測定A」と同じ結果になる係数を求めます。
結果としてFocus Distanceの半分の逆数でよいとわかりました。これを「測定B」と呼ぶことにします。

このとき「測定A」と「測定B」はほぼ同じDepth画面となりましたので近似できると考えます。[注意]
「測定A」を採用してしまう方がノードがシンプルで処理の負担も少ないですしね。

[注意]:厳密にいうとちょっと違いまして、測定BだとDepthマップが緩い球形になってしまっています。
測定Aは、Scene Depthはカメラの向きに直線を伸ばしたFocus Distanceの位置で垂直に交わる「平面」を表現しているものに対して、
測定Bは、カメラ位置からの距離だけを表現しているためです。

測定A
測定B

2に続く

まだまだ続きますが、今日はここまで。

参考サイト

チルトシフトレンズの被写界深度効果のCGによる再現(中根 智絵、馬場 雅志、日浦 慎作、浅田 尚紀) – CiNii
シャインプルーフの原理 – Wikipedia
Gaussian blur post processing material – Unreal Engine Forums
Blur silhouette of mesh with material or post processing?? – Unreal Engine Forum
Is this “the right way” to make a box blur material? – Unreal Engine Forum

記事の情報はお役に立ちましたか?

ご支援も承っています。
ご注意:返金のご対応はいたしかねます。あくまでも投げ銭としての位置付けであり、優待・特典等はございません。ご了承下さい。

22304:【UE5】チルトレンズの設計をしよう(1) ~必須となる「シャインプルーフの原理」~

v3

管理人が読んだおすすめの建築本

    

コメントを残す