這5毛特效,做得牛了,好評!


沒想到Graphics組件也能被玩出花來,先看看效果!



鏈接:https://store.cocos.com/app/detail/3199

不僅授人以魚,還有授人以漁!下面是GT大佬對cc.Graphics組件自定義渲染Demo的詳解。

背景

一直好奇 Cocos Creator cc.Graphics組件是如何渲染的,最近打算學習下官方的源碼。於是打開cc.Graphics默認的 Shader 看了下,好傢伙原來cc.GraphicsSDF有很緊密的聯繫。
本文簡單介紹下利用SDF信息自定義渲染cc.Graphics的一般方法,附上幾個例子。本文所有內容基於 Cocos Creator 2.4.2

看看shader

cc.Graphics默認的shader在下面位置(根據引擎安裝位置和版本有所不同)

C:\CocosDashboard_1.0.12\resources.editors\Creator\2.4.2\resources\static\default-assets\resources\effects\builtin-2d-graphics.effect

片元着色器代碼如下,筆者加了些註釋幫助理解

void main () {
    vec4 o = v_color;

    // alpha測試,這裏不用管
    ALPHA_TEST(o);

    // 計算AA(反走樣)距離,如果平臺支持fwidth就儘量用,AA更加準確
#if CC_SUPPORT_standard_derivatives
    float aa = fwidth(v_dist);
#else
    float aa = 0.05;
#endif

    // 在v_dist = 1或者-1附近進行AA處理
    float alpha = 1. - smoothstep(-aa, 0.abs(v_dist) - 1.0);
    o.rgb *= o.a;
    o *= alpha;

    gl_FragColor = o;
}


可以看到 Shader 除了做 AA,幾乎啥也沒幹,但是v_dist是幹什麼用的?
先用cc.Graphics畫一個簡單圖形,把v_dist的內容輸出看一下

// 用cc.Graphics畫一條Bezier曲線
graphics.strokeColor = cc.Color.WHITE;
graphics.lineWidth = 40;
graphics.moveTo(-212-139);
graphics.bezierCurveTo(-2131113823624675);
graphics.stroke();
// 修改graphics默認shader代碼
void main () {
    // v_dist作爲顏色值輸出(取絕對值避免負數不顯示)
    gl_FragColor = vec4(abs(v_dist));
    return;
}


右圖abs(v_dist)中間黑(值是0),兩邊白(值是1),實際上v_dist值範圍是[-1, 1]。輸出負數會被當0處理看不出效果,所以用absv_dist變成正數輸出。
v_dist上一篇提到的SDF是同類數據,在這裏表示當前片元到graphcis中線的距離,1或-1表示最邊緣,0表示在中線上。

改改 Shader

從紋理文件採樣

和普通的cc.Sprite不同,cc.Graphics沒有組裝uv信息傳到 Shader。
可以將v_dist從[-1, 1]映射到[0, 1]區間,然後直接在紋理上採樣。
下面的代碼大部分和原始shader相同,增加了texture變量和採樣過程

// 增加紋理uniform變量
uniform sampler2D texture;

void main () {
    vec4 o = v_color;

    ALPHA_TEST(o);

    #if CC_SUPPORT_standard_derivatives
      float aa = fwidth(v_dist);
    #else
      float aa = 0.05;
    #endif

    float alpha = smoothstep(aa, -aa, abs(v_dist) - 1.0);

    // 將v_dist值從[-1, 1]區間映射到[0, 1]
    float D = v_dist * 0.5 + 0.5;    

    // 採樣紋理
    o = texture2D(texture, vec2(D, 0.5));

    o.rgb *= alpha;
    gl_FragColor = o;
}


從程序紋理(色板)採樣

和紋理文件採樣的思路一樣,都是將v_dist映射到某個顏色。
這裏我們提供一個調色板函數實現這個映射,函數內部可以實現任何自己想要的漸變色。

// 一個彩虹色的色板,輸入t的範圍是[0, 1], 輸出一個顏色值
vec3 Pallete(float t) {
    // 滾動動起來
    t += cc_time.x;
    
    vec3 dcOffset = vec3(0.50.50.5);
    vec3 amp = vec3(1.1.1.);
    vec3 freq = vec3(1.1.1.);
    vec3 phase = vec3(0.0.33330.6666);
    return dcOffset + amp * cos(2. * 3.14159 * (freq * t + phase));
}

void main () {
    // ...其他都一樣
    // 用一個Pallete函數完成映射,函數背後可以是採樣,或者其他靜態、動態紋理
    // o = texture2D(texture, vec2(D, 0.5));
    o.rgb = Pallete(D);
    
    // ...其他都一樣
}

順便推薦一個在線漸變色配色網站:http://dev.thi.ng/gradients/
上面代碼中的色板係數從該網站獲得。

Demo和源碼

[論壇討論帖]

https://forum.cocos.org/t/topic/119268

[線上Demo體驗地址]

https://caogtaa.gitee.io/ccdemos/?scene=SceneGraphics

Demo 中還有更多基於cc.Graphics的 Shader 效果,包括 Mesh 可視化外發光僞3D,留給下次詳細介紹。歡迎來論壇留言討論!

更多精彩,請關注GT大佬公衆號




本文分享自微信公衆號 - Creator星球遊戲開發社區(creator-star)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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