1.問題
three.js中模型選中使用的是射線法,根據攝像機角度,鼠標點擊位置和模型選中的distance參數判斷來選中模型。對於原生的矢量模型完全沒有問題,但是當遇到導入的外部模型,如obj、stl等的時候,就發現完全選中不了,本文就如果解決選中外部模型和原生模型問題進行解決。
先說說射線法,參考文章:https://blog.csdn.net/qq_30100043/article/details/79054862
2.選中原生矢量模型
直接上代碼:
function click(e){ // 聲明 raycaster 和 mouse 變量 var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); // 通過鼠標點擊位置,計算出 raycaster 所需點的位置,以屏幕為中心點,范圍 -1 到 1 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); var objs=[]; for (var i = 0; i < intersects.length; i++) { var intersect = intersects[i]; if (intersect.object instanceof THREE.Mesh) { var obj = intersect.object; //把距離加到模型用戶數據里面,方便后面排序 obj.userData.distance = intersect.distance; objs.push(obj); } } //按照距離排序 objs = objs.sort(function (a, b) { return a.userData.distance - b.userData.distance; }); //objs就是按照距離由近到遠排列的選中模型數組集合 //todo:后面操作渲染展示等等... //.... }
3.選中外部模型
內容2中的方法可以實現完美選中立方體、圓柱等矢量三維模型,但是當場景中有obj等3d max導入的外部模型時卻無法選中,為什么呢?原因參考文章:https://segmentfault.com/a/1190000004382956。
(圖片來源:https://segmentfault.com/a/1190000004382956)
核心原因如上圖,外部模型本質是一個group,里面包含了多個mesh,而內容2里面的方法其實只查詢了scene下第一層的mesh模型,見下圖。
由此可以看出,要想選中外部模型,需要將遍歷對象修改為外部模型的children就可以了。代碼如下:
function click(e){ //聲明 raycaster 和 mouse 變量 var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); // 通過鼠標點擊位置,計算出 raycaster 所需點的位置,以屏幕為中心點,范圍 -1 到 1 mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; //通過鼠標點擊的位置(二維坐標)和當前相機的矩陣計算出射線位置 raycaster.setFromCamera(mouse, camera); //找到場景中所有外部模型 var scensObjs = []; main.scene.children.forEach(child => { for (var i = 0; i < child.children.length; i++) { var obj=child.children[i]; scensObjs.push(obj); } }); //返回選中的外部模型對象 var intersects = raycaster.intersectObjects(scensObjs); var objs = []; for (var i = 0; i < intersects.length; i++) { var intersect = intersects[i]; if (intersect.object instanceof THREE.Mesh) { var obj = intersect.object.parent; //把距離加到模型用戶數據里面,方便后面排序 obj.userData.distance = intersect.distance; objs.push(obj); } } //按照距離排序 objs = objs.sort(function (a, b) { return a.userData.distance - b.userData.distance; }); //objs就是按照距離由近到遠排列的選中模型數組集合 //todo:后面操作渲染展示等等... //.... }
用上面的方法就可以選中外部模型,不過會遇到一個問題,就是選中的外部模型不是整個模型,而是模型中的一部分,這個與模型有關系,上面就說過一個外部模型其實是一個group,里面有很多個mesh組成,射線法選中的模型只是一個mesh,也就是group的children的某一個。如果想返回整個模型,很簡單,取mesh的parent就可以了。代碼如下:
//假設selectedMesh是選中的外部模型中的一部分 var selectedMesh=...; //obj就是整個模型 var obj=selectedMesh.parent;