如何让Three.js sprite始终朝向Mapbox GL相机
实现Sprite始终朝向Mapbox GL相机的解决方案
核心逻辑
你不需要手动在Three.js场景内提取Mapbox相机参数,直接复用Mapbox自定义层的内置矩阵同步机制即可,绝大部分Three.js和Mapbox结合的场景都是用CustomLayerInterface做自定义层接入,Mapbox会在渲染回调里直接给你同步好相机相关的所有参数。
具体实现步骤
- 初始化自定义层时创建Three.js实例和你的Sprite对象
注意不要手动设置Three.js透视相机的fov、位置、近远裁剪面这类参数,所有参数会由Mapbox同步:const threeLayer = { id: '3d-sprite-layer', type: 'custom', renderingMode: '3d', onAdd(map, gl) { this.scene = new THREE.Scene(); // 只需要实例化相机,不需要手动配置参数 this.camera = new THREE.PerspectiveCamera(); // 初始化你的Sprite const spriteTex = new THREE.TextureLoader().load('你的贴图地址'); const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: spriteTex })); // 这里要把经纬度转换成Mapbox自定义层对应的世界坐标,再赋值给sprite.position sprite.position.set(转换后的x坐标, 转换后的y坐标, 转换后的z坐标); this.scene.add(sprite); this.sprite = sprite; this.renderer = new THREE.WebGLRenderer({ canvas: map.getCanvas(), context: gl, antialias: true }); this.renderer.autoClear = false; }, render(gl, mapMatrix) { // 重点:用Mapbox传入的视图投影矩阵直接更新Three.js相机的投影矩阵 this.camera.projectionMatrix.fromArray(mapMatrix); // Three.js原生Sprite默认会自动对齐相机,不需要额外操作直接渲染即可 this.renderer.resetState(); this.renderer.render(this.scene, this.camera); map.triggerRepaint(); } }; // 把自定义层添加到Mapbox实例 map.addLayer(threeLayer); - 如果你不是用原生Sprite,而是自定义的网格模型需要始终朝向相机,在渲染前加一行代码同步朝向即可:
// 写在render函数里,渲染之前执行 yourMesh.quaternion.copy(this.camera.quaternion);
注意事项
- Sprite如果出现位置偏移,优先检查你的经纬度转世界坐标的逻辑是否正确,不要修改Three.js相机的本身属性
- 不要额外监听Mapbox的相机移动事件手动同步,会出现画面抖动,直接用render回调里传入的矩阵性能和同步精度最高
内容的提问来源于stack exchange,提问作者daumann
相关产品推荐
相关产品推荐

