2013-11-22 76 views

回答

5

你有什麼是2D在屏幕上的位置。要做的第一件事是將該點從像素轉換爲標準化的設備座標 - -1爲1.然後,您需要找到該點代表的3D空間中的線條。爲此,您需要3D應用程序用於創建投影和相機的轉換矩陣/ ces。

通常,您有3個指標:投影,視圖和模型。當您爲一個對象指定頂點時,它們位於「對象空間」中。乘以模型矩陣給出「世界空間」中的頂點。視圖矩陣再次乘以「眼睛/相機空間」。投影再次乘以「剪輯空間」。剪輯空間具有非線性深度。將Z分量添加到鼠標座標將它們放入剪輯空間。您可以在任何線性空間中執行線/對象相交測試,因此您必須至少將鼠標座標移至眼圖空間,但在世界空間(或對象空間取決於場景圖)中執行相交測試更方便。

要將剪輯空間中的鼠標座標移至世界空間,請添加Z分量並乘以逆投影矩陣,然後乘以逆攝像機/視圖矩陣。要創建一條線,將計算沿着Z的兩個點 - fromto

enter image description here

在以下示例中,我有對象的列表,每一個位置和邊界半徑。當然,十字路口絕對不會完美匹配,但現在它的效果已經足夠好了。這不是僞代碼,但它使用我自己的矢量/矩陣庫。你必須在自己的地方替代你自己。

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; 
} 
+0

這是一個很好的解釋,謝謝你告訴了這麼久。我會嘗試這種方法。你能否也請分享函數的實現:'intersectSphere()'? –

+0

@ibrahimdemir謝謝!完成。祝你好運:) – jozxyqk

+0

'mat44 toWorld =(camera.projection * camera.transform).inverse();' 我不明白camera.projection和camera.transform矩陣是什麼。你能解釋一下還是在ninevehgl框架中寫出等價矩陣? –