【UE5】ヘアハイライト・天使の輪(Hair Highlight / Angel Ring)を作ってみた

始まり

こんな感じのヘアハイライト・天使の輪を作っていきます。
首から下を見るとトウリさんと認識できますが、マスクして見ると湊くんにしか見えねぇ。。。大歓迎だけど♪
深層学習モデルに顔面の類似度見てもらおうかな、そうなったらブログネタ行きだけど。
湊くんほどじゃないけどトウリさんの瞳も結構好きかも。

©まどそふと

ヘアハイライト・天使の輪とは

画像のように髪に適用されるハイライト表現をヘアハイライトと呼びます。輪っか状のものは見た目が天使の輪っかっぽいので、別称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
Jitter(Hash関数)でギザギザはコレね。

ハイライトのデザインをひし形にする

はてなブログの最大画像サイズの都合で3分割

return frac(sin(dot(Value, float2(12.9898, 78.233))) * Seed);
return Size - (Position.x + Position.y);

RhombusではなくSquare算出を使用しているのは、あんまり差がなかったからという単調な理由です。ちなみにこの部分を任意に変えて頂ければある程度自由なデザインが作れます。

例えば蝶々みたいなデザイン

カメラ、ライト、ハーフベクトルの作成



FaceShadowの回はカメラを正規化していたけど必要なかった説。

ひし形の高さをランダムにズラす


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に加算しています。

完成!!!

©まどそふと

かなり近い表現が出来たんじゃないでしょうか。

おわり!!!

か わ い い

マジでお三方とも雰囲気が似ている。眺めているだけで楽しいわ。
ぱれっとクオリア(CLEAR RAVE)はガイドラインが厳しいので共演NGです。。。

あとFaceShadowの完全版はたぶんおそらくそのうちやります。
その前にPythonさんと戯れたい気分になってしまいました。

というか、この輪郭線いいですね(自画自賛)。
輪郭線はポスト表現、ComputeShader版、UnityのMaterial Flags (GBuffer)を用いた輪郭線マスク、3本ほどネタがあるのでその日(気分)が来たら解放・放出します。