因爲圖形顯示的基本單位是三角形,那就先從一個三角形從世界座標轉到屏幕座標提及,例如三角形abchtml
乘以模型視圖矩陣就進入了視點座標系,其實就是相機所在的座標系,以下圖:web
進入視點座標系後,再乘以投影矩陣,就會變換到一個立方體內,以下圖:微信
這個時候整個三角形就位於中心位於座標系原點,邊長爲2的立方體內,在這個立方體內,三角形要計算光照,要裁剪,而後乘以視口矩陣,最後轉到屏幕上。優化
轉到屏幕上後,三角形的全部點的Z座標就是深度座標,必定在(0, 1)這個區間內,那麼哪些點的Z座標是0呢,在投影座標系中,必定是投影視景體的前剪切平面上的點,而投影視景體的後剪切平面上的點的Z座標就是1。webgl
根據以上三角形轉換到屏幕座標上的過程能夠分析出,鼠標在屏幕上點擊的時候,能夠獲得二維座標p(x, y),再加上深度座標的範圍(0, 1), 就能夠造成兩個三位座標A(x, y, 0), B(x, y, 1), 因爲它們的Z軸座標是0和1,則轉變到投影座標系的話,必定分別是前剪切平面上的點和後剪切平面上的點,也就是說,在投影座標系中,A點必定在能看見的全部模型的最前面,B點必定在能看見的全部的模型的最後邊,假設視口矩陣的逆矩幀,投影矩陣的逆矩陣,模型視圖矩陣的逆矩陣爲M, N, P,則 P * N * M * A = A1, P * N * M * B = B1, 在世界座標系中,點A1B1就能夠造成一個射線,此射線和模型再求交,就能選中模型。以下圖是在視點座標系中的情形。注意,求交能夠在視點座標系或者世界座標系計算均可以,但通常會在世界座標座標系中計算。spa
若是射線和全部的模型求交,顯然不是一個好辦法,通常狀況下會進行一些優化,好比先和模型的包圍盒求交,若是和模型的包圍盒不相交的話,就放過去,不然就接着往下進行,和模型的全部三角面片求交。3d
那麼什麼是包圍盒呢?在計算機圖形學與計算幾何領域,一組物體的包圍體就是將物體組合徹底包容起來的一個封閉空間。將複雜物體封裝在簡單的包圍體中,就能夠提升幾何運算的效率。一般簡單的物體比較容易檢查相互之間的重疊。其中有一種包圍盒叫作AABB, AABB的全稱是axis aligned bounding box,就是咱們經常提到軸向包圍盒,這個盒子的邊是平行於x/y/z軸的。 全部的2d和3d物體都是由點組成的,因此只要找出這些物體的最大值點和最小值點,那麼就可使用這兩個點表示該物體的AABB包圍盒了。
檢測碰撞的時候咱們只須要檢測這些物體的AABB(即他們的最大值點和最小值點)是否相交,就能夠判斷是否碰撞了。orm
判斷射線和包圍盒是否求交後,就輪到判斷是否和三角形求交了,最早想到的是 首先判斷射線是否與三角形所在的平面相交,若是相交,再判斷交點是否在三角形內。判斷射線是否與平面相交, 判斷點是否在三角形內.htm
three.js中的一個案例,名字叫webgl_interactive_lines.html,能夠選中一根線,並顯示一個小球。根據以上的思路,代碼註釋以下:blog
//鼠標點擊的屏幕座標轉換到視點座標系
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 ).unproject( camera );
//在視點座標系中造成射線
raycaster.set( camera.position,vector.sub( camera.position ).normalize() );
//射線和模型求交,選中一系列直線
var intersects = raycaster.intersectObjects( parentTransform.children, true);
if ( intersects.length > 0 ) {
if ( currentIntersected !== undefined )
{
currentIntersected.material.linewidth = 1;
}
//第一個直線
currentIntersected = intersects[ 0 ].object;
currentIntersected.material.linewidth = 5;
//把球設爲可見,而且位置移到鼠標點擊的屏幕位置
sphereInter.visible = true;
sphereInter.position.copy( intersects[ 0 ].point );
}
歡迎加微信 nuonuodi_1, 交流更多的技術問題