
效果就如图所示,这样的效果在cesium中本来是有Cesium.NearFarScalar这样的方法进行实现的,但是奈何考虑的性能问题在加载众多的点要素时,我选择了使用primitive的形式进行效果展现,那在primitive中就没提供Cesium.NearFarScalar属性去实现"近大远小"或者"远小近大"的效果。
不废话了先说思路,然后直接放代码,代码里面注释不多,关键是思路对齐。
我的需求是要实现数千个或者上万个站点的告警闪烁效果(一闪一闪的),所以在前期的实现上我就用Cesium.EllipseGeometry进行几何的加载,并使用着色器加图片的形式进行告警效果。但是出现的问题就是,primitive中的EllipseGeometry无法动态调整semiMajorAxis和semiMinorAxis.......
好吧,就只能换思路,思路也简单,就是根据相机视角的高度动态调整图片的大小即可。
javascript
const collection = new Cesium.PrimitiveCollection({ show:true })
collection.customName = 'HasOrder'
const axis = 1500;
const instance = new Cesium.GeometryInstance({
id: Date.now(),
geometry: new Cesium.EllipseGeometry({
center: Cesium.Cartesian3.fromDegrees('经度', '纬度', 50),
semiMajorAxis: axis,
semiMinorAxis: axis,
rotation: Cesium.Math.toRadians(0)
}),
attributes: {}
})
const instances = [];
instances.push(instance)
//关键在这里面
const dynamicWarnGLSL = `
uniform sampler2D image;
uniform float scale;
vec4 czm_getMaterial(vec2 vUv,vec2 viewPort,vec4 fragCoord)
{
vec2 st = vUv;
vec2 center = vec2(0.5, 0.5);
// 应用缩放
vec2 translatedSt = st - center;
vec2 scaledSt = translatedSt / scale;
vec2 finalSt = scaledSt + center;
// 使用step函数检查边界,性能更好
float inBounds = step(0.0, finalSt.x) * step(finalSt.x, 1.0) *
step(0.0, finalSt.y) * step(finalSt.y, 1.0);
vec4 img = texture(image, finalSt);
img.a = img.a * inBounds ;
if(img.a != 0.0){
img.a = sin(czm_frameNumber/35.0)+0.95;
}
return img;
}
`
const vertexShaderSource = `
in vec3 position3DHigh;
in vec3 position3DLow;
in vec3 normal;
in vec2 st;
in float batchId;
out vec3 v_positionEC;
out vec3 v_normalEC;
out vec2 v_st;
void main() {
vec4 p = czm_computePosition();
v_positionEC = (czm_modelViewRelativeToEye * p).xyz;
v_normalEC = czm_normal * normal;
v_st = st;
gl_Position = czm_modelViewProjectionRelativeToEye * p;
}
`;
const fragmentShaderSource = `
in vec2 v_st;
in vec3 v_positionEC;
in vec3 v_normalEC;
void main() {
vec3 positionToEyeEC = -v_positionEC;
vec3 normalEC = normalize(v_normalEC);
czm_materialInput materialInput;
materialInput.normalEC = normalEC;
materialInput.positionToEyeEC = positionToEyeEC;
materialInput.st = v_st;
//窗口尺寸
vec2 viewPort = gl_FragCoord.xy / czm_viewport.zw;
vec4 color = czm_getMaterial(v_st,viewPort,gl_FragCoord);
out_FragColor = color;
}
`;
const primitive = new Cesium.Primitive({
geometryInstances: noHasOrderList,
appearance: new Cesium.MaterialAppearance({
material: new Cesium.Material({
fabric: {
type: 'dynamicsPoint',
uniforms: {
image: '图片',
scale:1.0
},
source: dynamicWarnGLSL
}
}),
vertexShaderSource: vertexShaderSource,
fragmentShaderSource: fragmentShaderSource,
flat: true
})
})
collection.add(primitive)
viewer.scene.primitives.add(collection)
//监控相机的变化
// 监听相机变化(用于改变告警图层点位的尺寸)
viewer.camera.changed.addEventListener(() => {
try{
const cameraHeight = viewer.camera.positionCartographic.height;
let scale = 1.0;
if (cameraHeight >= maxHeight) {
scale = maxScale;
} else if (cameraHeight <= minHeight) {
scale = minScale;
} else {
const t = (cameraHeight - minHeight) / (maxHeight - minHeight);
scale = minScale + t * delta;
}
const layerName = "HasOrder";//primitive收集器的名称
//查找需要的primitive
for (let i = 0; i < viewer.scene.primitives._primitives.length; i++) {
let primitive = viewer.scene.primitives._primitives[i]
if (primitive.hasOwnProperty('customName')) {
if (primitive.customName.indexOf(layerName) != -1) {
primitive._primitives[0].appearance.material.uniforms.scale = scale;
}
}
}
}catch(error){
console.log(error);
}
});