作業環境
- Windows 10
- Visual Studio 2022
- Visual Studio Code
- Unreal Engine 5.3
始まり
こんな感じのヘアハイライト・天使の輪を作っていきます。
首から下を見るとトウリさんと認識できますが、マスクして見ると湊くんにしか見えねぇ。。。大歓迎だけど♪
深層学習モデルに顔面の類似度見てもらおうかな、そうなったらブログネタ行きだけど。
湊くんほどじゃないけどトウリさんの瞳も結構好きかも。
ヘアハイライト・天使の輪とは
画像のように髪に適用されるハイライト表現をヘアハイライトと呼びます。輪っか状のものは見た目が天使の輪っかっぽいので、別称AngelRingとも呼ばれています。2つの区別としては現実的なハイライト表現をヘアハイライト、天使の輪っかのようなアニメやトゥーン表現寄りのものをAngelRingとしている傾向が見られます。厳密な境界線はないはずなので、伝わる範囲であれば好きな方で呼んだらいいんじゃないですかね。
Hair Highlight / Angel Ring ノードを組んでいく
早速ですがノードを組んでいきます。
法線や接線、UVは全て疑似的に作成するため手順が多く、初見だと難しい部分があるかもしれません。まぁ習うより慣れろです。苦手な方は時間を掛けて頑張ってくださいな。筆者も学がないからどっちかというかそっち(どっち)派だし。
あと注意点としてショートからミディアムの子の方が相性いいです。ロングは出来ないことはないですが、頂点座標を球形にするには乖離し過ぎていて、ちょっぴり思い通りな制御が出来ないかもしれません。
ノードの紹介が順不同です。前提としてAnisotropicの作り方を理解していないとどうせ難しいだろうからもういいやと若干投げやりになっています。
球形法線と球形UVを疑似的に作成
前提としてキャラクターモデルのような複雑な形状でアニメやトゥーン表現寄りの綺麗な輪っかなハイライトを作ることはほぼ不可能です。
法線をイメージして頂ければわかると思いますが、球形に比べると向きが複雑すぎるのです。
球形ほどガッチガチに綺麗な法線を作ることは今回やる疑似的な計算でも難しいですが、ベイクされている法線を使うよりは改善できます。
UVはひし形のデザインをするために球形UVが必要なので、疑似的な球形座標を元に球形UVを算出しています。
return (all(V > 1.0) || all(V > -1.0)) ? normalize(V) : float3(0.0, 0.0, 0.0);
return float2(0.5 + atan2(Position.x, Position.y) / (2.0 * PI), 0.5 - asin(Position.z) / PI);
頭の中心位置を調整すると割と球形法線に近いものが再現できることが確認できます。
HairHighlightHead (0.0, 0.0, 0.0) | HairHighlightHead (0.0, 0.0, -125.0) |
---|---|
頭のサイズはその範囲内にハイライトが適用されるので任意に調整してください。今回は境界線にフェードを変えていないのでぶつ切りになります。ロングヘアだとこの辺りで支障が出そうな気がするのでsmoothstepでなんか上手いことやる必要がある気がします。
HairHighlightRadius (5.0, 5.0, 5.0) | HairHighlightRadius (10.0, 10.0, 10.0) |
---|---|
疑似的な球形UVはこんな感じです。所謂JitterTextureと呼ばれるものでハイライトを作るのであれば通常UVでもいいのですが、今回のように任意の形状をデザインとしたい場合には、不向きなため球形UVを用います。
通常UV | 疑似球形UV |
---|---|
ハイライトのデザインをひし形にする
※はてなブログの最大画像サイズの都合で3分割
return frac(sin(dot(Value, float2(12.9898, 78.233))) * Seed);
return Size - (Position.x + Position.y);
RhombusではなくSquare算出を使用しているのは、あんまり差がなかったからという単調な理由です。ちなみにこの部分を任意に変えて頂ければある程度自由なデザインが作れます。
ひし形の高さをランダムにズラす
return frac(sin(dot(Value, float2(12.9898, 78.233))) * Seed);
HairHighlightHeadTilledTexCoord
の区間ごとに高さをズラしています。
HighlightJitterShiftMin: 0.0 | HighlightJitterShiftMin: -0.5 |
---|---|
疑似的な接線の作成
return Shift == 0.0 ? T : normalize(T + N * Shift);
ハイライト計算に都合が良い接線を疑似的に作成しています。
ハイライトの計算
一般的なハイライト計算と基本的には同じです。差分はマスクとしてsmoothstepを追加している点です。powによる太さ調整だけだとデザイン以外の部分にも細い線が適用されてしまうため、smoothstepでちょん切っています。
スケールやエッジ調整のシャープパラメータ
PreSharpenMin/MaxとPostSharpenはsmoothstepの適用タイミングが異なるため使い分けが必要です。
HairHighlightDesignPreSharpenMin/Max
HairHighlightDesignPreSharpenMinでサイズ、エッジ調整をするとエッジがトゲトゲします。
パラメータ名 | パラメータ値 |
---|---|
HairHighlightDesignPreSharpenMin |
0.5 |
HairHighlightDesignPreSharpenMax |
1.0 |
HairHighlightDesignPostSharpen |
1.0 |
HairHighlightDesignPostSharpen
HairHighlightDesignPostSharpenでサイズ、エッジ調整をすると丸みを帯びます。
パラメータ名 | パラメータ値 |
---|---|
HairHighlightDesignPreSharpenMin |
0.0 |
HairHighlightDesignPreSharpenMax |
1.0 |
HairHighlightDesignPostSharpen |
2.0 |
ハイライトの適用
色の乗せ方はご自由にどうぞ。筆者はSceneColorに加算しています。
完成!!!
かなり近い表現が出来たんじゃないでしょうか。