Cocos2d-x shader學習3: sprite描邊(Outline)


Cocos2d-x 3.x的label使用了freetype字體引擎(http://www.freetype.org/),可以很輕松的實現描邊和陰影效果。所以本篇文章只針對於sprite來實現描邊效果。

官方demo中描邊shader沒有看懂,看效果好像是有點問題,透明的部分變成了黑色。作者也沒有怎么解釋,直接丟了一個網址出來(http://www.idevgames.com/forums/thread-3010.html),看樣子是參考了這個帖子。

后來從網上別人的博客中找到了一遍關於描邊shader的文章,這篇文章用的方法跟我想的差不多,優點是很容易理解,缺點是相對於官方demo給的描邊shader效率上差了點。原文地址:http://blog.csdn.net/u011281572/article/details/44999609。

原文的代碼考慮了label的描邊,這個對於現在的cocos3.x版本來說有點多余,我就對原文的代碼做了些改動,去掉了label描邊的那塊兒代碼,有些邏輯也做了一些改變,使得更容易理解一些。

下面是我改動后的代碼:

varying vec4 v_fragmentColor; // vertex shader傳入,setColor設置的顏色
varying vec2 v_texCoord; // 紋理坐標
uniform float outlineSize; // 描邊寬度,以像素為單位
uniform vec3 outlineColor; // 描邊顏色
uniform vec2 textureSize; // 紋理大小(寬和高),為了計算周圍各點的紋理坐標,必須傳入它,因為紋理坐標范圍是0~1

// 判斷在這個角度上距離為outlineSize那一點是不是透明
int getIsStrokeWithAngel(float angel)
{
    int stroke = 0;
    float rad = angel * 0.01745329252; // 這個浮點數是 pi / 180,角度轉弧度
    vec2 unit = 1.0 / textureSize.xy;//單位坐標
    vec2 offset = vec2(outlineSize * cos(rad) * unit.x, outlineSize * sin(rad) * unit.y); //偏移量
    float a = texture2D(CC_Texture0, v_texCoord + offset).a;
    if (a >= 0.5)// 我把alpha值大於0.5都視為不透明,小於0.5都視為透明
    {
        stroke = 1;
    }
    return stroke;
}

void main()
{
    vec4 myC = texture2D(CC_Texture0, v_texCoord); // 正在處理的這個像素點的顏色
    if (myC.a >= 0.5) // 不透明,不管,直接返回
    {
        gl_FragColor = v_fragmentColor * myC;
        return;
    }
    // 這里肯定有朋友會問,一個for循環就搞定啦,怎么這么麻煩!其實我一開始也是用for的,但后來在安卓某些機型(如小米4)會直接崩潰,查找資料發現OpenGL es並不是很支持循環,while和for都不要用
    int strokeCount = 0;
    strokeCount += getIsStrokeWithAngel(0.0);
    strokeCount += getIsStrokeWithAngel(30.0);
    strokeCount += getIsStrokeWithAngel(60.0);
    strokeCount += getIsStrokeWithAngel(90.0);
    strokeCount += getIsStrokeWithAngel(120.0);
    strokeCount += getIsStrokeWithAngel(150.0);
    strokeCount += getIsStrokeWithAngel(180.0);
    strokeCount += getIsStrokeWithAngel(210.0);
    strokeCount += getIsStrokeWithAngel(240.0);
    strokeCount += getIsStrokeWithAngel(270.0);
    strokeCount += getIsStrokeWithAngel(300.0);
    strokeCount += getIsStrokeWithAngel(330.0);

    if (strokeCount > 0) // 四周圍至少有一個點是不透明的,這個點要設成描邊顏色
    {
        myC.rgb = outlineColor;
        myC.a = 1.0;
    }

    gl_FragColor = v_fragmentColor * myC;
}

大致的邏輯是:
先判斷當前像素是否透明,如果不透明則直接返回。如果是透明像素,就判斷這個點周圍12個方向,每個方向距離當前像素距離是outlineSize的像素點是否透明,只要有一個是非透明像素,就把當前像素點設為描邊的顏色,並設置成非透明。
效果如下:
outline


免責聲明!

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



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