XNA:转换单个三角形会产生与转换模型不同的结果

时间:2014-05-21 18:33:53

标签: c# xna xna-4.0 intersection

我在XNA中写了一个光线三角形碰撞。要做到这一点,我正在从我的模型中生成一个三角形列表,然后我使用相同的矩阵进行变换,我用它来变换模型来绘制它。然后我在变换后的三角形列表上运行一个三角形交叉算法,看看我是否点击它。

据我所知,由于性能问题,这不是最好的解决方案,但转换光线并没有成功,所以我将继续这样做。

我的问题是单独变换的三角形不会生成与变换模型相同的形状。

The Problem

左边是XNA绘制的模型。右侧是响应鼠标点击的区域。 (为了得到这个图像,我生成了一个float?-s数组,其中我存储了三角形交集算法在变换后的三角形上测量的距离。然后,对于每个非空值,我在secreen上绘制了一个像素:像素的像素,交叉路口越靠近相机。)

我的假设是变换的三角形实际上产生了上面的形状。这意味着单独转换它们的椎骨不会产生与整体模型转换相同的结果。我不明白为什么。

这是绘图代码:

public void DrawMe(Camera camera, Matrix world, Texture2D texture)
        {
        foreach (ModelMesh mesh in ModelToDraw.Meshes)
            {
            foreach (BasicEffect effect in mesh.Effects)
                {
                effect.TextureEnabled = true;
                effect.Texture = texture;
                effect.EnableDefaultLighting();
                effect.PreferPerPixelLighting = true;

                effect.World = world;
                effect.Projection = camera.Projection;
                effect.View = camera.View;
                }
            mesh.Draw();
            }
        }

这是我用来转换三角形的代码: 在包含该片段信息的类中:

private void transformTriangles()   
    {
    for (int i=0; i<myTriangles.Length; i++)
        {
        transformedTriangles[i] = myTriangles[i].GetCopy();
        }
        foreach (Triangle t in transformedTriangles)
        {
        t.Transform(world);
        }
    }

myTriangles包含从模型中提取的三角形。它们存储在自定义Triangle类中。我测试了这些数据是否准确无误。

GetCopy只返回一个新的Triangle实例,其数据与生成它的实例相同。

世界就是我用来转换模型的矩阵。

在三角形类中:

public void Transform(Matrix transformation)
    {
    vertices[0] = Vector3.Transform(vertices[0], transformation);
    vertices[1] = Vector3.Transform(vertices[1], transformation);
    vertices[2] = Vector3.Transform(vertices[2], transformation);
    }

我的目标是让右侧的形状与左侧的形状相匹配。任何建议都表示赞赏。

谢谢!

编辑:

根据要求,这里是整个Triangle类:

class Triangle
    {
    public Vector3[] vertices;
    public Vector3 normal;

    public Triangle(Vector3 A, Vector3 B, Vector3 C)
        {
        vertices = new Vector3[3];
        vertices[0] = A;
        vertices[1] = B;
        vertices[2] = C;
        calculateNormal();
        }

    public Triangle(Vector3[] vertices)
        {
        this.vertices = vertices;
        calculateNormal();
        }

    private void calculateNormal()
        {
        Vector3 AB = new Vector3();
        Vector3 AC = new Vector3();

        AB = Vector3.Subtract(vertices[1], vertices[0]);
        AC = Vector3.Subtract(vertices[2], vertices[0]);
        normal = Vector3.Cross(AB, AC);
        normal.Normalize();
        }

    private Vector3 project(Vector3 projectUnto, Vector3 toProject)
        {
        float multiplier = Vector3.Dot(projectUnto, toProject)/Vector3.Dot(projectUnto, projectUnto);
        return Vector3.Multiply(projectUnto, multiplier);
        }

    private Vector3? calculateIntersectionPoint(Ray r)
        {
        if (Vector3.Dot(r.Direction, normal) == 0)
            {
            return null;
            }

        Vector3 I, w;
        float multiplier;

        w = Vector3.Subtract(vertices[0], r.Position);
        multiplier = Vector3.Dot(w, normal)/Vector3.Dot(r.Direction, normal);
        I = Vector3.Add(r.Position, Vector3.Multiply(r.Direction, multiplier));

        return I;
        }

    private bool inside(Vector3? i)
        {
        if (i == null)
            {
            return false;
            }
        float a, b, c;
        Vector3 AB, AC, BC, v, w, u, AI, BI, CI;
        Vector3 I = (Vector3) i;
        AB = Vector3.Subtract(vertices[1], vertices[0]);
        AC = Vector3.Subtract(vertices[2], vertices[0]);
        BC = Vector3.Subtract(vertices[2], vertices[1]);
        AI = Vector3.Subtract(I, vertices[0]);
        BI = Vector3.Subtract(I, vertices[1]);
        CI = Vector3.Subtract(I, vertices[2]);

        v = Vector3.Subtract(AB, project(Vector3.Multiply(BC, -1), AB));
        u = Vector3.Subtract(BC, project(Vector3.Multiply(AC, -1), BC));
        w = Vector3.Subtract(Vector3.Multiply(AC, -1), project(AB, Vector3.Multiply(AC, -1)));

        a = 1 - Vector3.Dot(v, AI)/Vector3.Dot(v, AB);
        b = 1 - Vector3.Dot(u, BI)/Vector3.Dot(u, BC);
        c = 1 - Vector3.Dot(w, CI)/Vector3.Dot(w, Vector3.Multiply(AC, -1));

        return a >= 0 && a <= 1 && b >= 0 && b <= 1 && c >= 0 && c <= 1;
        }

    public float? Intersects(Ray ray)
        {
        Vector3? I = calculateIntersectionPoint(ray);
        if (I == null)
            {
            return null;
            }

        if (inside(I))
            {
            Vector3 i = (Vector3) I;
            return Vector3.Distance(ray.Position, i);
            }

        return null;
        }

    public Triangle GetCopy()
        {
        return new Triangle(vertices);
        }

    public void Transform(Matrix transformation)
        {
        vertices[0] = Vector3.Transform(vertices[0], transformation);
        vertices[1] = Vector3.Transform(vertices[1], transformation);
        vertices[2] = Vector3.Transform(vertices[2], transformation);
        }
    }

编辑2:

根据请求,生成光线的代码。如果你问我,可能不会更标准:

private Ray getRay()
        {
        Vector3 nearPoint = BoardViewPort.Unproject(new Vector3(ms.X, ms.Y, 0), cam.Projection, cam.View, Matrix.Identity);
        Vector3 farPoint = BoardViewPort.Unproject(new Vector3(ms.X, ms.Y, 1), cam.Projection, cam.View, Matrix.Identity);
        Vector3 direction = farPoint - nearPoint;
        direction.Normalize();
        return new Ray(nearPoint, direction);
        }

1 个答案:

答案 0 :(得分:0)

转换后我根本没有重新计算正常情况。添加calculateNormal();转换函数结束时的语句解决了问题。