【问题标题】:Convex polygonisation of sprite精灵的凸多边形化
【发布时间】:2016-08-08 03:51:16
【问题描述】:

我正在为我的游戏开发一个碰撞系统,我希望它是通用的。 另外我想让物体在它们之间反弹,所以精灵的形状很重要。 我的问题是我需要将我的精灵形状转换为一个多边形/多边形。

我的最后一个问题是:您是否知道一种比我更容易的方法或一种使我的工作的方法?

现在,这里是我目前所做的详细信息:

我实现了轴分离算法来检测我的多边形之间的交叉点。

为了创建多边形,我首先实现了行进正​​方形算法来获取内部形状的轮廓,然后将其转换为线段。

我现在有一个多边形,但它可以是凹的,这就是为什么我需要找到一种方法将它分成多个凸多边形。

我尝试实现剪耳算法,但在某些情况下会失败。另外,我在某处读到,当多边形自相交时它不起作用。

以下是我的问题的一些糟糕的视觉效果:

另外,下面是我为那个精灵生成的骨架,很抱歉这是一个平局,但这只是为了给你更多的视觉信息:

如你所见,我也“裁剪”了角落(不知道怎么说)。

好的,那么剪耳算法应该在那个多边形上工作吗?问题来自我的实现还是它不应该工作?

我的下一个目标是在三角形仍然形成凸多边形的同时合并三角形。 如果你知道的话,我也在寻找一种更简单的方法。

提前致谢。

EDIT-1

我的三角测量实现代码:

#include "Triangulation.hh"

bool Triangulation::isConvex(const Position &a, const Position &b,
                             const Position &c) const {
  float crossp = (c.x - a.x) * (b.y - a.y) - (c.y - a.y) * (b.x - a.x);
  return (crossp >= 0 ? true : false);
}

bool Triangulation::inTriangle(const Position &a, const Position &b,
                               const Position &c, const Position &x) const {
  std::array<float, 3> barCoef = {0, 0, 0};

  barCoef[0] = ((b.y - c.y) * (x.x - c.x) + (c.x - b.x) * (x.y - c.y)) /
               (((b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y)));
  barCoef[1] = ((c.y - a.y) * (x.x - c.x) + (a.x - c.x) * (x.y - c.y)) /
               (((b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y)));
  barCoef[2] = 1.f - barCoef[0] - barCoef[1];

  for (float coef : barCoef) {
    if (coef >= 1 || coef <= 0)
      return false;
  }
  return true;
}

std::pair<bool, std::array<Position, 3>>
Triangulation::getEar(std::vector<Position> &polygon) const {
  int size = polygon.size();
  bool triTest = false;
  std::array<Position, 3> triangle;

  if (size < 3)
    return {false, triangle};
  else if (size == 3) {
    triangle = {polygon[0], polygon[1], polygon[2]};
    polygon.clear();
    return {true, triangle};
  } else {
    for (int i = 0; i < size; ++i) {
      triTest = false;
      triangle[0] = polygon[(i + size - 1) % size];
      triangle[1] = polygon[i];
      triangle[2] = polygon[(i + 1) % size];
      if (this->isConvex(triangle[0], triangle[1], triangle[2])) {
        for (const Position &point : polygon) {
          auto it = std::find(triangle.begin(), triangle.end(), point);

          if (it != triangle.end())
            continue;
          if (this->inTriangle(triangle[0], triangle[1], triangle[2], point)) {
            triTest = true;
            break;
          }
        }
        if (triTest == false) {
          polygon.erase(polygon.begin() + i);
          return {true, triangle};
        }
      }
    }
  }
  return {false, {}};
}

我的观点是逆时针顺序的,问题来自 isConvex 方法,对于我的第一张图像,它将返回 true。

编辑 2

感谢@svs的注释,我更新了EDIT 1中的代码供其他人查看,下面是我对获得的结果的错误绘图:

【问题讨论】:

  • 应该是 if (coef > 1 || coef

标签: c++ algorithm c++11 2d triangulation


【解决方案1】:

剪耳算法应该能够毫无问题地对这个多边形进行三角剖分,所以我认为你的实现有问题。您可以检查以下几件事,以确保您已正确实施:

  • 确保以一致的方式输入多边形顶点 - 顺时针或逆时针。例如,如果您有一个顶点为(0, 0), (1, 1), (1, 0), (0, 1) 的正方形,如果您使用逆时针方式,则应将多边形输入为顶点(0, 0), (0, 1), (1, 1), (1, 0)

  • 再次检查您的算法以测试顶点是否为ear。如果您使用顺时针方式,则如果顶点v[i-1]=(x[i-1], y[i-1])), v[i], v[i+1]=(x[i+1], y[i+1])) 的有符号区域为正并且多边形的任何点都不在v[i-1], v[i], v[i+1] 的内部,那么顶点v[i]=(x[i], y[i]) 就是耳朵。 Here 是签名区域的公式。

看到您的代码,您应该将顶点的删除语句移到多边形顶点循环之外。该算法的psedocode为:

for each vertex v[i] of the polygon:
    if v[i] is an ear:
        if there is no polygon vertex in triangle v[i-1], v[i], v[i+1]:
            delete vertex v[i] from the polygon

问题是您在检查三角形中是否存在多边形的顶点时删除了顶点。将您的代码更新为:

if (this->isConvex(triangle[0], triangle[1], triangle[2])) {
    for (const Position &point : polygon) {
        auto it = std::find(triangle.begin(), triangle.end(), point);

        if (it == triangle.end())
            continue;
        if (this->inTriangle(triangle[0], triangle[1], triangle[2], point)) {
            triTest = true;
            break;
        }
    }
    if (triTest == false) {
        polygon.erase(polygon.begin() + i);
        return {true, triangle};
    }
}

【讨论】:

  • 如果还有问题可以分享代码
  • 感谢您指出我看不到的错误。此外,我必须将 'if (it == triangle.end())' 更改为 'if (it != triangle.end())' 这是逻辑。我更新了我的帖子以再次使用糟糕的平局显示结果
猜你喜欢
  • 1970-01-01
  • 2015-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
  • 1970-01-01
  • 2012-08-04
  • 2011-01-28
相关资源
最近更新 更多