我无法找到在3D中使用射线追踪方法拾取正确且可理解的表达式。有没有人用任何语言实现这个算法?直接共享工作代码,因为由于伪代码无法编译,所以它们通常是用缺少的部分编写的。使用NinevehGL或OpenGL i-phone使用射线追踪在3D中拾取
1
A
回答
5
你有什么是2D在屏幕上的位置。要做的第一件事是将该点从像素转换为标准化的设备坐标 - -1为1.然后,您需要找到该点代表的3D空间中的线条。为此,您需要3D应用程序用于创建投影和相机的转换矩阵/ ces。
通常,您有3个指标:投影,视图和模型。当您为一个对象指定顶点时,它们位于“对象空间”中。乘以模型矩阵给出“世界空间”中的顶点。视图矩阵再次乘以“眼睛/相机空间”。投影再次乘以“剪辑空间”。剪辑空间具有非线性深度。将Z分量添加到鼠标坐标将它们放入剪辑空间。您可以在任何线性空间中执行线/对象相交测试,因此您必须至少将鼠标坐标移至眼图空间,但在世界空间(或对象空间取决于场景图)中执行相交测试更方便。
要将剪辑空间中的鼠标坐标移至世界空间,请添加Z分量并乘以逆投影矩阵,然后乘以逆摄像机/视图矩阵。要创建一条线,将计算沿着Z的两个点 - from
和to
。
在以下示例中,我有对象的列表,每一个位置和边界半径。当然,十字路口绝对不会完美匹配,但现在它的效果已经足够好了。这不是伪代码,但它使用我自己的矢量/矩阵库。你必须在自己的地方替代你自己。
vec2f mouse = (vec2f(mousePosition)/vec2f(windowSize)) * 2.0f - 1.0f;
mouse.y = -mouse.y; //origin is top-left and +y mouse is down
mat44 toWorld = (camera.projection * camera.transform).inverse();
//equivalent to camera.transform.inverse() * camera.projection.inverse() but faster
vec4f from = toWorld * vec4f(mouse, -1.0f, 1.0f);
vec4f to = toWorld * vec4f(mouse, 1.0f, 1.0f);
from /= from.w; //perspective divide ("normalize" homogeneous coordinates)
to /= to.w;
int clickedObject = -1;
float minDist = 99999.0f;
for (size_t i = 0; i < objects.size(); ++i)
{
float t1, t2;
vec3f direction = to.xyz() - from.xyz();
if (intersectSphere(from.xyz(), direction, objects[i].position, objects[i].radius, t1, t2))
{
//object i has been clicked. probably best to find the minimum t1 (front-most object)
if (t1 < minDist)
{
minDist = t1;
clickedObject = (int)i;
}
}
}
//clicked object is objects[clickedObject]
相反的intersectSphere
,你可以使用一个边框或其他隐式几何体,或者交叉网状的三角形(这可能需要建立一个kd树的性能原因)。
[编辑]
这里是line/sphere intersect的实现(基于上面的链接)。它假设球体位于原点,因此不要将from.xyz()
作为p
传递给from.xyz() - objects[i].position
。
//ray at position p with direction d intersects sphere at (0,0,0) with radius r. returns intersection times along ray t1 and t2
bool intersectSphere(const vec3f& p, const vec3f& d, float r, float& t1, float& t2)
{
//http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
float A = d.dot(d);
float B = 2.0f * d.dot(p);
float C = p.dot(p) - r * r;
float dis = B * B - 4.0f * A * C;
if (dis < 0.0f)
return false;
float S = sqrt(dis);
t1 = (-B - S)/(2.0f * A);
t2 = (-B + S)/(2.0f * A);
return true;
}
相关问题
- 1. 使用光线投射物体拾取
- 2. 多线程射线追踪
- 3. 射线追踪 - 反射
- 4. 3D仿射变换问题,在光线追踪
- 5. 用Pyglet拾取OpenGL
- 6. 射线追踪 - 混色
- 7. 射线追踪照明
- 8. 用Java拾取形状3D
- 9. 射线追踪 - 折射错误
- 10. 射线追踪反射颗粒感
- 11. 射线追踪的速度与例如OpenGL(或其他图形实现)
- 12. 追踪API使用
- 13. 如何在简单光线追踪器中使用纹理映射?
- 14. 绘制3D使用OpenGL
- 15. 射线追踪:Bresenham's vs Siddon算法
- 16. 纹理使用OpenGL中的2D纹理映射3D对象
- 17. 折射向量(光线追踪)
- 18. 光线追踪:仅使用单光线代替反射光线和折射光线
- 19. iPhone应用拾取声音
- 20. 带球体的射线追踪
- 21. 射线追踪阴影/底纹伪影
- 22. 射线追踪器回路订购
- 23. 如何在3D曲面重建中使用光线投射?
- 24. EXC_BAD_ACCESS,使用NSZombies追踪
- 25. 在MonoTouch中使用拾取器
- 26. 如何在现代OpenGL中进行光线追踪?
- 27. 通过计算着色器在OpenGL中进行光线追踪
- 28. 三维射线拾取精度
- 29. 追踪NSTimer发射
- 30. 2D光线追踪
这是一个很好的解释,谢谢你告诉了这么久。我会尝试这种方法。你能否也请分享函数的实现:'intersectSphere()'? –
@ibrahimdemir谢谢!完成。祝你好运:) – jozxyqk
'mat44 toWorld =(camera.projection * camera.transform).inverse();' 我不明白camera.projection和camera.transform矩阵是什么。你能解释一下还是在ninevehgl框架中写出等价矩阵? –