【发布时间】: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