Draw Mesh with mapbox-gl
结合 mapbox-gl 的自定义图层渲染 Mesh
,注意 @sakitam-gis/mapbox-ve 插件内部默认启用了高精度。
示例
Result
Loading...
Live Editor
function render(props) { const refDom = useRef(null); const store = leva.useCreateStore(); class MeshLayer { constructor (id) { this.id = id; this.type = 'custom'; this.renderingMode = '2d'; } get camera () { return this.sync.camera; } updateCamera() { this.sync.update(); } projectToWorld (coords) { let i = 0; const len = coords.length; const position = new Float32Array(len * 3); for (; i < len; i++) { const coord = coords[i]; const mc = mapboxgl.MercatorCoordinate.fromLngLat({ lng: coord[0], lat: coord[1], }, coord[2]); position.set([mc.x, mc.y, mc.z], i * 3); } return position; } onAdd (map, gl) { this.renderer = new Renderer(gl, { autoClear: false, }); this.scene = new Scene(); this.sync = new mbve.CameraSync(map, 'perspective', this.scene); this.updateCamera = this.updateCamera.bind(this); map.on('move', this.updateCamera); map.on('resize', this.updateCamera); const geometry = new Geometry(this.renderer, { position: { size: 3, data: this.projectToWorld([ [70.26608, 38.7213], [102.51084435117338, 24.846755709924764], [114.46396935117377, 39.232415634606724] ]), }, // position: { // size: 2, // data: new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]) // }, // uv: { // size: 2, // data: new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]) // } }); this.program = new Program(this.renderer, { vertexShader: ` attribute vec2 uv; attribute vec3 position; uniform vec3 cameraPosition; uniform mat4 viewMatrix; uniform mat4 modelMatrix; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: ` precision highp float; uniform float uTime; varying vec2 vUv; void main() { gl_FragColor.rgb = 0.5 + 0.3 * sin(vUv.yxx + uTime) + vec3(0.2, 0.0, 0.1); gl_FragColor.a = 1.0; } `, uniforms: { uTime: { value: 0.5 }, }, depthTest: false, }); this.mesh = new Mesh(this.renderer, { geometry, program: this.program, }); this.scene.add(this.mesh); this.updateCamera(); } onRemove () { this.mesh.destroy(); this.program.destroy(); } prerender () { } render () { this.scene.worldMatrixNeedsUpdate = true; this.renderer.render({ scene: this.scene, camera: this.camera, }); this.renderer.resetState(); } } const init = () => { mapboxgl.accessToken = 'pk.eyJ1IjoiZXhhbXBsZXMiLCJhIjoiY2p0MG01MXRqMW45cjQzb2R6b2ptc3J4MSJ9.zA2W0IkI0c6KaAhJfk9bWg'; const map = new mapboxgl.Map({ container: refDom.current, zoom: 3, center: [112.26608, 32.7213], pitch: 0, bearing: 0, // style: 'mapbox://styles/mapbox/satellite-streets-v12', style: { version: 8, glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf', sources: { tile: { type: 'raster', tiles: [ 'https://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}', ], tileSize: 256, }, }, layers: [ { id: 'tile', type: 'raster', source: 'tile', minzoom: 0, maxzoom: 22, paint: { 'raster-resampling': 'nearest', 'raster-fade-duration': 200, }, }, { id: 'background', type: 'background', layout: { visibility: 'none', }, }, ], }, // center: [-74.0066, 40.7135], // zoom: 15.5, // pitch: 45, // bearing: -17.6, antialias: true, projection: 'mercator' }); map.on('load', () => { const layer = new MeshLayer('mesh'); map.addLayer(layer); window.layer = layer; }); window.map = map; return map; } useEffect(() => { const map = init(); return () => { console.log(map); }; }, []); return ( <div className="live-wrap"> <div className="leva-wrap"> <Leva collapsed fill ></Leva> <LevaPanel collapsed store={store} fill></LevaPanel> </div> <div className="scene-canvas" ref={refDom}></div> </div> ); }