《我的飞机绕着宝岛飞》第三章(隐匿于云端的幻影神奇魔法)

前言

人生一迹,谨以此记录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>
相关推荐
gqkmiss24 分钟前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools
Summer不秃29 分钟前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰34 分钟前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter
Viktor_Ye40 分钟前
高效集成易快报与金蝶应付单的方案
java·前端·数据库
hummhumm42 分钟前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
乐闻x1 小时前
Vue.js 性能优化指南:掌握 keep-alive 的使用技巧
前端·vue.js·性能优化
一条晒干的咸魚1 小时前
【Web前端】创建我的第一个 Web 表单
服务器·前端·javascript·json·对象·表单
Amd7941 小时前
Nuxt.js 应用中的 webpack:compiled 事件钩子
前端·webpack·开发·编译·nuxt.js·事件·钩子
生椰拿铁You2 小时前
09 —— Webpack搭建开发环境
前端·webpack·node.js
狸克先生2 小时前
如何用AI写小说(二):Gradio 超简单的网页前端交互
前端·人工智能·chatgpt·交互