您的位置:首页 > 游戏 > 游戏 > Babylonjs学习笔记(十一)——加载geoJson文件

Babylonjs学习笔记(十一)——加载geoJson文件

2024/10/7 0:18:12 来源:https://blog.csdn.net/weixin_41718879/article/details/124710380  浏览:    关键词:Babylonjs学习笔记(十一)——加载geoJson文件
一、定义基本场景类
  • 定义场景
  • 定义相机
import { ArcRotateCamera, Color4, CubeTexture, Engine, GlowLayer, KeyboardEventTypes, Scene, Vector3 } from '@babylonjs/core';import { AdvancedDynamicTexture } from '@babylonjs/gui';class SceneManager {public engine: Engine;public scene: Scene;public camera: ArcRotateCamera;public advanceTexture: AdvancedDynamicTexture;public glowLayer: GlowLayer;constructor(canvas: HTMLCanvasElement) {this.engine = new Engine(canvas);const { scene, camera } = this.BuildScene();this.scene = scene;this.camera = camera;this.advanceTexture = AdvancedDynamicTexture.CreateFullscreenUI('ui');this.glowLayer = this.SetGlowLayer();this.setEnv();this.Resize();this.RenderLoop();}BuildScene(): { scene: Scene; camera: ArcRotateCamera } {const scene = new Scene(this.engine);scene.clearColor = new Color4(0, 0, 0, 0);const camera = new ArcRotateCamera('camera', 1.57, 1.57, 5.5, Vector3.Zero());camera.attachControl(this.engine.getRenderingCanvas(), true);camera.minZ = 0;camera.wheelPrecision = 20;camera.fov = 0.7;camera.lowerAlphaLimit = null;camera.upperAlphaLimit = null;camera.lowerBetaLimit = null;camera.upperBetaLimit = null;camera.inputs.removeByType('ArcRotateCameraMouseWheelInput');return {camera,scene};}SetGlowLayer(): GlowLayer {const glowLayer = new GlowLayer('gl');glowLayer.isEnabled = true;glowLayer.intensity = 0.3;return glowLayer;}RenderLoop() {this.engine.runRenderLoop(() => {this.scene.render();});}Resize() {if (window) {window.addEventListener('resize', () => {this.engine.resize();});}}// 切换调试面板public async RegisterInspectorOnInput(scene: Scene) {const isEnv = import.meta.env.MODE === 'development';if (isEnv) {await Promise.all([import('@babylonjs/core/Debug/debugLayer'), import('@babylonjs/inspector')]);scene.debugLayer.show({ embedMode: true });}const toggleInspector = () => {if (scene.debugLayer.isVisible()) scene.debugLayer.hide();else scene.debugLayer.show();};scene.onKeyboardObservable.add((kbInfo) => {if (kbInfo.type === KeyboardEventTypes.KEYDOWN && kbInfo.event.key === 'i') {toggleInspector();}});}setEnv() {const skybox = CubeTexture.CreateFromPrefilteredData('env/Earth_Skybox.env', this.scene);this.scene.createDefaultSkybox(skybox, false, 30, 0.98);const hdr = CubeTexture.CreateFromPrefilteredData('env/Earth_Env.env', this.scene);this.scene.environmentTexture = hdr;this.scene.autoClear = false; // Color bufferthis.scene.autoClearDepthAndStencil = false; // Depth and stencil, obviously}Dispose() {this.scene.dispose();this.engine.dispose();}
}export { SceneManager };
二、定义子类继承父类
  • 继承父类
  • 加载json文件
  • 利用墨卡托投影算法创建地图轮廓

import * as d3 from 'd3';

import earcut from 'earcut';

1.加载json文件

  LoadJson() {return new Promise<JSONType>((resolve) => {Tools.LoadFile('json/china.json', (response) => {try {const json = JSON.parse(response as string) as JSONType;resolve(json);} catch (error) {console.error(`地图json加载失败:${error}`);}});});}

 

2.生成边线和轮廓

2.1定义地图中心和投影算法

const center: [number, number] = [108.55, 34.32];
export function projection(args: [number, number]) {const result = d3.geoMercator().center(center).scale(5).translate([0, 0])(args) as [number, number];return result;
}

 2.2 封装创建多边形算法

// 创建多边形
export function CreatePolygon(path: Vector3[], scene: Scene) {return MeshBuilder.ExtrudePolygon('polygon',{shape: path,sideOrientation: Mesh.FRONTSIDE,depth: 0.5,// 这里设置会覆盖材质的颜色faceColors: [new Color4(1, 0, 0, 1), new Color4(0, 1, 0, 0.1), new Color4(1, 1, 1, 1)],faceUV: [new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1)]},scene,earcut);
}// 创建边界线
export function CreateBoundaryLine(path: Vector3[]) {const line = MeshBuilder.CreateLines('line', { points: path.concat(path[0]), updatable: true });line.color = Color3.Random();return line;
}

2.3 通过json数据创建多边形

CreateMapFromGeoJSON(geoJsonData: JSONType) {return new Promise<Boolean>((resolve) => {const { features } = geoJsonData;const _createPolygonsFromCoordinates = (coordinate: number[][][] | number[][], meshList: Mesh[], lineList: Mesh[]) => {coordinate.forEach(() => {//获取轮廓const path = coordinate[0].map((coord: any) => {const [x, y] = projection([coord[0], coord[1]]) as [number, number];// 投影在xz平面return new Vector3(x, 0, -y);});const polygon = CreatePolygon(path, this.scene);meshList.push(polygon);const line = CreateBoundaryLine(path);lineList.push(line);});};features.forEach((feature, groundIndex) => {const { center, name, centroid } = feature.properties;const { coordinates, type } = feature.geometry;const meshList: Mesh[] = [];const lineList: Mesh[] = [];if (type === 'Polygon') _createPolygonsFromCoordinates(coordinates, meshList, lineList);if (type === 'MultiPolygon') coordinates.forEach((item) => _createPolygonsFromCoordinates(item, meshList, lineList));if (meshList.length > 0) {const mergedMesh = Mesh.MergeMeshes(meshList, true, true, undefined, false, true);if (mergedMesh) {mergedMesh.name = name + groundIndex;this.regionList.push({name,center,centroid,mesh: mergedMesh});}}});resolve(true);});}

2.4 创建省份标签

//创建区域标签
export function CreateRegionLabel(regionList: TypeRegionList[], advanceTexture: AdvancedDynamicTexture) {const _drawText = (name: string, mesh: Mesh) => {const text = new TextBlock();text.text = name;text.fontSize = 12;text.color = 'white';advanceTexture.addControl(text);text.linkWithMesh(mesh);};const _drawImage = (mesh: Mesh) => {const image = new Image('point', 'textures/point.png');image.width = '70px';image.height = '70px';advanceTexture.addControl(image);image.linkWithMesh(mesh);// image.linkOffsetX = -15;// image.linkOffsetY = 0;};regionList.forEach((item) => {const { mesh, name } = item;_drawText(name, mesh);_drawImage(mesh);});
}

2.5 创建飞线


export function CreateFlyline(regionList: TypeRegionList[], scene: Scene) {const flylineCenter = [116.41995, 40.18994] as [number, number];const [x, y] = projection(flylineCenter);const origin = new Vector3(x, 0, -y);// 创建textureconst createLineTexture = (): Texture => {const textureColors = new Uint8Array([255, 255, 255, 0, 0, 255]);const texture = new RawTexture(textureColors,textureColors.length / 3,1,Engine.TEXTUREFORMAT_RGB,scene,false,true,Engine.TEXTURE_NEAREST_NEAREST);texture.wrapU = RawTexture.WRAP_ADDRESSMODE;texture.name = 'blue-white-texture';texture.uScale = 5;return texture;};const texture = createLineTexture();const createLinesInstance = (points: Vector3[]): GreasedLineBaseMesh => {const line = CreateGreasedLine('line',{points,updatable: true},{width: 0.008,colorMode: GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY},scene);return line;};regionList.forEach((city) => {const { centroid } = city;if (centroid) {const [x, y] = projection(centroid);const targetVec = new Vector3(x, 0, -y);CreateWave(new Vector3(targetVec.x, targetVec.y + 0.01, targetVec.z), scene);const middle = origin.add(targetVec).scale(0.5);let control = new Vector3(middle.x, 1, middle.z);// 创建贝塞尔曲线const curve = Curve3.CreateQuadraticBezier(origin, control, targetVec, 64);// 将贝塞尔曲线的点赋予lineconst line = createLinesInstance(curve.getPoints());(line.material as StandardMaterial).emissiveTexture = texture;texture.uScale = 5;scene.onBeforeRenderObservable.add(() => {texture.uOffset += -0.0005 * scene.getAnimationRatio();});}});
}

2.6 创建缩放动画

export function CreateWave(position: Vector3, scene: Scene) {const plane = MeshBuilder.CreatePlane('wave', { size: 0.15 });const mat = new StandardMaterial('mat');const texture = new Texture('textures/wave.png');mat.emissiveColor = Color3.White();mat.diffuseTexture = texture;mat.useAlphaFromDiffuseTexture = true;texture.hasAlpha = true;plane.material = mat;plane.position = position;plane.rotation.x = Math.PI / 2;let radio = 1.0; // 初始化缩放比例let size = 1; // 初始大小scene.onBeforeRenderObservable.add(() => {radio += 0.01; // 控制缩放速度const scling = size * radio;const initVector = new Vector3(scling, scling, scling);plane.scaling = initVector;if (radio <= 1.5) {plane.material!.alpha = (radio - 1) * 2; // 透明度从0到1} else if (radio > 1.5 && radio <= 2) {plane.material!.alpha = 1 - (radio - 1.5) * 2; // 透明度从1到0} else {radio = 1.0; // 重置缩放比例}});
}

2.7 创建action

export function AddEvent(regionList: TypeRegionList[]) {regionList.forEach((item) => {const { mesh, name } = item;mesh.actionManager = new ActionManager();// 改变样式actionmesh.actionManager.registerAction(new SetValueAction(ActionManager.OnPointerOverTrigger, mesh.material, 'diffuseColor', Color3.Blue()));mesh.actionManager.registerAction(new SetValueAction(ActionManager.OnPointerOutTrigger, mesh.material, 'diffuseColor', (mesh.material as StandardMaterial)!.diffuseColor));mesh.actionManager.registerAction(new InterpolateValueAction(ActionManager.OnPointerOverTrigger, mesh, 'scaling', new Vector3(1, -1.2, 1), 300));mesh.actionManager.registerAction(new InterpolateValueAction(ActionManager.OnPointerOutTrigger, mesh, 'scaling', new Vector3(1, 1, 1), 300));// 点击事件actionmesh.actionManager.registerAction(new ExecuteCodeAction({trigger: ActionManager.OnLeftPickTrigger,// 参数传递parameter: function (actionEvent: any) {return actionEvent.sourceEvent.key === 'R';}},(evt) => {console.log(evt, name);// 派发事件emitter.emit(EVENT_NAME.SET_PROVINCE_DATA, name as TProvinceKeys);}));});
}

3. 构造函数中调用

constructor(params: { canvas: HTMLCanvasElement; topList: String[] }) {const { canvas, topList } = params;super(canvas);// new HemisphericLight('ligt', Vector3.Up());this.LoadJson().then((geoJson: JSONType) => {this.CreateMapFromGeoJSON(geoJson).then(() => {// 创建区域标签CreateRegionLabel(this.regionList, this.advanceTexture);// 创建飞线CreateFlyline(this.regionList, this.scene);// 添加交互事件AddEvent(this.regionList);// 轮播this.SetupLoopInteraction();});});}

4 效果展示

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com