前言
本文将使用react和cesium进行智慧城市的实现,本篇主要讲解项目中的效果修改
地图底色修改
修改地图底色方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| export default function modifyMap(viewer) { let baseLayer = viewer.imageryLayers.get(0); baseLayer.invertColor = true;
baseLayer.filterRGB = [0, 50, 100]; const baseFragmentShader = viewer.scene.globe._surfaceShaderSet.baseFragmentShaderSource.sources;
for (let i = 0; i < baseFragmentShader.length; i++) { const strS = "color = czm_saturation(color, textureSaturation);\n#endif\n"; let strT = "color = czm_saturation(color, textureSaturation);\n#endif\n"; if (baseLayer.invertColor) { strT += ` color.r = 1.0 - color.r; color.g = 1.0 - color.g; color.b = 1.0 - color.b; `; } if (baseLayer.filterRGB) { strT += ` color.r = color.r*${baseLayer.filterRGB[0]}.0/255.0; color.g = color.g*${baseLayer.filterRGB[1]}.0/255.0; color.b = color.b*${baseLayer.filterRGB[2]}.0/255.0; `; }
baseFragmentShader[i] = baseFragmentShader[i].replace(strS, strT); } }
|
引入并使用
1 2 3
| import modifyMap from "./cesium/modifyMap";
modifyMap(viewer);
|

建筑材质修改
切换较多建筑地
为了能够更好的修改我们的材质,我们需要找一个楼层比较高的地方,于是我找了环城银泰那附近的建筑
- src/cesium/initView.js
1 2 3 4 5 6 7 8
| var postion = Cesium.Cartesian3.fromDegrees( 121.57, 29.79, 1500 );
|

绘制building材质
- src/cesium/modeifyBuild.js
根据高度设置渐变色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| tiles3d.tileVisible.addEventListener(function (tile) { const cesium3DTileCon = tile.content; const featuresLength = cesium3DTileCon.featuresLength; for (let i = 0; i < featuresLength; i++) { const model = cesium3DTileCon.getFeature(i).content._model;
const fragmentShaderSource = (model._rendererResources.sourceShaders[1] = ` varying vec3 v_positionEC;
void main() { czm_materialInput materialInput; // 获取模型position信息 vec4 position = czm_inverseModelView * vec4(v_positionEC, 1.0); // 根据高度来设置渐变颜色 float strength = position.z/200.0; gl_FragColor = vec4(strength,0.3*strength,strength, 1.0); }
`);
model._shouldRegenerateShaders = true; } });
|

设置动态光环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const fragmentShaderSource =(model._rendererResources.sourceShaders[1] = ` varying vec3 v_positionEC;
void main(){ czm_materialInput materialInput; // 获取模型position信息 vec4 position = czm_inverseModelView * vec4(v_positionEC, 1.0); // 根据高度来设置渐变颜色 float strength = position.z/200.0; gl_FragColor = vec4(strength,0.3*strength,strength, 1.0); // 动态光环 // czm_frameNumber获取当前帧数(一秒60帧) // fract(x),返回x的小数部分 float time = fract(czm_frameNumber/(60.0*2.0)); // 实现往返的操作 time = abs(time-0.5)*2.0; // clamp(x, min, max),返回x在min和max之间的最小值 float diff = abs(clamp(position.z/500.0, 0.0, 1.0) - time) ; // step(edge, x),如果x大于等于edge,返回1,否则返回0 diff = step(0.01, diff); gl_FragColor.rgb += vec3(0.5)*(1.0-diff); }
`);
|
添加光锥
光锥代码
安装gsap
光锥代码
- src/cesium/LightCone.js
- 121.5494, 29.80739 这个经纬度可以根据你想让他出现在哪里替换,我这里是点击了一下展示区域的中间位置,然后根据右下角的经纬度替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import * as Cesium from "cesium"; import gsap from "gsap";
export default class LightCone { constructor(viewer) { this.params = { height: 200, degress: 0, }; this.modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame( Cesium.Cartesian3.fromDegrees(121.5494, 29.80739, this.params.height), new Cesium.HeadingPitchRoll(this.params.degress, 0, 0) ); this.model = viewer.scene.primitives.add( new Cesium.Model.fromGltf({ url: "./model/pyramid.glb", show: true, scale: 200, minimumPixelSize: 12, maximumScale: 20000, debugShowBoundingVolume: false, debugWireframe: false, color: Cesium.Color.YELLOW.withAlpha(0.5), colorBlendMode: Cesium.ColorBlendMode.MIX, modelMatrix: this.modelMatrix, }) ); this.animate(); } animate() { gsap.to(this.params, { height: 300, degress: Math.PI, yoyo: true, repeat: -1, duration: 1, ease: "power1.inOut", onUpdate: () => { this.model.modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame( Cesium.Cartesian3.fromDegrees(121.5494, 29.80739, this.params.height), new Cesium.HeadingPitchRoll(this.params.degress, 0, 0) ); }, }); } }
|
引入并使用
1 2 3
| import LightCone from "./cesium/LightCone";
let lightCone = new LightCone(viewer);
|
添加区域飞线
安装依赖
@turf/turf这个包的作用是生成随机区域点
1
| import * as turf from "@turf/turf";
|
飞线代码
- src/cesium/RectFlyLight.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import * as Cesium from "cesium"; import * as turf from "@turf/turf";
export default class RectFlyLight { constructor(viewer) { this.bbox = [121.52, 29.79, 121.58, 29.85]; let points = turf.randomPoint(300, { bbox: this.bbox, }); let features = points.features; features.forEach((item) => { let point = item.geometry.coordinates; let start = Cesium.Cartesian3.fromDegrees(point[0], point[1], 0); let end = Cesium.Cartesian3.fromDegrees( point[0], point[1], 50 + Math.random() * 1000 ); let flyLine = viewer.entities.add({ polyline: { positions: [start, end], width: 2, material: Cesium.Color.RED.withAlpha(0.5), }, }); }); } }
|
App.jsx引入并使用
1 2 3
| import RectFlyLight from "./cesium/RectFlyLight";
let rectFlyLight = new RectFlyLight(viewer);
|

添加飞线自定义材质
- src/cesium/PolylineTrailMaterial.js
这里运用了前文讲解过的自定义materialProperty材质的知识,这里我不多阐述1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| import * as Cesium from "cesium"; import gsap from "gsap"; let typeNum = 0; export default class PolylineTrailMaterialProperty { constructor(color = new Cesium.Color(0.7, 0.6, 1.0, 1.0)) { this.color = color; typeNum++; this.num = typeNum; this.definitionChanged = new Cesium.Event(); Cesium.Material._materialCache.addMaterial( "PolylineTrailMaterial" + this.num, { fabric: { type: "PolylineTrailMaterial" + typeNum, uniforms: { uTime: 0, color: this.color, }, source: ` czm_material czm_getMaterial(czm_materialInput materialInput) { // 生成默认的基础材质 czm_material material = czm_getDefaultMaterial(materialInput); // 获取st vec2 st = materialInput.st; // 获取当前帧数,10秒内变化从0-1; float time = fract(czm_frameNumber / (60.0*10.0)); time = time * (1.0 + 0.1); // 平滑过渡函数 // smoothstep(edge0, edge1, value); // 参数1:边缘0,==8, // 参数2:边缘1,==10, // 参数3:当前值,==7 , result = 0 // 参数3:当前值,==9 , result = 0.5 // 参数3:当前值,==10 , result = 1 float alpha = smoothstep(time-0.1,time, st.s) * step(-time,-st.s); alpha += 0.05; // 设置材质的透明度 material.alpha = alpha; material.diffuse = color.rgb; return material; }
`, }, } );
this.params = { uTime: 0, }; gsap.to(this.params, { uTime: 1, duration: 2, repeat: -1, yoyo: true, }); } getType() { return "PolylineTrailMaterial" + this.num; } getValue(time, result) { result.uTime = this.params.uTime; return result; } equals(other) { return ( other instanceof PolylineTrailMaterialProperty && this.color === other.color ); } }
|
引用
1 2 3 4 5 6 7 8 9 10
| let polylineTrailMaterialProperty = new PolylineTrailMaterialProperty();
let flyLine = viewer.entities.add({ polyline: { positions: [start, end], width: 2, material: polylineTrailMaterialProperty, }, });
|
添加道路流光
网站导出
通过网站http://datav.aliyun.com/portal/school/atlas/area_selector 来导出我们的道路数据
在边界生成器找到我们智慧城市的定位

绘制道路

导出数据

我这里随便搞了几条线,追求完美的可以自己去绘制
道路流光配置
绘制流光折线
- src/cesium/RoadLight.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import * as Cesium from "cesium"; import SpritelineMaterialProperty from "./material/SpritelineMaterialProperty"; export default class RoadLightLine { constructor(viewer) { let geoJsonPromise = Cesium.GeoJsonDataSource.load( "./geojson/roadline.geojson" ); geoJsonPromise.then((dataSource) => { viewer.dataSources.add(dataSource); let entities = dataSource.entities.values; let spritelineMaterialProperty = new SpritelineMaterialProperty(); entities.forEach((item) => { let polyline = item.polyline; polyline.material = spritelineMaterialProperty; }); }); } }
|
配置材质
- src/cesium/material/SpritelineMaterialProperty.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| import * as Cesium from "cesium"; import gsap from "gsap"; export default class SpritelineMaterialProperty { constructor(name) { this.name = name; this.definitionChanged = new Cesium.Event(); Cesium.Material._materialCache.addMaterial("SpritelineMaterial", { fabric: { type: "SpritelineMaterial", uniforms: { uTime: 0, image: "./texture/spriteline1.png", }, source: ` czm_material czm_getMaterial(czm_materialInput materialInput) { // 生成默认的基础材质 czm_material material = czm_getDefaultMaterial(materialInput); // 获取st vec2 st = materialInput.st; // 根据uv采样颜色,fract(x)返回x的小数部分 vec4 color = texture2D(image, vec2(fract(st.s-uTime) , st.t)); // 设置材质的透明度 material.alpha = color.a; material.diffuse = color.rgb; return material; }
`, }, });
this.params = { uTime: 0, }; gsap.to(this.params, { uTime: 1, duration: 1, repeat: -1, ease: "linear", }); } getType() { return "SpritelineMaterial"; } getValue(time, result) { result.uTime = this.params.uTime; return result; } equals(other) { return ( other instanceof SpritelineMaterialProperty && this.name === other.name ); } }
|
引用
App.jsx引用
1 2 3
| import RoadLightLine from "./cesium/RoadLight"; let roadLightLine = new RoadLightLine(viewer);
|
创建雷达
雷达代码
- src/cesium/RadarLight.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import * as Cesium from "cesium"; import RadarMaterialProperty from "./material/RadarMaterialProperty";
export default class RadarLight { constructor(viewer) { this.radarMaterial = new RadarMaterialProperty("radarMaterial"); this.entity = viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees( 121.548, 29.794, 121.553, 29.799 ), material: this.radarMaterial, }, }); } }
|
雷达材质
- src/cesium/material/RadarMaterialProperty.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| import * as Cesium from "cesium"; import gsap from "gsap"; export default class RadarMaterialProperty { constructor(name) { this.name = name; this.definitionChanged = new Cesium.Event(); Cesium.Material._materialCache.addMaterial("RadarMaterial", { fabric: { type: "RadarMaterial", uniforms: { uTime: 0, }, source: ` czm_material czm_getMaterial(czm_materialInput materialInput) { // 生成默认的基础材质 czm_material material = czm_getDefaultMaterial(materialInput); // 旋转uv vec2 newSt = mat2( cos(uTime),-sin(uTime), sin(uTime),cos(uTime) )*(materialInput.st-0.5);
newSt = newSt+0.5;
// 获取st vec2 st = newSt; // 设置圆,外部透明,内部不透明 float alpha = 1.0 - step(0.5,distance(st,vec2(0.5))) ; // 按照角度来设置强弱 float angle = atan(st.x-0.5,st.y-0.5); // angle是从-pi到pi的,所以如果要设置从0-1的转变,需要加上pi float strength = (angle+3.1416)/6.2832;
// 将强弱与透明度结合 alpha = alpha*strength; material.alpha = alpha; material.diffuse = vec3(st.x,st.y,1.0); return material; }
`, }, });
this.params = { uTime: 0, }; gsap.to(this.params, { uTime: 6.28, duration: 1, repeat: -1, ease: "linear", }); } getType() { return "RadarMaterial"; } getValue(time, result) { result.uTime = this.params.uTime; return result; } equals(other) { return other instanceof RadarMaterialProperty && this.name === other.name; } }
|
引用
App.jsx引用
1 2 3
| import RadarLight from "./cesium/RadarLight";
let radarLight = new RadarLight(viewer);
|
创建光波特效
光波代码
- src/cesium/LightSpread.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import * as Cesium from "cesium"; import LightSpreadMaterialProperty from "./material/LightSpreadMaterialProperty"; import gsap from "gsap";
export default class LightSpread { constructor(viewer) { this.LightSpreadMaterial = new LightSpreadMaterialProperty( "LightSpreadMaterial" ); this.params = { minlot: 121.555, minLat: 29.81, maxlot: 121.56, maxLat: 29.815, }; this.entity = viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees( 121.555, 29.81, 121.56, 29.815 ), material: this.LightSpreadMaterial, }, }); gsap.to(this.params, { minlot: 121.56, minLat: 29.795, maxlot: 121.565, maxLat: 29.805, duration: 5, repeat: -1, ease: "linear", onUpdate: () => { this.entity.rectangle.coordinates = Cesium.Rectangle.fromDegrees( this.params.minlot, this.params.minLat, this.params.maxlot, this.params.maxLat ); }, }); } }
|
光波材质
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import * as Cesium from "cesium"; import gsap from "gsap"; export default class LightSpreadMaterialProperty { constructor(name) { this.name = name; this.definitionChanged = new Cesium.Event(); Cesium.Material._materialCache.addMaterial("LightSpreadMaterial", { fabric: { type: "LightSpreadMaterial", uniforms: { uTime: 0, image: "./texture/hexagon.png", }, source: ` czm_material czm_getMaterial(czm_materialInput materialInput) { // 生成默认的基础材质 czm_material material = czm_getDefaultMaterial(materialInput); vec2 st = materialInput.st; // 根据uv采样颜色 vec4 color = texture2D(image, st); material.diffuse = color.rgb; material.alpha = color.a; return material; }
`, }, });
this.params = { uTime: 0, }; gsap.to(this.params, { uTime: 6.28, duration: 1, repeat: -1, ease: "linear", }); } getType() { return "LightSpreadMaterial"; } getValue(time, result) { result.uTime = this.params.uTime; return result; } equals(other) { return ( other instanceof LightSpreadMaterialProperty && this.name === other.name ); } }
|
引用
App.jsx引用
1 2 3
| import LightSpread from "./cesium/LightSpread";
let lightSpread = new LightSpread(viewer);
|
光墙特效
光墙实现
- src/cesium/LightWall.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import * as Cesium from "cesium"; import LightWallMaterialProperty from "./material/LightWallMaterialProperty";
export default class LightWall { constructor(viewer) { this.LightWallMaterial = new LightWallMaterialProperty("LightWallMaterial"); this.entity = viewer.entities.add({ name: "lightWall", position: Cesium.Cartesian3.fromDegrees(121.55, 29.8, 200.0,), wall: { positions: Cesium.Cartesian3.fromDegreesArrayHeights([ 121.545, 29.8, 200.0, 121.555, 29.8, 200.0, 121.555, 29.81, 200.0, 121.545, 29.81, 200.0, 121.545, 29.8, 200.0, ]), material: this.LightWallMaterial, }, label: { text: "科技园光墙", font: "16px sans-serif", style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -20), fillColor: Cesium.Color.WHITE, }, }); } }
|
光墙材质
- src/cesium/material/LightWallMaterialProperty.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import * as Cesium from "cesium"; import gsap from "gsap"; export default class LightWallMaterialProperty { constructor(name) { this.name = name; this.definitionChanged = new Cesium.Event(); Cesium.Material._materialCache.addMaterial("LightWallMaterial", { fabric: { type: "LightWallMaterial", uniforms: { uTime: 0, image: "./texture/spriteline2.png", }, source: ` czm_material czm_getMaterial(czm_materialInput materialInput) { // 生成默认的基础材质 czm_material material = czm_getDefaultMaterial(materialInput); vec2 st = materialInput.st; // 根据uv采样颜色,fract函数,保留小数部分 // vec4 color = texture2D(image, vec2(fract(st.x-uTime) , st.y)); vec4 color = texture2D(image, vec2(fract(st.y+uTime) , st.x )); material.diffuse = color.rgb; material.alpha = color.a; return material; }
`, }, });
this.params = { uTime: 0, }; gsap.to(this.params, { uTime: 1, duration: 1, repeat: -1, ease: "linear", }); } getType() { return "LightWallMaterial"; } getValue(time, result) { result.uTime = this.params.uTime; return result; } equals(other) { return ( other instanceof LightWallMaterialProperty && this.name === other.name ); } }
|
引用
App.jsx引用
1 2 3
| import LightWall from "./cesium/LightWall";
let lightWall = new LightWall(viewer);
|
烟花粒子特效
- src/cesium/ParticleLight.js
烟花粒子代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import * as Cesium from "cesium";
export default class ParticleLight { constructor(viewer, color = Cesium.Color.WHITE) { this.boxEntity = viewer.entities.add({ name: "box", position: Cesium.Cartesian3.fromDegrees( 121.53, 29.82, 100), box: { dimensions: new Cesium.Cartesian3(100.0, 100.0, 100), material: Cesium.Color.RED.withAlpha(0), }, });
var particleSystem = new Cesium.ParticleSystem({ image: "./texture/smoke.png", minimumImageSize: new Cesium.Cartesian2(10, 10), maximumImageSize: new Cesium.Cartesian2(30, 30), startColor: color, endColor: Cesium.Color.WHITE.withAlpha(0), startScale: 0.1, endScale: 2.0, minimumSpeed: 1.0, maximumSpeed: 10.0, emitter: new Cesium.BoxEmitter(new Cesium.Cartesian3(250, 250, 100)), emissionRate: 3, lifetime: 5.0, modelMatrix: this.boxEntity.computeModelMatrix( viewer.clock.currentTime, new Cesium.Matrix4() ), }); viewer.scene.primitives.add(particleSystem); } }
|
引入
在App.jsx中
1 2 3 4 5
| import ParticleLight from "./cesium/ParticleLight"; let particleLight = new ParticleLight(viewer, Cesium.Color.RED); let particleLight1 = new ParticleLight(viewer, Cesium.Color.AQUA); let particleLight2 = new ParticleLight(viewer, Cesium.Color.GREEN);
|
结语
好了,cesium这一块就暂时告一段落了,我把代码放在了https://gitee.com/guJyang/smart-city-cesium,再见