【MME】髪用の動くハイライトエフェクトα版
MMEで使える、髪用の動くハイライトエフェクトを配布します。
動画に使ってから1年以上放置していたエフェクトです。先日マシュマロちゃんで「仕組みを知りたい」との話がありまして、私が直接中身を見てもらったほうが早いかなと思った経緯によりましてα版となっております。使えそうならお使いください。
概要
頭やカメラ、ライトの方向に従ってハイライトが上下に動きます。
専用テクスチャのGとBでハイライトの形状をコントロールできます。Gがハイライトの上端の形状になり、Bがハイライトの下端の形状になります。GやBの値をマスクとして乗算しているので、値が大きいほどハイライトが大きくなり、値が小さいほどハイライトが削れて小さくなります。Gが0.1以下だとハイライトが出ない領域になります。
参考までに、Shininetさんの「アヤベさん モデル Ver1.0.0」用のテクスチャを同梱してあります。
仕組み
メイン全体は以下のようになっています。マジックナンバーが多い。
#ifdef ADAPT_HIGH_TEXTURE
float3 AdaptHighTex = tex2Dfix( AdaptHighTextureSampler, IN.Tex, 0.0 ).rgb;
float3 AdaptHigh = AdaptHighTex;
//ライトによる移動量
float hairRateL = mul( -LightDirection, transpose(tgt3) ).y * 0.30;
//カメラによる移動量
float hairRateC = normalize( CameraPosition - tgtPos ).y * 0.50;
//頭の角度の影響を受けるか
//1:ハイライトを頭のXZ平面に沿って補正して出す(常に天使の輪みたいになる)
float localPos1 = mul( mul( CameraPosition - IN.Eye, WorldMatrixInv ) - tgtPos, transpose(tgt3) ).y;
//2:ハイライトを補正せずに出す
float localPos2 = ( mul( CameraPosition - IN.Eye, WorldMatrixInv ) - tgtPos ).y;
//ratio 1 and 2
float localPos = lerp( localPos1, localPos2, 0.5 );
//頭ボーンからの高さ
float dis = localPos - ( 1.8 + hairRateL + hairRateC );
//Adapt Highテクスチャの赤で、高さ情報にノイズを与える
AdaptHigh.r -= 0.5;
dis += AdaptHigh.r * 0.05;
//ハイライトの幅
float width = 0.08;
//幅に合わせてリマップ
float disRemap = ( dis - (-width) ) / ( width * 2.0 );
//テクスチャのGとBでマスク
AdaptHigh.gb = lerp( AdaptHigh.gb, 1.0, 0.9);
AdaptHigh.g = lerp( AdaptHigh.b, AdaptHigh.g, disRemap);
AdaptHigh.g *= step( 0.1, AdaptHighTex.g);
//ハイライトの形状
float highlight = step( 1.0 - width, ( 1.0 - abs(dis) ) * AdaptHigh.g );
//ハイライトの強さ
highlight *= max(dot( IN.Normal, -LightDirection), 0.0) * lerp( 0.25, 1.0, disRemap ) * dotLight;
Color.rgb += highlight * HIGHLIGHT_COLOR;
//Color.rgb = localPos2;
Color = saturate( Color );
#endif
ライトとカメラの影響
//ライトによる移動量
float hairRateL = mul( -LightDirection, transpose(tgt3) ).y * 0.30;
//カメラによる移動量
float hairRateC = normalize( CameraPosition - tgtPos ).y * 0.50;
tgtは頭のボーンです。ライトとカメラは計算方法が異なりますがどちらも頭ボーンから見た高低差(-1~+1)を移動量として扱っています。
文末の数値は影響の度合いです。大きくするとライトやカメラによるハイライトの移動量が大きくなります。
ハイライトの位置
//頭ボーンからの高さ
float dis = localPos - ( 1.8 + hairRateL + hairRateC );
//Adapt Highテクスチャの赤で、高さ情報にノイズを与える
AdaptHigh.r -= 0.5;
dis += AdaptHigh.r * 0.05;
localPosは頭ボーンからの高さ方向の位置です。disはlocalPosから基準値(1.8)までの距離です。1.8を変えればハイライトの出る位置の基準を調整できます。
専用テクスチャのRで位置にノイズを与えられます。
ハイライトの形状と強さ
//ハイライトの幅
float width = 0.08;
//幅に合わせてリマップ
float disRemap = ( dis - (-width) ) / ( width * 2.0 );
//テクスチャのGとBでマスク
AdaptHigh.gb = lerp( AdaptHigh.gb, 1.0, 0.9);
AdaptHigh.g = lerp( AdaptHigh.b, AdaptHigh.g, disRemap);
AdaptHigh.g *= step( 0.1, AdaptHighTex.g);
//ハイライトの形状
float highlight = step( 1.0 - width, ( 1.0 - abs(dis) ) * AdaptHigh.g );
//ハイライトの強さ
highlight *= max(dot( IN.Normal, -LightDirection), 0.0) * lerp( 0.25, 1.0, disRemap ) * dotLight;
widthはハイライトの幅です。dis=0を基準に、±widthの範囲がハイライトとなります。
disRemapはdisを[-width,+width]から[0.0,1.0]にリマップしたものです。
「ハイライトの形状」部分でdisの値を反転して、テクスチャのマスクで削っています。
「ハイライトの強さ」はmax(…)でライティングによる強弱、lerp(…)で上端ほど明るく下端ほど暗くなるようにしています。
ハイライトの色
Color.rgb += highlight * HIGHLIGHT_COLOR;
highlightがハイライトの形状と強さになっているので、ハイライトの色を乗せて元の色に足します。
以上です。α版ですがお楽しみいただければ幸いです。