如何建立网站视频教程,免费推广神器,桂林网站定制建设,网络营销的方式和手段文章目录 0.引言1.视频材质2.分辨率尺度3.云4.雾5.动态水面6.雷达扫描7.流动线8.电子围栏9.粒子烟花10.粒子火焰11.粒子天气 0.引言
现有的gis开发方向较流行的是webgis开发#xff0c;其中Cesium是一款开源的WebGIS库#xff0c;主要用于实时地球和空间数据的可视化和分析。… 文章目录 0.引言1.视频材质2.分辨率尺度3.云4.雾5.动态水面6.雷达扫描7.流动线8.电子围栏9.粒子烟花10.粒子火焰11.粒子天气 0.引言
现有的gis开发方向较流行的是webgis开发其中Cesium是一款开源的WebGIS库主要用于实时地球和空间数据的可视化和分析。它提供了丰富的地图显示和数据可视化功能并能实现三维可视化开发。本文将使用一些特殊的材质如视频材质、自定义材质和Cesium内置的一些特殊效果类、粒子系统等实现一些特效场景的模拟包括云、雾、动态水面、雷达扫描、流动线、电子围栏、粒子烟花、粒子火焰及粒子天气等。
1.视频材质
对于通过Entity方式和Primitive方式创建的几何实体下面介绍如何给几何实体贴上一个特殊的材质即视频材质。 视频资源网址 https://cesium.com/public/SandcastleSampleData/big-buck-bunny_trailer.mp4 1实现代码
6_1_视频材质.html!DOCTYPE html
html langen head meta charsetUTF-8 meta http-equivX-UA-Compatible contentIEedge meta nameviewport contentwidthdevice-width, initial-scale1.0 title视频/title script src./Build/Cesium/Cesium.js/script link relstylesheet href./Build/Cesium/Widgets/widgets.css style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; } .toolbar { position: absolute; top: 10px; left: 20px; background-color: rgb(0, 0, 0, 0); } /style
/head body div idcesiumContainer /div div classtoolbar select iddropdown onchangechange() option valueedit1视频材质/option option valueedit2视频重复/option /select /div video idmyVideo mutedtrue autoplaytrue looptrue styledisplay: none; source src./vedio/big-buck-bunny_trailer.mp4 typevideo/mp4 /video script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { timeline: false, animation: false, fullscreenButton: false, }); //viewer.scene.globe.depthTestAgainstTerrain false; const videoElement document.getElementById(myVideo); //将视频元素与模拟时钟同步 let synchronizer new Cesium.VideoSynchronizer({ clock: viewer.clock, element: videoElement }); viewer.clock.shouldAnimate true; var sphere viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(104, 39, 2200), ellipsoid: { radii: new Cesium.Cartesian3(1000, 1000, 1000), material: videoElement, }, }); //相机视角锁定sphere viewer.trackedEntity sphere; //改变视频重复个数 var isRepeat false; sphere.ellipsoid.material.repeat new Cesium.CallbackProperty( function (result) { if (isRepeat) { result.x 8; result.y 8; } else { result.x 1; result.y 1; } return result; }, false ); var dropdown document.getElementById(dropdown); function change() { switch (dropdown.value) { case edit1: isRepeat false; break; case edit2: isRepeat true; break; default: break; } } /script
/body /html2结果显示
2.分辨率尺度
在Cesium中可以通过viewer.resolutionScale获取或者设置渲染分辨率的缩放比例。当该属性值小于1.0时可以改善性能不佳的设备的显示效果而当该属性值大于1.0时将以更快的速度呈现分辨率并缩小比例从而提高视觉保真度。例如如果窗口的尺寸为640像素×480像素则将viewer.resolutionScale的值设置为0.5会导致场景以320像素×240像素渲染之后设置为2.0会导致场景以1280像素×960像素渲染。 1实现代码
6_2_分辨率尺度.html!DOCTYPE html
html langen head meta charsetUTF-8 meta http-equivX-UA-Compatible contentIEedge meta nameviewport contentwidthdevice-width, initial-scale1.0 title材质特效篇_分辨率尺度/title script src./Build/Cesium/Cesium.js/script link relstylesheet href./Build/Cesium//Widgets/widgets.css style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } .toolbar { position: absolute; top: 10px; left: 20px; background-color: rgba(0, 0, 0, 0.6); } /style /head body div idcesiumContainer /div div classtoolbar label stylecolor: white;分辨率尺度/label br / input typerange max2 step0.1 oninputchange() idR value1 input typetext stylewidth:70px; idresolutionValue value1 onchangechange2() /div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 }); var tileset viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: ./倾斜摄影/大雁塔3DTiles/tileset.json, })); viewer.zoomTo(tileset); function change() { //拿到滑动条当前值 var resolutionScale Number(R.value); //将值约束在0.1和2.0之间 resolutionScale Cesium.Math.clamp(resolutionScale, 0.1, 2.0); //文本框显示当前值 resolutionValue.value resolutionScale; //修改分辨率尺度 viewer.resolutionScale resolutionScale; } function change2() { var resolutionScale Number(resolutionValue.value); //将值约束在0.1和2.0之间 resolutionScale Cesium.Math.clamp(resolutionScale, 0.1, 2.0); R.value resolutionScale; change(); } /script /body /html2结果显示 调整前 调整后
3.云
在模拟实际场景时可以通过CloudCollection类在场景中渲染云同时支持手动修改云的大小、亮度等来模拟积云。基本思路为先使用CloudCollection类创建一个云集合然后在云集合中添加定义的不同样式的云。 1实现代码
6_3_云.html!DOCTYPE html
html langen head meta charsetutf-8 / meta http-equivX-UA-Compatible contentIEedge / meta nameviewport contentwidthdevice-width, initial-scale1, maximum-scale1, minimum-scale1, user-scalableno / meta namedescription contentFog post process meta namecesium-sandcastle-labels contentShowcases, Post Processing title材质特效篇_云/title link relstylesheet href./Build/Cesium/Widgets/widgets.css script typetext/javascript src./Build/Cesium/Cesium.js/script /head
style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } .toolbar { position: absolute; top: 10px; left: 20px; color: white; background-color: rgba(0, 0, 0, 0.6); }
/style body div idcesiumContainer/div div classtoolbar labelX轴尺寸/label br / input typerange min5 max50 step1 oninputchangeScale() idScaleX value25 input typetext stylewidth:70px; idScaleXValue value25 onchangechangeScaleX() br labelY轴尺寸/label br / input typerange min5 max50 step1 oninputchangeScale() idScaleY value12 input typetext stylewidth:70px; idScaleYValue value12 onchangechangeScaleY() br label亮度/label br / input typerange min0 max1 step0.01 oninputchangeBrightness() idBrightness value1 input typetext stylewidth:70px; idBrightnessValue value1 onchangechangeBrightnessValue() br /div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 }); //创建并添加云集合 var clouds viewer.scene.primitives.add( new Cesium.CloudCollection({ noiseDetail: 16.0, }) ); //添加云 var cloud clouds.add({ position: Cesium.Cartesian3.fromDegrees(114.39264, 30.52252, 100), scale: new Cesium.Cartesian2(25, 12), slice: 0.36, brightness: 1, }) //设置相机位置及方向 viewer.camera.lookAt( Cesium.Cartesian3.fromDegrees(114.39264, 30.52252, 100), new Cesium.Cartesian3(30, 30, -10) ); var ScaleX document.getElementById(ScaleX); //X轴尺寸 var ScaleXValue document.getElementById(ScaleXValue); //ScaleX滑动条值 var ScaleY document.getElementById(ScaleY); //Y轴尺寸 var ScaleYValue document.getElementById(ScaleYValue); //ScaleY滑动条值 var Brightness document.getElementById(Brightness); //亮度 var BrightnessValue document.getElementById(BrightnessValue); //亮度滑动条值 //Scale滑动条 function changeScale() { //拿到scaleX滑动条当前值 var sX Number(ScaleX.value); //文本框显示当前值 ScaleXValue.value sX; //拿到scaleY滑动条当前值 var sY Number(ScaleY.value); //x轴旋转文本框显示当前值 ScaleYValue.value sY; //修改云的比例 cloud.scale new Cesium.Cartesian2(sX, sY); } //ScaleX文本框 function changeScaleX() { //拿到scaleX文本框的值并赋值给滑动条 ScaleX.value Number(ScaleXValue.value); changeScale(); } //ScaleY文本框 function changeScaleY() { //拿到scaleY文本框的值并赋值给滑动条 ScaleY.value Number(ScaleYValue.value); changeScale(); } //Brightness滑动条 function changeBrightness() { //拿到Brightness滑动条滑动条当前值 var brightness Number(Brightness.value); //文本框显示当前值 BrightnessValue.value brightness; //修改云的亮度 cloud.brightness brightness; } //Brightness文本框 function changeBrightnessValue() { //拿到文本框的值并赋值给滑动条 Brightness.value Number(BrightnessValue.value); changeBrightness(); } /script
/body /html2结果显示
4.雾
Cesium在1.46版本之后新增了场景后处理功能。所谓场景后处理我们可以将其理解为一个不断叠加的过程。例如我们拍了一张照片拍完之后觉得该照片亮度不够于是我们在该照片的基础上进行了亮度的调整得到了一张新照片然后觉得新照片不够好看又在新照片的基础上添加了滤镜此后我们可能还会进行多次处理直到最后得到的照片满足我们的要求为止这个过程就类似于场景后处理即我们在绘制场景时可能会不断地对场景进行一些处理将最终符合我们要求的处理结果绘制到屏幕上。下面通过Cesium的场景后处理功能来实现雾的效果。 1实现代码
6_4_雾效果.html!DOCTYPE html
html langen head meta charsetutf-8 / meta http-equivX-UA-Compatible contentIEedge / meta nameviewport contentwidthdevice-width, initial-scale1, maximum-scale1, minimum-scale1, user-scalableno / meta namedescription contentFog post process meta namecesium-sandcastle-labels contentShowcases, Post Processing title材质特效篇_雾效果/title link relstylesheet href./Build/Cesium/Widgets/widgets.css script typetext/javascript src./Build/Cesium/Cesium.js/script /head
style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; }
/style body div idcesiumContainer/div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 }); var tileset viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: ./倾斜摄影/大雁塔3DTiles/tileset.json, })); viewer.zoomTo(tileset); var fragmentShaderSource //计算每个渲染顶点和视点相机的距离 float getDistance(sampler2D depthTexture, vec2 texCoords) { float depth czm_unpackDepth(texture2D(depthTexture, texCoords)); if (depth 0.0) { return czm_infinity; } vec4 eyeCoordinate czm_windowToEyeCoordinates(gl_FragCoord.xy, depth); return -eyeCoordinate.z / eyeCoordinate.w; } //按距离进行插值 float interpolateByDistance(vec4 nearFarScalar, float distance) { float startDistance nearFarScalar.x; float startValue nearFarScalar.y; float endDistance nearFarScalar.z; float endValue nearFarScalar.w; float t clamp((distance - startDistance) / (endDistance - startDistance), 0.0, 1.0); return mix(startValue, endValue, t); } //计算透明度 vec4 alphaBlend(vec4 sourceColor, vec4 destinationColor) { return sourceColor * vec4(sourceColor.aaa, 1.0) destinationColor * (1.0 - sourceColor.a); } uniform sampler2D colorTexture; //颜色纹理 内置变量 uniform sampler2D depthTexture; //深度纹理 内置变量 varying vec2 v_textureCoordinates; //屏幕采样点坐标 内置变量 uniform vec4 fogByDistance; //自定义属性 外部变量 uniform vec4 fogColor; //自定义属性 外部变量 void main(void) { float distance getDistance(depthTexture, v_textureCoordinates); vec4 sceneColor texture2D(colorTexture, v_textureCoordinates); float blendAmount interpolateByDistance(fogByDistance, distance); vec4 finalFogColor vec4(fogColor.rgb, fogColor.a * blendAmount); gl_FragColor alphaBlend(finalFogColor, sceneColor); }; var postProcessStage new Cesium.PostProcessStage({ //片源着色器 fragmentShader: fragmentShaderSource, uniforms: { fogByDistance: new Cesium.Cartesian4(0, 0, 600, 1.0), //距离 fogColor: Cesium.Color.WHITE, //颜色 }, }) viewer.scene.postProcessStages.add(postProcessStage); /script
/body /html2结果显示
5.动态水面
模拟水面效果也是Cesium场景中常见的功能例如有的项目可能通过绘制实体面并设置材质为淡蓝色来模拟水面。但是在实际生活中水面往往不是静止的而是动态的下面通过修改水面的材质来实现动态水面的效果。动态水面的具体实现思路为先准备一张水面纹理图片然后通过Primitive方式创建一个矩形实体使用EllipsoidSurfaceAppearance定义一个水面材质并给矩形实体设置该材质即可实现简单的动态水面效果。 1实现代码
6_5_动态水面.html!DOCTYPE html
html langen head meta charsetUTF-8 meta http-equivX-UA-Compatible contentIEedge meta nameviewport contentwidthdevice-width, initial-scale1.0 title材质特效篇_动态水面/title script src./Build/Cesium/Cesium.js/script link relstylesheet href./Build/Cesium/Widgets/widgets.css style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } /style /head body div idcesiumContainer /div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 terrainProvider: Cesium.createWorldTerrain() }); viewer.scene.globe.depthTestAgainstTerrain true;//开启深度检测后 会有高程遮挡效果 var rectangle new Cesium.GeometryInstance({ geometry: new Cesium.RectangleGeometry({ rectangle: Cesium.Rectangle.fromDegrees(95.0, 39.0, 100.0, 42.0), height: 3500.0 }) }); //定义外观 var rectangleAppearance new Cesium.EllipsoidSurfaceAppearance({ aboveGround: true, material: new Cesium.Material({ fabric: { type: Water, //材质类型 uniforms: { //baseWaterColor: new Cesium.Color.fromBytes(24, 173, 247, 100),//基础颜色 normalMap: ./RasterImage/图片/动态水面.jpg, //法线纹理贴图 frequency: 100.0, //波的数量 animationSpeed: 0.01, //水波震动速度 amplitude: 10.0 //振幅大小 }, } }), //重写shader修改水面的透明度 fragmentShaderSource: varying vec3 v_positionMC;\n varying vec3 v_positionEC;\n varying vec2 v_st;\n void main()\n {\n czm_materialInput materialInput;\n vec3 normalEC normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\n #ifdef FACE_FORWARD\n normalEC faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n #endif\n materialInput.s v_st.s;\n materialInput.st v_st;\n materialInput.str vec3(v_st, 0.0);\n materialInput.normalEC normalEC;\n materialInput.tangentToEyeMatrix czm_eastNorthUpToEyeCoordinates(v_positionMC, materialInput.normalEC);\n vec3 positionToEyeEC -v_positionEC;\n materialInput.positionToEyeEC positionToEyeEC;\n czm_material material czm_getMaterial(materialInput);\n #ifdef FLAT\n gl_FragColor vec4(material.diffuse material.emission, material.alpha);\n #else\n gl_FragColor czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);\n gl_FragColor.a0.55;\n #endif\n }\n }); var addRectangleGeometry new Cesium.Primitive({ geometryInstances: rectangle, appearance: rectangleAppearance }) viewer.scene.primitives.add(addRectangleGeometry); viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(108, 42, 6000000), }) /script /body /html2结果显示
6.雷达扫描
使用飞机或无人机沿着飞行路线进行雷达扫描的效果在实际应用中是很常见的。在Cesium中实现雷达扫描效果的方法有很多可以通过对Entity实体贴纹理并对材质进行不断的旋转来实现或者通过着色器重写Entity实体的材质shader来实现。比较而言前者对于新手来说更容易实现下面通过第一种方法来模拟雷达扫描效果。 1实现代码
6_6_雷达扫描.html!DOCTYPE html
html langen head meta charsetUTF-8 meta http-equivX-UA-Compatible contentIEedge meta nameviewport contentwidthdevice-width, initial-scale1.0 title材质特效篇_雷达扫描/title script src./Build/Cesium/Cesium.js/script link relstylesheet href./Build/Cesium//Widgets/widgets.css style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } /style /head body div idcesiumContainer /div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 }); var rotation 0; //纹理旋转角度 var amount 4; //旋转变化量 var rader { position: Cesium.Cartesian3.fromDegrees(114.40372, 30.52252), ellipse: { semiMajorAxis: 300.0, semiMinorAxis: 300.0, //指定材质 material: new Cesium.ImageMaterialProperty({ image: ./RasterImage/图片/color.png, color: new Cesium.Color(1.0, 0.0, 0.0, 0.7), }), // 不设置高度则无法渲染外框线 height: 0.0, //heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, //外边框 outline: true, outlineWidth: 2, outlineColor: new Cesium.Color(1.0, 1.0, 0.0, 1.0), //纹理旋转角度通过CallbackProperty回调 stRotation: new Cesium.CallbackProperty(function () { rotation amount; if (rotation 360 || rotation -360) { rotation 0; } //度数转弧度 return Cesium.Math.toRadians(rotation); }, false) } } //将rader添加进entity集合 viewer.entities.add(rader) var point viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(114.40372, 30.52252), point: { pixelSize: 10, color: Cesium.Color.RED, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND } }); viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(114.40372, 30.52252, 2000) }); /script /body /html2结果显示
7.流动线
Cesium中有许多封装好的内置纹理如条纹、颜色、虚线、棋盘、水面等但是这些内置纹理大多是静态的并不能满足我们在实际开发中的需求这时就需要我们通过自定义材质来达到特定的纹理效果。 自定义材质可以通过现有的内置材质派生也可以使用Fabric和GLSL来自定义。但是在实际开发中为了减少代码冗余我们通常将常用的自定义材质封装成一个个Material材质类以便复用下面将介绍如何封装一个自定义流动线材质类。 1实现代码
6_7_流动线.html!DOCTYPE html
html langen head meta charsetUTF-8 meta http-equivX-UA-Compatible contentIEedge meta nameviewport contentwidthdevice-width, initial-scale1.0 title材质特效篇_流动线/title script src./Build/Cesium/Cesium.js/script link relstylesheet href./Build/Cesium/Widgets/widgets.css script src./Build/js/jquery.min.js/script style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } /style
/head body div idcesiumContainer /div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: true, //是否显示动画工具 timeline: true, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 }); /* console.log(selectionIndicator,viewer.selectionIndicator); $(.cesium-viewer-selectionIndicatorContainer).css(display,none); */ viewer.scene.fxaa false viewer.scene.postProcessStages.fxaa.enabled false; var supportsImageRenderingPixelated viewer.cesiumWidget._supportsImageRenderingPixelated; if (supportsImageRenderingPixelated) { var vtxf_dpr window.devicePixelRatio; while (vtxf_dpr 2.0) { vtxf_dpr / 2.0; } viewer.resolutionScale vtxf_dpr; } //创建构造函数 function PolylineTrailLinkMaterialProperty(color, duration) { this._definitionChanged new Cesium.Event(); this._color undefined; this._colorSubscription undefined; this.color color; this.duration duration; this._time (new Date()).getTime(); } //Object.defineProperties() 方法直接在一个对象上定义新的属性或修改现有属性并返回该对象。 //Object.defineProperties(obj, props) //obj:在其上定义或修改属性的对象 props:要定义其可枚举属性或修改的属性描述符的对象。 Object.defineProperties(PolylineTrailLinkMaterialProperty.prototype, { isConstant: { get: function () { return false; } }, definitionChanged: { get: function () { return this._definitionChanged; } }, color: Cesium.createPropertyDescriptor(color) }); PolylineTrailLinkMaterialProperty.prototype.getType function (time) { return PolylineTrailLink; } PolylineTrailLinkMaterialProperty.prototype.getValue function (time, result) { if (!Cesium.defined(result)) { result {}; } result.color Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color); result.image Cesium.Material.PolylineTrailLinkImage; result.time (((new Date()).getTime() - this._time) % this.duration) / this.duration; return result; } PolylineTrailLinkMaterialProperty.prototype.equals function (other) { return this other || (other instanceof PolylineTrailLinkMaterialProperty amp;amp; Property.equals(this._color, other._color)) }; Cesium.PolylineTrailLinkMaterialProperty PolylineTrailLinkMaterialProperty; //纹理类型 Cesium.Material.PolylineTrailLinkType PolylineTrailLink; //纹理图片 Cesium.Material.PolylineTrailLinkImage ./RasterImage/图片/color.png; //纹理资源 Cesium.Material.PolylineTrailLinkSource czm_material czm_getMaterial(czm_materialInput materialInput)\n\ {\n\ float time czm_frameNumber/100.0;\n\ czm_material material czm_getDefaultMaterial(materialInput);\n\ vec2 st materialInput.st;\n\ vec4 colorImage texture2D(image, vec2(fract(3.0*st.s - time), st.s));\n\ material.alpha colorImage.a * color.a;\n\ material.diffuse (colorImage.rgbcolor.rgb)/2.0;\n\ return material;\n\ }; //time越小速度越慢 //colorImage控制纹理 //fract中 3.0是纹理个数 -time是逆时针 time是顺时针 //alpha 透明度 //diffuse 颜色 /* czm_material czm_getMaterial(czm_materialInput materialInput)\n\ {\n\ czm_material material czm_getDefaultMaterial(materialInput);\n\ vec2 st materialInput.st;\n\ vec4 colorImage texture2D(image, vec2(fract(st.s - time), st.t));\n\ material.alpha colorImage.a * color.a;\n\ material.diffuse (colorImage.rgbcolor.rgb)/2.0;\n\ return material;\n\ } */ //添加自定义材质 Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineTrailLinkType, { fabric: { //纹理类型 type: Cesium.Material.PolylineTrailLinkType, //传递给着色器的外部属性 uniforms: { color: new Cesium.Color(0.0, 0.0, 0.0, 1), image: Cesium.Material.PolylineTrailLinkImage, time: 0 }, //纹理资源 source: Cesium.Material.PolylineTrailLinkSource }, //是否透明 translucent: function (material) { return true; } }) var line viewer.entities.add({ name: PolylineTrailLink, polyline: { positions: Cesium.Cartesian3.fromDegreesArray([ 118.286419, 31.864436, 119.386419, 31.864436, 119.386419, 32.864436, 118.686419, 32.864436, ]), width: 10, //设置材质为自定义材质 material: new Cesium.PolylineTrailLinkMaterialProperty( Cesium.Color.fromBytes(255, 0, 0).withAlpha(0.8), /* 1000 */ ), } }); viewer.flyTo(line) /script
/body /html2结果显示
8.电子围栏
下面封装一个自定义电子围栏材质类能够对Entity墙体贴动态材质实现电子围栏效果。封装自定义电子围栏材质类的流程和封装自定义流动线材质类的流程一样。 1实现代码
6_8_电子围栏.html!DOCTYPE html
html langen head meta charsetUTF-8 meta http-equivX-UA-Compatible contentIEedge meta nameviewport contentwidthdevice-width, initial-scale1.0 title材质特效篇_电子围栏/title script src./Build/Cesium/Cesium.js/script link relstylesheet href./Build/Cesium/Widgets/widgets.css style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } /style
/head body div idcesiumContainer /div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 }); function DynamicWallMaterialProperty(color, duration) { this._definitionChanged new Cesium.Event(); this._color undefined; this._colorSubscription undefined; this.color color; this.duration duration; this._time (new Date()).getTime(); } Object.defineProperties(DynamicWallMaterialProperty.prototype, { isConstant: { get: function () { return false; } }, definitionChanged: { get: function () { return this._definitionChanged; } }, color: Cesium.createPropertyDescriptor(color) }); DynamicWallMaterialProperty.prototype.getType function (time) { return DynamicWall; } DynamicWallMaterialProperty.prototype.getValue function (time, result) { if (!Cesium.defined(result)) { result {}; } result.color Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color); result.image Cesium.Material.DynamicWallImage; result.time (((new Date()).getTime() - this._time) % this.duration) / this.duration; return result; } DynamicWallMaterialProperty.prototype.equals function (other) { return this other || (other instanceof DynamicWallMaterialProperty amp;amp; Property.equals(this._color, other._color)) }; Cesium.DynamicWallMaterialProperty DynamicWallMaterialProperty; Cesium.Material.DynamicWallType DynamicWall; Cesium.Material.DynamicWallImage ./RasterImage/图片/color.png;//图片 Cesium.Material.DynamicWallSource czm_material czm_getMaterial(czm_materialInput materialInput) { float time czm_frameNumber/100.0; czm_material material czm_getDefaultMaterial(materialInput); vec2 st materialInput.st; vec4 colorImage texture2D(image, vec2(fract(1.0*st.t - time), st.t)); material.alpha colorImage.a * color.a; material.diffuse (colorImage.rgbcolor.rgb)/2.0; return material; } //由上到下 //添加自定义材质 Cesium.Material._materialCache.addMaterial(Cesium.Material.DynamicWallType, { fabric: { //纹理类型 type: Cesium.Material.DynamicWallType, //传递给着色器的外部属性 uniforms: { color: new Cesium.Color(0.0, 0.0, 0.0, 1), image: Cesium.Material.DynamicWallImage, time: 0 }, //纹理资源 source: Cesium.Material.DynamicWallSource }, //是否透明 translucent: function (material) { return true; } }) var dynamicWall viewer.entities.add({ wall: { positions: Cesium.Cartesian3.fromDegreesArrayHeights([ 118.286419, 31.864436, 20000.0, 119.386419, 31.864436, 20000.0, 119.386419, 32.864436, 20000.0, 118.286419, 32.864436, 20000.0, 118.286419, 31.864436, 20000.0, ]), material: new Cesium.DynamicWallMaterialProperty(Cesium.Color.fromBytes(255, 200, 10).withAlpha(0.8), 3000), } }) viewer.flyTo(dynamicWall) /script
/body /html2结果显示
9.粒子烟花
粒子系统表示三维计算机图形学中用于模拟一些特定模糊现象的技术而这些现象用其他传统的渲染技术难以实现其真实感的物理运动规律。经常使用粒子系统模拟的现象有烟花、火焰、雨水及雪花等。简而言之粒子系统就是一种用于模拟真实现象的图形技术是由一个个的小图像集合而成的从远处看会形成一个“复杂”的场景来模拟一些现象。 Cesium粒子系统不仅是多个小图像的直接集合而且允许控制单个粒子的寿命、速度、位置等属性也正是由于粒子的各种属性可以控制才能够模拟各种复杂的场景。粒子系统效果在电影和电子游戏中应用广泛。下面使用粒子系统模拟烟花爆炸效果。 1实现代码
6_9_粒子烟花.html!DOCTYPE html
html langen head meta charsetutf-8 / meta http-equivX-UA-Compatible contentIEedge / meta namedescription contentParticle system fireworks. meta namecesium-sandcastle-labels contentBeginner, Showcases title材质特效篇_粒子烟花/title link relstylesheet href./Build/Cesium/Widgets/widgets.css script src./Build/Cesium/Cesium.js/script /head
style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; }
/style body div idcesiumContainer/div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 shouldAnimate: true, //必须开启,自动播放动画 }); /* Cesium.Math.setRandomNumberSeed(315); */ //东北天到指定原点变换矩阵,将粒子系统从模型坐标转换为世界坐标 const modelMatrix Cesium.Transforms.eastNorthUpToFixedFrame( Cesium.Cartesian3.fromDegrees(114.39664, 30.52052) ); //粒子发射器高度 const emitterInitialLocation new Cesium.Cartesian3(0.0, 0.0, 100.0); //粒子贴图 var particleCanvas; //绘制图形 function getImage() { if (!Cesium.defined(particleCanvas)) { particleCanvas document.createElement(canvas); particleCanvas.width 20; particleCanvas.height 20; const context2D particleCanvas.getContext(2d); context2D.beginPath(); //圆心x 圆心y 半径 起始角度 终止角度 逆时针 context2D.arc(10, 10, 8, 0, Cesium.Math.TWO_PI, true); context2D.closePath(); context2D.fillStyle rgba(255, 255, 255, 1); context2D.fill(); } return particleCanvas; } /* var radar viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees(114.40072, 30.51952, 114.40572, 30.52452), material: new Cesium.ImageMaterialProperty({ //image: new Cesium.CallbackProperty(drawCanvas, false), image:getImage(), //transparent: true }), } }); */ /* const minimumExplosionSize 30.0; //最小爆炸尺寸 const maximumExplosionSize 100.0; //最大爆炸尺寸 */ var particlePixelSize new Cesium.Cartesian2(7.0, 7.0); //粒子大小 var burstNum 400.0; //爆炸粒子个数 var lifetime 10.0; //粒子系统发射粒子的时间 var numberOfFireworks 20.0; //烟花个数 //创建烟花函数 function createFirework(offset, color, bursts) { var position Cesium.Cartesian3.add( emitterInitialLocation, offset, new Cesium.Cartesian3() ); //从发射位置创建表示转换的Matrix4 var emitterModelMatrix Cesium.Matrix4.fromTranslation(position); //随机设置烟花的生命周期 /* const size Cesium.Math.randomBetween( minimumExplosionSize, maximumExplosionSize ); const normalSize (size - minimumExplosionSize) / (maximumExplosionSize - minimumExplosionSize); const minLife 0.3; const maxLife 1.0; const life normalSize * (maxLife - minLife) minLife; */ viewer.scene.primitives.add( new Cesium.ParticleSystem({ image: getImage(), //粒子贴图 startColor: color, //粒子在其生命初期的颜色 endColor: color.withAlpha(0.0),//粒子在其生命结束的颜色 //particleLife: life, //粒子生命周期 particleLife: 1, //粒子生命周期 speed: 100.0, //粒子扩散速度 imageSize: particlePixelSize, //粒子像素大小 emissionRate: 0, //每秒要发射的粒子数 emitter: new Cesium.SphereEmitter(0.1), //系统粒子发射器 bursts: bursts, //粒子爆炸,ParticleBurst 的数组 lifetime: lifetime, //粒子系统发射粒子的时间 //updateCallback: force, //每帧都要调用一次回调函数以更新粒子 modelMatrix: modelMatrix, //将粒子系统从模型转换为世界坐标的4x4转换矩阵。 emitterModelMatrix: emitterModelMatrix,//在粒子系统局部坐标系内转换粒子系统发射器的4x4转换矩阵 loop: true //粒子循环爆发 }) ); } //粒子发射器偏移量范围 var xMin -100.0; var xMax 100.0; var yMin -80.0; var yMax 100.0; var zMin -50.0; var zMax 50.0; //设置随机颜色选项数组 var colorOptions [ { minimumRed: 0.75, green: 0.0, minimumBlue: 0.8, alpha: 1.0, }, { red: 0.0, minimumGreen: 0.75, minimumBlue: 0.8, alpha: 1.0, }, { red: 0.0, green: 0.0, minimumBlue: 0.8, alpha: 1.0, }, { minimumRed: 0.75, minimumGreen: 0.75, blue: 0.0, alpha: 1.0, }, ]; //创建烟花 for (let i 0; i numberOfFireworks; i) { var x Cesium.Math.randomBetween(xMin, xMax); var y Cesium.Math.randomBetween(yMin, yMax); var z Cesium.Math.randomBetween(zMin, zMax); var offset new Cesium.Cartesian3(x, y, z); //使用提供的选项创建随机颜色 var color Cesium.Color.fromRandom( colorOptions[i % colorOptions.length] ); //粒子爆炸,ParticleBurst 的数组,在周期时间发射粒子爆发 var bursts []; for (let j 0; j 3; j) { bursts.push( new Cesium.ParticleBurst({ time: Cesium.Math.nextRandomNumber() * lifetime, //粒子系统生命周期开始后以秒为单位的时间将发生爆发 minimum: burstNum, //爆发中发射的最小粒子数。 maximum: burstNum, //爆发中发射的最大粒子数。 }) ); } //传参创建烟花 createFirework(offset, color, bursts); } viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(114.39664, 30.52052, 2000) }) /script
/body /html2结果显示
10.粒子火焰
下面使用Cesium粒子系统模拟火焰燃烧效果。 1实现代码
6_10_粒子火焰.html!DOCTYPE html
html langen head meta charsetutf-8 / meta http-equivX-UA-Compatible contentIEedge / meta namedescription contentParticle system fireworks. meta namecesium-sandcastle-labels contentBeginner, Showcases title材质特效篇_粒子火焰/title link relstylesheet href./Build/Cesium/Widgets/widgets.css script src./Build/Cesium/Cesium.js/script /head
style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; }
/style body div idcesiumContainer/div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 shouldAnimate: true, //必须开启 自动播放动画 }); // 加载飞机模型 var entity viewer.entities.add({ model: { uri: ./3D格式数据/glb/Cesium_Air.glb, minimumPixelSize: 64 }, position: Cesium.Cartesian3.fromDegrees(114.39264, 30.52252, 100) }); //视角追踪模型 viewer.trackedEntity entity; //计算把粒子系统从模型坐标系转到世界坐标系指定原点的矩阵 const modelMatrix Cesium.Transforms.eastNorthUpToFixedFrame( Cesium.Cartesian3.fromDegrees(114.39264, 30.52252, 100) ); //计算模型坐标系的平移矩阵 function computeEmitterModelMatrix() { //定义粒子发射器的方向、俯仰角以及翻滚角 var hpr Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, new Cesium.HeadingPitchRoll()); //定义一个由平移旋转和缩放定义的仿射变换 var trs new Cesium.TranslationRotationScale(); //火焰位置 //平移 trs.translation Cesium.Cartesian3.fromElements(2.5, 4.0, 1.0, new Cesium.Cartesian3()); //旋转 trs.rotation Cesium.Quaternion.fromHeadingPitchRoll(hpr, new Cesium.Quaternion()); return Cesium.Matrix4.fromTranslationRotationScale(trs, new Cesium.Matrix4()); } var particleSystem new Cesium.ParticleSystem({ image: ./RasterImage/图片/fire.png, startScale: 1.0, //开始比例 endScale: 4.0, //结束比例 particleLife: 1.0, //粒子生命周期 speed: 5.0, //粒子速度 imageSize: new Cesium.Cartesian2(20, 20), //粒子图形尺寸 emissionRate: 5.0, //每秒发射粒子个数 lifetime: 16.0, //粒子系统发射粒子的时间 modelMatrix: modelMatrix, //将粒子系统从模型转换为世界坐标的4x4转换矩阵 emitterModelMatrix: computeEmitterModelMatrix() //在粒子系统局部坐标系内转换粒子系统发射器的4x4转换矩阵 }) viewer.scene.primitives.add(particleSystem); /script
/body /html2结果显示
11.粒子天气
常见的粒子特效还有雨、雪等粒子天气特效下面使用Cesium粒子系统模拟天气特效包括下雨天与下雪天两种情况。 1实现代码
6_11_粒子天气.html!DOCTYPE html
html langen head meta charsetutf-8 / meta http-equivX-UA-Compatible contentIEedge / meta namedescription contentParticle system fireworks. meta namecesium-sandcastle-labels contentBeginner, Showcases title材质特效篇_粒子天气/title link relstylesheet href./Build/Cesium/Widgets/widgets.css script src./Build/Cesium/Cesium.js/script /head
style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } .toolbar { position: absolute; top: 10px; left: 20px; background-color: rgb(0, 0, 0, 0); }
/style body div idcesiumContainer/div div classtoolbar select iddropdown onchangechange() option valuesnow雪/option option valuerain雨/option option valuenullnull/option /select /div script Cesium.Ion.defaultAccessToken 你的token; var viewer new Cesium.Viewer(cesiumContainer, { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 shouldAnimate: true, //必须开启 terrainProvider: Cesium.createWorldTerrain(), }); //粒子特效位置 var position new Cesium.Cartesian3.fromDegrees(114.39664, 30.52052, 2000); var modelMatrix new Cesium.Matrix4.fromTranslation(position) //模拟下雪天粒子特效常量定义 const snowRadius 100000.0; //下雪的范围半径 const minimumSnowImageSize new Cesium.Cartesian2(10, 10); //雪花最小尺寸 const maximumSnowImageSize new Cesium.Cartesian2(20, 20); //雪花最大尺寸 //创建Cartesian3对象用于在回调函数中实时更新粒子位置 var snowGravityScratch new Cesium.Cartesian3(); //粒子更新回调函数 function snowUpdate (particle) { //计算提供的笛卡尔坐标系的标准化形式 Cesium.Cartesian3.normalize( particle.position, //要标准化的笛卡尔坐标 snowGravityScratch //结果存储对象 ); //将提供的笛卡尔分量乘以标准的标量 Cesium.Cartesian3.multiplyByScalar( snowGravityScratch, //要缩放的笛卡尔坐标 //要与之相乘的标量负值代表粒子位置下降即粒子从上往下落 Cesium.Math.randomBetween(-30.0, -300.0), snowGravityScratch //结果存储对象 ); //粒子位置根据snowGravityScratch变化 Cesium.Cartesian3.add( particle.position, snowGravityScratch, particle.position ); }; // 雨 const rainRadius 100000.0; //下雨的范围半径 const rainImageSize new Cesium.Cartesian2(20, 35); //15,30分别代表宽高 var rainGravityScratch new Cesium.Cartesian3(); //粒子更新回调函数 function rainUpdate (particle) { //计算提供的笛卡尔坐标系的标准化形式 Cesium.Cartesian3.normalize( particle.position, //要标准化的笛卡尔坐标 rainGravityScratch //结果存储对象 ); //将提供的笛卡尔分量乘以标准的标量 Cesium.Cartesian3.multiplyByScalar( rainGravityScratch, //要缩放的笛卡尔坐标 -1000.0, //要与之相乘的标量雨比雪下落速度快的多 所以这个值负的多点 rainGravityScratch //结果存储对象 ); //粒子位置根据rainGravityScratch变化 Cesium.Cartesian3.add( particle.position, rainGravityScratch, particle.position ); }; //粒子系统-雪配置项 var snowOption { modelMatrix: modelMatrix, //将粒子系统从模型转换为世界坐标的4x4转换矩阵。 lifetime: 15.0, //粒子系统发射粒子的时间以秒为单位 emitter: new Cesium.SphereEmitter(snowRadius), //该系统的粒子发射器 startScale: 0.5, //在粒子寿命开始时应用于粒子图像的初始比例 endScale: 1.0, //在粒子寿命结束时应用于粒子图像的最终比例。 image: ./RasterImage/图片/snowflake_particle.png, //粒子贴图 emissionRate: 7000.0, //每秒要发射的粒子数 startColor: Cesium.Color.WHITE.withAlpha(0.0), //粒子在其生命初期的颜色。 endColor: Cesium.Color.WHITE.withAlpha(1.0), //粒子寿命结束时的颜色。 minimumImageSize: minimumSnowImageSize, //设置宽度的最小范围以高度为单位在该范围上可以随机缩放粒子图像的尺寸(以像素为单位) maximumImageSize: maximumSnowImageSize, //设置最大宽度边界以高度为单位在该边界以下可以随机缩放粒子图像的尺寸(以像素为单位) updateCallback: snowUpdate, //每帧都要调用一次回调函数以更新粒子 } //粒子系统-雨配置项 var rainOption { modelMatrix: modelMatrix,//将粒子系统从模型转换为世界坐标的4x4转换矩阵。 lifetime: 15.0,//粒子系统发射粒子的时间以秒为单位 emitter: new Cesium.SphereEmitter(rainRadius),//该系统的粒子发射器 startScale: 1.0,//在粒子寿命开始时应用于粒子图像的初始比例 endScale: 0.0,//在粒子寿命结束时应用于粒子图像的最终比例。 image: ./RasterImage/图片/circular_particle.png,//粒子贴图 emissionRate: 9000.0,//每秒要发射的粒子数 startColor: new Cesium.Color(1, 1, 1, 0.0),//粒子在其生命初期的颜色。 endColor: new Cesium.Color(1.0, 1.0, 1.0, 0.98),//粒子寿命结束时的颜色。 imageSize: rainImageSize,//粒子贴图尺寸 updateCallback: rainUpdate,//每帧都要调用一次回调函数以更新粒子 } //默认下雪天 viewer.scene.primitives.add(new Cesium.ParticleSystem(snowOption)); //下拉框回调函数 var dropdown document.getElementById(dropdown); function change() { switch (dropdown.value) { case snow: viewer.scene.primitives.removeAll(); viewer.scene.primitives.add(new Cesium.ParticleSystem(snowOption)); break; case rain: viewer.scene.primitives.removeAll(); viewer.scene.primitives.add(new Cesium.ParticleSystem(rainOption)); break; case null: viewer.scene.primitives.removeAll(); break; default: break; } } //设置相机视角 /* viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(114.39664, 30.40052, 10000), orientation: { heading: 4.731089976107251, pitch: -0.32003481981370063, }, }) */ //设置相机初始位置 viewer.scene.camera.setView({ destination: new Cesium.Cartesian3(-2318006.190591779, 5016113.738321363,3239729.8052793955), orientation: { heading: 5.0433812878480655, pitch: -0.25943108890985744, roll: 0.000002292722656171975 }, duration: 0.0 }); /script
/body /html2结果显示 cesium文章涉及数据
参考资料 [1] 郭明强. 《WebGIS之Cesium三维软件开发》; 2023-04-01 [accessed 2024-01-27]. [2] WaqarLeaver. Cesium开源water材质和粒子效果示例代码研究; 2021-05-30 [accessed 2024-01-27]. [3] GIS兵墩墩. C2——cesium流动特效; 2020-11-04 [accessed 2024-01-27]. [4] 那那那那那么长的哲尘. Cesium实现流动线/动态纹理; 2024-01-11 [accessed 2024-01-27].