加载碰撞器环境loadCollider后,之前正常工作的opendoor点击不起作用了。而且通过日志发现这个门点击区域有了偏转
loadCollider(model) {
const that = this
const gltfScene = model // 模型
this.box3d = new THREE.Box3() // 表示三维空间中的一个轴对齐包围盒
that.box3d.setFromObject(model) // 计算和世界轴对齐的一个对象 Object3D(含其子对象)的包围盒
gltfScene.updateMatrixWorld(true) //更新物体及其后代的全局变换。
const toMerge = {} // 合并组合
gltfScene.traverse(c => {
if (c.isMesh && c.material.color !== undefined) {
// 根据颜色将所有模型分类
const MeshBVH = c.material.color.getHex()
toMerge[MeshBVH] = toMerge[MeshBVH] || []
toMerge[MeshBVH].push(c)
}
})
// 环境 :创建一个组合
that.environment = new THREE.Group()
for (const hex in toMerge) {
const arr = toMerge[hex] // 获得同一个颜色的模型数组
arr.forEach(mesh => {
that.environment.attach(mesh) // 将mesh作为子级来添加到该对象中,同时保持该object的世界变换。
})
}
that.geometries = [] //视觉几何数组
that.environment.updateMatrixWorld(true) //更新模型世界坐标
that.environment.traverse(c => {
if (c.geometry) {
// if (c.name === 'Plane056') {
// that.id = c.id
// console.log(c.id, 'cid')
// }
const cloned = c.geometry.clone() //克隆几何结构
cloned.applyMatrix4(c.matrixWorld) // 对当前物体应用这个变换矩阵,并更新物体的位置、旋转和缩放。
// 移除位置外的其他属性
for (const key in cloned.attributes) {
if (key !== 'position') {
cloned.deleteAttribute(key)
}
}
that.geometries.push(cloned) //添加到视觉几何数组
}
})
that.mergedGeometry = mergeBufferGeometries(that.geometries, false)
that.mergedGeometry.boundsTree = new MeshBVH(that.mergedGeometry, {
lazyGeneration: false
}) //生成 BVH 并使用新生成的索引
that.collider = new THREE.Mesh(that.mergedGeometry)// 生成网格
that.visualizer = new MeshBVHVisualizer(that.collider, that.params.visualizeDepth) // 网格bvh可视化工具()
// that.visualizer.layers.set(that.currentlayers)
that.scene.add(that.visualizer) //可视化工具
that.scene.add(that.environment) // 环境
that.scene.add(model)
},
getIntersects(event, group) {
event.preventDefault()// 阻止默认的点击事件执行,
let rayCaster = new THREE.Raycaster()
let mouse = new THREE.Vector2()
//通过鼠标点击位置,计算出raycaster所需点的位置,以屏幕为中心点,范围-1到1;event.clientX鼠标点击位置
mouse.x = (event.clientX / window.innerWidth) * 2 - 1
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1 // 这里为什么是-号,没有就无法点中
//通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
rayCaster.setFromCamera(mouse, this.camera)
let intersects = rayCaster.intersectObjects([group], true)
return intersects
},
// 打开门
opendoor(event) {
// let arr = null
for (const k in this.doors) {
if (this.doors[k].group && this.camera) {
const result = this.getIntersects(event, this.doors[k].group)
if (result.length > 0) {
this.open_door(k)
}
}
}
},
open_door(index) {
console.log("index:" + index);
const { isclose, axis, group, rotation, rotate_deg } = this.doors[index]
group.rotation[axis] = isclose ? rotation + rotate_deg : rotation
this.doors[index].isclose = !isclose
}
检查下控制台日志,看看是否有与碰撞器环境或点击门相关的错误消息。如果有,请找到错误消息并确定是哪个脚本或代码导致的。或者重新加载场景模型看看。
出现您所描述的问题可能是由于加载碰撞器环境后,场景中的物体在位置或者旋转上发生了变化,导致之前的点击事件不再适用。这种情况下,您可以考虑在场景更新后重新设置之前的点击事件,或者在加载碰撞器环境前先记录场景中各个物体的位置和姿态信息,之后再使用这些信息更新点击事件。
关于点击区域偏转的问题,可能是由于加载的碰撞器环境和场景中的物体坐标系不同,导致物体的位置和姿态信息计算错误。您可以尝试在加载碰撞器环境时根据坐标系的差异进行相应的转换,来保证计算的正确性。同时,也建议您检查一下加载的碰撞器环境是否正确,是否与场景中的物体对应。
以下答案由GPT-4.5Plus大模型(语音)与博主A努力中.......共同编写:
这是因为碰撞检测会占用鼠标/触摸事件。当启用碰撞检测后,三维场景不再响应鼠标点击等事件。
有几种解决方法:
js
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function onMouseClick() {
// 临时禁用碰撞检测
scene.children.forEach(obj => { obj.children[0].visible = false; });
// 执行点击事件逻辑
// ...
// 恢复碰撞对象可见性
scene.children.forEach(obj => { obj.children[0].visible = true; });
}
js
const controls = new PointerLockControls(camera);
controls.addEventListener( 'click', () => {
// 单击时执行点击逻辑
} );
PointerLockControls 可以同时支持碰撞检测和鼠标事件。
js
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function getIntersects(point, scene) {
raycaster.setFromCamera(point, camera);
return raycaster.intersectObjects(scene.children);
}
function onMouseClick() {
mouse.x = event.clientX / window.innerWidth * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
const intersects = getIntersects(mouse, scene);
if (intersects.length > 0) {
const object = intersects[0].object;
// 执行点击对象的逻辑
}
}
这种方法可以同时支持碰撞检测和点击事件。
可能是由于加载Collider后对门(opendoor)的物理属性或Collider组件造成了影响导致的。您可以尝试检查门的物理属性和Collider组件是否已正确设置,并确保它们与其他组件和GameObject的参数相匹配。
此外,您还可以考虑在运行时使用调试工具检查门的Collider组件是否与它本来应该匹配的位置、大小和旋转相符合。您可以通过手动调整Collider组件的参数来解决偏移问题。另外,您还可以检查门的触发类型(例如,它是否应该是一个触发器或一个坚实的物体)以及它是否有正确的物理材质。
最后,如果以上方法都无法解决您的问题,您可以考虑重新创建门对象或尝试使用更稳定的Collider组件(例如MeshCollider或BoxCollider)来代替原来的Collider。