我正在使用Three.js在Mapbox GL JS页面中渲染一些自定义图层,遵循此示例。我想添加射线投射以确定用户单击了哪个对象。
问题在于我只从Mapbox获取一个投影矩阵,用于渲染场景:
class CustomLayer {
type = 'custom';
renderingMode = '3d';
onAdd(map, gl) {
this.map = map;
this.camera = new THREE.Camera();
this.renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true,
});
this.scene = new THREE.Scene();
// ...
}
render(gl, matrix) {
this.camera.projectionMatrix = new THREE.Matrix4()
.fromArray(matrix)
.multiply(this.cameraTransform);
this.renderer.state.reset();
this.renderer.render(this.scene, this.camera);
}
}
这个渲染效果非常好,并且可以在我移动/旋转/缩放地图时跟踪视图的变化。
不幸的是,当我尝试添加射线投射时,会出现错误:
raycast(point) {
var mouse = new THREE.Vector2();
mouse.x = ( point.x / this.map.transform.width ) * 2 - 1;
mouse.y = 1 - ( point.y / this.map.transform.height ) * 2;
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, this.camera);
console.log(raycaster.intersectObjects(this.scene.children, true));
}
这给了我一个异常:
THREE.Raycaster: Unsupported camera type.
我可以将通用的THREE.Camera
变更为THREE.PerspectiveCamera
而不影响场景的渲染:
this.camera = new THREE.PerspectiveCamera(28, window.innerWidth / window.innerHeight, 0.1, 1e6);
这个修复了异常,但是没有记录任何对象。经过一番探究,我们发现相机的projectionMatrixInverse
全是NaN
,我们可以通过计算来解决这个问题:
raycast(point) {
var mouse = new THREE.Vector2();
mouse.x = ( point.x / this.map.transform.width ) * 2 - 1;
mouse.y = 1 - ( point.y / this.map.transform.height ) * 2;
this.camera.projectionMatrixInverse.getInverse(this.camera.projectionMatrix); // <--
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, this.camera);
console.log(raycaster.intersectObjects(this.scene.children, true));
}
现在,每当我点击魔方的两个面时,我会得到两个交点。它们之间的距离为0:
[
{ distance: 0, faceIndex: 10, point: Vector3 { x: 0, y: 0, z: 0 }, uv: Vector2 {x: 0.5, y: 0.5}, ... },
{ distance: 0, faceIndex: 11, point: Vector3 { x: 0, y: 0, z: 0 }, uv: Vector2 {x: 0.5, y: 0.5}, ... },
]
很明显这里出了问题。查看setCamera
的代码,它涉及到projectionMatrix
和matrixWorld
。我能否设置matrixWorld
或者直接使用投影矩阵构造射线?似乎只需要投影矩阵就可以渲染场景,所以我希望只需要投影矩阵就可以进行射线投射。
完整示例请参见此CodePen。
this.camera.updateMatrixWorld(true);
,但没有用。行为相同,这样做代替或额外添加this.camera.projectionMatrixInverse
一行。 - danvkupdateMatrixWorld
前后,this.camera.matrixWorld
都是单位矩阵。 - danvk