在 Cocos Creator 中自定义渲染 cc.Graphics

引言:

GT 是我们的 Cocos Star Writer,长期活跃于社区,最近输出了许多与 Shader 有关的内容,后续他还会为我们带来 SDF 方面的分享。

一直好奇 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(-213, 111, 38, 236, 246, 75);
graphics.stroke();
// 修改graphics默认shader代码
void main () {
    // v_dist作为颜色值输出(取绝对值避免负数不显示)
    gl_FragColor = vec4(abs(v_dist));
    return;
}

335e2282e9a7cdbf343009193aed3a30.png

右图 abs(v_dist) 中间黑(值是0),两边白(值是1),实际上 v_dist 的值范围是[-1, 1]。输出负数会被当0处理看不出效果,所以用 absv_dist 变成正数输出。

v_dist 在这里表示当前片元到 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;
}

3cdcd5b73a442b82f90edc344fedd696.png

从程序纹理(色板)采样

和纹理文件采样的思路一样,都是将 v_dist 映射到某个颜色。

这里我们提供一个调色板函数实现这个映射,函数内部可以实现任何自己想要的渐变色。

// 一个彩虹色的色板,输入t的范围是[0, 1], 输出一个颜色值
vec3 Pallete(float t) {
    // 滚动动起来
    t += cc_time.x;
    
    vec3 dcOffset = vec3(0.5, 0.5, 0.5);
    vec3 amp = vec3(1., 1., 1.);
    vec3 freq = vec3(1., 1., 1.);
    vec3 phase = vec3(0., 0.3333, 0.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/
上面代码中的色板系数从该网站获得。

b69c2d428b1c4ad4d9fd5152d38224cd.gif

Demo 和源码

• 代码:

https://github.com/caogtaa/CCTricks/tree/master/assets/Demo/Graphics

• 论坛讨论帖:

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

• Demo 体验地址:

https://github.com/caogtaa/CCTricks/tree/master/assets/Demo/Graphics

da8b79010e94ad3799a497fb539f6c75.gif

2753322ac2af219518ee213aca6040b8.jpeg

2d10668a45d4e6aac4497f5c7977e9f4.jpeg

>>左右滑动查看更多

Demo 中还有更多基于 cc.Graphics 的 shader 效果,包括 Mesh 可视化、外发光、伪 3D,留给下次详细介绍。欢迎在论坛留言讨论。


「Cocos 开发者沙龙」深圳站,将于9月4日下午14:00正式举行!

Cocos 引擎技术总监 Panda 将详解 Cocos Creator 3.3 最新技术突破与功能革新,更有腾讯光子高级工程师宝爷、亚马逊云科技资深解决方案架构师王泽耀、TradPlus 运营总监 Joyce、华为海思麒麟 GPU 团队资深工程师刘月、腾讯开心鼠、腾讯在线教育部终端开发工程师敖显厅重磅加盟,为大家带来一系列干货分享。

此外,本次依然开放「现场一对一技术支持」,限额 5 个团队。Cocos 引擎团队核心成员将全程驻场,你可以携带自己的作品和问题同他们进行一对一技术交流,名额有限,赶快扫描下方二维码报名吧!

>>一对一技术支持报名通道。我们将抽选5个团队,被选中的团队将以短信形式通知。

点击【阅读原文】报名吧,期待你的加入!

往期精彩

90597096e3b01136213a6d5a95b4fb84.png

dabe57cb9f0753c63ff9e2ba55db176a.png

c76dd1606fa2504d6b7788e837f4e099.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cocos Creator 3.x 版本cc.Line 组件已经被废弃,可以使用 Graphics 组件来绘制随机闪电。具体实现步骤如下: 1. 在场景编辑器创建一个节点,添加 Graphics 组件。 2. 编写脚本,获取 Graphics 组件,在 onEnable 生命周期回调函数调用绘制随机闪电的方法。具体实现方法如下: ``` cc.Class({ extends: cc.Component, properties: { duration: 0.2, // 闪电持续时间 offset: 10, // 闪电偏移量 boltWidth: 5, // 闪电宽度 color: cc.Color.WHITE // 闪电颜色 }, onEnable: function () { this.schedule(this.drawBolt, this.duration); }, onDisable: function () { this.unschedule(this.drawBolt); }, drawBolt: function () { var g = this.getComponent(cc.Graphics); g.clear(); var startPos = cc.v2(0, 0); // 起点坐标 var endPos = cc.v2(cc.winSize.width, cc.winSize.height); // 终点坐标 var midPos = cc.v2(startPos.x + (endPos.x - startPos.x) / 2, startPos.y + (endPos.y - startPos.y) / 2); // 点坐标 // 生成随机偏移量 var offset1 = cc.v2(Math.random() * this.offset - this.offset / 2, Math.random() * this.offset - this.offset / 2); var offset2 = cc.v2(Math.random() * this.offset - this.offset / 2, Math.random() * this.offset - this.offset / 2); // 绘制闪电 g.strokeColor = this.color; g.lineWidth = this.boltWidth; g.moveTo(startPos.x, startPos.y); g.lineTo(midPos.x + offset1.x, midPos.y + offset1.y); g.lineTo(endPos.x + offset2.x, endPos.y + offset2.y); g.stroke(); } }); ``` 这段代码将在节点上使用 Graphics 组件绘制随机闪电,每隔一定时间刷新一次。可以根据需要调整闪电的持续时间、偏移量、宽度和颜色等参数。需要注意的是,随机闪电的绘制效果可能会受到屏幕分辨率的影响,可以根据需要调整起点和终点坐标来适配不同的屏幕大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值