对于拾取对象,我实现了一种类似于此处描述的光线投射算法。将鼠标单击转换为射线(具有原点和方向)后,下一个任务是将该射线与场景中的所有三角形相交以确定每个网格的命中点。
我还实现了基于此处描述的三角形相交测试算法。我的问题是,我们应该如何在执行交叉时考虑对象的变换?显然,我不想将变换矩阵应用于所有顶点,然后进行交集测试(太慢)。
编辑:
这是我正在使用的 UnProject 实现(顺便说一下,我正在使用 OpenTK)。我比较了结果,它们与GluUnProject
给我的结果相匹配:
private Vector3d UnProject(Vector3d screen)
{
int[] viewport = new int[4];
OpenTK.Graphics.OpenGL.GL.GetInteger(OpenTK.Graphics.OpenGL.GetPName.Viewport, viewport);
Vector4d pos = new Vector4d();
// Map x and y from window coordinates, map to range -1 to 1
pos.X = (screen.X - (float)viewport[0]) / (float)viewport[2] * 2.0f - 1.0f;
pos.Y = 1 - (screen.Y - (float)viewport[1]) / (float)viewport[3] * 2.0f;
pos.Z = screen.Z * 2.0f - 1.0f;
pos.W = 1.0f;
Vector4d pos2 = Vector4d.Transform(pos, Matrix4d.Invert(GetModelViewMatrix() * GetProjectionMatrix()));
Vector3d pos_out = new Vector3d(pos2.X, pos2.Y, pos2.Z);
return pos_out / pos2.W;
}
然后我使用这个函数来创建一条射线(有原点和方向):
private Ray ScreenPointToRay(Point mouseLocation)
{
Vector3d near = UnProject(new Vector3d(mouseLocation.X, mouseLocation.Y, 0));
Vector3d far = UnProject(new Vector3d(mouseLocation.X, mouseLocation.Y, 1));
Vector3d origin = near;
Vector3d direction = (far - near).Normalized();
return new Ray(origin, direction);
}