通过cesium实现空间点对地面圆周的发散效果
图片效果

需求:
1.实现空间某一点到地面圆的发散效果
2.地面圆有一定高度。
3.线条要有动画,圆要旋转
思路:
1.圆使用cesium中的wall实现,将圆拆分成多份,将多份wall拼接成圆。
2.拆分点的需要通过终止点进行计算,需要将经纬度点转换成笛卡尔坐标系的点,然后求出当前点的对应法向量(Cesium.eastNorthUpToFixedFrame)。
3.线条间隔通过material中的fbric中的glsl修改纹理的局部展示不展示。
4.墙体旋转和线条的运动通过scene中的preRender函数进行监听,然后实时修改
代码实现:
//cesiumContainer.js
import * as Cesium from 'cesium'
import { shaderLines } from './shader.js'
class CesiumContainer {
constructor(params) {
this.viewer = null
this.scene = null
this.camera = null
this.host = params.host
this.wallData = null
this.startLongitude = null
this.startLatitude = null
this.height = null
this.radius = null
this.step = null
this.wallHeight = null
this.distance = null
this.primitiveLine = null
this.pointNormal = null
this.primitiveWall = null
this.material = null
this.sourceFbric = null
}
}
Object.assign(CesiumContainer.prototype, {
init() {
this.setToken()
const params = {}
this.viewer = new Cesium.Viewer('viewer-container', params)
this.scene = this.viewer.scene
this.camera = this.viewer.scene.camera
this.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(120, 42, 1100),
orientation: {
heading: Cesium.Math.toRadians(-112),
pitch: Cesium.Math.toRadians(-12),
rool: 0.0
},
duration: 0
})
this.createDTWallLine(120, 42, 10000, 1000, 10000, 32) // 墙线中心点位置,高度,半径长度,墙步长
},
setToken() {
Cesium.Ion.defaultAccessToken = 'xxx'
},
createDTWallLine(startLongitude, startLatitude, height, wallHeight, radius, step = 8) {
this.startLongitude = startLongitude;
this.startLatitude = startLatitude;
this.height = height;
this.radius = radius;
this.step = step;
this.wallHeight = wallHeight
this.distance = radius
this.pointNormal = Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(Cesium.Cartesian3.fromDegrees(this.startLongitude, this.startLatitude, 0), new Cesium.Cartesian3())
// 获取拆分点
this.getAllPoints()
this.createWall();
// 绘制线条
this.createDtLine();
this.ainimaton();
},
createWall() {
const wallGeometries = []
this.wallData.forEach((line, index) => {
let wallGeometry
if(index !== this.wallData.length - 1) {
wallGeometry = new Cesium.WallGeometry({
positions: Cesium.Cartesian3.fromDegreesArrayHeights([
line[0], line[1], 0,
line[0], line[1], line[2],
this.wallData[index + 1][0], this.wallData[index + 1][1], 0,
this.wallData[index + 1][0], this.wallData[index + 1][1], this.wallData[index + 1][2],
]),
})
} else {
wallGeometry = new Cesium.WallGeometry({
positions: Cesium.Cartesian3.fromDegreesArrayHeights([
line[0], line[1], 0,
line[0], line[1], line[2],
this.wallData[0][0], this.wallData[0][1], 0,
this.wallData[0][0], this.wallData[0][1], this.wallData[0][2],
]),
})
}
wallGeometries.push(wallGeometry)
})
const wallInstanceFir = [];
const wallInstanceSec = []
wallGeometries.forEach((elt, index) => {
if(index % 2 ===1) {
wallInstanceFir.push(
new Cesium.GeometryInstance({
geometry: elt,
attributes : {
color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE)
}
})
)
} else {
wallInstanceSec.push(
new Cesium.GeometryInstance({
geometry: elt,
attributes : {
color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE)
}
})
)
}
})
this.primitiveWall = this.viewer.scene.primitives.add(new Cesium.Primitive({
geometryInstances: [...wallInstanceSec, ...wallInstanceFir],
appearance: new Cesium.PerInstanceColorAppearance()
}))
},
createDtLine() {
this.sourceFbric = shaderLines()
let polylineCollection = new Cesium.PolylineCollection();
this.material = new Cesium.Material({
fabric: {
source: this.sourceFbric,
uniforms: {
color: Cesium.Color.fromCssColorString('rgb(255, 0, 0)'),
other: 0,
}
},
// translucent: true
})
this.wallData.forEach(line => {
polylineCollection.add({
positions: [
Cesium.Cartesian3.fromDegrees(this.startLongitude, this.startLatitude, this.height),
Cesium.Cartesian3.fromDegrees(line[0], line[1], line[2])
],
width: 5,
material: this.material
});
})
this.primitiveLine = this.viewer.scene.primitives.add(polylineCollection)
},
getAllPoints() {
const startCartographic = new Cesium.Cartographic(Cesium.Math.toRadians(this.startLongitude), Cesium.Math.toRadians(this.startLatitude), 0.0);
const startCartesian = Cesium.Ellipsoid.WGS84.cartographicToCartesian(startCartographic);
const transform = Cesium.Transforms.eastNorthUpToFixedFrame(startCartesian);
//根据步长计算x,y偏移量
this.wallData = [];
for (let i= 0; i < this.step; i++) {
const distanceX = this.distance * Math.cos(2 * Math.PI * i / this.step);
const distanceY = this.distance * Math.sin(2 * Math.PI * i / this.step);
const offsetInENU = new Cesium.Cartesian3(distanceX, distanceY, 0.0);
const newCartesian = Cesium.Matrix4.multiplyByPoint(transform, offsetInENU, new Cesium.Cartesian3());
const newCartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(newCartesian);
const newLongitude = Cesium.Math.toDegrees(newCartographic.longitude);
const newLatitude = Cesium.Math.toDegrees(newCartographic.latitude);
this.wallData.push(
[
newLongitude, newLatitude, this.wallHeight
]
)
}
},
ainimaton() {
let angle = 1.0;
let other = 0.125;
this.viewer.scene.preRender.addEventListener((scene, time) => {
if(this.primitiveLine && this.pointNormal) {
angle += 0.002;
const quaternionRot = Cesium.Quaternion.fromAxisAngle(this.pointNormal, angle, new Cesium.Quaternion()) ;
const finalMatrix = Cesium.Matrix4.fromTranslationQuaternionRotationScale(new Cesium.Cartesian3(0.0, 0.0, 0.0), quaternionRot, new Cesium.Cartesian3(1.0, 1.0, 1.0));//Cesium.Matrix4.multiply(Cesium.Matrix4.fromTranslation(Cesium.Cartesian4.fromCartesian3(this.pointNormal)), rotatedMatrix, new Cesium.Matrix4());
this.primitiveLine.modelMatrix = finalMatrix;
this.primitiveWall.modelMatrix = finalMatrix;
other -= 0.001;
if(other <= -0.25) other = 0;
this.material.uniforms.other = other;
}
});
}
})
export default CesiumContainer
//shader.js
export const shaderLines = () => {
const fabricData = `
uniform vec4 color;
uniform vec4 color1;
uniform vec2 center;
uniform float other;
float getColorAlpha(vec2 st) {
float alphaTemp;
if((st.x + other) < 0.) {
alphaTemp = 0.;
} else if((st.x + other) < .125) {
alphaTemp = 1.;
} else if ( (st.x + other) < .25) {
alphaTemp = 0.;
} else if ( (st.x + other) < .375) {
alphaTemp = 1.;
} else if ( (st.x + other) < .5) {
alphaTemp = 0.;
} else if ( (st.x + other) < .625) {
alphaTemp = 1.;
} else if ( (st.x + other) < .75) {
alphaTemp = 0.;
} else if ( (st.x + other) < .875) {
alphaTemp = 1.;
} else {
alphaTemp = 0.;
}
return alphaTemp;
}
czm_material czm_getMaterial(czm_materialInput materialInput) {
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
// float alpha = distance(st.x, center.x);
material.diffuse = color.rgb;
material.alpha = getColorAlpha(st);
return material;
}
`
return fabricData
}

浙公网安备 33010602011771号