我無法找到在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框架中寫出等價矩陣? –