前言
在一些智慧城市、智慧园区等等数字孪生的项目里,往往需要实现一些炫酷的特效去展示孪生数据,今天来教大家实现一个"电子围栏"的特效,可以用于区域范围展示、建筑效果选中等等功能,效果如下图。
基本原理
图形学中给模型贴图的原理是通过给每一个顶点加上一个‘UV’坐标,再通过这个左边取贴图读取相应的像素值,两个点之间的‘UV’坐标会插值。那么如何让贴图移动起来呢?原理很简单,我们只需要每一帧都给‘UV’坐标加上一个偏移的值,这样每一帧读取的像素值就会改变,贴图就‘移动’起来了。
cesium实现
要实现这个效果,我们先用WallGeometry创建一个‘围栏’的模型,代码如下,需要注意的是我们要把appearance的faceForward设置为true,不然看不到‘围栏’的背面
const wall = new Cesium.WallGeometry({
positions : Cesium.Cartesian3.fromDegrees(points),
});
const geometry = Cesium.WallGeometry.createGeometry(wall);
const instanceTop = new Cesium.GeometryInstance({
geometry : geometry,
attributes : {
color : Cesium.ColorGeometryInstanceAttribute.fromColor(Color.AQUA)
},
});
let wallMesh = viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instanceTop,
asynchronous: false,
appearance : new Cesium.PerInstanceColorAppearance({
flat: true,
faceForward: true,
renderState: {
depthTest: {
enabled: true
}
}
})
})
);
接下来我们准备两张贴图,然后再修改一下appearance
let wallMesh = viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instanceTop,
asynchronous: false,
appearance : new Cesium.MaterialAppearance({
faceForward: true,
material: new Cesium.Material({
fabric: {
type: "Image",
uniforms: {
image: "./img/glowWall.png",
},
},
}),
})
})
);
修改后可以得到以下的效果
目前贴图还是静止的,我们再来修改material来贴图动起来
let wallMesh = viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instanceTop,
appearance : new Cesium.MaterialAppearance({
faceForward: true,
material: new Cesium.Material({
fabric: {
type: "zfImage",
uniforms: {
image: "./img/glowWall.png",
},
source: `czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
//这里通过不断对st.t加上偏移,让贴图动起来, * 3是可以让贴图重复贴三次。
vec4 colorImage = texture(image,vec2(st.s, fract(st.t * 3.0 - czm_frameNumber * 0.032)));
material.alpha = colorImage.a;
material.diffuse = colorImage.rgb;
return material;
}`,
},
}),
}),
asynchronous: false
})
);
优化效果
我们可以看到目前有了一个基本的‘电子围栏’的效果,但是感觉还是差点,比如顶部围栏消失太过生硬。
解决这个问题我们可以在一张贴图去让其渐变
let wallMesh = viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instanceTop,
appearance : new Cesium.MaterialAppearance({
faceForward: true,
material: new Cesium.Material({
fabric: {
type: "zfImage",
uniforms: {
image: "./img/glowWall.png",
image1:"./img/glowWall.jpg"
},
source: `czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
vec4 colorImage = texture(image,vec2(st.s, fract(st.t * 3.0 - czm_frameNumber * 0.032)));
vec4 color2 = texture(image1, st);
material.alpha = colorImage.a * color2.x;
material.diffuse = colorImage.rgb;
return material;
}`,
},
}),
}),
asynchronous: false
})
);