Unity3d 用鼠標拾取模型的頂點
第一節
近來想做一個東西,想實現3D MAX的部份功能,第一步用鼠標拾取模型的頂點,
那么首先要做的是獲取鼠標發出的射線與模型的碰撞點!
先截個圖,
用到了Physics.Raycast方法,就是射線檢測碰撞的方法!
RaycastHit hit;
Ray ray = Camera.mainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 100))
{
Debug.Log(hit.collider.gameObject.name);
if (hit.collider.gameObject.name == "Sphere") return;
spheretransform.position = hit.point;
}
那么要注意幾個問題:
1.場景中的攝像機必須是主攝像機
主攝像機是什么意思呢?就是攝像機的tag是MainCamera
2. Ray ray = Camera.mainCamera.ScreenPointToRay(Input.mousePosition);
Camera.ScreenPointToRay()方法其實就是“通過2D屏幕坐標在
3D空間中拾取”,我們的3D場景經過攝像機的投影,變成了2D圖像,顯示在了屏幕上,那么通過逆運算,就可以換算出鼠標點的位置的3D位置,從而可以進一步選取3D場景中的物體!當然這個攝像機是離不開的,是那個攝像機渲染的當前場景,就要用哪個攝像機進行ScreenPointToRay()來進行運算!
先說一下射線,射線是什么東西呢?
Ray,Ray有兩個字段,origin和direction,其中origin就是攝像的起始點,
direction是射線的方向!
Physics.Raycast(Ray ray,out RaycastHit,float distance)
第一個參數就是一條射線,就是判斷射線與其它物體的碰撞!
碰撞之后會返回RaycastHit信息,distance是射線發出的距離
(我理解的對不對,望兄弟們指教!)
通過Physics.Raycast()可以out出一個參數(形參),RaycastHit,這個可以獲取到碰撞點RaycastHit.point;那么為了明顯的看到它,我用了一個紅色材質的球體,球體要小一些,不斷設置球體的位置為碰撞點的位置,大家就很容易看到結果對不對!
在調試的過程中,我發現紅色的球不斷的向屏幕移動過來,不解到底是什么原因,后來分析是因為,射線不斷的紅球發生了碰撞,碰撞點在球的表面,所以球就不斷向屏幕外移動,所以要加一句
if (hit.collider.gameObject.name == "Sphere") return;
4.我附上“通過2D屏幕坐標在3D空間中拾取”的理論文章
用XNA語言描述
最近在做到和3D模型的拾取有關的東西,找到了這篇不錯的文章,加上自己的修改,基本解決了鼠標點擊3D模型獲取3D模型的坐標點的問題。所以轉過來記錄下。
拾取原理
拾取主要用來表示能過鼠標在屏幕上單擊來選中某個3D模型,然后就可以獲取這個模型信息,同時也可以對這個模型進行編輯。
拾取算法的主要思想是:得到鼠標點擊處的屏幕坐標,通過投影矩陣和觀察矩陣把該坐標轉換為通過視點和鼠標點擊點的一條射入場景的光線,該光線如果與場景模型的三角形相交,則獲取該相交三角形的信息。
拾取的具體過程如下:
1.使用獲取鼠標當前狀態。
2.把屏幕坐標轉換為屏幕空間坐標。 屏幕中心是(0, 0),屏幕右下角是 (1*(屏幕寬度/屏幕高度), 1)。屏幕空間的x坐標這樣計算: ((鼠標x坐標) / (屏幕寬度/2))-1.0f) *(屏幕寬度/屏幕高度) 屏幕空間的y坐標這樣計算: (1.0f ? ((鼠標y坐標) / (屏幕高度/ 2 ) )
3.計算攝像機視圖中的寬度和高度的截距比。如下計算: view ratio = tangent(camera field of view / 2 ) 通常,你只需要一次,然后保存這個結果供以后使用。在攝像機視野改變的時候,你需要重新計算。
4.把屏幕空間坐標轉換成攝像機空間坐標系近景裁剪平面中的一個點。 Near point = ((屏幕空間x坐標)*(近景裁剪平面的Z值)*(view ratio ), (屏幕空間y坐標)*(近景裁剪平面的Z值)*(view ratio ), (-近景裁剪平面的Z值) )
5.把屏幕空間坐標轉換成攝像機空間坐標系遠景裁剪平面中的一個點。 Far point = ((屏幕空間x坐標)* (遠景裁剪平面的Z值)*(view ratio ), (屏幕空間y坐標)*(遠景裁剪平面的Z值 )*(view ratio), (-遠景裁剪平面的Z值) )
6.使用Invert 獲得攝像機視圖矩陣的一個Invert的拷貝。使用攝像機視圖矩陣(Matrix)來把世界坐標轉化成攝像機坐標,使用這個反轉的矩陣可以把攝像機坐標轉化成世界坐標。 Matrix invView = Matrix.Invert(view);
7.使用反轉的視圖矩陣(view Matrix ) 和Transform方法把遠景點和近景點轉換成世界空間坐標。 Vector3 worldSpaceNear = Vector3.Transform(cameraSpaceNear, invView); Vector3 worldSpaceFar = Vector3.Transform(cameraSpaceFar, invView);
8.創建一個射線(Ray)類的對象,起點是近景點,指向遠景點。 Ray pickRay = new Ray(worldSpaceNear, worldSpaceFar - worldSpaceNear);
9.對世界空間中的所有物體循環調用 Intersects 方法來檢測 Ray 是否與其相交。如果相交,則檢測是不是目前為止距玩家最近的物體,如果是,記錄下這個物體以及距離值,替換掉之前找到的最近的物體的記錄。當完成對所有物體的檢測后,最后一次記錄的那個物體就是玩家用鼠標點擊的距離玩家最近的物體。
|
對於,我理解不對的,還請大家多交流,謝謝!
今天不能上傳圖片,改天上傳一些相關圖片,以后理論性的文章,多以XNA語言進行描述,呵呵!晚安!