【发布时间】:2020-03-28 11:53:47
【问题描述】:
我在 this example 之后的 Mapbox GL JS 页面中使用 Three.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都是NaNs,我们可以通过计算来修复:
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}, ... },
]
很明显有些东西在这里不起作用。查看code for setCamera,它涉及projectionMatrix 和matrixWorld。有没有办法可以设置matrixWorld,或者只使用投影矩阵直接构造光线投射器的光线?看来我只需要投影矩阵来渲染场景,所以我希望它也是我投射光线所需要的。
完整示例in this codepen。
【问题讨论】:
-
"有什么方法可以设置
matrixWorld"你试过updateMatrixWorld()吗?所有的相机也是 Object3Ds... -
@Barthy 我尝试在 codepen 中添加
this.camera.updateMatrixWorld(true);来代替this.camera.projectionMatrixInverse行,但无济于事。同样的行为。 -
@Barthy 具体来说,
this.camera.matrixWorld是调用updateMatrixWorld之前和之后的单位矩阵。 -
还有一些关于这个 mapbox-gl 问题的有趣材料github.com/mapbox/mapbox-gl-js/issues/7395
-
@abhishekranjan 下面的答案是解决方案,包括。一个功能齐全的 JS Fiddle。如果喜欢,请点赞。晚上我也会看看你的问题。
标签: three.js mapbox-gl-js raycasting