shader畫圓利用smoothstep函數抗鋸齒


當前環境opengl es 2.0,  不用ebo情況下, 直接6個頂點組成兩個三角形,拼接成一個正方形,

fragment shader代碼里判斷所有片元距離中心點之間的距離,大於半徑的片元輸出透明度為0,gl_FragColor = vec4(0,0,0,0.0),

小於等於半徑內的顏色為白色,gl_FragColor = vec4(1.0,1.0,1.0,0.0),到此為止繪制出的白色圓圈鋸齒非常明顯

 

 圖中疊了3層圓圈。

 

如果給圓圈的邊界外擴比如5個像素,在這5個像素內,白色透明度從0% 到 100%,這是在運行會發現邊界鋸齒感好了很多,幾乎沒有的感覺

 

 ,核心思想就是給圓圈的邊緣預留一段區間,在此區間進行邊緣和邊緣外界顏色、透明度的漸變,可以自己寫自己寫划算公式,但更方便是使用smoothstep方法進行區間比列換算,

    smoothstep(x,y,a) = [0, 1] ,總是返回[0, 1]區間之類的數, 純數學領域范圍的應用,其實就是初中數學區間比例換算么 區間[a, b] 與區間[m, n]之間的換算方法。

 

附上最近寫的 動態水波紋fragment shader代碼:

所謂的動態就是 cpu 里好比起了一個定時器,實時的計算當前正在擴大的圓的半徑,把這個半徑值傳遞給gpu ,gpu實時去給每個片元計算當前是在圈內還是圈外

//
//  
//  Created by JD on 2020/6/12
//
//

#ifdef GL_ES
precision highp float;
#endif

uniform vec2 center;

uniform float currentRadius;  //當前逐漸擴大的半徑
uniform float alphaChangeVal; //c++端是讓其隨時間遞增,此處時被當作被減去的值而得到最終的透明度
uniform float solidRadius;    //中間的不變實心半徑




/*
    表現需求:
    
    1,圓圈越變越大  ok
    2,圓圈默認從中心點往外透明度漸變    ok
    3,隨時間的推移,圓圈變大的同時整體越變越透明 alphaChangeVal    ok

*/
void main(void)
{


    vec2 distanceVec = gl_FragCoord.xy - center.xy;
    float fragToCenterLength = sqrt(pow(distanceVec.x, 2) + pow(distanceVec.y, 2));

    // float min = 0;
    // float max = currentRadius;
    
    //110 255 170
    float redColor = 0.43;
    float greenColor = 1.0;
    float blueColor = 0.67;

    
    //平滑過度距離插值區間
    float smoothStepLength = 1.5;



    /* 
    期望的邊界是理論最遠邊界currentRadius,但圓圈的邊緣部分為了抗鋸齒,需要平滑過度透明度,所以額外加上被用來做為平滑過度的一個距離區間1.5
    由此聯想到當圓形擴散到最大半徑值時,為了保證外邊緣抗鋸齒,
    那么圓形最大半徑就要比外界設置的理論值再增長1.5,所以需要給外界的矩形大小增加1.5,
    或者不改變外界矩形,而是改變圓圈的最大理論值,讓其減去1.5

    為方便處理我采用了后者,不麻煩外界參與這種平滑過度計算范圍加減,直接在當前shader內處理;
    采用后者的話,最終采用了平滑過渡的圓圈會比采用前者的半徑小1.5,不過這種視覺上的差異可以在此項目中忽略。



    */
    


        if(solidRadius > 0 && fragToCenterLength <= solidRadius - smoothStepLength)
        { //內圈
            gl_FragColor= vec4(redColor,greenColor,blueColor,1);
        }
        else if(solidRadius > 0 && fragToCenterLength <= solidRadius)
        {  //內圈邊緣過度區間  [alpha=1 , 中間圓環當前統一動態alpha值:alphaChangeVal]
            float ratio = smoothstep(solidRadius - smoothStepLength, solidRadius, fragToCenterLength);

            float alpha = 1 - alphaChangeVal;
            gl_FragColor= vec4(redColor,greenColor,blueColor, ratio * (alpha - 1) +  1);
            
        }else if(fragToCenterLength <= currentRadius - smoothStepLength)
        { 
            //外環
            float alpha = 1 - alphaChangeVal;
            //外環中心點往外透明度 不使用漸變
            gl_FragColor = vec4(redColor,greenColor,blueColor,alpha);

        }
        else if(fragToCenterLength <= currentRadius)
        { //外圈過度區間 [alphaChangeVal, 0]
            float ratio = smoothstep(currentRadius - smoothStepLength, currentRadius, fragToCenterLength);
            float alpha = 1 - alphaChangeVal;
            gl_FragColor = vec4(redColor,greenColor,blueColor,(ratio - 1) * ( 0 - alpha));
        }
        else
        {//外圈以外
            gl_FragColor = vec4(0,0,0,0.0);
        }




}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM