Minkowski与3D凸多面体的差异

时间:2018-11-23 20:17:35

标签: c++ collision-detection

我对碰撞检测了解不多,我正在尝试精确解决3D碰撞。为此,我使用Minkowski差。问题是,我在计算两个形状之间的差异时遇到问题。

我尝试做的事情: 在2D中,您可以通过在A的边缘中循环来找到2个多边形(A和B)的M.差,方法是使用A的反向边缘法线找到B的正确支撑顶点,然后用支撑顶点替换A的边缘B。然后通过遍历B的边缘来做类似的事情。

所以基本上,在3D中,我尝试通过使用三角形而不是边缘来做同样的事情。似乎有点工作,而且有点失败(这是M.相同立方体旋转45度的立方体的差): Click to view image.

如图所示,中间有一个怪异的洞。我认为这不正常,因为我们应该以闭合的形状结束。

以下是我的代码(请注意,代码没有经过优化,因为我不确定如何选择支撑顶点,因此我没有选择,我选择了所有顶点)。

这里是负责Minkowski内容的类(如果方法上有// OK,我很确定它可以工作):

#include "TransformedPolyhedron.h"
#include "Array.h"
#include "graphics/MeshLoader.h"
#include <iostream>

using namespace graphics;

namespace math
{
  TransformedPolyhedron::TransformedPolyhedron(Polyhedron& polyhedron)
  {
    this->polyhedron = &polyhedron;
  }

  //OK
  ArrayList<int>& TransformedPolyhedron::getIndices() const
  {
    return polyhedron->getIndices();
  }

  //OK
  ArrayList<Vector3> TransformedPolyhedron::getTransformedPositions() const
  {
    ArrayList<Vector3>& positions = polyhedron->getPositions();
    ArrayList<Vector3> result(positions.size());

    for(int i=0;i<result.size();i++)
    {
      result[i] = transformation.transform(positions[i]);
    }
    return result;
  }

  //OK(?)
  ArrayList<TriangleFace> TransformedPolyhedron::getTriangleFaces(const ArrayList<Vector3>& positions) const
  {
    ArrayList<int>& indices = getIndices();
    ArrayList<TriangleFace> result;
    for(int i=0;i<indices.size();i+=3)
    {
      Vector3& v1 = positions[indices[i]];
      Vector3& v2 = positions[indices[i + 1]];
      Vector3& v3 = positions[indices[i + 2]];
      result.add(TriangleFace(v1, v2, v3));
    }
    return result;
  }

  ArrayList<Vector3> TransformedPolyhedron::getSupportingVertex(const Vector3& normal, const ArrayList<Vector3>& positions) const
  {
    double maxDot = normal.dot(positions[0]);
    for(int i=0;i<positions.size();i++)
    {
      double dot = normal.dot(positions[i]);
      if(dot > maxDot)
      {
        maxDot = dot;
      }
    }
    ArrayList<Vector3> result;
    for(int i=0;i<positions.size();i++)
    {
      Vector3& position = positions[i];
      double dot = normal.dot(position);
      if(dot >= maxDot)
      {
        result.add(position);
      }
    }
    return result;
  }

  Polyhedron TransformedPolyhedron::minkowskiDifference(const TransformedPolyhedron& poly) const
  {
    ArrayList<int> resultIndices;
    ArrayList<Vector3> resultPositions;

    ArrayList<Vector3> thisPositions = getTransformedPositions();
    ArrayList<TriangleFace> thisTriangleFaces = getTriangleFaces(thisPositions);

    ArrayList<Vector3> polyPositions = poly.getTransformedPositions();
    ArrayList<TriangleFace> polyTriangleFaces = poly.getTriangleFaces(polyPositions);
    //this
    for(int i=0;i<thisTriangleFaces.size();i++)
    {
      TriangleFace& triangle = thisTriangleFaces[i];
      Vector3 normal = triangle.getNormal();
      normal*=(-1);
      ArrayList<Vector3> supportingVectors = poly.getSupportingVertex(normal, polyPositions);
      for(int k=0;k<supportingVectors.size();k++)
      {
        Vector3& supportingVector = supportingVectors[k];
        for(int j=0;j<3;j++)
        {
          Vector3 toAdd = triangle[j] - supportingVector;

          resultIndices.add(resultPositions.size());
          resultPositions.add(toAdd);
        }
      }
    }
    //poly
    for(int i=0;i<polyTriangleFaces.size();i++)
    {
      TriangleFace& triangle = polyTriangleFaces[i];
      Vector3 normal = triangle.getNormal();
      normal*=(-1);
      ArrayList<Vector3> supportingVectors = getSupportingVertex(normal, thisPositions);
      for(int k=0;k<supportingVectors.size();k++)
      {
        Vector3& supportingVector = supportingVectors[k];
        for(int j=0;j<3;j++)
        {
          Vector3 toAdd = triangle[j] - supportingVector;

          resultIndices.add(resultPositions.size());
          resultPositions.add(toAdd);
        }
      }
    }

    return Polyhedron(resultPositions, resultIndices);
  }

  //OK
  void TransformedPolyhedron::transform(const Matrix4& transformation)
  {
    this->transformation = transformation;
  }

  //ok
  GLuint TransformedPolyhedron::loadToGPU(int* amount) const
  {
    ArrayList<int>& indices = getIndices();
    ArrayList<Vector3> positions = getTransformedPositions();
    ArrayList<float> textures(positions.size()*2);
    ArrayList<float> positionsArray(positions.size()*3);
    for(int i=0;i<positions.size();i++)
    {
      positionsArray[3*i] = positions[i].getX();
      positionsArray[3*i + 1] = positions[i].getY();
      positionsArray[3*i + 2] = positions[i].getZ();
    }
    Array<float> apos(positionsArray.toArray(), positionsArray.size());
    Array<int> aind(indices.toArray(), indices.size());
    Array<float> atex(textures.toArray(), textures.size());
    *amount = indices.size();
    return MeshLoader::loadIndexedVertices(apos, atex, aind);
  }
}

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

好吧,我发现算法有什么问题,基本上我只是在计算“平移的面孔”,而不是在计算边缘扫过的部分,这是一篇关于minkowski和及其计算方法的论文:liris.cnrs.fr/Documents/Liris-3813.pdf(请参阅有关CVMS算法的部分)

最后,对于碰撞检测来说,这是非常糟糕的性能,因此,正如评论中指出的那样,我实现了用于碰撞检测的GJK算法和用于碰撞响应的EPA算法,效果很好。

GJK + EPA:http://hacktank.net/blog/?p=93