使用Three.js Raycaster实现鼠标移动碰撞检测时遇camera未定义错误
解决Three.js Raycaster鼠标移动碰撞检测时的"无法读取camera属性"错误
我希望在鼠标移动(MouseMove)后检测碰撞,使用Three.js的Raycaster实现,但出现以下错误:
无法读取未定义的属性(读取'camera')
代码如下:
bindIFrameMousemove(iframe){ iframe.contentWindow.addEventListener('mousemove', function(event) { const mouse = new Vector2(); var clRect = iframe.getBoundingClientRect(); var evt = new CustomEvent('mousemove', {bubbles: true, cancelable: false}); const clientX = (window.TouchEvent && event instanceof TouchEvent) ? event.changedTouches[0].clientX : event.clientX; const clientY = (window.TouchEvent && event instanceof TouchEvent) ? event.changedTouches[0].clientY : event.clientY; const x = ( clientX / window.innerWidth ) * 2 - 1; const y = - ( clientY / window.innerHeight ) * 2 + 1; iframe.dispatchEvent(evt); event.preventDefault(); mouse.x= ( clientX / window.innerWidth ) * 2 - 1; mouse.y = - ( clientY / window.innerHeight ) * 2 + 1; Raycaster.setFromCamera( mouse, this.context.camera ); const intersects = Raycaster.getIntersectObjects(this.scene.children ,true ); console.log(intersects) if (intersects.length > 0) { console.log("intersects !!"); } }); };
错误原因
- this指向异常:
addEventListener的普通回调函数中,this指向的是iframe.contentWindow,而非外部类/对象的上下文,导致this.context和this.scene均为undefined,读取camera属性时触发错误。 - Raycaster使用错误:
Raycaster是Three.js的类,必须先实例化才能调用方法,直接用类调用setFromCamera不符合API规范。 - 方法名拼写错误:Three.js中获取相交对象的方法是
intersectObjects,而非getIntersectObjects。
修复方案
方案一:用箭头函数绑定上下文
箭头函数会继承外部作用域的this,直接解决指向问题:
bindIFrameMousemove(iframe){ // 实例化Raycaster const raycaster = new THREE.Raycaster(); iframe.contentWindow.addEventListener('mousemove', (event) => { const mouse = new THREE.Vector2(); var clRect = iframe.getBoundingClientRect(); var evt = new CustomEvent('mousemove', {bubbles: true, cancelable: false}); const clientX = (window.TouchEvent && event instanceof TouchEvent) ? event.changedTouches[0].clientX : event.clientX; const clientY = (window.TouchEvent && event instanceof TouchEvent) ? event.changedTouches[0].clientY : event.clientY; // 修正坐标计算:基于iframe自身宽高,避免窗口偏移问题 const x = ((clientX - clRect.left) / clRect.width) * 2 - 1; const y = -((clientY - clRect.top) / clRect.height) * 2 + 1; iframe.dispatchEvent(evt); event.preventDefault(); mouse.x = x; mouse.y = y; // 使用实例化的raycaster,this指向外部上下文 raycaster.setFromCamera(mouse, this.context.camera); const intersects = raycaster.intersectObjects(this.scene.children, true); console.log(intersects) if (intersects.length > 0) { console.log("intersects !!"); } }); };
方案二:提前保存外部this引用
如需兼容不支持箭头函数的环境,可在回调外部保存this的引用:
bindIFrameMousemove(iframe){ const raycaster = new THREE.Raycaster(); const self = this; // 保存外部上下文的this iframe.contentWindow.addEventListener('mousemove', function(event) { const mouse = new THREE.Vector2(); var clRect = iframe.getBoundingClientRect(); var evt = new CustomEvent('mousemove', {bubbles: true, cancelable: false}); const clientX = (window.TouchEvent && event instanceof TouchEvent) ? event.changedTouches[0].clientX : event.clientX; const clientY = (window.TouchEvent && event instanceof TouchEvent) ? event.changedTouches[0].clientY : event.clientY; // 修正坐标计算 const x = ((clientX - clRect.left) / clRect.width) * 2 - 1; const y = -((clientY - clRect.top) / clRect.height) * 2 + 1; iframe.dispatchEvent(evt); event.preventDefault(); mouse.x = x; mouse.y = y; // 使用保存的self访问外部上下文 raycaster.setFromCamera(mouse, self.context.camera); const intersects = raycaster.intersectObjects(self.scene.children, true); console.log(intersects) if (intersects.length > 0) { console.log("intersects !!"); } }); };
额外注意事项
- 确保外部作用域中
this.context.camera和this.scene已正确初始化,避免出现undefined。 - 鼠标坐标计算需基于iframe的位置和宽高,否则会出现点击偏移问题。
内容的提问来源于stack exchange,提问作者Y Z
相关产品推荐
相关产品推荐

