前言
人生一迹,谨以此记录Cesium相关系列知识
问题背景:飞机绕着宝岛飞的过程中,需要对飞机进行隐形和现形!
书接上回,上回咱们说到:"小红加油机"和我驾驶的飞机,在宝岛上空进行了一场惊心动魄的空中追赶加油。加油完成,飞机的燃油表指针再次跳跃到了安全区域。我通报给塔台加油成功,并告知即将执行隐形模式以测试新近升级的隐形技术。地面控制人员回应了确认信号,紧张的氛围似乎稍微缓和了一些。
随着一声清脆的开关响起,飞机外壳表面开始发生微妙的变化。采用先进的隐形材料和设计的机身,逐渐扭曲周围的光线,使得飞机的轮廓开始模糊,慢慢和背景的天空融为一体。这种科技奇迹仿佛赋予了我的小型飞机魔法般的力量,它像幽灵一样在云层中穿梭,不留痕迹。
我仔细监视着仪表盘上的各项读数,确保所有系统都正常工作。虽然外界无法再观察到我们的存在,但机内的传感器依旧忠实地反馈着周遭环境的每一个细节。此时,我的飞机就像是宝岛上空的一只隐秘的眼睛,洞察着下方的一切,而且毫无声息。
再次凭借技术的辅助,我的飞机成了高空的幽灵,即便是雷达也难以捕捉到它的踪迹。我心中涌动着混合着兴奋与敬畏的情感,对于祖国能有如此尖端飞行装备感到很自豪。
问题复现:cesium加载模型或取消模型动画太突兀!如何能让模型渐变消失或渐变出现?
(重点思路:在于如何丝滑地动态改变透明度?)
一、Cesium加载Entity
注意加载模型的参数设置与,加载完并定位到模型(zoomTo),以避免找不到加载的模型。
less
var position = Cesium.Cartesian3.fromDegrees( 113.31751382542802, 32.7160812520516,500);
var model_entity = viewer.entities.add({
name: "model_entity",
position: position,
model: {
show: true,
uri: "Data/airPlane_cesium.gltf",
scale: 1.0, // 缩放比例
minimumPixelSize: 128, // 最小像素大小
maximumScale: 20000, // 模型的最大比例尺大小。minimumPixelSize的上限
incrementallyLoadTextures: true, // 加载模型后纹理是否可以继续流入
runAnimations: true, // 是否应启动模型中指定的glTF动画
clampAnimations: true, // 指定glTF动画是否应在没有关键帧的持续时间内保持最后一个姿势
shadows: Cesium.ShadowMode.ENABLED,
heightReference: Cesium.HeightReference.NONE,
color:Cesium.Color.WHITE.withAlpha(1)
},
});
viewer.zoomTo(model_entity); //定位到模型
二、改变模型透明度
首先需要确定Cesium是否可以更改Entity模型的透明度,经过查找找到Entity的属性参数model里面有一个color可以更改其值,达到透明度的效果。
ini
model_entity.model.color = Cesium.Color.WHITE.withAlpha(0)
三、定时器动态更改模型透明度
第一个直达脑子的想法是,利用定时器动态去更改模型透明度,说干就干,马上开写,见下文代码。
ini
// 设置初始透明度为 1
var alpha = 1.0;
model_entity.model.color = Cesium.Color.WHITE.withAlpha(alpha);
// 创建定时器,每隔一段时间减少透明度
var intervalId = setInterval(function() {
// 每次调用减少透明度
alpha -= 0.1;
// 更新实体颜色的透明度
model_entity.model.color = Cesium.Color.WHITE.withAlpha(alpha);
// 检查透明度是否已经达到或低于0
if (alpha <= 0) {
clearInterval(intervalId); // 清除定时器
console.log('完毕'); // 打印"完毕"
}
}, 100); // 这里的100表示定时器每100毫秒执行一次
写完,一运行,马上傻眼了,效果很差劲,如我预想的,一卡一卡地,但是不死心,始终是觉得100ms和透明度减少的大小存在一定偏差,只需要调到一个合适的值就OK了,但是方法错了终究是错了,奈何怎么调整都达不到丝滑变化的效果。
四、requestAnimationFrame丝滑改变透明度
requestAnimationFrame是一个浏览器原始方法,官方定义如下: 详情请移步-->全面理解 requestAnimationFrame,总之千言万语一句话,这个方法是浏览器本身自带的,目的是用来做丝滑动画,消除卡顿,抖动等异常效果。
五、Cesium线性插值模块
那么动态改变透明度的动态卡顿问题解决了,接下来就是解决透明度值的变化幅度的问题,刚开始想到了线性变化,在cesiumAPI中有一个函数为Math.lerp。此步骤主要是为了线性调整透明度变化吧,用递增或者是递减固定值,始终是觉得不够丝滑,不如直接用已有的函数动态插值。
sql
// 用于计算指定时间参数在两个值之间的线性插值,这个功能通常用于在动画和过渡中平滑地从一个值变化到另一个值
// time:插值所处的时间点,它是一个介于0.0和1.0之间的归一化值。
// time = 0,返回start;time=1,返回end
Cesium.Math.lerp(start, end, time);
六、透明度函数
注意事项:
1、需要提前在add模型的时候,就赋予模型model属性color值,否则会出现跳帧现象。
2、更改startAlpha和endAlpha以及初始color值,可以实现渐显(淡出)效果
ini
// 设置参数
var startAlpha = 1.0;
var endAlpha = 0.0;
var duration = 200; // 持续2秒
var startTime = null;
function updateAlpha(timestamp) {
if (!startTime) startTime = timestamp;
var elapsed = timestamp - startTime;
// 计算当前透明度并更新模型透明度(线性插值)
var alpha = Cesium.Math.lerp(startAlpha, endAlpha, elapsed / duration);
gltfEntity.model.color = Cesium.Color.WHITE.withAlpha(alpha);
if (elapsed < duration) {
// 浏览器重绘前的回调函数(替代定时器消除卡顿效果,用于流畅高性能动画效果)
requestAnimationFrame(updateAlpha);
} else {
gltfEntity.model.color = Cesium.Color.WHITE.withAlpha(endAlpha);
// 到达目标透明度后,可选择是否删除实体
// viewer.entities.remove(gltfEntity);
}
}
// 开始动画
requestAnimationFrame(updateAlpha)
七、全部代码
xml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>我的飞机绕着宝岛飞</title>
<!-- <link rel="stylesheet" href="./CesiumUnminified/Widgets/widgets.css">
<script type="text/javascript" src="./CesiumUnminified/Cesium.js"></script> -->
<link rel="stylesheet" href="./Cesium/Widgets/widgets.css">
<script type="text/javascript" src="./Cesium/Cesium.js"></script>
</head>
<body>
<button id="modelDisappear" style="width: 80px;height: 30px;color: black;">渐隐</button>
<div id="cesiumdiv"></div>
<script type="text/javascript">
let viewer = new Cesium.Viewer('cesiumContainer');
// 更换底图
let imageryLayers = viewer.imageryLayers;
let map = new Cesium.UrlTemplateImageryProvider({
url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}", //高德地图
minimumLevel: 3,
maximumLevel: 16,
});
imageryLayers.addImageryProvider(map); //添加地图贴图
// 场景定位
viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(121.195,21.813,738947.02),
orientation :{
heading : Cesium.Math.toRadians(355.1),
pitch : Cesium.Math.toRadians(-75.3),
roll :0.0
}
});
var position = Cesium.Cartesian3.fromDegrees( 113.31751382542802, 32.7160812520516,500);
var model_entity = viewer.entities.add({
name: "model_entity",
position: position,
model: {
show: true,
uri: "Data/airPlane_cesium.gltf",
scale: 1.0, // 缩放比例
minimumPixelSize: 128, // 最小像素大小
maximumScale: 20000, // 模型的最大比例尺大小。minimumPixelSize的上限
incrementallyLoadTextures: true, // 加载模型后纹理是否可以继续流入
runAnimations: true, // 是否应启动模型中指定的glTF动画
clampAnimations: true, // 指定glTF动画是否应在没有关键帧的持续时间内保持最后一个姿势
shadows: Cesium.ShadowMode.ENABLED,
heightReference: Cesium.HeightReference.NONE,
color:Cesium.Color.WHITE.withAlpha(1)
},
});
viewer.trackedEntity = model_entity; // 聚焦模型
viewer.zoomTo(model_entity); //定位到模型
// 设置参数
var startAlpha = 1.0;
var endAlpha = 0.0;
var duration = 2000; // 持续2秒
var startTime = null;
// 绑定点击事件到按钮上
let btn = document.getElementById('modelDisappear')
btn.addEventListener('click',() =>{
// 开始动画
requestAnimationFrame(updateAlpha)
})
function updateAlpha(timestamp) {
if (!startTime) startTime = timestamp;
var elapsed = timestamp - startTime;
// 计算当前透明度并更新模型透明度(线性插值)
var alpha = Cesium.Math.lerp(startAlpha, endAlpha, elapsed / duration);
model_entity.model.color = Cesium.Color.WHITE.withAlpha(alpha);
if (elapsed < duration) {
// 浏览器重绘前的回调函数(替代定时器消除卡顿效果,用于流畅高性能动画效果)
requestAnimationFrame(updateAlpha);
} else {
model_entity.model.color = Cesium.Color.WHITE.withAlpha(endAlpha);
// 到达目标透明度后,可选择是否删除实体
// viewer.entities.remove(gltfEntity);
}
}
</script>
</body>
</html>