是否可以在cocoscreator里做出这种效果

请问,在Cocos Creator中如何引用像paperjs这样的第三方js库呢?

这个就要看你的运行平台了,看官方介绍,这样可能原生平台并不能很好的使用这个库,而且这个是矢量绘图的,需要使用纹理的话,还是选择shader实现更为灵活,至于导入方法,如果没有包体限制,你应该可以简单按js模块的方式导入使用,就是整个库拷到资源目录下,也许你可以考虑插件脚本,不过那个我也没用过,官方手册里面有怎么操作

我也倾向于shader实现,更符合常规需求一些,只是想到优化和调试就很头疼

下半年才入行的新手,先抽空去看了点shader里glsl(最费时,感觉自己是笨蛋),
然后看了下metaball算法,初高中数学足够理解(高数已经完全百分百还给老师了…高中里向量也换给老师了…)
接着要感谢下,坛子里有大神提供了2.0.x的shader代码,借此我只需要关心shader脚本怎么写。
拿来修改了下,然后用自己的shader脚本实验了下

注意:游戏运行在微信小游戏平台,非原生

实现方式1:一个和屏幕同分辨率的sprite,设置其使用自定义shader,在update里把所有的ball(刚体)的实时位置(50个)传给shader,在里面计算:

卡到爆炸。。。。刚体也挤成一堆
转gif看着流畅,实际奇卡无比

实现方式2:50个ball,给50个sprite,大小比ball大些(长宽为ball直径的2倍吧),每个sprite都使用的shader,并且在update里判断,对任一个ball对应的sprite,把其他ball相对其的位置传进去(太远的不传)

一个sprite一个drawcall。。。。50+drawcall。。。。
流畅多了。但这是660手机。
拿同事果6试了下,依然卡炸(骁龙430表现勉强30帧,比果6好点点)

帖子里还有没用shader,用系统的Graphics做的,但这个我就完全不理解了。

总之就是:自己做的太卡,不能实用,不知如何优化

1赞

实现方式2每个sprite都用shader是什么意思?shader的作用是什么?

明白了

update里把50个sprite的位置更新到对应50个ball上,并给sprite用的shader里传入其他ball的相对位置,在shader里metaball的算法绘制sprite里的颜色。

你说用graphcis来计算我理解不来,我想到的是逐像素运算绘制,然后我翻了翻文档,木有这种做法

https://github.com/chongshengzhujue/testball
这是用graphics做的demo,但是这个其实比shader更卡,效果也差

但我做的在果6上卡到帧率20-50间波动

看起来效果还是很不错的,一个来说要看你的shader实现,另一个小游戏性能就那样了,我这边的项目shader和粒子只用在非核心部分,或者出现频率低的地方,或者影响范围不大的地方,50个对象卡的话,可以考虑把对象放大然后数量减少试试

在update里遍历每个ball,计算其他ball相对这个ball的位置
即ball1.convertToNodeSpaceAR(ball2.convertToWorldSpaceAR(cc.Vec2.ZERO))
如果太远(超过4 * 8或自己定),就不管
否则吧这个位置的x和y放进数组里,传给这个ball的着色器的sPos
经过试验基本不会超过20个,故sPos大小我定义为40.
所有球半径固定为8,对应sprite的尺寸36*36,故着色器里有18.0 36.0。
如果需要不同大小也应该可以通过传值给shader的方式实现吧。

着色器:
井define Rad 8.0
井define RadPow 64.0
varying vec2 uv0;
uniform float sPos[40];
float energy(float x1, float y1, float x2, float y2) {
     return RadPow / ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
void main () {
     float x = uv0.x * 36.0 - 18.0;
     float y = 18.0 - uv0.y * 36.0;
     float energyVal = 0.0;
     if((x * x + y * y) < RadPow) {
          energyVal = 2.0;
     } else {
          energyVal += energy(x, y, 0.0, 0.0);
          for(int i = 0; i < 20; i++) {
               if(sPos[i * 2] < -1600.0 || sPos[i * 2 + 1] < -1600.0) {
                    continue;
               }
               energyVal += energy(sPos[i * 2], sPos[i * 2 + 1], x, y);
          }
     }
     if(energyVal >= 1.0) {
          gl_FragColor = vec4(0.0,0.0,1.0,1.0);
     } else {
          gl_FragColor = vec4(0,0,0,0);
     }
}

下面是shader的脚本。用的论坛里那个帖子提供的demo,未修改顶点着色器

shader中if和for通常会认为是具有很大开销的操作,我不是shader高手,这些也是以前接触shader的时候查到的,当然优化起来也没那么简单,或许从算法改进和业务的平衡点上下手才比较符合我们的一般做法

网上应该可以搜到不少shader的优化方式,不过以以前的经验来看,反正不是所有shader的优化都是有用的……

完全不懂游戏开发的时候就知道gpu的分支判断不行。。。。但结果还是这么写了。。。
看到回复后,在想要不要写
a[0] = xx
a[1] =xx
硬性的把循环写成顺序

看了下shader优化文章,不应这么个想法。有空再试试。

井define Rad 8.0
井define RadPow 64.0
varying vec2 uv0;
uniform float sPos[40];

float energy(float x, float y, float k) {
float energyVal = 1.0 / k;
energyVal += step(-680.0, sPos[0]) / ((sPos[0] - x) * (sPos[0] - x) + (sPos[1] - y) * (sPos[1] - y));
。。。。。
。。。。。
energyVal += step(-680.0, sPos[38]) / ((sPos[38] - x) * (sPos[38] - x) + (sPos[39] - y) * (sPos[39] - y));
return energyVal * RadPow;
}
void main () {
float x = uv0.x * 36.0 - 18.0;
float y = 18.0 - uv0.y * 36.0;
float k = x * x + y * y;
float energyVal = (1.0 - step(RadPow, k)) * 10.0 + step(RadPow, k) * energy(x, y, k);
gl_FragColor = vec4(0.0,0.0,1.0,step(1.0, energyVal));
}
如上用step干掉了if判断。。。
然而结果似乎没什么影响(骁龙430)

甚至。。。还掉了点

step对if的优化并不是任何情况都有效,有时候会造成逆优化,关键在于理解if会造成的真正影响,除去shader算法的问题,还得考虑运行环境本身能够到什么一个程度,找个折中点

https://zhuanlan.zhihu.com/p/33260382 这篇文章讲了一些,我看了下应该还是有参考意义

1赞

你这个 是 vert还是frag ,shader中需要 两个脚本(v和f) 能不能贴出你的完整的v和f 参考一下