這里只是記錄一下坑,方便查閱,內容主要援引自: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);
}
}
