在openGL中,我有一个3D模型,我正在使用“Fast,Minimum Storage Ray / Triangle Intersection”(http://jgt.akpeters.com/papers/MollerTrumbore97/)文章中解释的代码执行光线三角交叉。
使用以下代码将我的光标位置取消投影到世界空间:
bool SCamera::unproject(Vector3 input, Vector3 & output){
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT,viewport); //Grab screen info
float x = input.mX;
float y = input.mY;
float z = input.mZ;
Matrix4 P, Mv, res;
P = getProjection();
Mv = getCameraTransform();
Vector3 N; //Cursor point translated to having 0,0 at screen center
N.mX = ((x-viewport[0]) / viewport[2])*2 - 1;
N.mY = ((y-viewport[1]) / viewport[3])*2 - 1;
N.mZ = z*2-1;
res = P * Mv; //Multiply P * Mv to get transform
Vector3 w = res.inverse() * N; //Apply transform to N.
output.mX = w[0];
output.mY = w[1];
output.mZ = w[2];
return true;
}
之后,我通过以下方式形成一条光线:
unproject(Vector3(xClick, yClick,0),resultUnproject)
ray.origin = cameraPosition;
ray.direction = resultUnproject - ray.origin;
ray.direction.normalize();
现在,最后我试图通过三角形代码(上面链接)运行这条光线,但我似乎无法正确转换它。我目前的尝试如下:
Matrix4 mview, T;
mview = getModelview();
T = mview.inverse();
ray.origin = T*ray.origin;
ray.direction = T*ray.direction;
ray.direction.normalize();
出于某种原因,这不起作用。我的光线错了吗?或者改造错了?
一种方法可能是:
获取光线原点,并在世界空间中沿光线方向以单位距离计算出一个点。然后,转换到两个点 - 即乘以变换矩阵的逆。然后,您可以根据两个平移点之间的差异确定新的光线方向。检查此方向是否与原稿不同将很快告诉您是否缺少步骤。
我对此的解决方案是执行sje397建议,但只使用结果作为您的新光线。
所以在我的项目(XNA)中,给定ray
从游标中取消投影:
rayTransform = Matrix.Invert(model_transform);
//Transform ray (or more accurately its defining components into a new ray)
Vector3 v1 = Vector3.Transform(ray.Position, rayTransform);
Vector3 v2 = Vector3.Transform((ray.Position + ray.Direction), rayTransform);
transformedray = new Ray(v1, v2 - v1);
这里的model_transform
生成方式与着色器的变换相同(即没有交换世界/本地乘法或任何东西)
这在我的项目中工作正常,拾取的目标是以各种方式旋转,变换和缩放。
此外,您可能会发现这有点不合适,但如果您仍然遇到问题,您是否确定要取消投影光标并生成拾取光线的代码正常工作?我猜想如果你的三角形拾取代码有效,它就会让我看起来就像它以一种“四舍五入”的方式获得光线。
在我的项目中,我拿了两个点,一个'在'视口'平面上'所以Vector3(cursorx,cursory,0)
再次这个,但在Z轴Vector3(cursorx,cursory,1)
上进展。取消投影这两点,第一个结果是你的起源,差异是你的方向。
祝好运!
所以我终于有了这个工作,虽然我对如何不满意。在我的例子中,单个模型旋转在渲染之前被应用为变换,因此我最终必须通过模型视图矩阵变换目标三角形。
我上面试图做的是通过在物体周围移动光线的原点来计算一条用于相同目的的光线,这就好像物体已被旋转一样。不幸的是,我无法完全正确地计算数学。
最终结果意味着每个三角形一个变换,而不是每个光线一个变换。幸运的是,它似乎并没有那么糟糕的性能,因为我只是用它来挑选。
如果你有一些光线(已经变换到世界空间)并且你想检查它是否与一个对象/三角形相交,你需要将它乘以对象的反转矩阵。这是一些伪代码:
NewRayPosition = Vector3.Transform(OldRay.Position, Matrix.Invert(Transformation);
NewRayDirection = Vector3.Transform(OldRay.Direction, Matrix.Invert(Rotation*Scale));
NewRayDirection.Normalize();
通过平移,缩放和旋转将光线位置相乘,但仅通过缩放和旋转方向。由于性能原因,按照您的方式进行操作是不可接受的。更多这里:http://www.cl.cam.ac.uk/teaching/1999/AGraphHCI/SMAG/node2.html#SECTION00024100000000000000