Cesium实现的光柱效果
效果展示:
可以通过拼接两个entity来实现这个效果:
全部代码;
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>光柱</title>
<script src="https://cdn.bootcdn.net/ajax/libs/cesium/1.97.0/Cesium.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/cesium/1.102.0/Widgets/widgets.min.css" rel="stylesheet">
<style>
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="cesiumContainer"></div>
<script type="module">
import { ConeGlow } from './ConeGlow.js'
const viewer = new Cesium.Viewer('cesiumContainer', {
infoBox: false,
selectionIndicator: false,
navigation: false,
animation: false,
shouldAnimate: false,
timeline: false,
baseLayerPicker: false,
geocoder: false,
homeButton: false,
sceneModePicker: false,
navigationHelpButton: false,
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}"
})
});
;
let goneGlow = new ConeGlow(viewer, Cesium.Cartesian3.fromDegrees(113.222 , 23.222 ), {
height: 5000,
bottomRadius: 200,
color: Cesium.Color.RED
});
new ConeGlow(viewer, Cesium.Cartesian3.fromDegrees(113.233 , 23.223 ), {
height: 5000,
bottomRadius: 200,
color: Cesium.Color.GREEN
});
viewer.scene.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(113.222 , 23.222 , 30000) });
</script>
</body>
</html>
ConeGlow.js
import "./ConeGlowMaterial/BottomCircle.js";
import "./ConeGlowMaterial/BottomRotateCircle.js";
export class ConeGlow {
constructor(viewer, position, options) {
this.viewer = viewer;
this.position = position;
this.options = options; //color 颜色 height 光柱高度 bottomRadius 底部圆的半径
this.height = options.height || 300;
this.bottomRadius = options.bottomRadius || 30;
this.color = options.color || Cesium.Color.AQUA; //给个亮亮的颜色
this.addCone();
this.addBottomCircle();
this.addBottomRotateCircle();
}
//添加圆锥体
addCone() {
var modelMatrix = Cesium.Matrix4.multiplyByTranslation(
Cesium.Transforms.eastNorthUpToFixedFrame(this.position),
new Cesium.Cartesian3(0.0, 0.0, this.height * 0.5), new Cesium.Matrix4()
);
var cylinderGeometry = new Cesium.CylinderGeometry({
length: this.height,
topRadius: 0.0,
bottomRadius: this.bottomRadius * 0.7,
vertexFormat: Cesium.MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat
});
var cone = new Cesium.GeometryInstance({
geometry: cylinderGeometry,
modelMatrix: modelMatrix,
});
this.cylinderPrimitive = this.viewer.scene.primitives.add(new Cesium.Primitive({
geometryInstances: [cone],
appearance: new Cesium.MaterialAppearance({
material: new Cesium.Material({
fabric: {
type: "VtxfShader1",
uniforms: {
color: this.color,
alpha: 2
},
source: `
uniform vec4 color;
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
float dis = distance(st, vec2(0.5));
material.diffuse =2.9 * color.rgb;
material.alpha = color.a * dis * alpha ;
return material;
}
`
},
translucent: false
}),
faceForward: false, // 当绘制的三角面片法向不能朝向视点时,自动翻转法向,从而避免法向计算后发黑等问题
closed: true // 是否为封闭体,实际上执行的是是否进行背面裁剪
}),
}));
this.viewer.scene.preUpdate.addEventListener(this.preUpdateHandle, this);
}
preUpdateHandle() {
//圆锥闪烁动画
this.cylinderPrimitive.appearance.material.uniforms.alpha += 0.05;
if (this.cylinderPrimitive.appearance.material.uniforms.alpha > 2.5) {
this.cylinderPrimitive.appearance.material.uniforms.alpha = 2;
}
}
//添加底部圆
addBottomCircle() {
this.bottomCircle = this.viewer.entities.add({
position: this.position,
ellipse: {
semiMinorAxis: this.bottomRadius * 2,
semiMajorAxis: this.bottomRadius * 2,
height: 0.0,
material: new Cesium.ConeGlowBottomCircleMaterialProperty(this.color),
}
});
}
//添加底部旋转圆
addBottomRotateCircle() {
let stRotation = 360;
this.bottomRotateCircle = this.viewer.entities.add({
position: this.position,
ellipse: {
semiMinorAxis: this.bottomRadius * 1.45,
semiMajorAxis: this.bottomRadius * 1.45,
height: 0.0,
material: new Cesium.ConeGlowBottomRotateCircleMaterialProperty(this.color),
stRotation: new Cesium.CallbackProperty(e => {
stRotation--;
stRotation < 0 && (stRotation = 360);
return Cesium.Math.toRadians(stRotation);
}, false),
}
});
}
//移除光柱体
remove() {
//移除事件监听
this.viewer.scene.preUpdate.removeEventListener(this.preUpdateHandle, this);
this.viewer.entities.remove(this.bottomRotateCircle);
this.viewer.entities.remove(this.bottomCircle);
this.viewer.scene.primitives.remove(this.cylinderPrimitive);
}
}
ConeGlowMaterial/BottomCircle.js
import { createBottomCircleTexture } from "./Texture.js"
function ConeGlowBottomCircleMaterialProperty(color) {
this._definitionChanged = new Cesium.Event();
this._color = undefined;
this._colorSubscription = undefined;
this.color = color;
}
Object.defineProperties(ConeGlowBottomCircleMaterialProperty.prototype, {
isConstant: {
get: function() {
return false;
}
},
definitionChanged: {
get: function() {
return this._definitionChanged;
}
},
color: Cesium.createPropertyDescriptor("color")
});
ConeGlowBottomCircleMaterialProperty.prototype.getType = function(time) {
return "ConeGlowBottomCircle";
}
ConeGlowBottomCircleMaterialProperty.prototype.getValue = function(time, result) {
if (!Cesium.defined(result)) {
result = {};
}
result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
result.image = Cesium.Material.ConeGlowBottomCircleImage;
return result;
}
ConeGlowBottomCircleMaterialProperty.prototype.equals = function(other) {
return this === other ||
(other instanceof ConeGlowBottomCircleMaterialProperty &&
Cesium.Property.equals(this._color, other._color))
}
Cesium.ConeGlowBottomCircleMaterialProperty = ConeGlowBottomCircleMaterialProperty;
Cesium.Material.ConeGlowBottomCircleType = "ConeGlowBottomCircle";
Cesium.Material.ConeGlowBottomCircleImage = createBottomCircleTexture();
Cesium.Material.ConeGlowBottomCircleSource =
"czm_material czm_getMaterial(czm_materialInput materialInput)\n\
{\n\
czm_material material = czm_getDefaultMaterial(materialInput);\n\
vec2 st = materialInput.st;\n\
vec4 colorImage = texture2D(image, vec2(st ));\n\
material.alpha = colorImage.a * color.a;\n\
material.diffuse = 1.5* color.rgb ;\n\
return material;\n\
}";
Cesium.Material._materialCache.addMaterial(Cesium.Material.ConeGlowBottomCircleType, {
fabric: {
type: Cesium.Material.ConeGlowBottomCircleType,
uniforms: {
color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
image: Cesium.Material.ConeGlowBottomCircleImage,
time: 0
},
source: Cesium.Material.ConeGlowBottomCircleSource
},
translucent: function(material) {
return true;
}
});
ConeGlowMaterial/BottomRotateCircle.js
import { createBottomRotateCircleTexture } from "./Texture.js"
function ConeGlowBottomRotateCircleMaterialProperty(color) {
this._definitionChanged = new Cesium.Event();
this._color = undefined;
this._colorSubscription = undefined;
this.color = color;
}
Object.defineProperties(ConeGlowBottomRotateCircleMaterialProperty.prototype, {
isConstant: {
get: function() {
return false;
}
},
definitionChanged: {
get: function() {
return this._definitionChanged;
}
},
color: Cesium.createPropertyDescriptor("color")
});
ConeGlowBottomRotateCircleMaterialProperty.prototype.getType = function(time) {
return "ConeGlowBottomRotateCircle";
}
ConeGlowBottomRotateCircleMaterialProperty.prototype.getValue = function(time, result) {
if (!Cesium.defined(result)) {
result = {};
}
result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
result.image = Cesium.Material.ConeGlowBottomRotateCircleImage;
return result;
}
ConeGlowBottomRotateCircleMaterialProperty.prototype.equals = function(other) {
return this === other ||
(other instanceof ConeGlowBottomRotateCircleMaterialProperty &&
Cesium.Property.equals(this._color, other._color))
}
Cesium.ConeGlowBottomRotateCircleMaterialProperty = ConeGlowBottomRotateCircleMaterialProperty;
Cesium.Material.ConeGlowBottomRotateCircleType = "ConeGlowBottomRotateCircle";
Cesium.Material.ConeGlowBottomRotateCircleImage = createBottomRotateCircleTexture();
Cesium.Material.ConeGlowBottomRotateCircleSource =
"czm_material czm_getMaterial(czm_materialInput materialInput)\n\
{\n\
czm_material material = czm_getDefaultMaterial(materialInput);\n\
vec2 st = materialInput.st;\n\
vec4 colorImage = texture2D(image, vec2(st ));\n\
material.diffuse = 2.5 * color.rgb ;\n\
material.alpha = colorImage.a ;\n\
return material;\n\
}";
Cesium.Material._materialCache.addMaterial(Cesium.Material.ConeGlowBottomRotateCircleType, {
fabric: {
type: Cesium.Material.ConeGlowBottomRotateCircleType,
uniforms: {
color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
image: Cesium.Material.ConeGlowBottomRotateCircleImage,
time: 0
},
source: Cesium.Material.ConeGlowBottomRotateCircleSource
},
translucent: function(material) {
return true;
}
});
ConeGlowMaterial/Texture.js
//底部圆材质图片
export function createBottomCircleTexture() {
let canvas = document.createElement("canvas");
canvas.width = 512;
canvas.height = 512;
let ctx = canvas.getContext("2d");
let gradient = ctx.createRadialGradient(256, 256, 0, 256, 256, 256);
gradient.addColorStop(0.1, "rgba(255, 255, 255, 1.0)");
gradient.addColorStop(0.2, "rgba(255, 255, 255, 0.0)");
gradient.addColorStop(0.3, "rgba(255, 255, 255, 0.9)");
gradient.addColorStop(0.5, "rgba(255, 255, 255, 0.0)");
gradient.addColorStop(0.9, "rgba(255, 255, 255, 0.2)");
gradient.addColorStop(1.0, "rgba(255, 255, 255, 1.0)");
ctx.clearRect(0, 0, 512, 512);
ctx.beginPath();
ctx.arc(256, 256, 256, 0, Math.PI * 2, true);
//ctx.fillStyle = "rgb(0, 155, 255)";
ctx.fillStyle = gradient;
ctx.fill();
ctx.restore();
return canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
}
//底部运动圆材质图片
export function createBottomRotateCircleTexture() {
let canvas = document.createElement("canvas");
canvas.width = 512;
canvas.height = 512;
let ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 512, 512);
ctx.strokeStyle = "rgb(255, 255, 0)";
ctx.setLineDash([80, 80]);
ctx.lineWidth = 30;
ctx.arc(256, 256, 241, 0, Math.PI * 2, true);
ctx.stroke();
return canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
}