cesium 水面、淹没 效果

2022-11-26,,,

水面效果

参考:

 http://cesiumcn.org/topic/158.html

 http://api.rivermap.cn/cesium/rivermap/map.html

 https://blog.csdn.net/weixin_42496466/article/details/80747565

demo效果:

主要代码:

//绘制水面波浪效果
drawWater: function(){
this.viewer.scene.globe.depthTestAgainstTerrain = false;
var waterFace=[
130.0, 30.0, 0,
150.0, 30.0, 0,
150.0, 10.0, 0,
130.0, 10.0, 0];
var waterPrimitive = new Cesium.Primitive({
show:true,// 默认隐藏
allowPicking:false,
geometryInstances : new Cesium.GeometryInstance({
geometry : new Cesium.PolygonGeometry({
polygonHierarchy : new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights(waterFace)),
//extrudedHeight: 0,//注释掉此属性可以只显示水面
//perPositionHeight : true//注释掉此属性水面就贴地了
})
}),
// 可以设置内置的水面shader
appearance : new Cesium.EllipsoidSurfaceAppearance({
material : new Cesium.Material({
fabric : {
type : 'Water',
uniforms : {
//baseWaterColor:new Cesium.Color(0.0, 0.0, 1.0, 0.5),
//blendColor: new Cesium.Color(0.0, 0.0, 1.0, 0.5),
//specularMap: 'gray.jpg',
//normalMap: '../assets/waterNormals.jpg',
normalMap: '本地贴图地址 或 base64',
frequency: 1000.0,
animationSpeed: 0.01,
amplitude: 10.0
}
}
}),
fragmentShaderSource:'varying vec3 v_positionMC;\nvarying vec3 v_positionEC;\nvarying vec2 v_st;\nvoid main()\n{\nczm_materialInput materialInput;\nvec3 normalEC = normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nmaterialInput.s = v_st.s;\nmaterialInput.st = v_st;\nmaterialInput.str = vec3(v_st, 0.0);\nmaterialInput.normalEC = normalEC;\nmaterialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, materialInput.normalEC);\nvec3 positionToEyeEC = -v_positionEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef FLAT\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\
gl_FragColor.a=0.5;\n#endif\n}\n'//重写shader,修改水面的透明度
})
});
this.viewer.scene.primitives.add(waterPrimitive); this.viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(140, 20, 6000000.0),
orientation : {
heading: Cesium.Math.toRadians(0.0), //默认朝北0度,顺时针方向,东是90度
pitch: Cesium.Math.toRadians(-90), //默认朝下看-90,0为水平看,
roll: Cesium.Math.toRadians(0) //默认0
}
}); }

注意这里

this.viewer.scene.globe.depthTestAgainstTerrain = false;

淹没效果需要将其设置为 true;当其值为 true 时,水面效果  会出现缝隙,如下图所示。

贴图从参考链接中可获取,这里附上:

//pic.ikafan.com/imgp/L3Byb3h5L2h0dHAvYXBpLnJpdmVybWFwLmNuL2Nlc2l1bS9CdWlsZC9DZXNpdW1Vbm1pbmlmaWVkL0Fzc2V0cy9UZXh0dXJlcy93YXRlck5vcm1hbHMuanBn.jpg

淹没效果

参考:

 https://github.com/liyangis/sn_cesium

demo效果:

主要代码(包含未用到的热力图效果代码):

import Cesium from 'cesium/Source/Cesium'
import HeatMap from "../modules/heatmap";
// 淹没分析
export default class SubmergenceAnalysis {
constructor(viewer, isTerrain = true, height_max, height_min, step, map_type,positionsArr,speed) {
this.viewer = viewer
this.isTerrain = isTerrain
this.handler = null
this.tempEntities = []
this.polygonEntities = []
this.linePositionList = []
this.tempPoints = []
this.extrudedHeight = height_min
this.height_max = height_max
this.height_min = height_min
this.step = step
// 默认是范围图/深度图
this.map_type = map_type
this.polygon_degrees = positionsArr
this.speed = speed
//this._initViewStatus(this.viewer)
this._addDisListener()
}
_initViewStatus(viewer) {
var scene = viewer.scene
scene.globe.depthTestAgainstTerrain = true
viewer.camera.flyTo({
//scene.camera.setView({
// 摄像头的位置
destination: Cesium.Cartesian3.fromDegrees(108.9, 34, 5000.0),
orientation: {
heading: Cesium.Math.toRadians(0.0),//默认朝北0度,顺时针方向,东是90度
pitch: Cesium.Math.toRadians(-20),//默认朝下看-90,0为水平看,
roll: Cesium.Math.toRadians(0)//默认0
}
});
viewer.skyAtmosphere = false
}
// 根据矩形范围得到行列数点坐标和高程信息
_getPoints(xmin, xmax, ymin, ymax) {
const x_count = 10
const y_count = 10
let cartesians = new Array(x_count * y_count);
const x_d = (xmax - xmin) / x_count
for (var i = 0; i < x_count; ++i) {
const start_pt = { x: xmin + i * x_d, y: ymax }
const end_pt = { x: xmin + i * x_d, y: ymin }
for (let j = 0; j < y_count; j++) {
const offset = j / (y_count - 1);
const x = Cesium.Math.lerp(start_pt.x, end_pt.x, offset);
const y = Cesium.Math.lerp(start_pt.y, end_pt.y, offset);
cartesians[j + i * y_count] = Cesium.Cartographic.fromDegrees(x, y);
}
}
return cartesians }
_getHeights(cartesians, extrudedHeight, callback) { var terrainProvider = new Cesium.createWorldTerrain({
requestVertexNormals: true
})
// 根据地形计算某经纬度点的高度
var promise = Cesium.sampleTerrainMostDetailed(terrainProvider, cartesians);
Cesium.when(promise, function (updatedPositions) { let positions = updatedPositions.filter(d => {
const cartographic = d
if (cartographic) {
const h_d = extrudedHeight - cartographic.height
return h_d > 0
}
})
positions = positions.map(d => {
const cartographic = d
let h = extrudedHeight - cartographic.height
return {
x: Cesium.Math.toDegrees(cartographic.longitude),
y: Cesium.Math.toDegrees(cartographic.latitude),
value: h
} }) if (callback) { callback(positions)
}
});
} _addDisListener() {
let viewer = this.viewer
let scene = viewer.scene
let linePositionList = this.linePositionList
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
this.handler = new Cesium.ScreenSpaceEventHandler(scene.canvas)
// 绘制线
this._drawLine(linePositionList)
//this.loadGrandCanyon()
// 绘制面
if (this.map_type) {
this._drawPoly(this.polygon_degrees)
} else {
// 得到插值网格
const bounds = {
west: 115.8784,
east: 115.9614,
south: 39.9912,
north: 40.0381
} const positions_cartesian = this._getPoints(bounds.east, bounds.west, bounds.south, bounds.north)
this._getHeights(positions_cartesian, this.extrudedHeight, (d) => {
this.heatMapObj = new HeatMap(this.viewer, d, bounds);
})
} }
_reDraw() {
this.tempPoints = []
this.linePositionList.length = 0
this.areaPositionList.length = 0
for (let entity of this.tempEntities) {
this.viewer.entities.remove(entity)
}
this.tempEntities = []
} _drawLine(linePositionList) {
let lineStyle = {
width: 2,
material: Cesium.Color.CHARTREUSE
} let entity = this.viewer.entities.add({
polyline: lineStyle,
}) entity.polyline.positions = new Cesium.CallbackProperty(function () {
return linePositionList
}, false) this.polygonEntities.push(entity)
}
_drawPoint(point_Cartesian3) {
let entity =
this.viewer.entities.add({
position: point_Cartesian3,
point: {
pixelSize: 10,
color: Cesium.Color.GOLD,
// disableDepthTestDistance: Number.POSITIVE_INFINITY,
// heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
}
})
this.tempEntities.push(entity)
} _drawPoly(degrees) {
const that = this
let entity =
this.viewer.entities.add({
polygon: {
hierarchy: {},
material: new Cesium.Color.fromBytes(64, 157, 253, 100),
perPositionHeight: true, }
})
entity.polygon.hierarchy = new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(degrees))
entity.polygon.extrudedHeight = new Cesium.CallbackProperty(() => that.extrudedHeight, false)
this.polygonEntities.push(entity)
} // 世界坐标转经纬坐标
_car3ToLatLon(cartesian) {
let cartographic = Cesium.Cartographic.fromCartesian(cartesian)
let longitudeString = Cesium.Math.toDegrees(cartographic.longitude)
let latitudeString = Cesium.Math.toDegrees(cartographic.latitude)
return {
lon: longitudeString,
lat: latitudeString,
height: cartographic.height
}
} //移除整个资源
remove() {
let viewer = this.viewer
for (let tempEntity of this.tempEntities) {
viewer.entities.remove(tempEntity)
}
for (let lineEntity of this.polygonEntities) {
viewer.entities.remove(lineEntity)
}
this.handler.destroy()
}
start() {
const that = this
this.timer = window.setInterval(() => {
if ((that.height_max > that.extrudedHeight) && (that.extrudedHeight >= that.height_min)) {
that.extrudedHeight = that.extrudedHeight + that.step
} else {
that.extrudedHeight = that.height_min
}
if (!that.map_type) {
if (this.heatMapObj) {
const bounds = {
west: 115.8784,
east: 115.9614,
south: 39.9912,
north: 40.0381
}
const positions_cartesian = this._getPoints(bounds.east, bounds.west, bounds.south, bounds.north)
this._getHeights(positions_cartesian, this.extrudedHeight, (d) => {
this.heatMapObj.update(d);
})
}
} },that.speed*1000)
if (that.map_type) {
that._drawPoly(that.polygon_degrees)
} else {
if (this.heatMapObj) { } } }
clear() {
let viewer = this.viewer
if (this.timer) {
window.clearInterval(this.timer)
this.timer = null
}
this.extrudedHeight = this.height_min;
if (this.heatMapObj)
this.heatMapObj.show(false)
for (let entity of this.polygonEntities) {
viewer.entities.remove(entity)
}
viewer.skyAtmosphere = true; }
changeMapType(type) {
if (!type) {
if (!this.heatMapObj) {
// 得到插值网格
const bounds = {
west: 115.8784,
east: 115.9614,
south: 39.9912,
north: 40.0381
}
const positions_cartesian = this._getPoints(bounds.east, bounds.west, bounds.south, bounds.north)
this._getHeights(positions_cartesian, this.extrudedHeight, (d) => {
this.heatMapObj = new HeatMap(this.viewer, d, bounds);
})
} this.heatMapObj && this.heatMapObj.show(true)
for (let entity of this.polygonEntities) {
entity.show = false;
}
} else {
this.heatMapObj.show(false)
for (let entity of this.polygonEntities) {
entity.show = true;
}
}
} // 切割一部分地形
loadGrandCanyon() {
var globe = this.viewer.scene.globe;
const viewer = this.viewer
// viewer.skyAtmosphere = false,
// Pick a position at the Grand Canyon
var position = Cesium.Cartographic.toCartesian(new Cesium.Cartographic.fromDegrees(115.9165534, 40.0139345, 100));
var distance = 30000.0;
var boundingSphere = new Cesium.BoundingSphere(position, distance); globe.clippingPlanes = new Cesium.ClippingPlaneCollection({
modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(position),
planes: [
new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3(-1.0, 0.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, -1.0, 0.0), distance)
],
unionClippingRegions: true
});
globe.clippingPlanes.enabled = true;
viewer.camera.viewBoundingSphere(boundingSphere, new Cesium.HeadingPitchRange(0.5, -0.5, boundingSphere.radius * 5.0));
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
} }

 洪水淹没效果

在上一步的基础上,希望达到“洪水顺着河流向前淹没”效果

效果如下图:(注:只能在特定地区,特定观察角度,效果才会稍好一点

cesium 水面、淹没 效果的相关教程结束。

《cesium 水面、淹没 效果.doc》

下载本文的Word格式文档,以方便收藏与打印。