这其实是一个很简单能实现的效果,百度搜索随便一搜会出现很多博客。
为什么还要再出一个?想在这里把我找到的实现此效果的方法及策略来一个综合对比。
个人觉得自己的实现方式相对来说性能会好一些。代码量相对少很多。
所有给出的代码直接粘贴到cesium官方沙盒示例里面就可以运行。
第一种实现方式:
百度搜索出来的,80%源代码粘贴过来的。大致看了下采用后处理方式渲染,必须开启深度检测。
代码中直接添加了1000个实体,很卡,可视化效果也一般般。
const viewer = new Cesium.Viewer("cesiumContainer");
viewer.scene.globe.depthTestAgainstTerrain = true;
var entity = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(111.0, 40.0, 1500),
billboard: {
image: "../images/Cesium_Logo_overlay.png",
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
}
});
viewer.flyTo(entity);
for (var i = 0; i < 1000; i++) {
var cartographicCenter = Cesium.Cartographic.fromDegrees(110 + Math.random() * 1,
40 + Math.random() * 1,
0);
var scanColor = new Cesium.Color(0.0, 1.0, 0.0, 1);
var lastStage = addCircleScanPostStage(viewer, cartographicCenter, 1000, scanColor, 4000);
}
//扩散效果Shader
function getScanSegmentShader() {
var scanSegmentShader = "\n\
uniform sampler2D colorTexture;\n\
uniform sampler2D depthTexture;\n\
in vec2 v_textureCoordinates;\n\
uniform vec4 u_scanCenterEC;\n\
uniform vec3 u_scanPlaneNormalEC;\n\
uniform float u_radius;\n\
uniform vec4 u_scanColor;\n\
\n\
vec4 toEye(in vec2 uv,in float depth)\n\
{\n\
vec2 xy = vec2((uv.x * 2.0 - 1.0),(uv.y * 2.0 - 1.0));\n\
vec4 posIncamera = czm_inverseProjection * vec4(xy,depth,1.0);\n\
posIncamera = posIncamera/posIncamera.w;\n\
return posIncamera;\n\
}\n\
\n\
vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point)\n\
{\n\
vec3 v01 = point - planeOrigin;\n\
float d = dot(planeNormal,v01);\n\
return (point-planeNormal * d);\n\
}\n\
float getDepth(in vec4 depth)\n\
{\n\
float z_window = czm_unpackDepth(depth);\n\
z_window = czm_reverseLogDepth(z_window);\n\
float n_range = czm_depthRange.near;\n\
float f_range = czm_depthRange.far;\n\
return (2.0 * z_window - n_range - f_range)/(f_range-n_range);\n\
} \n\
void main()\n\
{\n\
out_FragColor = texture(colorTexture,v_textureCoordinates);\n\
float depth = getDepth(texture(depthTexture,v_textureCoordinates));\n\
vec4 viewPos = toEye(v_textureCoordinates,depth);\n\
vec3 prjOnPlane = pointProjectOnPlane(u_scanPlaneNormalEC.xyz,u_scanCenterEC.xyz,viewPos.xyz);\n\
float dis = length(prjOnPlane.xyz - u_scanCenterEC.xyz);\n\
if(dis<u_radius)\n\ {\n\ float f=1.0-abs(u_radius - dis )/ u_radius;\n\ f=pow(f,4.0);\n\
out_FragColor=mix(out_FragColor,u_scanColor,f);\n\ }\n\ } \n\ ";
return scanSegmentShader;
}
/*
添加扩散效果扫描线
viewer
cartographicCenter 扫描中心
radius 半径 米
scanColor 扫描颜色
duration 持续时间 毫秒
*/
function addCircleScanPostStage(viewer, cartographicCenter, maxRadius, scanColor, duration) {
var _Cartesian3Center = Cesium.Cartographic.toCartesian(cartographicCenter);
var _Cartesian4Center = new Cesium.Cartesian4(_Cartesian3Center.x, _Cartesian3Center.y, _Cartesian3Center.z, 1);
var _CartograhpicCenter1 = new Cesium.Cartographic(cartographicCenter.longitude, cartographicCenter.latitude, cartographicCenter.height + 500);
var _Cartesian3Center1 = Cesium.Cartographic.toCartesian(_CartograhpicCenter1);
var _Cartesian4Center1 = new Cesium.Cartesian4(_Cartesian3Center1.x, _Cartesian3Center1.y, _Cartesian3Center1.z, 1);
var _time = (new Date()).getTime();
var _scratchCartesian4Center = new Cesium.Cartesian4();
var _scratchCartesian4Center1 = new Cesium.Cartesian4();
var _scratchCartesian3Normal = new Cesium.Cartesian3();
var ScanPostStage = new Cesium.PostProcessStage({
fragmentShader: getScanSegmentShader(),
uniforms: {
u_scanCenterEC: function () {
var temp = Cesium.Matrix4.multiplyByVector(viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center);
return temp;
},
u_scanPlaneNormalEC: function () {
var temp = Cesium.Matrix4.multiplyByVector(viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center);
var temp1 = Cesium.Matrix4.multiplyByVector(viewer.camera._viewMatrix, _Cartesian4Center1, _scratchCartesian4Center1);
_scratchCartesian3Normal.x = temp1.x - temp.x;
_scratchCartesian3Normal.y = temp1.y - temp.y;
_scratchCartesian3Normal.z = temp1.z - temp.z;
Cesium.Cartesian3.normalize(_scratchCartesian3Normal, _scratchCartesian3Normal);
return _scratchCartesian3Normal;
},
u_radius: function () {
return maxRadius * (((new Date()).getTime() - _time) % duration) / duration;
},
u_scanColor: scanColor
}
});
viewer.scene.postProcessStages.add(ScanPostStage);
return ScanPostStage;
}
第二种方式:和第三种方式一样,扩展材质属性,唯一的区别在shder不一样,替换第三种方式的shader就可以看到效果。和第三种方式相比区别在不能支持多个波同时扩散。
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
material.diffuse = 1.5 * color.rgb;
vec2 st = materialInput.st;
float dis = distance(st, vec2(0.5, 0.5));
float per = fract(time);
if(dis > per * 0.5){
//material.alpha = 0.0;
discard;
}else {
material.alpha = color.a * dis / per / 2.0;
}
return material;
}
第三种方式:这种方式在网上应该有类似的实现方案,就是扩展一个MaterialProperty,其中着色器代码自己加工修改过,能够自己自定义扩散圆数量,算法逻辑就不详细介绍,有需要的直接粘贴过去使用即可。循环最大值是写死的10,默认最大只支持9个圆扩散。这种方式加载1000个性能是没有影响的,就相当于加载了普通的1000个圆形实例。
const viewer = new Cesium.Viewer("cesiumContainer");
let Color = Cesium.Color;
let defaultValue = Cesium.defaultValue;
let defined = Cesium.defined;
let Event = Cesium.Event;
let createPropertyDescriptor = Cesium.createPropertyDescriptor;
let Property = Cesium.Property;
let Material = Cesium.Material;
var defaultColor = Color.WHITE;
function ElliposidWaveMaterialProperty(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
this._definitionChanged = new Event();
this._color = undefined;
this._colorSubscription = undefined;
this.color = options.color;
this.count = options.count || 1;
this.duration = Cesium.defaultValue(options.duration, 1e3);
this.gradient = Cesium.defaultValue(options.gradient, 0.1);
this._time = performance.now();
}
Object.defineProperties(ElliposidWaveMaterialProperty.prototype, {
isConstant: {
get: function () {
return false;
}
},
definitionChanged: {
get: function () {
return this._definitionChanged;
}
},
color: createPropertyDescriptor("color")
});
ElliposidWaveMaterialProperty.prototype.getType = function (time) {
return Material.EllipsoidWaveType;
};
ElliposidWaveMaterialProperty.prototype.getValue = function (time, result) {
if (!defined(result)) {
result = {};
}
result.color = Property.getValueOrClonedDefault(this._color, time, defaultColor, result.color);
if (this._time === undefined) {
this._time = time.secondsOfDay;
}
result.time = (performance.now() - this._time) / this.duration;
result.count = this.count;
result.gradient = 1 + 10 * (1 - this.gradient);
return result;
};
ElliposidWaveMaterialProperty.prototype.equals = function (other) {
return this === other || //
(other instanceof ElliposidWaveMaterialProperty &&
Property.equals(this._color, other._color));
};
Material.EllipsoidWaveType = "EllipsoidWave";
const ElliposidWaveMaterial = "czm_material czm_getMaterial(czm_materialInput materialInput) { \n\
czm_material material = czm_getDefaultMaterial(materialInput); \n\
material.diffuse = 1.5 * color.rgb; \n\
vec2 st = materialInput.st; \n\
float dis = distance(st, vec2(0.5, 0.5)); \n\
float per = fract(time); \n\
if (dis > 0.5) { \n\
discard; \n\
} else { \n\
float perDis = 0.5 / count; \n\
float disNum; \n\
float bl = .0; \n\
for (int i = 0; i < 10; i++) {\n\
if(float(i) > count) {\n\
break;\n\
} \n\
disNum = perDis * float(i) - dis + per / count; \n\
if (disNum > 0.0) { \n\
if (disNum < perDis) { \n\
bl = 1.0 - disNum / perDis; \n\
} \n\
else if(disNum - perDis < perDis) { \n\
bl = 1.0 - abs(1.0 - disNum / perDis); \n\
} \n\
material.alpha = pow(bl, gradient); \n\
} \n\
} \n\
} \n\
return material; \n\
}";
Material._materialCache.addMaterial(Material.EllipsoidWaveType, {
fabric: {
type: Material.EllipsoidWaveType,
uniforms: {
color: new Color(1, 0, 0, 1.0),
time: 1,
count: 1,
duration: 1000,
gradient: 0.1
},
source: ElliposidWaveMaterial
},
translucent: function () {
return true;
}
});
for (var i = 0; i < 1000; i++) {
let greenCircle = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(110 + Math.random() * 1,
40 + Math.random() * 1,
10),
name: "Green circle at height with outline",
ellipse: {
semiMinorAxis:1000.0,
semiMajorAxis: 1000.0,
height: 10.0,
material: new ElliposidWaveMaterialProperty({
color: Color.GREEN,
count: 3,
duration: 3000,
gradient: 0.2,
})
},
});
}
viewer.zoomTo(viewer.entities);
浙公网安备 33010602011771号