【问题标题】:XNA: Transforming individual triangles gives different results than transforming modelXNA:转换单个三角形会产生与转换模型不同的结果
【发布时间】:2014-05-21 18:33:53
【问题描述】:

我正在 XNA 中编写射线-三角形碰撞。为此,我从我的模型中生成一个三角形列表,然后用我用来变换模型以绘制它的相同矩阵对其进行变换。然后我在变换的三角形列表上运行一个三角形相交算法,看看我是否击中它。

我知道由于性能问题这不是最好的解决方案,但是转换光线没有奏效,所以我要这样做。

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

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

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

这里是绘图代码:

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 实例,其数据与生成它的实例相同。

world 只是我用来转换模型的矩阵。

在三角形类中:

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);
        }

【问题讨论】:

  • Triangle 是类还是结构?请出示您的碰撞代码。
  • 老实说,我不知道你在那里做什么花哨的东西。以前从未见过有人这样做。尤其是inside 方法似乎做得太多了。查看here 了解如何计算重心坐标。我强烈建议清理你的数学(或者至少编写单元测试来充分测试它)。这可能是您的光线变换一开始就不起作用的原因。并使用合理的变量名!
  • 顺便说一句,你知道像*、- 和+ 这样的常用运算符对于向量来说是重载的,对吧?使用这些而不是 Vector3.Subtract 等。这将使您的代码更具可读性。
  • 数学的声音。它非常适合未转换的模型。
  • 那么射线呢。你能添加你如何生成它的代码吗?

标签: c# xna xna-4.0 intersection


【解决方案1】:

我只是没有在转换后重新计算法线。添加calculateNormal(); Transform 函数末尾的语句解决了这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-03
    • 2023-03-23
    • 2019-09-11
    • 2011-03-29
    • 1970-01-01
    • 1970-01-01
    • 2017-04-04
    • 1970-01-01
    相关资源
    最近更新 更多