shdertoy學習系列4- 雷達(2)

上文中的雷達僅繪製了圓邊和掃描線,漸變區域還未添加

#define PI 3.1415926535897932384626433832795


// 繪製線,傳入參數,圓心,線的終點, 片元座標
float LineToPointDistance2D( vec2 a, vec2 b, vec2 p)
{
    vec2 pa = p - a;    //片元座標-圓心座標
    vec2 ba = b - a;   // 線終點座標-圓心座標
    //片元座標到圓心的距離/半徑
    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0); //clamp函數會將x限制在minVal和maxVal之間。float clamp(float x, float minVal, float maxVal)
    //片元座標減去   半徑*片元元座標到圓心的距離/半徑,當在圓外時,h爲1 ,則長度爲 pa-ba
    //當在圓內時,  長度大於pa-ba
    return length( pa - ba*h );
}

// 傳入參數 傳入圓心座標,旋轉的角度,返回的線終點座標,
//傳入了線的初始終點座標
vec2 rotatePoint(vec2 center,float angle,vec2 p)
{
    float s = sin(angle);
    float c = cos(angle);

    // translate point back to origin:
    p.x -= center.x;
    p.y -= center.y;

    // rotate point
    float xnew = p.x * c - p.y * s;
    float ynew = p.x * s + p.y * c;

    // translate point back:
    p.x = xnew + center.x;
    p.y = ynew + center.y;
    return p;
}


void getBlips(float radius, out vec2[1] blipsOut)
{
    vec2 cen = iResolution.xy/2.0;
    float sec = iDate[3];
    float mdl = mod(sec,10.0);

    //From 1 to 6
    float cstepRot = ((sec-mdl)/10.0)+1.0;
    float factorRot = cstepRot/6.0;

    float factorLen = sin(factorRot)/2.0;
    float len = radius*factorLen;//0.5;);
    vec2 targetP = vec2(cen.x,cen.y+len);
    float ang  =  PI*factorRot*2.0;
    targetP = rotatePoint(cen,ang,targetP);

    blipsOut[0] = targetP;
}

//傳入參數 歸一化的 線終點座標-圓心
// 歸一化的 片元座標-圓心座標
float angleVec(vec2 a_, vec2 b_)
{
    vec3 a = vec3(a_, 0);
    vec3 b = vec3(b_, 0);
    float dotProd = dot(a,b);  //b在a向量上的投影長度
    vec3 crossprod = cross(a,b);// a,b的法向量
    float crossprod_l = length(crossprod); //法向量的長度
    float lenProd = length(a)*length(b);   // a向量和b向量的模長
    float cosa = dotProd/lenProd;       //cos a即爲 a向量與 b向量的夾角  a·b = |a||b|cos∠(a, b)  點積公式
    float sina = crossprod_l/lenProd;     // sin 值  |a×b| = |a||b|sin∠(a,b)      叉積公式
    float angle = atan(sina, cosa);     //角度 返回值的在(-π - π)
    // x,y的符號 決定了反正切的結果,可判斷xy所在的象限,反正弦與反餘弦返回值在(-π/2 - π/2)之間,不能唯一確定
    //x和y的關係,因此選用反正切來判斷x、y的關係

    //  法向量與 ab法向量的點積 ab cos a 如果小於0,則意味着a在第二象限(π/2- π)  則證明ab的法向量向下,
    if(dot(vec3(0,0,1), crossprod) < 0.0)
        angle=90.0;
    return (angle * (180.0 / PI));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 center =iResolution.xy/2.0; //獲取片元中心座標
    float minRes = min(center.x,center.y); //取x,y中較小的一個爲中心,否則圓形會超出canvas的範圍
    float radius =minRes-minRes*0.1; //半徑爲最小分辨率值的90%
    float circleWitdh = radius*0.02;//圓的寬度爲半徑*0.02
    float lineWitdh = circleWitdh*0.8;  //線的寬度爲半徑*0.8
    float angleStela = 180.0;  //角度
    vec2 lineEnd =  vec2(center.x,center.y+radius);    //線的終點,初始的時候即爲中心點+圓的半徑

    float blue =0.0;
    float green =0.0;//綠色分量默認爲0

    float distanceToCenter = distance(center,fragCoord.xy);//計算中心到片元的距離
    float disPointToCircle=abs(distanceToCenter-radius);//片元到圓心的距離與半徑判斷

    //繪製圓圈,判斷  片元到圓心的距離與半徑 是否小於圓的寬度
    if (disPointToCircle<circleWitdh)
    {
        green= 1.0-(disPointToCircle/circleWitdh); //如果小於圓的寬度,則證明在圓內,賦值綠色分量
    }

    // 旋轉線,角度=負的實踐*1.2
    float angle = (-iTime*1.2);
    // 旋轉點之後,重新獲取線的終點
    lineEnd = rotatePoint(center,angle,lineEnd);

    // 繪製線,傳入參數,圓心,線的終點, 片元座標
    float distPointToLine = LineToPointDistance2D(center,lineEnd,fragCoord.xy);
    //如果點距離線的距離小於線的寬度
    if (distPointToLine<lineWitdh)
    {
        // 1減去 點到線的距離/線的寬度, 當先距離線越近時,顏色越深
        green = 1.0-distPointToLine/lineWitdh;

    }


    //繪製漸變扇形
    //傳入參數 歸一化的 線終點座標-圓心
    // 歸一化的 片元座標-圓心座標
    float angleStelaToApply = angleVec(normalize(lineEnd-center),normalize(fragCoord.xy-center));

    //angleStela =180° 如果待繪製的片元 與基準線的角度小於180
    //且距離圓心的距離小於半徑- 原文是radius-circleWitdh/2.0+1.0 ,考慮了線寬因素,學習就簡化了

    //此處angleStelaToApply<angleStela 是多餘的判斷,因爲反正切已經在180°之內了
    if (distanceToCenter<radius)
    {
         //角度因子,1.0- 待用的角度/180 ,值在1.0之內
        float factorAngle = 1.0-angleStelaToApply/angleStela;
       //將值重新計算
        float finalFactorAngle = (factorAngle*0.5)-0.15;

         //如果最終的值大於原來的green了,則重新賦值
        //這是由於此前已經對圓邊,掃描線賦值了,如果不進行判斷,會將之前的值重寫
        if (finalFactorAngle>green)
            green=finalFactorAngle;



     
    }
   // float jg=center.x>390.0?1.0:0.0;  //調試使用

    fragColor = vec4(0.0,green,blue,1.0);
}


現在這個結果就跟原文的差不多了,只要再添加隨機點就可以了,

angleVec這個函數的最後一個返回還有點沒太理解,先記錄,理解了再補上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章