一、简介
基于矢量geojson数据构建建筑、植被、道路等,实现城市场景底座。
涉及渲染的性能优化无非就是众所周知的那些事儿。
视锥剔除、mesh合并、减少draw call、四叉树、八叉树、数据压缩、WebWorker、着色器优化等。下面是对东莞市数十万建筑以及海量3D树的渲染测试。
二、效果
三、代码
const unit = 1;
const sceneControl = InitHelper.init3D(new Vector3(0, 5000, 0));
const container = document.querySelector("#map") as HTMLElement;
container && sceneControl.render(container);
const { scene, camera, renderer } = sceneControl;
const control = InitHelper._createControls(camera, document.body, scene);
renderer.shadowMap.type = BasicShadowMap;
InitHelper.addLight(scene, new Vector3(3 / unit, 2 / unit, 1 / unit), unit);//插件初始化
const centerGeo = new Vector3(113.739834, 23.052766, 0);
const imageryLayers = new ImageryLayers();
imageryLayers.add(tdtImageryLayerIMG);
imageryLayers.add(tdtImageryLayerLabel);
const map = new Map({threeModule: {scene, camera, renderer, control},center: centerGeo,earthOptions: {useEarth: true},imageryLayers: imageryLayers,unit: unit,terrainLayer: guangdongTerrain,castShadow: true,receiveShadow: true
})
///////////loading///////////////////
map.addEventListener(MapEventType.onProgress, (v) => {console.log(v.progress);if (v.progress > 0.8) {const mask = document.getElementById('mask');mask!.style.display = 'none';}
});
////////////////////树///////////////////////
const treePipline = new TreePipelineSprite({imageryLayer: tdtImageryLayerIMG,widthBottomHeight: true,level: 14,
})
treePipline.addTo(map);
///////////////////////建筑///////////////////////
const buildingPipline = new BuildingPipline({// pbfUrl: map.staticPath + '/static/' + 'shijingshan.bpf',pbfUrl: map.staticPath + '/static/' + 'dongguan441900.pbf',heightProp: 'height',bottomHeight: 10,
})
buildingPipline.addTo(map);
///////////////////////GUI参数设置界面///////////////////////////
initGui(map, {show: true
});
//////////////////////////建筑设置面板////////////////////////////////////
// initBuildingGui(map, buildingPipline);
////////////////////////////材质切换/////////////////////////////
import RoamingPath, { PointWithPitch } from './RoamingPath';
const pathPos: PointWithPitch[] = [{ position: new Vector3(113.653087, 22.763037, 10000), pitch: -20 },{ position: new Vector3(113.662839, 22.779383, 1000), pitch: -20 },{ position: new Vector3(113.667659, 22.806545, 700), pitch: -30 },{ position: new Vector3(113.668767, 22.824555, 500), pitch: -30 },{ position: new Vector3(113.660551, 22.861560, 400), pitch: -30 },{ position: new Vector3(113.656820, 22.907300, 300), pitch: -30 },{ position: new Vector3(113.657126, 22.922037, 300), pitch: -30 },{ position: new Vector3(113.661291, 22.933088, 300), pitch: -30 },{ position: new Vector3(113.669534, 22.945224, 300), pitch: -30 },{ position: new Vector3(113.710343, 22.992263, 500), pitch: -30 }
];const line: any = [];
const pathPosWord: PointWithPitch[] = [];
for (let index = 0; index < pathPos.length; index++) {const pointCoord = pathPos[index];line.push([pointCoord.position.x, pointCoord.position.y]);const coord3DXYZ = CoordUtil.LonLatTo3DXYZ(pointCoord.position.x, pointCoord.position.y, pointCoord.position.z);pathPosWord.push({position: coord3DXYZ,pitch: pointCoord.pitch - 50});
}const path = new RoamingPath(pathPosWord, 35, 'speed');
path.addEventListener('start', () => {console.log('Roaming started');
});path.addEventListener('end', () => {console.log('Roaming ended');
});path.addEventListener('update', (camera, delta) => {console.log('Updating camera', camera.position);
});
use.useframe(() => {const delta = path.getDelta();path.update(camera, delta);
})
const buttons = document.querySelectorAll("#btns button");
buttons.forEach(button => {button.addEventListener("click", function () {const buttonId = this.id;switch (buttonId) {case "one":path.start({ height: 0 });break;case "two":path.stop();break;default:alert("未知按钮被点击");}});
});