Regenerate Points 实现解析! Marching Squares !

编辑器里 Regenerate Points 功能怎么实现?节点动态加载了 spriteFrame ,怎么重新获取碰撞组件多边形顶点数组 points?

62c4ccdf46d9e625ac7be9416f0e0912.gif

背景

Cocos Creator 编辑中,多边形碰撞组件中有一个 Regenerate Points 的功能,这个功能可以根据组件依附的节点上的 Sprite 组件的贴图的像素点来自动生成相应轮廓的顶点。Threshold 指明生成贴图轮廓顶点间的最小距离,值越大则生成的点越少。

8fdd5c9eeaa444f6a675856deebc76d3.png
Regenerate Points

白玉无冰源于兴趣,对其中的实现做一些研究。最终研究成果如下文所示。

实现

编辑器中的实现主要以下几步:

  • 读取图片所有的像素点数据

  • 计算围成轮廓的像素点

  • 计算顶点(处理Threshold)

  • 对结果进行坐标转换

以下是在 Canvas 中计算轮廓(红边)和和计算顶点(蓝点)的效果。

c638d52c002aef90fa079f5028ff50b4.gif
实现效果

获取像素点数据

编辑中读取像素数据用了sharp这个库去读取。

4ebe1923e90c8db08f8b070dd8e2d4be.png
编辑器中读取像素数据

白玉无冰这里采用 Canvas 获取图片像素数据。

const img = new Image();
img.crossOrigin = 'anonymous';
img.src = './白玉无冰.png';

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

img.onload = function () {
    main();
};
const main = function () {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(img, 0, 0);
    const canvasImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = canvasImageData.data;
    // data 就是像素数据,从左往右,从上往下的像素数据
}

计算围成轮廓的像素点

核心思路是参考 Marching Squares 算法:

  • 先从上到下,从左到右的顺序,找到第一个不透明的点。

  • 根据当前点的 左上/左边/上边/当前点 四个点的透明值计算一个值,根据这个值判断往哪个方向移动

  • 移动后继续计算,继续移动,直到回到第一个点

简单来说就是,找一个点,然后逆时针环绕一圈。

先看看如何根据当前点周围的透明度值计算一个值,这里巧妙地使用了二进制相加,可以通过和判断不同情况。

/*
checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent
+---+---+
| 1 | 2 |
+---+---+
| 4 | 8 | <- current pixel (curx,cury)
+---+---+
*/
// 以下为伪代码
let state = 0;
let tl = {x:(x-1), y:(y-1)}
state += (containsPoint(tl)&&getAlphaByPos(tl)>0)? 1:0;
let tr = {x:(x-1), y:(y)}
state += (containsPoint(tr)&&getAlphaByPos(tr)>0)? 2:0;
let bl = {x:(x-1), y:(y)}
state += (containsPoint(bl)&&getAlphaByPos(bl)>0)? 4:0;
let br = {x:(x), y:(y)}
state += (containsPoint(br)&&getAlphaByPos(br)>0)? 8:0;

根据不同的值,走不同的方向。

4726bed996564fc6003692a73f9bd2d8.png
不同的值不同的方向

这里

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值