多边形裁剪与Gizmo!新版!Cocos Creator !

Posted by lamyoung on August 4, 2020

支持缩放旋转,支持合图,支持gizmo添加节点和调整位置,支持顺时针逆时针。

效果预览与使用

原理

回顾

gizmo入门探索介绍了 gizmo 与多边形裁剪的配合。

使用 mesh 实现多边形裁剪图片 中介绍了 mesh 和切耳法的相关使用。

相比mask组件,这种meshRenderer的实现可以降低两个draw call

因为小伙伴使用的比较多,这边对这个多边形裁剪图片进行一次升级,增加易用性!

升级后添加了以下几个特性:

  • 升级版本至 Cocos Creator 2.4 (一些接口的变化)
  • 支持多边形节点顺时针和逆时针两种方式
  • 支持 gizmo 直接添加多边形节点
  • 支持节点缩放旋转后,gizmo 的正确显示
  • 支持合图,图片资源可以勾选 packable

接下来就大致讲解主要特性的原理吧。

分割多边形

这次不采用切耳法分割分割了,而是采用poly2tri这个库去分割(注意这个库有严格的限制)。

主要计算顶点索引过程如下。

// 计算顶点索引 
const ids = [];
// 多边形切割 poly2tri,支持简单的多边形,确保顶点按顺序且不自交
const countor = this.vertexes.map((p) => { return { x: p.x, y: p.y } }); 
const swctx = new poly2tri.SweepContext(countor, { cloneArrays: true });

swctx.triangulate();
const triangles = swctx.getTriangles();
triangles.forEach((tri) => {
    tri.getPoints().forEach(p => {
        const i = countor.indexOf(p as any);
        ids.push(i);
    });
})
mesh.setIndices(ids);

支持合图

引用一张 @GT 的图。

SpriteFrame 里含有这个uv信息,这里可以做一次转换,先计算 0~1 的比例,再做一次转化坐标。

private _lerp(a: number, b: number, w: number) {
    return a + w * (b - a);
}
const uv = this.spriteFrame.uv;
const texture = this.spriteFrame.getTexture();
/**
*    t
* l     r
*    b
*/
const uv_l = uv[0];
const uv_r = uv[6];
const uv_b = uv[3];
const uv_t = uv[5];

// 计算uv
const uvs = [];
for (const pt of this.vertexes) {
    const u = this._lerp(uv_l, uv_r, (pt.x + texture.width / 2 + this.offset.x) / texture.width);
    const v = this._lerp(uv_b, uv_t, (pt.y + texture.height / 2 - this.offset.y) / texture.height);
    uvs.push(cc.v2(u, v));
}
mesh.setVertices(gfx.ATTR_UV0, uvs);

gizmo 增加多边形顶点

整体思路是先根据所有顶点画线段,给线段添加事件监听,在点击位置添加一个节点。

点击转换坐标有个坑,y的坐标要用一个高度减去后再转换(感谢@GT的pr)。

start: (x, y, event, param) => {
    y = this._view.offsetHeight - y;
    // 转换不正确,会有偏移 todo
    let position = cc.v2(x, y);
    position = Editor.GizmosUtils.snapPixelWihVec2(position);
    position = this._view.pixelToWorld(position);
    position = node.convertToNodeSpaceAR(position);
}

gizmo 支持旋转缩放

整体来说,就是将坐标点先做缩放,再做旋转处理即可。

this._tool.plot(target.vertexes.map((p) => {
    let scaleX = node.scaleX;
    let scaleY = node.scaleY;
    let angle = -node.angle * Math.PI / 180;
    const cos_angle = Math.cos(angle);
    const sin_angle = Math.sin(angle);

    const v = Editor.GizmosUtils.snapPixelWihVec2(p.mul(this._view.scale));
    return cc.v2(
    (v.x * cos_angle * scaleX + v.y * sin_angle * scaleY),
    -(-v.x * sin_angle * scaleX + v.y * cos_angle * scaleY)
    );
}), position);

小结

坐标转换!旋转!跳跃!不停歇!

以上为白玉无冰使用 Cocos Creator v2.4 实现 "多边形裁剪!" 的技术分享。欢迎分享给身边的朋友!

知识不过是潜在的力量,只有将它组织成明确的行动计划,并指引它朝着某个明确目的发挥作用的时候,知识才是力量。

更多

3D摇杆
两种方法实现亮度/饱和度/对比度的调整
Assembler 源码解读及使用
物理挖洞系列
█ 原创文章导航 █



原文链接
完整代码(见readme)
原创文章导航