共计 11636 个字符,预计需要花费 30 分钟才能阅读完成。
该计划借鉴了多个大佬的,把代码理了一遍再整合了一下做了个汇合(算是一个练手的 demo)
重点👇
这里初始化地球的时候留神下这个参数 requestRenderMode
(缩小 Cesium 渲染新帧总工夫并缩小 Cesium 在应用程序中总体 CPU 使用率),如果你开启了,那么流线材质就会动一下就不动了,切记!!!!
上面是 vue 组件代码
https://segmentfault.com/u/yo…
<template>
<div class="tole">
<div id="cesiumContainer" style="height: 100%;width: 100%">
</div>
</div>
</template>
<script>
import * as Cesium from 'cesium/Cesium'
import widget from 'cesium/Widgets/widgets.css'
var viewer = null
export default {data(){
return{viewer:null}
},
mounted(){console.log(widget);
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlZGMwM2M2OC02ZGYwLTQ5NzQtYjBkOS1lYTM0MmYxNTZlZTkiLCJpZCI6NjEwNTMsImlhdCI6MTYyNTY0ODgzN30.9B76dtOIBsNmX3laJ5VXFOqt2NlBT-n16j4ppUF8IYA'
// viewer = new Cesium.CesiumWidget('cesiumContainer')
viewer = new Cesium.Viewer("cesiumContainer",{
animation: false, // 暗藏动画控件
baseLayerPicker: false, // 暗藏图层抉择控件
fullscreenButton: false, // 暗藏全屏按钮
vrButton: false, // 暗藏 VR 按钮,默认 false
geocoder: false, // 暗藏地名查找控件
homeButton: false, // 暗藏 Home 按钮
infoBox: false, // 暗藏点击因素之后显示的信息窗口
sceneModePicker: false, // 暗藏场景模式抉择控件
selectionIndicator: true, // 显示实体对象抉择框,默认 true
timeline: false, // 暗藏工夫线控件
navigationHelpButton: false, // 暗藏帮忙按钮
scene3DOnly: true, // 每个几何实例将只在 3D 中出现,以节俭 GPU 内存
shouldAnimate: true, // 开启动画自动播放
sceneMode: 3, // 初始场景模式 1:2D 2:2D 循环 3:3D,默认 3
requestRenderMode: false, // 缩小 Cesium 渲染新帧总工夫并缩小 Cesium 在应用程序中总体 CPU 使用率
// 如场景中的元素没有随仿真工夫变动,请思考将设置 maximumRenderTimeChange 为较高的值,例如 Infinity
maximumRenderTimeChange: Infinity,
// 天地图影像
// imageryProvider: new Cesium.WebMapTileServiceImageryProvider({// url: "http://t0.tianditu.com/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=39ca2b2b8dc2f3e1e9c3de07f4d4de57",
// layer: "tdtBasicLayer",
// style: "default",
// format: "tiles",
// tileMatrixSetID: "GoogleMapsCompatible",
// show: true,
// maximumLevel: 18
// })
})
this.viewer = viewer
// 增加天地图标注
// viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({// url: "http://t0.tianditu.com/cia_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cia&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default.jpg&tk=39ca2b2b8dc2f3e1e9c3de07f4d4de57",
// layer: "tdtAnnoLayer",
// style: "default",
// format: "tiles",
// tileMatrixSetID: "GoogleMapsCompatible",
// show: true
// }));
viewer.cesiumWidget.creditContainer.style.display = "none"
// 增加线
// var orangeOutlined = viewer.entities.add({
// name:
// "Orange line with black outline at height and following the surface",
// polyline: {
// positions: Cesium.Cartesian3.fromDegreesArrayHeights([
// -75,
// 39,
// 0,
// -125,
// 39,
// 0,
// ]),
// width: 5,
// material: new Cesium.PolylineOutlineMaterialProperty({
// color: Cesium.Color.ORANGE,
// outlineWidth: 2,
// outlineColor: Cesium.Color.BLACK,
// }),
// },
// });
// console.log(orangeOutlined);
// 增加点位
var entity = viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(120.9677706,30.7985748,2.61),
point: {
color: Cesium.Color.RED, // 点位色彩
pixelSize: 10 // 像素点大小
},
label : {
text : '测试名称',
font : '14pt Source Han Sans CN', // 字体款式
fillColor:Cesium.Color.BLACK, // 字体色彩
backgroundColor:Cesium.Color.AQUA, // 背景色彩
showBackground:true, // 是否显示背景色彩
style: Cesium.LabelStyle.FILL, //label 款式
outlineWidth : 2,
verticalOrigin : Cesium.VerticalOrigin.CENTER,// 垂直地位
horizontalOrigin :Cesium.HorizontalOrigin.LEFT,// 程度地位
pixelOffset:new Cesium.Cartesian2(10,0) // 偏移
}
});
console.log(entity);
// 这里通过算法失去曲线
let mm = this.parabola([-75,39,-175,39])
var polyline = new Cesium.PolylineGeometry({
positions: mm,
width : 2
});
const instance = new Cesium.GeometryInstance({
geometry: polyline,
id: 'flyline',
})
// 增加至场景
this.viewer.scene.primitives.add(
new Cesium.Primitive({geometryInstances: [instance],
appearance: this.getFlylineMaterial(),
releaseGeometryInstances: false,
compressVertices: false,
})
)
},
methods:{
computeFlyline(point1 = [-75, 39],
point2 = [-175,39],
h = 500000
) {let flyline = getBSRxyz(...point1, ...point2, h)
return flyline
// 将数据转换为 cesium polyline positions 格局
function getBSRxyz(x1, y1, x2, y2, h) {let arr3d = getBSRPoints(x1, y1, x2, y2, h)
let arrAll = []
for (let ite of arr3d) {arrAll.push(ite[0])
arrAll.push(ite[1])
arrAll.push(ite[2])
}
return Cesium.Cartesian3.fromDegreesArrayHeights(arrAll)
}
function getBSRPoints(x1, y1, x2, y2, h) {let point1 = [y1, 0]
let point2 = [(y2 + y1) / 2, h]
let point3 = [y2, 0]
let arr = getBSR(point1, point2, point3)
let arr3d = []
for (let i = 0; i< arr.length; i++) {let x = ((x2 - x1) * (arr[i][0] - y1)) / (y2 - y1) + x1
arr3d.push([x, arr[i][0], arr[i][1]])
}
return arr3d
}
// 生成贝塞尔曲线
function getBSR(point1, point2, point3) {
var ps = [{ x: point1[0], y: point1[1] },
{x: point2[0], y: point2[1] },
{x: point3[0], y: point3[1] }
]
// 100 每条线由 100 个点组成
let guijipoints = CreateBezierPoints(ps, 100)
return guijipoints
}
// 贝赛尔曲线算法
// 参数:// anchorpoints: [{x: 116.30, y: 39.60}, {x: 37.50, y: 40.25}, {x: 39.51, y: 36.25}]
function CreateBezierPoints(anchorpoints, pointsAmount) {var points = []
for (var i = 0; i < pointsAmount; i++) {var point = MultiPointBezier(anchorpoints, i / pointsAmount)
points.push([point.x, point.y])
}
return points
}
function MultiPointBezier(points, t) {
var len = points.length
var x = 0,
y = 0
var erxiangshi = function(start, end) {
var cs = 1,
bcs = 1
while (end > 0) {
cs *= start
bcs *= end
start--
end--
}
return cs / bcs
}
for (var i = 0; i < len; i++) {var point = points[i]
x +=
point.x *
Math.pow(1 - t, len - 1 - i) *
Math.pow(t, i) *
erxiangshi(len - 1, i)
y +=
point.y *
Math.pow(1 - t, len - 1 - i) *
Math.pow(t, i) *
erxiangshi(len - 1, i)
}
return {x: x, y: y}
}
},
parabola(twoPoints) { // 抛物线绘制
let s = []
let startPoint = [twoPoints[0],twoPoints[1],0]; // 终点的经度、纬度
s = s.concat(startPoint)
let step = 80; // 线的多少,越多则越平滑(但过多浏览器缓存也会占用越多)
let heightProportion = 0.125; // 最高点和总间隔的比值
let dLon = (twoPoints[2] - startPoint[0])/step; // 经度差值
let dLat = (twoPoints[3] - startPoint[1])/step; // 纬度差值
let deltaLon = dLon * Math.abs(111000*Math.cos(twoPoints[1])); // 经度差(米级)
let deltaLat = dLat * 111000; // 纬度差(米),1 纬度相差约 111000 米
let endPoint = [0,0,0]; // 定义一个端点(前面将进行 startPoint 和 endPoint 两点画线)let heigh = (step * Math.sqrt(deltaLon*deltaLon+deltaLat*deltaLat) * heightProportion).toFixed(0)*2;
let x2 = (10000*Math.sqrt(dLon*dLon+dLat*dLat)); // 小数点扩充 10000 倍,进步精确度
let a = (heigh/(x2*x2));
function y(x,height) {return height - a*x*x;}
for(var i = 1;i <= step; i++){ // 逐“帧”画线
endPoint[0] = startPoint[0] + dLon; // 更新 end 点经度
endPoint[1] = startPoint[1] + dLat; // 更新 end 点纬度
let x = x2*(2*i/step-1); // 求抛物线函数 x
endPoint[2] = (y(x,heigh)).toFixed(0)*1; // 求 end 点高度
s = s.concat(endPoint)
// end 点变为 start 点
startPoint[0] = endPoint[0];
startPoint[1] = endPoint[1];
startPoint[2] = endPoint[2];
}
return Cesium.Cartesian3.fromDegreesArrayHeights(s)
},
getFlylineMaterial(){
// 创立材质,在 MaterialAppearance 中若不增加根底材质,模型将会通明
var material = new Cesium.Material.fromType('Color')
material.uniforms.color = Cesium.Color.ORANGE
// 飞线成果 - 飞线距离,宽度 2
let fragmentShaderSource = `
varying vec2 v_st;
varying float v_width;
varying float v_polylineAngle;
varying vec4 v_positionEC;
varying vec3 v_normalEC;
void main()
{
vec2 st = v_st;
// 箭头飞线,宽度 8
float xx = fract(st.s*10.0 + st.t - czm_frameNumber/60.0);
if (st.t<0.5) {xx = fract(st.s*10.0 - st.t - czm_frameNumber/60.0);
}
float r = 0.0;
float g = xx;
float b = xx;
float a = xx;
// 飞线边框
if (st.t>0.8||st.t<0.2) {
g = 1.0;
b = 1.0;
a = 0.4;
}
gl_FragColor = vec4(r,g,b,a);
}
`
// 自定义材质
const aper = new Cesium.PolylineMaterialAppearance({
material: material,
translucent: true,
vertexShaderSource: `
#define CLIP_POLYLINE
void clipLineSegmentToNearPlane(
vec3 p0,
vec3 p1,
out vec4 positionWC,
out bool clipped,
out bool culledByNearPlane,
out vec4 clippedPositionEC)
{
culledByNearPlane = false;
clipped = false;
vec3 p0ToP1 = p1 - p0;
float magnitude = length(p0ToP1);
vec3 direction = normalize(p0ToP1);
float endPoint0Distance = czm_currentFrustum.x + p0.z;
float denominator = -direction.z;
if (endPoint0Distance > 0.0 && abs(denominator) < czm_epsilon7)
{culledByNearPlane = true;}
else if (endPoint0Distance > 0.0)
{
float t = endPoint0Distance / denominator;
if (t < 0.0 || t > magnitude)
{culledByNearPlane = true;}
else
{
p0 = p0 + t * direction;
p0.z = min(p0.z, -czm_currentFrustum.x);
clipped = true;
}
}
clippedPositionEC = vec4(p0, 1.0);
positionWC = czm_eyeToWindowCoordinates(clippedPositionEC);
}
vec4 getPolylineWindowCoordinatesEC(vec4 positionEC, vec4 prevEC, vec4 nextEC, float expandDirection, float width, bool usePrevious, out float angle)
{
#ifdef POLYLINE_DASH
vec4 positionWindow = czm_eyeToWindowCoordinates(positionEC);
vec4 previousWindow = czm_eyeToWindowCoordinates(prevEC);
vec4 nextWindow = czm_eyeToWindowCoordinates(nextEC);
vec2 lineDir;
if (usePrevious) {lineDir = normalize(positionWindow.xy - previousWindow.xy);
}
else {lineDir = normalize(nextWindow.xy - positionWindow.xy);
}
angle = atan(lineDir.x, lineDir.y) - 1.570796327;
angle = floor(angle / czm_piOverFour + 0.5) * czm_piOverFour;
#endif
vec4 clippedPrevWC, clippedPrevEC;
bool prevSegmentClipped, prevSegmentCulled;
clipLineSegmentToNearPlane(prevEC.xyz, positionEC.xyz, clippedPrevWC, prevSegmentClipped, prevSegmentCulled, clippedPrevEC);
vec4 clippedNextWC, clippedNextEC;
bool nextSegmentClipped, nextSegmentCulled;
clipLineSegmentToNearPlane(nextEC.xyz, positionEC.xyz, clippedNextWC, nextSegmentClipped, nextSegmentCulled, clippedNextEC);
bool segmentClipped, segmentCulled;
vec4 clippedPositionWC, clippedPositionEC;
clipLineSegmentToNearPlane(positionEC.xyz, usePrevious ? prevEC.xyz : nextEC.xyz, clippedPositionWC, segmentClipped, segmentCulled, clippedPositionEC);
if (segmentCulled)
{return vec4(0.0, 0.0, 0.0, 1.0);
}
vec2 directionToPrevWC = normalize(clippedPrevWC.xy - clippedPositionWC.xy);
vec2 directionToNextWC = normalize(clippedNextWC.xy - clippedPositionWC.xy);
if (prevSegmentCulled)
{directionToPrevWC = -directionToNextWC;}
else if (nextSegmentCulled)
{directionToNextWC = -directionToPrevWC;}
vec2 thisSegmentForwardWC, otherSegmentForwardWC;
if (usePrevious)
{
thisSegmentForwardWC = -directionToPrevWC;
otherSegmentForwardWC = directionToNextWC;
}
else
{
thisSegmentForwardWC = directionToNextWC;
otherSegmentForwardWC = -directionToPrevWC;
}
vec2 thisSegmentLeftWC = vec2(-thisSegmentForwardWC.y, thisSegmentForwardWC.x);
vec2 leftWC = thisSegmentLeftWC;
float expandWidth = width * 0.5;
if (!czm_equalsEpsilon(prevEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1) && !czm_equalsEpsilon(nextEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1))
{vec2 otherSegmentLeftWC = vec2(-otherSegmentForwardWC.y, otherSegmentForwardWC.x);
vec2 leftSumWC = thisSegmentLeftWC + otherSegmentLeftWC;
float leftSumLength = length(leftSumWC);
leftWC = leftSumLength < czm_epsilon6 ? thisSegmentLeftWC : (leftSumWC / leftSumLength);
vec2 u = -thisSegmentForwardWC;
vec2 v = leftWC;
float sinAngle = abs(u.x * v.y - u.y * v.x);
expandWidth = clamp(expandWidth / sinAngle, 0.0, width * 2.0);
}
vec2 offset = leftWC * expandDirection * expandWidth * czm_pixelRatio;
return vec4(clippedPositionWC.xy + offset, -clippedPositionWC.z, 1.0) * (czm_projection * clippedPositionEC).w;
}
vec4 getPolylineWindowCoordinates(vec4 position, vec4 previous, vec4 next, float expandDirection, float width, bool usePrevious, out float angle)
{
vec4 positionEC = czm_modelViewRelativeToEye * position;
vec4 prevEC = czm_modelViewRelativeToEye * previous;
vec4 nextEC = czm_modelViewRelativeToEye * next;
return getPolylineWindowCoordinatesEC(positionEC, prevEC, nextEC, expandDirection, width, usePrevious, angle);
}
attribute vec3 position3DHigh;
attribute vec3 position3DLow;
attribute vec3 prevPosition3DHigh;
attribute vec3 prevPosition3DLow;
attribute vec3 nextPosition3DHigh;
attribute vec3 nextPosition3DLow;
attribute vec2 expandAndWidth;
attribute vec2 st;
attribute float batchId;
varying float v_width;
varying vec2 v_st;
varying float v_polylineAngle;
varying vec4 v_positionEC;
varying vec3 v_normalEC;
void main()
{
float expandDir = expandAndWidth.x;
float width = abs(expandAndWidth.y) + 0.5;
bool usePrev = expandAndWidth.y < 0.0;
vec4 p = czm_computePosition();
vec4 prev = czm_computePrevPosition();
vec4 next = czm_computeNextPosition();
float angle;
vec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev, angle);
gl_Position = czm_viewportOrthographic * positionWC;
v_width = width;
v_st.s = st.s;
v_st.t = st.t;
// v_st.t = czm_writeNonPerspective(st.t, gl_Position.w);
v_polylineAngle = angle;
vec4 eyePosition = czm_modelViewRelativeToEye * p;
v_positionEC = czm_inverseModelView * eyePosition; // position in eye coordinates
//v_normalEC = czm_normal * normal; // normal in eye coordinates
}
`,
fragmentShaderSource: fragmentShaderSource
})
return aper;
},
}
}
</script>
<style scope lang="scss">
.tole{
width: 100%;
height: 100%;
}
</style>
这里有两个曲线算法 computeFlyline
和parabola
, 任选其一即可
其中一个来自于
https://www.cnblogs.com/s3131…
另一个忘了(原作者能够分割我)
正文完