maptalks 开发GIS地图(14)maptalks.three.07 - bloom
1. 这个demo有着比较惊艳的效果,很多实际在用的项目上都采用了这种效果。
2. 添加地图并初始化建筑。
1 var baseLayer = new maptalks.TileLayer('tile', { 2 urlTemplate: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', 3 subdomains: ['a', 'b', 'c', 'd'], 4 attribution: '© <a href="http://osm.org">OpenStreetMap</a> contributors, © <a href="https://carto.com/">CARTO</a>' 5 }); 6 7 var map = new maptalks.Map("map", { 8 center: [13.412830873144912, 52.53720286413957], 9 zoom: 16, 10 pitch: 70, 11 bearing: 180, 12 centerCross: true, 13 doubleClickZoom: false 14 }); 15 // features to draw 16 var features = []; 17 buildings.forEach(function (b) { 18 features = features.concat(b.features); 19 }); 20 // the ThreeLayer to draw buildings 21 var threeLayer = new maptalks.ThreeLayer('t', { 22 forceRenderOnMoving: true, 23 forceRenderOnRotating: true, 24 // animation: true 25 }); 26 var stats; 27 var buildingMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(19,19,38)' }); 28 var buildingMeshes = []; 29 30 threeLayer.prepareToDraw = function (gl, scene, camera) { 31 stats = new Stats(); 32 stats.domElement.style.zIndex = 100; 33 document.getElementById('map').appendChild(stats.domElement); 34 35 var light = new THREE.DirectionalLight(0xffffff); 36 light.position.set(0, -10, 10).normalize(); 37 scene.add(light); 38 39 this.initBloom(); 40 this.setRendererRenderScene(); 41 42 features.forEach(function (g) { 43 var heightPerLevel = 10; 44 var levels = g.properties.levels || 1; 45 var mesh = threeLayer.toExtrudePolygon(maptalks.GeoJSON.toGeometry(g), { 46 height: heightPerLevel * levels, 47 topColor: '#fff', 48 // interactive: false 49 }, buildingMaterial); 50 buildingMeshes.push(mesh); 51 }); 52 threeLayer.addMesh(buildingMeshes); 53 addLines(); 54 55 }; 56 threeLayer.addTo(map);
3. 初始化 bloom 效果。
1 /** 2 * initBloom 3 * */ 4 maptalks.ThreeLayer.prototype.initBloom = function () { 5 const params = { 6 exposure: 1, 7 bloomStrength: 4.5, 8 bloomThreshold: 0, 9 bloomRadius: 0, 10 debug: false 11 }; 12 const renderer = this.getThreeRenderer(); 13 const size = this.getMap().getSize(); 14 this.composer = new THREE.EffectComposer(renderer); 15 this.composer.setSize(size.width, size.height); 16 17 const scene = this.getScene(), camera = this.getCamera(); 18 this.renderPass = new THREE.RenderPass(scene, camera); 19 20 this.composer.addPass(this.renderPass); 21 22 const bloomPass = this.bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(size.width, size.height)); 23 bloomPass.renderToScreen = true; 24 bloomPass.threshold = params.bloomThreshold; 25 bloomPass.strength = params.bloomStrength; 26 bloomPass.radius = params.bloomRadius; 27 28 // composer.setSize(size.width, size.height); 29 // composer.addPass(renderPass); 30 this.composer.addPass(bloomPass); 31 this.bloomEnable = true; 32 }
4. 添加道路线。
道路线分两种,一种是角色不发光,没有白色移动物在上面跑,另外一种是橘色发光,有白色物体在沿线移动。
1 function addLines() { 2 fetch('./data/berlin-roads.txt').then(function (res) { 3 return res.text(); 4 }).then(function (geojson) { 5 geojson = LZString.decompressFromBase64(geojson); 6 geojson = JSON.parse(geojson); 7 var lineStrings = maptalks.GeoJSON.toGeometry(geojson); 8 var data = [], data1 = []; 9 var classMap = {}; 10 lineStrings.forEach(lineString => { 11 const fclass = lineString.getProperties().fclass; 12 classMap[fclass] = fclass; 13 //main road 14 if (fclass && (fclass.includes('primary') || fclass.includes('secondary') || fclass.includes('tertiary'))) { 15 data1.push(lineString); 16 } else { 17 data.push(lineString); 18 } 19 }); 20 const list = []; 21 data.forEach(lineString => { 22 list.push({ 23 lineString, 24 len: lineLength(lineString) 25 }); 26 }); 27 data = list.sort(function (a, b) { 28 return b.len - a.len 29 }); 30 31 baseLines = data.slice(0, 200).map(function (d) { 32 var line = threeLayer.toLine(d.lineString, {}, baseLineMaterial); 33 line.getObject3d().layers.enable(1); 34 return line; 35 }); 36 threeLayer.addMesh(baseLines); 37 38 addExtrudeLine(data1); 39 40 }); 41 } 42 43 var material = new THREE.MeshBasicMaterial({ 44 color: 'rgb(255,45,0)', transparent: true, blending: THREE.AdditiveBlending 45 }); 46 var highlightmaterial = new THREE.MeshBasicMaterial({ color: '#ffffff', transparent: true }); 47 var lines, lineTrails; 48 49 function addExtrudeLine(lineStrings) { 50 var timer = 'generate line time'; 51 console.time(timer); 52 const list = []; 53 lineStrings.forEach(lineString => { 54 list.push({ 55 lineString, 56 len: lineLength(lineString) 57 }); 58 }); 59 lineStrings = list.sort(function (a, b) { 60 return b.len - a.len 61 }); 62 63 lines = lineStrings.slice(0, 1000).map(d => { 64 var line = threeLayer.toExtrudeLine(d.lineString, { altitude: 0, width: 4, height: 1 }, material); 65 line.getObject3d().layers.enable(1); 66 return line; 67 }); 68 lineTrails = lineStrings.slice(0, 300).map(function (d) { 69 var line = threeLayer.toExtrudeLineTrail(d.lineString, { altitude: 0, width: 5, height: 2, chunkLength: d.len / 40, speed: 1, trail: 6 }, highlightmaterial); 70 line.getObject3d().layers.enable(1); 71 return line; 72 }); 73 74 console.log('lines.length:', lines.length); 75 console.timeEnd(timer); 76 threeLayer.addMesh(lines); 77 threeLayer.addMesh(lineTrails); 78 initGui(); 79 // threeLayer.config('animation', true); 80 animation(); 81 }
5. 建筑的数据使用的是 building.js
类似geojson 的json数据。没有geojson前面的头,直接就是对象数据。
6.道路的数据使用的是 ./data/berlin-roads.txt
可以看出,这是一份加密数据,使用 LZString.decompressFromBase64 进行解密。解析后的数据就比较正常了。应该是geojson格式的数据了。
然后对数据截取一部分作为白光bloom效果的路线。
并且为了保证移动物的平滑性,把每个数据平均分为了1000份,这样移动物移动的时候,就比较光滑了。
7. 页面显示
8. 源码地址
https://github.com/WhatGIS/maptalkMap