共计 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…
另一个忘了(原作者能够分割我)
正文完