ThreeJS中的點擊與交互——Raycaster的用法

基礎概念

座標系

咱們的手機屏幕是二維的,可是咱們展現物體的世界是三維的,當咱們在構建一個物體的時候咱們是以一個三維世界既是世界座標來構建,而轉化爲屏幕座標展現在咱們眼前,則須要經歷多道矩陣變化,中間webGL替咱們操做了許多事情。

clipboard.png

  • 世界座標系:在webGL中,世界座標系是以屏幕中心爲原點(0, 0, 0),且是始終不變的。你面對屏幕,你的右邊是x正軸,上面是y正軸,屏幕指向你的爲z正軸。長度單位這樣來定:窗口範圍按此單位剛好是(-1,-1,-1)到(1,1,1)。
  • 屏幕座標系:

webGL的重要功能之一就是將三維的世界座標通過變換、投影等計算,最終算出它在顯示設備上對應的位置,這個位置就稱爲設備座標。在屏幕、打印機等設備上的座標是二維座標。html

  • 視點座標系:

是以視點(照相機)爲原點,以視線的方向爲Z+軸正方向的座標系中的方向。webGL會將世界座標先變換到視點座標,而後進行裁剪,只有在視線範圍(視見體)以內的場景纔會進入下一階段的計算。前端

Raycaster

Raycaster threeJs官方文檔web

這個類設計用於鼠標去獲取在3D世界被鼠標選中的一些物體api

Raycaster( origin, direction, near, far ) 

origin — 射線的起點向量。
direction — 射線的方向向量,應該歸一標準化。
near — 全部返回的結果應該比 near 遠。Near不能爲負,默認值爲0。
far — 全部返回的結果應該比 far 近。Far 不能小於 near,默認值爲無窮大。

找到點擊物體的大體思路

clipboard.png

鼠標在屏幕上點擊的時候,獲得二維座標p(x, y),再加上深度座標的範圍(0, 1), 就能夠造成兩個三位座標A(x1, y1, 0), B(x2, y, 1), 因爲它們的Z軸座標是0和1,則轉變到投影座標系的話,必定分別是前剪切平面上的點和後剪切平面上的點,也就是說,在投影座標系中,A點必定在能看見的全部模型的最前面,B點必定在能看見的全部的模型的最後邊,將AB點連成線,AB線穿過的物體就是被點擊的物體。而 Three.js提供一個射線類Raycasting來拾取場景裏面的物體。更方便的使用鼠標來操做3D場景。(不過在實際代碼中咱們組成射線的兩個點是攝像機所在視點與屏幕上點擊的點鏈接而成的射線)webgl

來一個Raycasting的官方實例spa

代碼實現

function onDocumentMouseDown(e) {
    e.preventDefault();
    
    //將鼠標點擊位置的屏幕座標轉成threejs中的標準座標,具體解釋見代碼釋義
    mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
    //新建一個三維單位向量 假設z方向就是0.5
    //根據照相機,把這個向量轉換到視點座標系
      var vector = new THREE.Vector3(mouse.x, mouse.y,0.5).unproject(camera);

    //在視點座標系中造成射線,射線的起點向量是照相機, 射線的方向向量是照相機到點擊的點,這個向量應該歸一標準化。
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());

    //射線和模型求交,選中一系列直線
    var intersects = raycaster.intersectObjects(objects);
    console.log('imtersrcts=' + intersects)

    if (intersects.length > 0) {
        //選中第一個射線相交的物體
        SELECTED = intersects[0].object;
        var intersected = intersects[0].object;
        console.log(intersects[0].object)
    }


}

代碼釋義

clipboard.png

//獲得
 mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
 mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
  
 推導過程:
 設A點爲點擊點(x1,y1),x1=e.clintX, y1=e.clientY
 設A點在世界座標中的座標值爲B(x2,y2);
 
 因爲A點的座標值的原點是以屏幕左上角爲(0,0);
 咱們能夠計算可得以屏幕中心爲原點的B'值
 x2' = x1 - innerWidth/2
 y2' = innerHeight/2 - y1
 又因爲在世界座標的範圍是[-1,1],要獲得正確的B值咱們必需要將座標標準化
 x2 = (x1 -innerWidth/2)/(innerwidth/2) = (x1/innerWidth)*2-1
 同理得 y2 = -(y1/innerHeight)*2 +1

參考資料

Three.js中的拾取
OpenGL中各類座標系的理解
threejs對象拾取
《計算機圖形學》
前端填坑指南.net

相關文章
相關標籤/搜索