夜風のMixedReality

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

MRTK HandTrianglesShaderの中身を読み解く その⑩ ジオメトリシェーダーを読み解く Ⅶ Fly_B164()前半

本日はMRTK HandTrianglesShaderの調査枠です。

ジオメトリシェーダーを少しづつ読み解いています。

〇Fly_B164()

この関数ではメッシュが展開されながらパルスが流れる機能を行っているようです。

f:id:Holomoto-Sumire:20200102122316j:plain

f:id:Holomoto-Sumire:20200102122159g:plain

中身を見ていきます。

  float3 Q0_Q164;
        float3 Q1_Q164;
        float3 Q2_Q164;
        Fly_B164(vxIn[0].posWorld,vxIn[1].posWorld,vxIn[2].posWorld,Transition_Q160,_Max_Hover_,_Max_In_Angle_,_Max_Out_Angle_,Out_UV_1_Q154,Out_UV_2_Q154,Out_UV_3_Q154,Vec2_Q167,Nearest_P_Q163,FadingOut_Q160,Q0_Q164,Q1_Q164,Q2_Q164);
    void Fly_B164(
        float3 P0,
        float3 P1,
        float3 P2,
        float Transition,
        float Max_Hover,
        float Max_In_Angle,
        float Max_Out_Angle,
        float2 UV0,
        float2 UV1,
        float2 UV2,
        float2 PulseOrigin,
        float3 Nearest_P,
        bool Fading_Out,
        out float3 Q0,
        out float3 Q1,
        out float3 Q2    )
    {
        float3 N = normalize(cross(P1-P0,P2-P1));
        
        float k01 = dot(normalize((UV0+UV1)*0.5-PulseOrigin),normalize(UV1-UV0));
        float k12 = dot(normalize((UV1+UV2)*0.5-PulseOrigin),normalize(UV2-UV1));
        float k20 = dot(normalize((UV0+UV2)*0.5-PulseOrigin),normalize(UV2-UV0));
        
        float3 pulseDir = normalize( normalize(P1-P0)*k01+normalize(P2-P1)*k12 + normalize(P2-P0)*k20);
        float3 axis = normalize(cross(N,pulseDir));
        float3 center = Nearest_P; //(P0+P1+P2)/3.0;
        
        float angle, k;
        if (Fading_Out) {
            //float t = Transition<0.5 ? 2.0*(0.5-Transition)*(0.5-Transition) : 2.0*(0.5-Transition)*(0.5-Transition)+0.5;
            float t = smoothstep(0,1,Transition);
            angle = -Max_Out_Angle * (1.0-t);
            k = (1-t) * Max_Hover;
        } else {
            float t = smoothstep(0,1,Transition);
        //    float t = Transition*Transition;
            angle = Max_In_Angle * (1.0-t);
            k = (1-Transition) * Max_Hover;
        }
        
        float3 p0 = Rotate_Bid164(angle,center,axis,P0);
        float3 p1 = Rotate_Bid164(angle,center,axis,P1);
        float3 p2 = Rotate_Bid164(angle,center,axis,P2);
        
        if (false) {  ///(!Fading_Out) {
            float t = (Transition);
            p0 = Nearest_P + (p0-Nearest_P)*t;
            p1 = Nearest_P + (p1-Nearest_P)*t;
            p2 = Nearest_P + (p2-Nearest_P)*t;
        }
        
        Q0 = p0 + N * k;
        Q1 = p1 + N * k;
        Q2 = p2 + N * k;
        
        
    }

float3 P0=vxIn[0].posWorld(一つ目の頂点の座標)

float3 P1=vxIn[1].posWorld(二つ目の頂点の座標)

float3 P2=vxIn[2].posWorld(三つ目の頂点の座標)

float Transition=Transition_Q160(Pulse()で使用された変数)

float Max_Hover=Max_Hover(プロパティでのMax Hoverrの値 デフォルトで0.004)

float Max_In_Angle=Max_In_Angle(プロパティでのMax In Angleの値 デフォルトでは0.6)

float Max_Out_Angle=Max_Out_Angle_(プロパティでのMax Out Angleの値 デフォルトでは0.4)

float2 UV0=Out_UV_1_Q154(一つ目の頂点の位置ベクトル)

float2 UV1,=Out_UV_2_Q154(二つ目の頂点の位置ベクトル)

float2 UV2,=Out_UV_3_Q154(三つ目の頂点の位置ベクトル)

float2 PulseOrigin=Vec2_Q167(Pulse_Origin)

float3 Nearest_P=Nearest_P_Q163(Find_Nearest_B163()で定まる変数)

bool Fading_Out=FadingOut_Q160(Pulse()でfadeOutが≠0であればTrue)

out float3 Q0=Q0_Q164

out float3 Q1=Q1_Q164

out float3 Q2 =Q2_Q164

というように各パラメータに代入されます。

f:id:Holomoto-Sumire:20200519090938j:plain

        float3 N = normalize(cross(P1-P0,P2-P1));
        
        float k01 = dot(normalize((UV0+UV1)*0.5-PulseOrigin),normalize(UV1-UV0));
        float k12 = dot(normalize((UV1+UV2)*0.5-PulseOrigin),normalize(UV2-UV1));
        float k20 = dot(normalize((UV0+UV2)*0.5-PulseOrigin),normalize(UV2-UV0));

NはP1-P0とP2-P1の外積を正規化した値が代入されます。 このP0,P1,P2はそれぞれメッシュの頂点ベクトルなのでこれはメッシュの回転を方向を指定しているようです。

(参考)

qiita.com

k01,k12,k20は2頂点のベクトルを合成し0.5をかけたものからPulseOriginを引いたものを正規化した値と、2頂点のベクトルを引いたものを正規化とのドット積(内積)が代入されます。

       float3 pulseDir = normalize( normalize(P1-P0)*k01+normalize(P2-P1)*k12 + normalize(P2-P0)*k20);
        float3 axis = normalize(cross(N,pulseDir));
        float3 center = Nearest_P; //(P0+P1+P2)/3.0;

pulseDir(パルスの方向)は2つ目の頂点のベクトルから一つ目の頂点のベクトルを引き正規化したものにk01,k12,k10をかけた値の和をさらに正規化したものが代入されます。

axis(軸)にはメッシュの回転とパルスの方向のクロス積(外積)を正規化した値が代入されます。

center(中心)にはメッシュの重心(PulseOrigin)が入ります。

●Fading_Out(Pulse()でfadeOutが≠0であればTrue)がオンの場合
if (Fading_Out) {
                    //float t = Transition<0.5 ? 2.0*(0.5-Transition)*(0.5-Transition) : 2.0*(0.5-Transition)*(0.5-Transition)+0.5;
                    float t = smoothstep(0,1,Transition);
                    angle = -Max_Out_Angle * (1.0 - t);
                    k = (1 - t) * Max_Hover;
                }

smoothstep関数はある値が [最小、最大] の範囲内にある場合、0 と 1 の間のスムーズなエルミート補間を返します。

docs.microsoft.com

qiita.com

エルミート補間は二点間を正確に通る多項式で間を補完することを指すようです。

ここではtは0と1の間でTransition(Pulse()で使用された変数)の間を補完する多項式が返されます。

具体的にはsmoothstepは,0と1のときに傾きが0, 0のとき値が0, 1のとき値が1となる特性を持つ3次関数

3(transition)^2-2(transition)^3

となるようです。

angleにはMax_Out_Angle_(プロパティでのMax Out Angleの値 デフォルトでは0.4)に-1をかけたものと積の値と(1.0-t)の積が代入されます。

kには1からtを引いた値とMax_Hover(プロパティでのMax Hoverrの値 デフォルトで0.004)との積が代入されます。

●Fading_Out(Pulse()でfadeOutが≠0であればTrue)がオフの場合
     else {
                    float t = smoothstep(0,1,Transition);
                    //    float t = Transition*Transition;
                    angle = Max_In_Angle * (1.0 - t);
                    k = (1 - Transition) * Max_Hover;
                }

tには0と1の間でTransition(Pulse()で使用された変数)の間を補完する多項式が返されます。

angleにはMax_Out_Angleではなく、Max_In_Angle(プロパティでのMax In Angleの値 デフォルトでは0.6)と1からtを引いた値の積が代入されます。

kには1からTransitionを引いた値とMax_Hover(プロパティでのMax Hoverrの値 デフォルトで0.004)との積が代入されます。

        float3 p0 = Rotate_Bid164(angle,center,axis,P0);
        float3 p1 = Rotate_Bid164(angle,center,axis,P1);
        float3 p2 = Rotate_Bid164(angle,center,axis,P2);
        
        if (false) {  ///(!Fading_Out) {
            float t = (Transition);
            p0 = Nearest_P + (p0-Nearest_P)*t;
            p1 = Nearest_P + (p1-Nearest_P)*t;
            p2 = Nearest_P + (p2-Nearest_P)*t;
        }
        
        Q0 = p0 + N * k;
        Q1 = p1 + N * k;
        Q2 = p2 + N * k;
        
        
    }

p0,p1,p2にはそれぞれRotate_Bid164のangle,center,axis,PXでの帰り値が指定されます。

Pulseを生み出すうえでこのFly()がとても重要であることが分かったので続きはまた後日ゆっくりと読み解きます。