CocosCreator Effect (Shader) - 斜条纹如何画

在这里插入图片描述

左图是原图,没有使用九宫格sliced。也没有在图集中。这篇文章作为基础,只考虑如何画斜条纹。另外两篇文章讨论了如何处理在九宫格和在图集中使用的问题。
注意,所有的改动都在这里:


  void main () {
    vec4 o = vec4(1, 1, 1, 1);
    #if USE_TEXTURE
      CCTexture(texture, v_uv0, o);
    #endif
    o *= v_color;
	// 在这里进行斜条纹的绘制
    ALPHA_TEST(o);
    #if USE_BGRA
      gl_FragColor = o.bgra;
    #else
      gl_FragColor = o.rgba;
    #endif
  }
}%

亮度提升

其实把r,g,b都加个数就可以了,但是为了更加自然,我把亮度调节到当前值与vec3(1,1,1)的中间位置。这样无论是亮的部分或是暗的部分,都会呈现出一些变化,而不会把亮部“曝光过渡”。

    vec3 one = vec3(1, 1, 1);
    float fin = .5;
    o.rgb = mix(o.rgb, one, fin * .5);

在这里插入图片描述

方式1,平移x,求奇偶

这种方式开销较大,切角度控制不均匀不方便,不推荐使用。学习shader的可以理解一下。

一条分界线

有了亮度的区别,那么我们就可以以不同的亮度显示出一条线来。实际上是两种不同的亮度拼凑出一条线。

    vec3 one = vec3(1, 1, 1);
    float fin = step(v_uv0.x, v_uv0.y);
    o.rgb = mix(o.rgb, one, fin * .5);

在这里插入图片描述

从图像就能看出来,uv坐标轴是这样的:
x轴从左上角到右上角为[0,1]
y轴从左上角到左下角为[0,1],
注意跟我们习惯的右下角原点坐标系是y轴相反,且原点在左上角。
另外step的意义,例如 float fin = step(a,b):当a小于b时返回0,否则返回1。好像是一个开关。0乘在下面的mix函数中,就代表不做变换,完全用原值。而1则代表做变换。

平移分界线求每个使能结果的和的奇偶性

平移x,得到不同的边缘斜线部分的覆盖。数一数有多少个。它们一定是呈现1,2,3,4,5,6…这样的自然数的。那么我们在对2求模,根据得到的结果是0还是1,来作为开关。1就是变亮,0就是不变亮。

    vec3 one = vec3(1, 1, 1);
    float rate = step(v_uv0.x, v_uv0.y);
    rate += step(v_uv0.x + .1, v_uv0.y);
    rate += step(v_uv0.x + .2, v_uv0.y);
    rate += step(v_uv0.x + .3, v_uv0.y);
    rate += step(v_uv0.x + .4, v_uv0.y);
    rate += step(v_uv0.x + .5, v_uv0.y);
    rate += step(v_uv0.x + .6, v_uv0.y);
    rate += step(v_uv0.x + .7, v_uv0.y);
    rate += step(v_uv0.x + .8, v_uv0.y);
    rate += step(v_uv0.x + .9, v_uv0.y);
    rate += step(v_uv0.x - .1, v_uv0.y);
    rate += step(v_uv0.x - .2, v_uv0.y);
    rate += step(v_uv0.x - .3, v_uv0.y);
    rate += step(v_uv0.x - .4, v_uv0.y);
    rate += step(v_uv0.x - .5, v_uv0.y);
    rate += step(v_uv0.x - .6, v_uv0.y);
    rate += step(v_uv0.x - .7, v_uv0.y);
    rate += step(v_uv0.x - .8, v_uv0.y);
    rate += step(v_uv0.x - .9, v_uv0.y);

    float fin = mod(rate, 2.0);
    o.rgb = mix(o.rgb, one, fin * .5);

在这里插入图片描述
想一想如果修改其中2.0,和 .5这两个呈现什么效果?
比如对应改为:4.0和.2
在这里插入图片描述
不过这不是最终想要的哈。

方式2,只按x轴求模做step,再旋转

这个方式就比较好了,不需要求多个step,只需要一个step即可。可以360度均匀无死角旋转,对时间动画比较友好。

x求模

    float fin = mod(v_uv0.x, .1) * 10.0;
    o.rgb = mix(o.rgb, one, fin * .5);

其中由于模.1,取值[0,0.1]幅度比较小,不容易观察,所以我在后面放大了10倍。
在这里插入图片描述

在中间亮度处做一下step

    float fin = mod(v_uv0.x, .1);
    fin = step(.05, fin);
    o.rgb = mix(o.rgb, one, fin * .5);

注意之前乘的10倍已经去掉了,因为我们从0.05处求step就可以变为0或1。
在这里插入图片描述

旋转

条纹已经出来了,我们把输入的uv先旋转一下。用旋转后的uv做条纹处理看看。
t就是旋转的弧度,比如下面的四分之π就是45度。具体它往哪边转,大家自己体会一下。不是高中数学的坐标轴方向我也很蒙,多调试,结果当成经验就好。

    float t = 3.1416 / 4.0;
    mat2 rot = mat2(cos(t), -sin(t), sin(t), cos(t));
    vec2 uv2 = v_uv0 * rot;
    float fin = mod(uv2.x, .1);
    fin = step(.05, fin);
    o.rgb = mix(o.rgb, one, fin * .5);

在这里插入图片描述

处理锯齿

上图其实已经基本完成了,但是明显的狗牙齿我们不能忍。先把step改smoothstep试试:

    float fin = mod(uv2.x, .1);
    // fin = step(.05, fin);
    fin = smoothstep(.05-.01, .05+.01, fin);
    o.rgb = mix(o.rgb, one, fin * .5);

在这里插入图片描述
这样一来我们干掉了一半的狗牙。想想另一半,突变在求模的函数上,不连续,直接用模值还真没办法。因为smoothstep函数似乎不能直接用在一个不连续的值上。(如果有小伙伴能直接用的话可以教教我)
那么我尝试着把不连续的模值构造成连续的。其实在.05附近连续的即可:反转一下每偶数个模周期的值就行了。
下面我把基础值提出,求了模周期奇偶even,并且按照奇偶性的区间翻转了smoothstep的结果:

    float t = 3.1416 / 4.0;
    mat2 rot = mat2(cos(t), -sin(t), sin(t), cos(t));
    vec2 uv2 = v_uv0 * rot;
    float x = uv2.x;
    float d = .05;
    float hd = d / 2.0;
    float d10 = d / 10.0;
    float even = mod(floor(x/d), 2.0);
    float fin = smoothstep(hd-d10, hd+d10, mod(x, d));
    fin = (1.0 - even) * fin + even * (1.0 - fin);
    o.rgb = mix(o.rgb, one, fin * .5);

所谓“翻转”就是指用1减一下。就是0~1之间的函数图形上下反过来了。
另外里面的d变成了hd,d的1半。在实际操作中发现的。当对奇偶性进行了翻转,结果原来的两个断面接在了一起,造成了条纹宽度变大了一倍,那么在一开始就先缩小一倍。大家可以自行体验。
在这里插入图片描述
到此,线条造型部分就已经完成了。

处理透明部分

由于按钮图片有个阴影,那么阴影按常理是不要加条纹的。就根据其透明度来判断即可。注意里面的enable变量如何得来和使用。
一般来说我喜欢用smoothstep代替step,它可以使交接部分变得平滑,此处透明度的处理上也是一样的原理。毕竟从一个临界值硬生生的分开总是不好的。

    float t = 3.1416 / 4.0;
    mat2 rot = mat2(cos(t), -sin(t), sin(t), cos(t));
    vec2 uv2 = v_uv0 * rot;
    float x = uv2.x;
    float d = .05;
    float hd = d / 2.0;
    float d10 = d / 10.0;
    float even = mod(floor(x/d), 2.0);
    float fin = smoothstep(hd-d10, hd+d10, mod(x, d));
    fin = (1.0 - even) * fin + even * (1.0 - fin);
    float min_gray = .5;
    float enable = smoothstep(min_gray-.2, min_gray, o.a);
    o.rgb = mix(o.rgb, one, fin * enable * .5);

在这里插入图片描述
此时就是开头的图片结果了。

总结

以上的方式和流程也是我做这个效果时的处理方式。我觉得记录的已经足够详细了。可能后面要补充一下旋转,因为这里的旋转轴是角上的点。如果围绕中心点选择呢?还需要做一些平移反平移的变换。
另外,下面有个文章在这个基础上做了针对九宫格的兼容性变换。就比如这个图,我是需要用在各种尺寸的长方形按钮上的。那么就要sliced(九宫格)模式了。如果直接用这篇文章的结论,画出来的线会出现明显的折射感。
还有,如果所用到的图,在图集里面该怎么办?另一篇文章讲解了如何对图集的图做一个兼容性变换。
各种变换都是提前做出变换,要让这篇文章用到的输入还能照常使用,不需要改变代码。

CocosCreator Effect (Shader) - 反九宫格补偿
CocosCreator Effect (Shader) - 反图集打包(Packable)补偿

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值