使用光线投射器(Raycaster)实现点击拾取模型

完整代码点这里

该类用来处理光线投射。光线投射主要用于物体选择、碰撞检测以及图像成像等方面。
这里利用他来做:点击拾取模型功能。
可以这么想像:点击屏幕时,就会从视线方向发出一条射线,这条射线可能穿过场景中的多个模型,利用该类提供的方法能够拾取到这些模型。
(1)初始化

this.raycaster = new THREE.Raycaster();
this.mouse = new THREE.Vector2();

(2)绑定点击事件

window.addEventListener('click', this.clickModel, false);

(3)拾取点击对象,进行操作

clickModel(event) {
    console.log(this.scene) //可以打印看看scene下面的children有哪些对象
    this.mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    this.mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;    
    this.raycaster.setFromCamera(this.mouse, this.camera);//更新射线
    var intersects = this.raycaster.intersectObject(this.scene.children, true); //参数1:检测对象,参数2:是否检测该对象的children
    //intersects 与射线相交的模型
    for (var i = 0; i < intersects.length; i++) {
        intersects[i].object.material.color.set(0xff0000); //对获取到的模型改变颜色
   }
}

intersectObjects函数:检查射线和对象之间的所有交叉点(包含或不包含后代,根据第二个参数决定)。交叉点返回按距离排序,最接近的为第一个。
在这里插入图片描述
点击图中黑圈部分,发现不仅窗户变色了,里面的盒子也变色了,这是因为上面的代码中我们把与射线相交的所有模型都做了变色操作(for循环里面)。
至于点击一个窗户而导致其他所有窗户都变色了,这是模型的原因,大概意思就是所有窗户在建模时作为了一个模块。(自己的理解,不对的话望指正)
实际需求中,我们可能更多的是获取我们所点击的最表面的模型,因此只要对intersects 的第一个元素进行操作就好了。

去掉for循环,增加以下代码:

const res = intersects.filter(res => res && res.object)[0];
if(res && res.object) {
    res.object.material.color.set(0xff0000);
}

再次点击同一个位置,盒子就没变色啦~
在这里插入图片描述
遇到的问题:实际需求中,模型都是通过objLoader加载进去的,由于我需求中还有一个房顶,在放大时会隐藏起来,但点击房子里的模型时射线总会第一个与房顶相交,因此获取到的第一个模型总不是我想要的。所以我这里还用了group,将房子和房子中的模型放进group中,intersectObjects检测group以及其后代就可以了,这样房顶就不在检测对象中了。

this.group = new THREE.Group();
this.group.add(...); //将你的模型放进去
this.scene.add(this.group);//将group放入场景中
this.raycaster.intersectObject(this.group, true);
发布了9 篇原创文章 · 获赞 0 · 访问量 168
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览