見出し画像

NormalMapを手描きする、というお話

こんにちは、見障子ゆきです。

今回はNormalMapをペイント系ツールで手描きしてみるお話です。
前回の投稿からの地続きの話ですが、この記事だけでも一応問題なく読めるようになってる……ハズです!
(前回の記事ではNormal(法線)について解説しているので、気になる方はどうぞ!)

かなりニッチな技術ですが、さっそくやっていきましょう!


■まず始めに

身も蓋もない話ですが、手描きしなくても済むならしない方が良いです。(細かな話はのちほど記載しますが、主にデータの正確性に欠けます)

今回は「2DイラストにNormalMapを適応させる」事を目的に、正確性より表現性を重視します。

という訳で、この2Dイラストに対するノーマルマップを手描きします。

前回も登場したイラスト

・動作環境

<ペイントツール>
・ClipStudioPaint や Photoshop などのペイントツール
  加算・減算レイヤーがあれば他のツールでもOKです。
  加算レイヤーがあればどうにでもなりそう。

<NormalMapを取り込むツール>
・Unity 2022
(NormalMapに対応していればUnityである必要はありませんが、
 UnityのNormalMapは正規化処理などに対応しているので
 今回はそれを活用しています)

■NormalMapを手描きするやり方

いろいろな説明をすっ飛ばして書きます。
(詳しい解説や原理は後で説明します)

  1. 赤色(R)のみで「右からライトが当たった時の陰影」を塗ります。

  2. 緑色(G)のみで「上からライトが当たった時の陰影」を塗ります。

  3. 青色(B)で塗りつぶしたレイヤーを用意します。

  4. 上の「1.」~「3.」を加算で合成します。

「1.」。右からライトが当たったと想定した陰影
「2.」。上からライトが当たったと想定した陰影。
「3.」。青(B255)ベタ塗りのレイヤー。
「4.」。「1.」~「3.」を加算で重ねた画像(NormalMap完成!)

「1.」や「2.」を塗る際は、赤255(or緑255)を50%透明にした状態(赤ならR128)を中間色として描きます。
その上から明るくなる箇所を「加算レイヤー」で、暗くなる箇所を「減算レイヤー」で塗ると楽です。

この際に重要な点として、落ち影は塗ってはいけません
落ち影とは光が何かに遮られて落ちる影のことです。
髪の落ち影を肌に乗せる、等は不要ということですね。

「4.」まで出来たらお使いのツールにNormalMapとして取り込んで反映してみてください。
ライトを動かして、イメージしていたライティングが反映されているか確認して、必要であれば「1.」「2.」を調整します。

グリグリ動かして確かめてみる

Q.ライティングの上下が逆になってる???

A.NormalMapを取り込むツールによっては、緑色の明暗を反転させる必要があります。
下からライトが当たったと仮定して塗るか、お使いのペイントツールにトーンカーブがあるならGreenのみのトーンを逆転(右下下がりの直線)にすると明暗を逆転できます。

Photoshopのトーンカーブで、緑の明暗を逆転する例

・Unityへの取り込み

「4.」まで完了した画像をUnityで取り込んで、NormalMapの設定を行ってApplyすればOKです。

Inspectorから、TextureTypeをNormalMapへ変更

■法線Mapに詳しい方向けの補足(懸念など)

ここまでの説明の時点で、NormalMapに詳しい方であれば「ん??」と思われたと思います。
その通りで、このやり方はいくらかの問題を抱えています。
 ①色の変化が極端な箇所(線画付近など)の法線が荒れやすい事
 ②1dot毎に格納されたVector情報が正規化されていない事
 ③Bを255のベタ塗りにしてしまっている事
 ④3D上でUV展開した物の場合、向きを気にする必要がある事
  (④は文字通り気を付けるだけなので割愛します)

①については実際、今回のサンプルデータででもライティング結果がジャギってしまっている事があります。
R成分とG成分で塗りこむ際、線画が分からなくなる位に食い込むようなマスク取りにした方がベターかと思います。

②、③についてはUnityの機能に頼る事で不問としています。
UnityのNormalMapの扱いの中で、"おそらく(※)"正規化処理やBの値の再計算が行われているようです。

NormalMapの設定前(未処理)状態と、
NormalMap設定を完了させたものを適用した図

②で正規化されていない事で起きる主な問題は下記かと思います。
 ・Shader計算時、内積計算時にVector長の分の補正が掛かる可能性
  (Shader計算やツールによって若干変わります)
お使いのツールがUnityではない環境の場合、
 ・テクスチャ側の正規化処理を行うツールを用意して事前に処理
 ・Shader側で、NormalMapをtex2Dした後にnormalize処理を行う
 ・テクスチャ描く時点でライティング結果に補正が掛かる事込みで描く
のいずれかの対応は必要になるかもしれません。

③は「R・G成分が決まっている単位ベクトル(長さが1のベクトル)の場合、本来残りのBは自動的に決まるハズだからベタ塗りにしていいの?」という話です。
Unity上であればNormalMap設定時にBの値を再計算しているようなので、極端な話B成分を塗っていなくても問題無いようです。

(※)"おそらく"
試しに自前で正規化処理&画像出力を実装して比較したところ、わずかに色の誤差や、Unityの方は微妙にVector長が1を超えるカラーピクセルが見られました。
それでもUnity上で処理された方が綺麗でした。なんでやねん。
画質優先で何かしらの実装が採用されている気はします。

■なぜこの方法でNormalMapを塗れるの?

ここからは解説編です。
冒頭では理由をすっ飛ばして、「1.右からライトが当たった時の陰影を赤」「2.上から~~陰影を緑」とした所の解説編です。

・NormalMapに格納されている情報の正体

前回の記事で「Normal=垂直=法線」という話で、
 ・NormalMapは法線データの集合体
 ・法線を意図していじることが出来る
ということに触れました。

NormalMapはまさに、意図していじった法線データの集合体です。
各ピクセル事に法線データが格納されています。

法線は3Dベクトルの実態を持っていて、(x,y,z)で表現できます。
対してカラー情報はRGB(A)で表現できます。(R,G,B)や(R,G,B,A)という具合。
そうです、置き換えているだけです。
いじった法線の x →Rに、y →Gに、z →Bに格納したのがNormalMapです。

この際、法線は「-1.0 ~ 1.0」の値をxyzそれぞれ取り得ますが、
RGBの範囲は「0~255」なので、「法線:-1.0 = RGB:0」「法線:1.0 = RGB:255」として置き換えて扱われます。
中間「法線:0.0」は大体「RGB:128」です。

・今回の方法で塗れる理由

x →Rなので、Rが横方向(x)の法線情報を持ちます
R128の中間を境に、+に増えるほど法線は右向きに、-に減るほど法線は左向きであるとして扱われます。

Rが横方向の法線情報を持っている、のイメージ図

極論、これをイメージしながら色を指定することが出来ればOKです!
でも「法線が右に向いている」事を想像して描くのは正直難しい。

ここで前回の法線の解説のとおり、法線は光の角度と向き合うほど明るくなることを利用します。
ここで、画像より右側に光源があると仮定します。

画像の右側に光源があると考えた時、
 ・Rの値が大きいほど画像としての色は明るくなる
 ・右向きの法線はさらに右に光源がある場合に明るくなる
という具合に、Rの強さ(=法線の方向)の見た目と「右からライトが当たった時の陰影」の見た目が一致します。

ので、「右からライトが当たった時の陰影」をイメージして塗ると、結果的にそのまま横方向の法線(x)を指定できることになります。
NormalMapが見た目独特だけど、なんとなく立体的に見える理由でもあります。

緑(G)に関しても同様です。
y →Gなので、yは上下方向の法線情報を持っています。
y が強いほど法線としては上を向くので、上からのライトを想定して塗ると結果が一致します。

・ちなみにNormalMapのBは……

ちなみに青(B)は法線の性質上、RとGが決まっていれば自動的に決まる項目です。
Unityで扱う上では自動で計算されるため、ベタ塗りでOKです。

一応解説しておくと、青(B)は z 情報を持つことになります。
z は前後の法線情報です。y の上下情報とは別です。
これをRG同様に手描きで塗るなら、「真正面からライトが当たった時」を塗ることになります。
が、落ち影無しで塗るので、イラストに描画されてる範囲はある程度必ず光が当たることになります。
具体的にはB127以下には基本的にならないので、B128を基準として上から加算だけで塗ってOKです。

・ちなみに落ち影なしで塗る理由は?

法線と光の角度によって基本的な明るさが決まる、というのは前回の記事の通りです。
が、落ち影は法線とは無関係に影を落として暗くなります。
つまり落ち影とは法線(Normal)と別の要因であるため、NormalMapとして扱ってはいけないというのが理由です。

落ち影有りで塗ってしまうと、落ち影ではなく暗い色としての法線として計算されるため、意図したライティングの結果が得られなくなります。

■この手法が向いている表現の場

正直、使いどころはかなり狭いと思ってます。誰が使うんだこの技術……。
映像媒体ならこんなこと研究しなくても多少アニメ作画的に描いてしまう方が直感的で汎用性も高いです。

あるとするなら、ゲームのようなインタラクティブ性(プレイヤーの操作に応じて画面が変わる場など)を活かした場になるでしょうか。

と思ってちょっと調べてみたら、Live2Dに自作のNormalMapを適応させている作品も見かけました。
なるほど、Live2Dは想像してなかったなぁ。素晴らしい発想。
(「Live2D NormalMap」とかで検索するとすぐにヒットすると思います)

■最後に

前回にも増して小難しい話になっちゃいましたが、これがいつかどなたかの役に立つといいなぁと思って吹っ切りました。
次回はもうちょっと軽めな話も書きたいですね。

また今回の記事のために、自前でNormalMap正規化ツールを実装してUnity側のNormalMap用の挙動を調べてみたりすることになりました。
が、結果、Unity側の挙動はよく分からないけどなんかいい感じ、だということが分かりました。すごいなぁと思いました(小学生並みの感想)。

#NormalMap
#法線マップ
#手描き
#Unity
#解説


この記事が気に入ったらサポートをしてみませんか?