three.js raycaster射線碰撞的坑 (當canvas大小 不是屏幕大小是解決拾取物體的辦法)


這里只是記錄一下坑,方便查閱,內容主要援引自:three.js Raycaster 射線拾取 canvas不占滿整屏時射線拾取存在偏差

1. 世界坐標系: 世界坐標系位於屏幕的中心(0,0,0),往右側是x軸,往上是y軸,垂直屏幕朝向的是z軸.所以屏幕的左下角是(-1,-1),右上角是(1,1);

2. 屏幕坐標系: webgl會將三維的坐標經過計算,在屏幕里正常顯示.

在根據模型或者網格去進行碰撞測試時,我們選擇的點一般就是攝像機的位置(相當於人眼的位置,在屏幕上點擊的位置,組成一條射線)

初始化,比如:

var mouse = new THREE.Vector2();

var raycaster = new THREE.Raycaster();

mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;

mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

raycaster.setFromCamera(mouse,camera) // 也可以給構造函數傳參的形式寫

var intersects = raycaster.intersectObjects( scene.children ); // 這里的children,如果你是引入的模型,那么模型加載parse的時候,可以使用一個變量存儲你需要檢測的對象,這里必須傳入

但是當你的瀏覽器屏幕的縮放比不一致的時候,你就會看到一個很奇葩的現象,你的模型偏了,你的鼠標永遠都選不到目標,然后審查一下元素,可能會出現winner.innerHeight,window.innerWidth 遠大於或者小於屏幕視口實際尺寸的情況(我當時還以為是無限鼠標的鍋,后來才想到可能是屏幕的縮放導致的).這時需要重新去定義射線的初始化.我在開始部分原因的那段代碼就可以很好的解決:

functioninitRay(){

// 屏幕坐標轉標准設備坐標

let x = ((event.clientX - mainCanvas.getBoundingClientRect().left) / mainCanvas.offsetWidth) *2-1;// 標准設備橫坐標

// 這里的mainCanvas是個dom元素,getBoundingClientRectangle會返回當前元素的視口大小.

let y = -((event.clientY - mainCanvas.getBoundingClientRect().top) / mainCanvas.offsetHeight) *2+1;// 標准設備縱坐標

let standardVector =newTHREE.Vector3(x, y,1);// 標准設備坐標

// 標准設備坐標轉世界坐標

let worldVector = standardVector.unproject(camera);

// 射線投射方向單位向量(worldVector坐標減相機位置坐標)

let ray = worldVector.sub(camera.position).normalize();

// 創建射線投射器對象

letrayCaster =newTHREE.Raycaster(camera.position, ray);

// 返回射線選中的對象 第二個參數如果不填 默認是false

letintersects = rayCaster.intersectObjects(scene.children,true);

if(intersects.length >0) {

// console.log(intersects[0].object);

  }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM