Cocos Creator | 使用 mesh 实现多边形裁剪图片!

和 mask 裁剪图片说拜拜,用上高性能的 shader 。文章底部获取完整代码!


one 1


效果预览


83032d3b19308b8cc31c13c2705da63f.jpeg

two 2

主页下方列表选项如何实现

使用方法:

  1. 创建一个空节点

  2. 添加用户脚本组件 mesh-texture-mask

  3. 添加图片

  4. 添加修改多边形顶点坐标

a6274929a03cc28cde46c369c97281cf.jpeg

three 3

实现原理

创建 mesh

mesh 是什么? mesh 是决定一个物体形状的东西。例如在二维中可以是正方形、圆形、三角形等;在三维中可以是正方体、球体、圆柱体等。

mesh 初始化需要一个 VertexFormat 对象。这个对象是顶点格式对象。

f3a457bc398791cbba9b38b43d79293d.jpeg

其中 name 是对应顶点着色器的 attribute 变量的值。 type 对应数据类型,决定了每个数据大小。

3a1d0a3e98104ad205309d39d2211543.jpeg

num 对应有几个数据分量(猜的哈哈!)。例如二维坐标和纹理uv坐标一般只有xy两个分量,所以设置为2;三维坐标有xyz三个变量,所以值为3;而颜色一般有 rgba 四个分量,所以设置为4。

3bf7a7c9a2750190a026f3a8007b16a7.png

normalize 表示归一化。

a269ce54586340d7046dfa880fdb8f2c.jpeg

对于我们的多边形裁剪图片,只需要一个二维坐标和一个纹理uv坐标,创建 mesh 参考代码如下:

const gfx = cc.gfx;
let mesh = new cc.Mesh();
mesh.init(new gfx.VertexFormat([
    { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
    { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
]), this.vertexes.length, true);

four 4


计算纹理 uv 坐标

纹理uv坐标系在左上角,u轴是向右,v轴是向下,范围是 0~1。而我们的坐标系在中间,x轴向右,y轴向上。

所以我们可以先求出x,y在左下角的占比,然后再反转一下y轴,转成uv坐标系。参考代码如下。

const vx = (pt.x + this.texture.width / 2 + this.offset.x) / this.texture.width;
const vy = 1.0 - (pt.y + this.texture.height / 2 + this.offset.y) / this.texture.height;

five 5

计算顶点索引

首先需要知道一个概念,绘制一个形状实际上是绘制多个三角形。一个多边形可以分割成多个三角形,而顶点索引是告诉它如何去绘制这些三角形。

b9aec698070e4101462a9ce70ac42d30.jpeg

如何将一个多边形切割成多个三角形?可以采用'耳切法'的方式。把多边形的一个耳朵切掉,然后再对剩下的多边形再次切割。

53dc3551c972ef152ec102aefc0c5a37.jpeg

怎么样的耳朵才能切呢?这个耳朵的顶点需要满足是凸顶点且没有其他顶点在这个耳朵里。

ffe98caa90b295105b6e2104c58ce4ea.jpeg

如何判断是凸顶点呢?首先要知道向量外积的定义,表示向量的法向量。方向根据右手法则确定,就是手掌立在a、b所在平面的向量a上,掌心由a转向b的过程中,大拇指的方向就是外积的方向。

f113f406db6cc73e310ceb99cc70375a.jpeg

对于cc.Vec2的外积就是面积,有正负之分,也是根据右手法则确定。

c7fdd02c4ba09f65ff63cac4b5ec1b16.png

若多边形ABCDEF顶点以逆时针顺序排序的话,AB x BC > 0 表示B点是凸顶点。参考代码如下。

const v1 = p2.sub(p1);
const v2 = p3.sub(p2);
if (v1.cross(v2) >= 0) {
    // 是凸点
}

判断点D是否在三角形ABC内,可以通过外积计算点与线的位置关系判断出。

56a3c439a09f73e71ac75291d3371334.jpeg

// 判断一个点是否在三角形内
_testInTriangle(point, triA, triB, triC) {
    let AB = triB.sub(triA), AC = triC.sub(triA), BC = triC.sub(triB), AD = point.sub(triA), BD = point.sub(triB);
    return (AB.cross(AC) >= 0 ^ AB.cross(AD) < 0)  // D,C 在AB同同方向
        && (AB.cross(AC) >= 0 ^ AC.cross(AD) >= 0) // D,B 在AC同同方向
        && (BC.cross(AB) > 0 ^ BC.cross(BD) >= 0); // D,A 在BC同同方向
},

最后把以上综合起来就可以计算出顶点索引。

 235c60f4013aaf20327fd3765934edbf.gif

以上就是本次的分享,

如有问题或新的想法欢迎留言嗷~

如果您在使用 Cocos Creator 2D/3D 的过程中

 get 了独到的开发心得、见解或是方法

欢迎分享出来

帮助更多开发者们解决技术问题

让游戏开发更简单~

期待您与我们联系~

722168ccd60da8b2d0e6279ca890e15f.gif

更多精彩

d1aa7a30b8da7b121dcd87db45fc9095.gif

Cocos 荣获金茶奖 2019 最佳游戏服务企业

Cocos Creator | 自由/约束的绳索效果

Cocos Creator 通用框架设计——资源管理

Cocos Creator v2.2.2 正式发布

来啊,斗图啊!Cocos 官方定制表情包来啦~

  - end -  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值