在项目中,实现完卫星通信线之后,又有一个新需求,需要通信线根据火箭移动而移动,相当于追踪效果,思考之后通过 Entity CallbackProperty
实现。
实际上是通过自定义材质类,通过着色器代码实现。
本文包含移动连接线核心代码、完整代码以及在线示例三部分。
// 获取火箭模型实体
const entity = dataSource.entities.getById("Vulcan");
// 模型视角跟随
viewer.trackedEntity = entity;
// 设置观察角度
entity.viewFrom = new Cesium.Cartesian3(-1000, 100,-1000);
// 添加通信线
viewer.entities.add({
polyline: {
// 回调更新连接线.
positions: new Cesium.CallbackProperty(function (time, result) {
const position1 = entity.position.getValue(time);
return [position,position1];
}, false),
width: 5,
material: new SatelliteMaterialProperty({
color: new Cesium.Color(1.0, 0.0, 1.0, 0.1),
speed: 50,
count: 10,
gradient: 0.2
}),
},
});
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Use correct character set. -->
<meta charset="utf-8"/>
<!-- Tell IE to use the latest, best version. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<title>Cesium dynamic line</title>
<script src="http://openlayers.vip/examples/csdn/Cesium.js"></script>
<script src="./cesium_init.js"></script>
<script src="http://www.openlayers.vip/examples/resources/jquery-3.5.1.min.js"></script>
<style>
@import url(./Widgets/widgets.css);
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?f80a36f14f8a73bb0f82e0fdbcee3058";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<div id="cesiumContainer"></div>
<script>
// 创建三维球
const viewer = init();
// 火箭模拟发射数据
const czml = [
{
"id": "document",
"name": "SpaceX",
"version": "1.0",
"clock": {
"interval": "2023-06-14T10:00:00Z/2023-06-14T10:17:33Z",
"currentTime": "2023-06-14T10:00:00Z",
"multiplier": 10,
"range": "CLAMPED",
"step": "SYSTEM_CLOCK_MULTIPLIER"
}
},
{
"id": "Vulcan",
"availability": "2023-06-14T10:00:00Z/2023-06-14T10:17:33Z",
"name": "Vulcan",
"billboard": {
"show": true,
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAAjSURBVChTYyAa/EcDUGEIgIphAKg0XRSAAFQMDqDChAADAwDC13+BJ+0oDwAAAABJRU5ErkJgggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"scale": 1,
"pixelOffset": {
"cartesian2": [
0, 0
]
},
"eyeOffset": {
"cartesian": [
0, 0, 0
]
},
"horizontalOrigin": "CENTER",
"verticalOrigin": "CENTER",
"color": [
{
"interval": "2023-06-14T10:00:00Z/2023-06-14T10:10:00Z",
"rgba": [
0, 255, 0, 255
]
},
{
"interval": "2023-06-14T10:10:00Z/2023-06-14T10:13:20Z",
"rgba": [
255, 255, 0, 255
]
},
{
"interval": "2023-06-14T10:13:20Z/9999-12-31T23:59:59.9999999Z",
"rgba": [
255, 0, 255, 255
]
}
]
},
"label": {
"show": false,
"text": "Vulcan",
"font": "21pt Lucida Console",
"style": "FILL_AND_OUTLINE",
"scale": 0.5,
"pixelOffset": {
"cartesian2": [
5, -4
]
},
"horizontalOrigin": "LEFT",
"verticalOrigin": "CENTER",
"fillColor": [
{
"interval": "2023-06-14T10:00:00Z/2023-06-14T10:10:00Z",
"rgba": [
0, 255, 0, 255
]
},
{
"interval": "2023-06-14T10:10:00Z/2023-06-14T10:13:20Z",
"rgba": [
255, 255, 0, 255
]
},
{
"interval": "2023-06-14T10:13:20Z/9999-12-31T23:59:59.9999999Z",
"rgba": [
255, 0, 255, 255
]
}
],
"outlineColor": {
"rgba": [
0, 0, 0, 255
]
},
"outlineWidth": 2
},
"path": {
"show": [
{
"interval": "2023-06-14T10:00:00Z/2023-06-14T10:17:33Z",
"boolean": true
}
],
"width": 5,
"resolution": 1,
"leadTime": [
{
"interval": "2023-06-14T10:00:00Z/2023-06-14T10:17:33Z",
"epoch": "2023-06-14T10:00:00Z",
"number": [
0, 1053,
1053, 0
]
}
],
"trailTime": [
{
"interval": "2023-06-14T10:00:00Z/2023-06-14T10:17:33Z",
"epoch": "2023-06-14T10:00:00Z",
"number": [
0, 0,
1053, 1053
]
}
],
"material": {
polylineGlow: {
color: [{
"interval": "2023-06-14T10:00:00Z/2023-06-14T10:10:00Z",
rgba: [255, 0, 0, 255],
},
{
"interval": "2023-06-14T10:10:00Z/2023-06-14T10:13:20Z",
rgba: [0, 0, 255, 255],
},
{
"interval": "2023-06-14T10:13:20Z/9999-12-31T23:59:59.9999999Z",
rgba: [255, 0, 255, 255],
}
],
glowPower: 0.25,
// taperPower: 0.5,
},
},
},
"model": {
"show": true,
"gltf": [
{
"interval": "2023-06-14T10:00:00Z/9999-12-31T23:59:59.9999999Z",
"uri": "https://cesium.com/public/SandcastleSampleData/launchvehicle.glb"
}
],
"minimumPixelSize": 128,
"scale": 3,
"runAnimations": false,
},
"position": {
"interpolationAlgorithm": "LAGRANGE",
"interpolationDegree": 2,
"referenceFrame": "FIXED",
"epoch": "2023-06-14T10:00:00Z",
"cartesian": [
0.000, -2174195.199042614, 4389988.019058515, 4070606.7900844226,
250.000, -2828836.74243954, 4527941.384141082, 4322899.592600973,
750.000, -3812052.7676919936, 3910960.7948377975, 4168079.0591541207,
1053.000, -3929362.40133975, 3277792.786767426, 3795371.463871257,
]
},
"orientation": {
"velocityReference": "#position"
},
},
];
// 添加火箭车
const launchCar = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(
127.69435837574487,38.808381761124146,0.0
),
model: {
uri: "https://openlayers.vip/examples/resources/model/car.glb",
scale: 3.0,
minimumPixelSize: 128
},
});
const clock = viewer.clock;
// 获取当前时刻位置
const position = launchCar.position.getValue(clock.currentTime);
const dataSourcePromise = viewer.dataSources.add(
Cesium.CzmlDataSource.load(czml)
);
dataSourcePromise
.then(function (dataSource) {
// 获取火箭模型实体
const entity = dataSource.entities.getById("Vulcan");
// 模型视角跟随
viewer.trackedEntity = entity;
// 设置观察角度
entity.viewFrom = new Cesium.Cartesian3(-1000, 100,-1000);
// 添加通信线
viewer.entities.add({
polyline: {
// 回调更新连接线.
positions: new Cesium.CallbackProperty(function (time, result) {
const position1 = entity.position.getValue(time);
return [position,position1];
}, false),
width: 5,
material: new SatelliteMaterialProperty({
color: new Cesium.Color(1.0, 0.0, 1.0, 0.1),
speed: 50,
count: 10,
gradient: 0.2
}),
},
});
viewer.zoomTo(viewer.entities);
})
.catch(function (error) {
console.error(error);
});
/**
* @description:卫星通信材质
* @date: 2023年6月17日10:43:18
*/
function SatelliteMaterialProperty(options) {
// 默认参数设置
this._definitionChanged = new Cesium.Event();
this.color = options.color;
}
Object.defineProperties(SatelliteMaterialProperty.prototype, {
isConstant: {
get: function() {
return false;
}
},
definitionChanged: {
get: function() {
return this._definitionChanged;
}
},
color: Cesium.createPropertyDescriptor('color')
});
SatelliteMaterialProperty.prototype.getType = function(time) {
return 'SatelliteMaterial';
};
SatelliteMaterialProperty.prototype.getValue = function(time, result) {
if (!Cesium.defined(result)) {
result = {};
}
result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
viewer.scene.requestRender();
return result;
};
SatelliteMaterialProperty.prototype.equals = function(other) {
return this === other ||
(other instanceof SatelliteMaterialProperty &&
Cesium.Property.equals(this._color, other._color));
};
Cesium.Material.SatelliteType = 'SatelliteMaterial';
Cesium.Material.SatelliteSource = `
uniform vec4 color;
uniform float speed;
uniform float percent;
uniform float gradient;
uniform float count;
czm_material czm_getMaterial(czm_materialInput materialInput){
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
float t =fract(czm_frameNumber * speed / 1000.0);
float v = 1.0-(1.0-smoothstep(gradient,0.0,fract(st.x*count-t)))*0.95;
material.diffuse = color.rgb/10.0 + vec3(v)*9.0;
material.alpha = color.a;
return material;
}
`;
Cesium.Material._materialCache.addMaterial(Cesium.Material.SatelliteType, {
fabric: {
type: Cesium.Material.SatelliteType,
uniforms: {
color: new Cesium.Color(1.0, 0.0, 1.0, 0.1),
speed: 30.0,
gradient: 0.2,
count: 15,
},
source: Cesium.Material.SatelliteSource
},
translucent: function(material) {
return true;
}
});
</script>
</body>
</html>
示例创建小车模型以及火箭发射,模拟小车追踪火箭通信效果。