夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

MRTK HandTrianglesShaderの中身を読み解く その⑥ ジオメトリシェーダーを読み解く Ⅲ

本日もMRTKのHandTrianglesShaderの勉強枠です。

前々回からHandTrianglesShaderのジオメトリシェーダーを読み解いていきます。 長いのでその③ 序Ⅲです。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

  float Transition_Q160;
        bool FadingOut_Q160;
        float Saturation_Q160;
        float Fade_Color_Q160;
        Pulse_B160(Distance_Q159,Result_Q150,_Pulse_Enabled_,Result_Q149,_Pulse_Width_,_Pulse_Outer_Size_,_Pulse_Lead_Fuzz_,_Pulse_Tail_Fuzz_,_Pulse_Vary_,_Pulse_Color_Width_,Transition_Q160,FadingOut_Q160,Saturation_Q160,Fade_Color_Q160);
   void Pulse_B160(
        float Distance,
        float Noise,
        bool Pulse_Enabled,
        float Pulse,
        float Pulse_Width,
        float Pulse_Outer_Size,
        float Pulse_Lead_Fuzz,
        float Pulse_Tail_Fuzz,
        float Pulse_Vary,
        float Pulse_Saturation,
        out float Transition,
        out bool FadingOut,
        out float Saturation,
        out float Fade_Color    )
    {
        Transition = 1.0;
        Saturation = 1.0;
        Fade_Color = 1.0;
        
        if (Pulse_Enabled) {
            float d = Distance - Pulse_Vary*Noise; 
            
            float totalSize = Pulse_Outer_Size+Pulse_Vary+Pulse_Width;
            float pulseFront = Pulse * totalSize;
        
            float edge1 = pulseFront-Pulse_Width*0.5*Pulse_Lead_Fuzz;
            float fadeIn = saturate(1.0-ramp_Bid160(edge1,pulseFront,d));
            float fadeOut = saturate(1.0-ramp_Bid160(pulseFront-Pulse_Width,pulseFront-Pulse_Width+Pulse_Width*0.5*Pulse_Tail_Fuzz,d));
            Saturation = saturate(smoothstep(edge1-Pulse_Saturation,edge1,d));
        
            float clip = 1.0-step(Pulse_Outer_Size,d);
            
            Transition= saturate(fadeIn-fadeOut)*clip;
            FadingOut = fadeOut>0.0;
            Fade_Color = 1.0-fadeOut;
        }
        
    }

・float Distance =Distance_Q159(ポリゴンの重心ベクトルと_Pulse_Originのベクトルの距離)

・float Noise=Result_Q150( Cell_Noise_2D_B150()で処理された変数)

・bool Pulse_Enabled=Pulse_Enabled(プロパティでのPulseEnabledのチェックボックス)

・float Pulse=Result_Q149(AutoPulseがMaterialでオンになっている場合、時間をPeriodで割った少数部分オフの場合_Pulseの値が代入されます。)

・float Pulse_Width=Pulse_Width(プロパティで設定されたPulse Widthの値が入ります。デフォルトでは1が入ります。)

・float Pulse_Outer_Size=Pulse_Outer_Size(プロパティで設定されたPulse Outer Sizeの値が入ります。デフォルトでは1.05が入ります。)

・float Pulse_Lead_Fuzz=Pulse_Lead_Fuzz(プロパティで設定されたPulse Lead Fuzzの値が入ります。defaultでは0.67が入ります。)

・float Pulse_Tail_Fuzz=Pulse_Tail_Fuzz(プロパティで設定されたPulse Lead Fuzzの値が入ります。defaultでは0.8が入ります。)

・float Pulse_Vary=Pulse_Vary(プロパティで設定されたPulse Varyの値が入ります。defaultでは0.075が入ります。)

・float Pulse_Saturation=Pulse_Color_Width(プロパティで設定されたPulse Color Widthの値が入ります。defaultでは1が入ります)

・out float Transition=Transition_Q160

・out bool FadingOut=FadingOut_Q160

・out float Saturation=Saturation_Q160

・out float Fade_Color=Fade_Color_Q160

Pulse_B160()ではProperties{}でマテリアルから指定された値とここまでジオメトリシェーダー内で計算した変数が一度に引数として使用されています。

        Transition = 1.0;
        Saturation = 1.0;
        Fade_Color = 1.0;

Transition_Q160、Saturation_Q160、Fade_Color_Q160にそれぞれ1が代入されます。

       if (Pulse_Enabled) {
            float d = Distance - Pulse_Vary*Noise; 
            
            float totalSize = Pulse_Outer_Size+Pulse_Vary+Pulse_Width;
            float pulseFront = Pulse * totalSize;
        
            float edge1 = pulseFront-Pulse_Width*0.5*Pulse_Lead_Fuzz;
            float fadeIn = saturate(1.0-ramp_Bid160(edge1,pulseFront,d));
            float fadeOut = saturate(1.0-ramp_Bid160(pulseFront-Pulse_Width,pulseFront-Pulse_Width+Pulse_Width*0.5*Pulse_Tail_Fuzz,d));
            Saturation = saturate(smoothstep(edge1-Pulse_Saturation,edge1,d));
        
            float clip = 1.0-step(Pulse_Outer_Size,d);
            
            Transition= saturate(fadeIn-fadeOut)*clip;
            FadingOut = fadeOut>0.0;
            Fade_Col

PulseEnabledがオンの場合次の処理が行われます。

         float d = Distance - Pulse_Vary*Noise; 

dにポリゴンの重心ベクトルと_Pulse_Originのベクトルの距離からプロパティで設定されたPulse Varyの値とCell_Noise_2D_B150()で処理された変数をかけたものが減算されます。

            float totalSize = Pulse_Outer_Size+Pulse_Vary+Pulse_Width;
            float pulseFront = Pulse * totalSize;

totalSizeにはプロパティで設定されたPulse Outer Sizeの値とPulse Varyの値とPulse Widthの値の和が代入されます。デフォルトでは1.05+0.075+1=2.125の値が入ります。

pulseFrontにはAutoPulseがMaterialでオンになっている場合、時間をPeriodで割った少数部分とtotalSizeの積が代入されます。AutoPulseがオフの場合_Pulseの値とtotalSizeの積が入ります。

          float edge1 = pulseFront-Pulse_Width*0.5*Pulse_Lead_Fuzz;
            float fadeIn = saturate(1.0-ramp_Bid160(edge1,pulseFront,d));
            float fadeOut = saturate(1.0-ramp_Bid160(pulseFront-Pulse_Width,pulseFront-Pulse_Width+Pulse_Width*0.5*Pulse_Tail_Fuzz,d));
            Saturation = saturate(smoothstep(edge1-Pulse_Saturation,edge1,d));

edge1にはpulseFrontから0.5とプロパティで設定されたPulse Widthの値とPulse Lead Fuzzの値が積算された値が減算されたものが代入されます。

            float fadeIn = saturate(1.0-ramp_Bid160(edge1,pulseFront,d));

ramp_Bid160()は425~429行目で記述されています。

    float ramp_Bid160(float start, float end, float x)
    {
    //    return saturate((x-start)/(end-start));
        return smoothstep(start,end,x);
    }

start、end、 xにはそれぞれedge1、pulseFront、dの値がそれぞれ入ります。

このメソッドではsaturate*1=(x-start)/(end-start)の値を0~1の間に定めます。(例:0.5= 0.5 、1.6 =1、2.7=1)

smoothstep()は

float smoothstep(float a, float b, float x)
{
  float t = saturate((x - a)/(b - a));
  return t * t * (3.0 - (2.0 * t));
}

というメソッドになります。

これは2つの数値からなる範囲ともう一つの数値を用いて0.0~1.0までの間で滑らかに変化する値を返す関数です。

thebookofshaders.com

qiita.com

ramp_Bid160()はsaturate*2=(x-start)/(end-start)の値を0~1の間に定め値を返します。

fadeInには1からramp_Bid160()の値を引いた数を0~1の間に定めた値を返します。

    float fadeOut = saturate(1.0-ramp_Bid160(pulseFront-Pulse_Width,pulseFront-Pulse_Width+Pulse_Width*0.5*Pulse_Tail_Fuzz,d));

fadeOutにはpulseFront-Pulse_WidthとpulseFront-Pulse_Width+Pulse_Width0.5Pulse_Tail_Fuzz、dの値をramp_Bid160()に通し帰ってきた値を1から引いた値を0~1に定めたものが代入されます。

fadeIn、fadeOutにて通されたramp_Bid160()は正の数を入力したときはそのままの数、負の数が入力されたときはは0を返す処理をしているようです。これはランプ関数と呼ばれる関数になります。

            Saturation = saturate(smoothstep(edge1-Pulse_Saturation,edge1,d));

Saturationにはsmoothstep(edge1-Pulse_Saturation,edge1,d)を0~1に定めたものが代入されます。

smoothstep(edge1-Pulse_Saturation,edge1,d)はedge1からPulse_Saturationを引いたものとedge1の線をdで補完した値になります。

            float clip = 1.0-step(Pulse_Outer_Size,d);
            
            Transition= saturate(fadeIn-fadeOut)*clip;
            FadingOut = fadeOut>0.0;
          Fade_Color = 1.0-fadeOut;

clipにはstep(Pulse_Outer_Size,d)を1から引いた値が入ります。

step(a,x)関数ではxがa未満の場合は0.0を、それ以上の場合は1.0の二値化を行う関数です。

つまりここではPulse_Ourer_Sizeがd未満であれば0を,以上であれば1の値を返します。

よってclipはPulse_Ourer_Sizeがd未満であれば1を,以上であれば0の値を返します。

TransitionにはfadeInとfadeOutの差をclipで乗算した値が代入されます。

つまりPulse_Outer_Sizeがd未満であればTransitionの値は0、以上であればTransitionはそのままfadeInとfadeOutの差が代入されます。

Fade_Colorには1とfadeOutとの差分が代入されます。 fadeOutは0より大きいためFade_Colorは1より大きな値を取ることはありません。

以上がPulse_B160()で行っている処理です。

〇Pulse_B160()の処理のまとめ

①Pulseがマテリアル側でオンになっていない場合Transition、Saturation、Fade_Color にはそれぞれ1.0が代入されます。

②dはポリゴンの重心ベクトルと_Pulse_Originのベクトルの距離からプロパティで設定されたPulse Varyの値とCell_Noise_2D_B150()で処理された変数をかけたものが減算されます。

③Pulse_Ourer_Sizeの値がdの値と比べ以上か、以下かによってclipの値が0,1に定まります。

④totalSizeにはプロパティで設定されたPulse Outer Sizeの値とPulse Varyの値とPulse Widthの値の和が代入されます。デフォルトでは1.05+0.075+1=2.125の値が入ります。

⑤pulseFrontにはAutoPulseがMaterialでオンになっている場合、時間をPeriodで割った少数部分と④の積が代入されます。AutoPulseがオフの場合_Pulseの値と④の積が入ります。

重要なところはこのような感じでしょうか?

ざっとすべての処理を見終わってから実際の値を基に変化を見ていきます。

*1:x-start)/(end-start

*2:x-start)/(end-start