概要
現実世界のものをデジタルカメラで撮影して
そこからノーマルマップを起こすとき
4方向のライトをあてた4枚の画像から作ることがある。
(撮影方法等の参考:http://cgcompo.blog134.fc2.com/blog-entry-63.html)
この4枚のテクスチャからノーマルマップを生成する処理をShaderForgeで実装してみる。
ただし、サンプルの画像、それから生成される正しいノーマルマップが手元にないので検証はできてません。
また、ノーマルマップの合成はリアルタイム処理でやる必要はほとんどの場合ありません。
動作を確認しやすいためUnity環境でテストしました。
環境
Unity5.5.2p4
ShaderForge v1.36
実装
4枚のテクスチャは、それぞれ上下左右から当てられたライトの画像となる。
これらはグレースケールに変換されて、その画像から合成する。
左からあたったライトの画像で、輝度が高い(白い)ところは面が左に向いていると仮定する。
このときノーマルマップのRの値は0になる。
右の場合は面が右に向いているのでRが1になる。
この2つの画像を合成するときオーバレイの処理で合成する。
(https://blender.jp/modules/newbb/viewtopic.php?viewmode=flat&topic_id=174&forum=4)
オーバレイの式は
明度の高い部分と低い部分の鮮やかさが上がります。彩かさが上がるため、画像全体にかけると一見キレイになったかのような錯覚に陥りやすいので、注意しましょう。錯覚です。
全体の色調を統一するためや塗り斑、主線に色を付けるためなどによく利用されています。
計算式は以下のようになります。重ねられるレイヤー(下のレイヤー)の中間値で乗算とスクリーンを使い分けているようです。
Pa < 128 の場合
Pn = Pa * Pb * 2 / 255
Pa >= 128 の場合
Pn = 2 * (Pa + Pb - Pa * Pb / 255) - 255
です。Pn、Pa、Pb を0~1の範囲とする場合、
Pa < 0.5のとき
Pn = Pa * Pb * 2
Pa >= 0.5のとき
Pn = 1 - 2 * ( 1 - Pa ) * ( 1 - Pb )
となります。
(https://ofo.jp/osakana/cgtips/blendmode.phtml#overlay)
これらを踏まえて実装する。
実装内容は以下の通り。
Unityでの実行結果。
左がノーマルマップをそのまま表示したもの。
右が合成されたノーマルマップをもとにライティングした結果。
どちらもQuadで平面のもの。
しかしノーマルマップによって凹凸のライティングが処理されている。
課題点
オーバレイの計算式で「0.5未満のときは」という条件式があったが
これは必要なく「Pn = 1 - 2 * ( 1 - Pa ) * ( 1 - Pb )」で求まる気がする。
Zの値はカメラのレンズからライトを当てたときの明暗になると思うけども
物理的にそれは不可能なので、実際はどうやって処理しているのか???
検証ができないのでテスト用のサンプルデータが欲しい!
感想
できあがったノーマルマップだけではSprite Lampのようなコントラストの強いライト処理にはならない。
まよわずSprite Lampを買おう!
ノーマルマップの合成は実行できたとしてもDiffuseマップって
カメラでどうやって撮影するんでしょうか?
ライトを上下左右以外にも前方向から当てるでしょうか?謎