c# - C# 中的高效 AABB/三角形交集

标签 c# graphics 3d geometry

任何人都可以推荐任何公共(public) AABB/三角形交叉算法的 CSharp 的有效端口。

我一直在研究 Moller 的方法,抽象描述 here ,如果我要移植它,我可能会从 this C++ version 开始. This C++ library by Mike Vandelay这似乎也是一个很好的起点。

...或...任何其他可以采用 Vector3 的三角形并告诉我它是否与 AABB 相交的“轮子”)相对有效。

似乎有多种算法,但大多数似乎是用 C++ 编写的,或者只是在白皮书中进行了抽象描述,我需要为我们的应用程序提供特定于 C# 的实现。效率不是关键,但 C# 才是。 (当然效率显然也不错 ;p )

在我涉足“数学”端口之前,任何 C# 选项 ;) 将不胜感激!谢谢。

最佳答案

对于任意两个凸网格,要判断它们是否相交,需要检查是否存在分离平面。如果是,则它们不相交。平面可以从任一形状的任何面或边叉积中选取。

平面被定义为法线和 Origo 的偏移量。因此,您只需检查 AABB 的三个面和三角形的一个面。

bool IsIntersecting(IAABox box, ITriangle triangle)
{
    double triangleMin, triangleMax;
    double boxMin, boxMax;

    // Test the box normals (x-, y- and z-axes)
    var boxNormals = new IVector[] {
        new Vector(1,0,0),
        new Vector(0,1,0),
        new Vector(0,0,1)
    };
    for (int i = 0; i < 3; i++)
    {
        IVector n = boxNormals[i];
        Project(triangle.Vertices, boxNormals[i], out triangleMin, out triangleMax);
        if (triangleMax < box.Start.Coords[i] || triangleMin > box.End.Coords[i])
            return false; // No intersection possible.
    }

    // Test the triangle normal
    double triangleOffset = triangle.Normal.Dot(triangle.A);
    Project(box.Vertices, triangle.Normal, out boxMin, out boxMax);
    if (boxMax < triangleOffset || boxMin > triangleOffset)
        return false; // No intersection possible.

    // Test the nine edge cross-products
    IVector[] triangleEdges = new IVector[] {
        triangle.A.Minus(triangle.B),
        triangle.B.Minus(triangle.C),
        triangle.C.Minus(triangle.A)
    };
    for (int i = 0; i < 3; i++)
    for (int j = 0; j < 3; j++)
    {
        // The box normals are the same as it's edge tangents
        IVector axis = triangleEdges[i].Cross(boxNormals[j]);
        Project(box.Vertices, axis, out boxMin, out boxMax);
        Project(triangle.Vertices, axis, out triangleMin, out triangleMax);
        if (boxMax <= triangleMin || boxMin >= triangleMax)
            return false; // No intersection possible
    }

    // No separating axis found.
    return true;
}

void Project(IEnumerable<IVector> points, IVector axis,
        out double min, out double max)
{
    double min = double.PositiveInfinity;
    double max = double.NegativeInfinity;
    foreach (var p in points)
    {
        double val = axis.Dot(p);
        if (val < min) min = val;
        if (val > max) max = val;
    }
}

interface IVector
{
    double X { get; }
    double Y { get; }
    double Z { get; }
    double[] Coords { get; }
    double Dot(IVector other);
    IVector Minus(IVector other);
    IVector Cross(IVector other);
}

interface IShape
{
    IEnumerable<IVector> Vertices { get; }
}

interface IAABox : IShape
{
    IVector Start { get; }
    IVector End { get; }
}

interface ITriangle : IShape {
    IVector Normal { get; }
    IVector A { get; }
    IVector B { get; }
    IVector C { get; }
}

一个很好的例子是方框 (±10, ±10, ±10) 和三角形 (12,9,9),(9,12,9),(19,19,20)。没有一个面可以用作分离平面,但它们不相交。分离轴为<1,1,0>,由<1,0,0>和<-3,3,0>的叉积得到。

Graph

关于c# - C# 中的高效 AABB/三角形交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17458562/

相关文章:

Java - LWJGL 加载纹理,只有我加载的最新纹理有效

3d - 脸部 3D 重建

c# - 打印列表项

c# - AspNet Identity Core - 登录时的自定义声明

c# - 如何在.net 项目中使用非托管dll?

java - 使用图形的桨碰撞侧检测

ios - Scenekit - SCNNode 的多次旋转和轴的方向

c# - MonthCalendar 中的奇怪错误突然开始发生

javascript - 图表.org : how to draw scatterplots with full circle as symbol?

c# - 在 Windows 窗体用户控件中嵌入 XNA 游戏