5

問題は次のPolygon::FindAxisLeastPenetrationとおりです。

double Polygon::FindAxisLeastPenetration(unsigned int *faceIndex, const Polygon &polygonA, const Polygon &polygonB) const {
  double bestDistance = -std::numeric_limits<double>::infinity();
  unsigned int bestIndex;

  for (unsigned int i = 0; i < polygonA.points.size(); i++) {
    Vector2D n = polygonA.normals[i];
    Vector2D nw = polygonA.rotationMatrix * n; //ROTATION
    Matrix22 buT = polygonB.rotationMatrix.Transposed();
    n = buT * nw; //ROTATION

    Vector2D support = polygonB.points[polygonB.GetSupport(-n)];

    Vector2D vertex = polygonA.points[i];
    vertex = polygonA.rotationMatrix * vertex; //ROTATION
    vertex.Add(polygonA.body->GetPosition());
    vertex.Subtract(polygonB.body->GetPosition());
    vertex = buT * vertex; // ROTATION
    double distance = n.DotProduct(support - vertex);
    if (distance > bestDistance) {
      bestDistance = distance;
      bestIndex = i;
    }
  }
  *faceIndex = bestIndex;

  return bestDistance;
}

unsigned int Polygon::GetSupport(const Vector2D &dir) const {
  double bestProjection = -std::numeric_limits<double>::infinity();
  unsigned int bestIndex = 0;

  for (unsigned int i = 0; i < points.size(); i++) {
    Vector2D vertex = points[i];
    double projection = vertex.DotProduct(dir);

    if (projection > bestProjection) {
      bestProjection = projection;
      bestIndex = i;
    }
   }

  return bestIndex;
}

Manifold Polygon::CheckCollision(const Polygon &polygonA, const Polygon &polygonB) const {
  Manifold result;
  result.objectA = polygonA.body;
  result.objectB = polygonB.body;
  unsigned int indexA;
  double penetrationA = Polygon::FindAxisLeastPenetration(&indexA, polygonA, polygonB);
  if (penetrationA >= 0.0) {
    result.intersects = false;
    return result;
  }

  unsigned int indexB;
  double penetrationB = Polygon::FindAxisLeastPenetration(&indexB, polygonB, polygonA);

  if (penetrationB >= 0.0) {
    result.intersects = false;
    return result;
  }

  result.intersects = true;
  //...
  return result;

Rectangle::Rectangle(double width, double height) : Polygon() {
  double hw = width / 2.0;
  double hh = height / 2.0;
  points.push_back(Vector2D(-hw, -hh));
  points.push_back(Vector2D(hw, -hh));
  points.push_back(Vector2D(hw, hh));
  points.push_back(Vector2D(-hw, hh));

  //  points.push_back(Vector2D(0, 0));
  //  points.push_back(Vector2D(width, 0));
  //  points.push_back(Vector2D(width, height));
  //  points.push_back(Vector2D(0, height));

  normals.push_back(Vector2D(0.0, -1.0));
  normals.push_back(Vector2D(1.0, 0.0));
  normals.push_back(Vector2D(0.0, 1.0));
  normals.push_back(Vector2D(-1.0, 0.0));

  center.x = 0;
  center.y = 0;

}

polygon.rotationMatrixMatrix222x2 行列である型のオブジェクトです。
polygon.pointsベクトルでstd::vector<Vector2D>満たされています。インスタンス
polygon.bodyへのポインタです。Objectこの場合、位置を取得するためにのみ使用されます。と座標
polygon.body->positionのインスタンスです。ボディの位置ベクトルを返します。Vector2DXY
Vector2D polygon.body->GetPosition()

ポイントを中心に回転が行われることを除いて、正常に機能します[0, 0]が、重心の周りを回転するはずです。

ポイントを中心とした回転は次のようにできることを知っています:

rotationMatrix * (vertex - point) + point

また、ポリゴンをレンダリングするときにもうまく機能します。しかし、衝突検出ではありません。

この場合、特定の点を中心にベクトルを回転させるにはどうすればよいですか?

編集:これが私がこれまでに持っているものです

double Polygon::FindAxisLeastPenetration(unsigned int *faceIndex, const Polygon &polygonA, const Polygon &polygonB) const {
  double bestDistance = -std::numeric_limits<double>::infinity();
  unsigned int bestIndex;

  for (unsigned int i = 0; i < polygonA.points.size(); i++) {
    // Calculate normal
    unsigned int j = i == points.size() ? 0 : i + 1;
    Vector2D n;
    // Rotate points
    Vector2D p1 = polygonA.rotationMatrix * (polygonA.points[i] - polygonA.Center()) + polygonA.Center();
    Vector2D p2 = polygonA.rotationMatrix * (polygonA.points[j] - polygonA.Center()) + polygonA.Center();
    n.x = p2.y - p1.y;
    n.y = -(p2.x - p1.x);
    n.Normalize();

    Vector2D support = polygonB.points[polygonB.GetSupport(-n)];
    support = polygonB.rotationMatrix * (support - polygonB.Center()) + polygonB.Center();
    support.Add(polygonB.body->GetPosition());

    Vector2D vertex = polygonA.points[i];
    vertex = polygonA.rotationMatrix * (vertex - polygonA.Center()) + polygonA.Center(); //ROTATION
    vertex.Add(polygonA.body->GetPosition());

    double distance = n.DotProduct(support - vertex);
    if (distance > bestDistance) {
      bestDistance = distance;
      bestIndex = i;
    }
  }
  *faceIndex = bestIndex;

  return bestDistance;
}

unsigned int Polygon::GetSupport(const Vector2D &dir) const {
  double bestProjection = -std::numeric_limits<double>::infinity();
  unsigned int bestIndex = 0;

  for (unsigned int i = 0; i < points.size(); i++) {
    Vector2D vertex = rotationMatrix * (points[i] - center) + center;
    double projection = vertex.DotProduct(dir);

    if (projection > bestProjection) {
      bestProjection = projection;
      bestIndex = i;
    }
   }

  return bestIndex;
}

今のところ、最適化についてはあまり気にしていません。同じ問題があります。中心を中心に回転すると、衝突が正しく検出されません。ただし、中心が使用されている[0, 0]か使用されていない場合、衝突検出は適切に機能しますが、回転は正しく行われません。

編集:衝突検出前に回転しても、同じ問題が発生します。これまでのところ、中心が になるようにポリゴンを変換するのが最善の方法でした[0, 0]が、角度によっては衝突が検出されませんでした。今何をすべきかわからない。

編集: スクリーンショット (重心が常に になるようにポリゴンが変換されてい[0, 0]ます。この場合、ポリゴンは長方形です) 衝突検出はここではうまく機能しませんでした ここでは衝突検出がうまく機能しませんでした

ここでも衝突検出がうまく機能しませんでした ここでも衝突検出がうまく機能しませんでした

ここでは衝突検出がうまく機能しました ここでは衝突検出がうまく機能しました

編集:Rectangleクラスを追加しました。

4

1 に答える 1