Cesium实现动态旋转四棱锥(2023.9.11)

news2024/11/29 12:45:35

Cesium实现动态悬浮旋转四棱锥效果 2023.9.11

  • 1、引言
  • 2、两种实现思路介绍
    • 2.1 思路一:添加已有的四棱锥(金字塔)模型实现(简单但受限)
    • 2.2 思路二:自定义四棱锥几何模型实现(复杂且灵活)
  • 3、代码实现及效果展示
    • 3.1 思路一
      • 3.1.1 代码实现
      • 3.1.2 展示结果
    • 3.2 思路二
      • 3.2.1 代码实现
      • 3.2.2 展示结果
  • 4、总结

1、引言

        最近看到一些数字城市特效,其中包含四棱锥动态旋转的效果,乍一看眼前一亮,静下来来冷静思考觉得实现起来应该也十分简单,于是打算写此博客与诸位开发者共同分享,当然也是为了记录学习点滴!🕺🕺🕺❤️❤️❤️

2、两种实现思路介绍

        顾名思义,动态悬浮旋转四棱锥效果中的关键词包括:四棱锥(金字塔)、旋转、动态

2.1 思路一:添加已有的四棱锥(金字塔)模型实现(简单但受限)

        寻找并选择一个现成的四棱锥模型(gltfglb文件),调用Cesium添加Model的API将其作为模型加载到三维场景当中,之后动态设置旋转角度、位置高度即可。
        假设准备好的模型文件为pyramid.glb文件,利用Windows系统自带的3D查看器通过设置跳跃、悬浮等动作即可预览动态效果。

在这里插入图片描述
在这里插入图片描述

2.2 思路二:自定义四棱锥几何模型实现(复杂且灵活)

        调用Cesium底层API自定义几何形状(Geometry)和原型(Primitive),构造属于四棱锥的DrawCommand类实现create方法在三维场景Scene中添加四棱锥几何形状并设置纹理显示,实现update方法在每一帧画面中更新显示动态旋转及上下悬浮效果。

图1 四棱锥几何立体示意
注:红色圆圈代表顶点、橙色数字代表顶点索引编号、蓝色实线代表各边。

        值得注意的是,我们仍需明确有关正四棱锥的一些数学理论知识:在三维立体几何空间中,四棱锥包含5个顶点、6个三角面(1个四边形可拆分为2个三角形),每个顶点包含X、Y、Z这三个坐标。如果给所有顶点从0开始进行顺序编号,那么各个三角面就能根据三个顶点索引随着确定,相应地纹理赋值也能随之确定。

3、代码实现及效果展示

        接下来将具体调用CesiumAPI按照上述两种思路分别进行实现,具体代码如下:

3.1 思路一

3.1.1 代码实现


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Cesium旋转金字塔-jjg</title>
  <!-- 引入Cesium -->
  <script src="https://unpkg.com/cesium@1.84.0/Build/Cesium/Cesium.js"></script>
  <link rel="stylesheet" href="https://unpkg.com/cesium@1.84.0/Build/Cesium/Widgets/widgets.css">
  <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
  <link rel="stylesheet" href="https://unpkg.com/element-ui@2.15.5/lib/theme-chalk/index.css">
  <script src="https://unpkg.com/element-ui@2.15.5/lib/index.js"></script>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body,
    #viewer-container {
      width: 100%;
      height: 100%;
      overflow: hidden;
    }

    .cesium-widget-credits{ 
      display:none!important; 
      visibility:hide!important; 
    }
    .cesium-viewer-toolbar{
      display:none!important; 
      visibility:hide!important;
    }
    .form-container {
      position: absolute;
      left: 10px;
      top: 90px;
      padding: 10px 15px;
      border-radius: 4px;
      border: 1px solid rgba(128, 128, 128, 0.5);
      color: #ffffff;
      background: rgba(0, 0, 0, 0.4);
      box-shadow: 0 3px 14px rgb(128 128 128 / 50%);
      max-width: 380px;
    }
    button {
      background: transparent;
      border: 1px solid #00d0ffb8;
      color: white;
      padding: 7px 9px;
      border-radius: 2px;
      margin: 3px;
      cursor: pointer
    }
    .tip-item {
      margin: 2px 0px;
      padding: 5px 1px;
    }
  </style>
</head>

<body>
  <div id="viewer-container"></div>
  <div class="form-container" id="formContainer">
    <button onclick="setvisible('add')" style="margin-left:120px;">添加旋转金字塔</button>
    <button onclick="setvisible('remove')">移除旋转金字塔</button>
  </div>
  <script>
    var viewer = null;
    var modelEntity = null;

    // 开关
    function setvisible(value) {
      switch (value) {
        case 'add':
          addPyramidModel();
          break;
        case 'remove':
          removeRotateCircle();
          break;
      }
    }
    // 添加旋转金字塔
    function addPyramidModel() {
        let hpr = new Cesium.HeadingPitchRoll(
            Cesium.Math.toRadians(0),
            Cesium.Math.toRadians(180),//0朝下 180朝上
            Cesium.Math.toRadians(0)
        )
        let r = Cesium.Math.toRadians(2);
        let lon = 121.50320483066757, lat = 31.23641093043576, height = 382.83983348350085,isUp = true;
        // let position = Cesium.Cartesian3.fromDegrees(121.50320483066757, 31.23641093043576, 382.83983348350085);
        modelEntity = this.viewer.entities.add({
            position:  new Cesium.CallbackProperty(e => {
              if(height > 400)
              {
                height = 400;
                isUp = false;

              }
              else if(height < 350)
              {
                height = 350;
                isUp = true;
              }
              if(isUp)
              {
                height += 1.0;
              }
              else
              {
                height -= 1.0;
              }
              
              return Cesium.Cartesian3.fromDegrees(lon,lat,height);
            }, false),
            //旋转起来
            orientation: new Cesium.CallbackProperty(e => {
                window.console.log(e);
                hpr.heading += r;
               
                let position = Cesium.Cartesian3.fromDegrees(lon,lat, height);
                return Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
            }, false),
            model: {
                uri: "pyramid.glb",//this.style.modelUrl
                scale: 40,//this.style.scale || 
                color: Cesium.Color.YELLOW.withAlpha(0.8),
                colorBlendMode: Cesium.ColorBlendMode.MIX,
            }
        });
    
      viewer.flyTo(modelEntity);
    }

    // 移除旋转金字塔
    function removeRotateCircle() {
      if(modelEntity != null)
      {
        viewer.entities.remove(modelEntity);
        modelEntity.destroy();
        modelEntity = null;
      }
    }

    // init
    function initPage() {
      // 切换自己的token
      Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlYTQ2ZjdjNS1jM2E0LTQ1M2EtOWM0My1mODMzNzY3YjYzY2YiLCJpZCI6MjkzMjcsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1OTE5NDIzNjB9.RzKlVTVDTQ9r7cqCo-PDydgUh8Frgw0Erul_BVxiS9c';
      // 初始化
      viewer = new Cesium.Viewer("viewer-container", {
        infoBox: false,
        shouldAnimate: true,
        vrButton: true,
        geocoder: false,
        homeButton: false,
        sceneModePicker: false,
        baseLayerPicker: false,
        navigationHelpButton: false,
        animation: false,//动画控制不显示
        timeline: false,//时间线不显示
        fullscreenButton: false,//全屏按钮不显示
        terrainProvider: Cesium.createWorldTerrain({
           requestWaterMask: true, // 水特效
           requestVertexNormals: true // 地形光
        }),
      });
      // 加载倾斜摄影 大雁塔
      
      //var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
      //  url: 'http://earthsdk.com/v/last/Apps/assets/dayanta/tileset.json'
      //}));
      //viewer.flyTo(tileset);
      viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
        url: 'http://earthsdk.com/v/last/Apps/assets/dayanta/tileset.json',
        show: true,
        backFaceCulling: true,
       })
      ).readyPromise.then((tileset) => {
        //拉伸模型高度代码
        let heightOffset = -26;
        var boundingSphere = tileset.boundingSphere;
        var cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center);
        var surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0);
        var offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset);
        var translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
        tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
        //viewer.zoomTo(tileset)
        viewer.flyTo(tileset);
      })
    }
    // 
    window.onload = function () {
      initPage();
    }


    
  </script>
</body>

</html>

3.1.2 展示结果

3.2 思路二

3.2.1 代码实现


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <style>
    .cesium-widget-credits{ 
      display:none!important; 
      visibility:hide!important; 
    }
    .cesium-viewer-toolbar{
      display:none!important; 
      visibility:hide!important;
    }
    .middleTop {
      width: 300px;
      height: 30px;
      position: fixed;
      top: 10px;
      left: 20px;
      text-align: center;
      background: red;
      opacity: 0.6;
    }
    button {
      background: gray;
      border: 1px solid #00d0ffb8;
      color: white;
      padding: 7px 9px;
      border-radius: 2px;
      margin: 3px;
      cursor: pointer
    }
    .tip-item {
      margin: 2px 0px;
      padding: 5px 1px;
    }
  </style>
  <script src="https://cesium.com/downloads/cesiumjs/releases/1.89/Build/Cesium/Cesium.js"></script>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.89/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
  <!-- <script src="https://cesium.com/downloads/cesiumjs/releases/1.108/Build/Cesium/Cesium.js"></script>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.108/Build/Cesium/Widgets/widgets.css" rel="stylesheet"> -->
</head>
<body>
  <div id="cesiumContainer" style="width:100%;height:100%;">
  </div>
  <div class="middleTop" id="demo2">
    <div class="map-tool">
      <button id="addTetrahedron" class="newBtn">添加倒立四棱锥</button>
      <button id="removeTetrahedron" class="newBtn">移除一个倒立四棱锥</button>
    </div>
  </div>
  <script>
    Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIwZDhhOThhNy0zMzUzLTRiZDktYWM3Ni00NGI5MGY2N2UwZDUiLCJpZCI6MjQzMjYsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1ODUwMzUwNDh9.DYuDF_RPKe5_8w849_y-sutM68LM51O9o3bTt_3rF1w";
    const viewer = new Cesium.Viewer('cesiumContainer', { // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
      baseLayerPicker: false,
        //shadows: true,
        shouldAnimate: true,
      infoBox: false,
      animation: false,//动画控制不显示
      timeline: false,//时间线不显示
      fullscreenButton: false, //全屏按钮不显示
      terrainProvider: Cesium.createWorldTerrain({
        requestWaterMask: true, // 水特效
        requestVertexNormals: true // 地形光
      }),
      selectionIndicator: false, // By JIAO Jingguo 2022.9.21 移除Cesium自带的绿色聚焦瞄准框
       //imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
       //  url: 'http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer',
       //}),
    });
    viewer._cesiumWidget._creditContainer.style.display = "none";//去除版权信息
    //viewer.scene.globe.depthTestAgainstTerrain = true;
    let silhouette = null,skylineAnayStages = null;//天际线分析工具
    //打开天际线分析
    function openSkylineAnay() {
      if(skylineAnayStages){
        silhouette.enabled=true;
        return;
      }
      skylineAnayStages = viewer.scene.postProcessStages;
      let edgeDetection = Cesium.PostProcessStageLibrary.createEdgeDetectionStage();
      let postProccessStage = new Cesium.PostProcessStage({
        //此后处理阶段的唯一名称,供组合中其他阶段参考,如果未提供名称,将自动生成GUID
        // name:name,
        //unform着色器对象 textureScale
        fragmentShader: 'uniform sampler2D colorTexture;' +
            'uniform sampler2D depthTexture;' +
            'varying vec2 v_textureCoordinates;' +
            'void main(void)' +
            '{' +
            'float depth = czm_readDepth(depthTexture, v_textureCoordinates);' +
            'vec4 color = texture2D(colorTexture, v_textureCoordinates);' +
            'if(depth<1.0 - 0.000001){' +
            'gl_FragColor = color;' +
            '}' +
            'else{' +
            'gl_FragColor = vec4(1.0,0.0,0.0,1.0);' +
            '}' +
            '}'
      });
 
      //PostProcessStage:要使用的片段着色器。默认sampler2D制服是colorTexture和depthTexture。
      let postProccesStage_1 = new Cesium.PostProcessStage({
        // name:obj.name+'_1',
        fragmentShader: 'uniform sampler2D colorTexture;' +
            'uniform sampler2D redTexture;' +
            'uniform sampler2D silhouetteTexture;' +
            'varying vec2 v_textureCoordinates;' +
            'void main(void)' +
            '{' +
            'vec4 redcolor=texture2D(redTexture, v_textureCoordinates);' +
            'vec4 silhouetteColor = texture2D(silhouetteTexture, v_textureCoordinates);' +
            'vec4 color = texture2D(colorTexture, v_textureCoordinates);' +
            'if(redcolor.r == 1.0){' +
            'gl_FragColor = mix(color, vec4(5.0,0.0,0.0,1.0), silhouetteColor.a);' +
            '}' +
            'else{' +
            'gl_FragColor = color;' +
            '}' +
            '}',
        //uniform着色器对象
        uniforms: {
          redTexture: postProccessStage.name,
          silhouetteTexture: edgeDetection.name
        }
      });
 
      //如果inputPreviousStageTexture 是 true,则每个阶段输入是场景渲染到的输出纹理或之前执行阶段的输出纹理
      //如果inputPreviousStageTexture是false,则合成中每个阶段的输入纹理都是相同的
      silhouette= new Cesium.PostProcessStageComposite({
        stages:[edgeDetection,postProccessStage,postProccesStage_1], //PostProcessStage要按顺序执行 的 s 或组合的数组。
        inputPreviousStageTexture:false,//是否执行每个后处理阶段,其中一个阶段的输入是前一个阶段的输出。否则每个包含阶段的输入是组合之前执行的阶段的输出
        uniforms:edgeDetection.uniforms//后处理阶段制服的别名
      })
      skylineAnayStages.add(silhouette);
    };
    
    function closeSkylineAnay(){ //关闭天际线分析
      if(silhouette != null)
        silhouette.enabled=false;
    };
    function flyToTianJin() {
      viewer.camera.flyTo({
        destination : Cesium.Cartesian3.fromDegrees(117.17888105784743,39.06048272010123, 5000),
        orientation : {
          heading : Cesium.Math.toRadians(0.0),
          pitch : Cesium.Math.toRadians(-90.0),
          roll: 0.0,
        }
      });
    };

      // 添加四棱锥
      document.getElementById("addTetrahedron").addEventListener("click", function (e) {
        onLineTetra();// By JIAO Jingguo 2023.8.31
      });
      // 移除四棱锥
      document.getElementById("removeTetrahedron").addEventListener("click", function (e) {
        removeSinglePrimitive();// By JIAO Jingguo 2023.8.31
      });

      let addedPrimitives = [];
      function onLineTetra() // By JIAO Jingguo 2023.8.31 源自 Mars3d源码启发 和 网上资料
      {
        function TetrahedronPrimitive(options){
          this.show = true;
          this._command = undefined;
          this._enuMatrix=undefined;
          this._scaleMatrix=undefined;
          this._localPosition = options.position;
          this._createCommand = createCommand;
          this._angle=0;
          this._distance= Cesium.defaultValue(options.distance,1);
          this._setInterval=undefined;
          this._viewer= viewer;
          this._speed= Cesium.defaultValue(options.speed,1.0);
          this._color= Cesium.defaultValue(options.color,new  Cesium.Color(1.0,0.0,0.0,0.8));
          this._scale= Cesium.defaultValue(options.scale,new  Cesium.Cartesian3(10, 10, 15));
          this._texture=undefined;
          // this._imageUrl= Cesium.buildModuleUrl('./fence.png');
          this._modelMatrix=computeModelMatrix(this);
          this._height=computeHeight(this);
          //debugger
          // createTexture(this);
      }
      TetrahedronPrimitive.prototype.update=function(frameState) {
          if (!this.show)
          {
              return;
          }
          if (! Cesium.defined(this._command))
          {
              this._command = this._createCommand(frameState.context,this);
              this._command.pickId = 'v_pickColor';
          }
          if ( Cesium.defined(this._command))
          {
              frameState.commandList.push(this._command);
          }
      }
      TetrahedronPrimitive.prototype.isDestroyed=function() {
          return false;
      }
      TetrahedronPrimitive.prototype.destroy=function() {
          if ( Cesium.defined(this._command))
          {
              this._command.shaderProgram = this._command.shaderProgram && this._command.shaderProgram.destroy();
          }
          return  Cesium.destroyObject(this);
      }

      //开启动画
      TetrahedronPrimitive.prototype.startAnimate=function(){
        let that=this;
        this._setInterval=setInterval(animateFunc,5);
          function animateFunc(){
              that._angle=that._angle+0.01;
            if(Math.sin(that._angle) < 0)
            {
              that._height=0.01;
            }
            else
            {
              that._height=-0.01;
            }

              let translation =  new Cesium.Cartesian3( 0, 0, that._height );
              Cesium.Matrix4.multiplyByTranslation(that._modelMatrix, translation, that._modelMatrix);
              let rotationZ =  Cesium.Matrix4.fromRotationTranslation( Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(that._speed)));
              Cesium.Matrix4.multiply(that._modelMatrix, rotationZ, that._modelMatrix);
          }
      }
      //关闭动画
      TetrahedronPrimitive.prototype.closeAnimate=function(){
          clearInterval(this._setInterval);
      }
      //创建command
      function createCommand(context,tetrahedronPrimitive) {
          var translucent = false;
          var closed = true;
          var vs = creaateVertexShader();
          var fs = createFragmentShader();
          // 借用一下Appearance.getDefaultRenderState
          var rawRenderState =  Cesium.Appearance.getDefaultRenderState(translucent, closed, undefined);
          var renderState =  Cesium.RenderState.fromCache(rawRenderState);
          var vertexShaderSource = new  Cesium.ShaderSource({
              sources: [vs]
          });
          var fragmentShaderSource = new  Cesium.ShaderSource({
              sources: [fs]
          });
          var uniformMap = {
              color: function() {
                  return tetrahedronPrimitive._color;
              },
              myImage: function() {
                  if (Cesium.defined(tetrahedronPrimitive._texture)) {
                      return tetrahedronPrimitive._texture;
                  } else {
                      return tetrahedronPrimitive._viewer.scene.context.defaultTexture;
                  }
              }
          };
          let attributeLocations = {
              position: 0,
              textureCoordinates:1
          };
          var shaderProgram =  Cesium.ShaderProgram.fromCache({
              context: context,
              vertexShaderSource: vertexShaderSource,
              fragmentShaderSource: fragmentShaderSource,
              attributeLocations: attributeLocations
          });
          return new  Cesium.DrawCommand({
              vertexArray: createVertexArray(context),
              primitiveType:  Cesium.PrimitiveType.TRIANGLES,
              renderState: renderState,
              shaderProgram: shaderProgram,
              uniformMap: uniformMap,
              owner: this,
              pass:  Cesium.Pass.TRANSLUCENT,
              modelMatrix: tetrahedronPrimitive._modelMatrix,
          });
      }
      //创建vertexArray
      function createVertexArray(context) {
          let attributeLocations = {
              position: 0,
              textureCoordinates:1
          };
          var positionsAndIndice=cereatePositionsAndIndice();
          var geometry = new  Cesium.Geometry({
              attributes: {
                  position: new  Cesium.GeometryAttribute({
                      // 使用double类型的position进行计算
                      // componentDatatype : Cesium.ComponentDatatype.DOUBLE,
                      componentDatatype:  Cesium.ComponentDatatype.FLOAT,
                      componentsPerAttribute: 3,
                      values: positionsAndIndice.positions
                  }),
                  textureCoordinates: new  Cesium.GeometryAttribute({
                      componentDatatype:  Cesium.ComponentDatatype.FLOAT,
                      componentsPerAttribute: 2,
                      values: positionsAndIndice.sts
                  }),
              },
              // Workaround Internet Explorer 11.0.8 lack of TRIANGLE_FAN
              indices: positionsAndIndice.indices,
              primitiveType:  Cesium.PrimitiveType.TRIANGLES,
              boundingSphere:  Cesium.BoundingSphere.fromVertices(positionsAndIndice.positions)
          });
          //计算geometry的法向量
          var geometryNormal=  Cesium.GeometryPipeline.computeNormal(geometry);
          var vertexArray =  Cesium.VertexArray.fromGeometry({
              context: context,
              geometry: geometryNormal,
              attributeLocations: attributeLocations,
              bufferUsage:  Cesium.BufferUsage.STATIC_DRAW,
          });
          return vertexArray;
      }
      //创建顶点数组与索引
      function cereatePositionsAndIndice(){
          var positions = new Float64Array(5 * 3);
          // position 0
          positions[0] = 0.0;
          positions[1] = 1.0;
          positions[2] = 0.0;

          // position 1
          positions[3] = -1.0;
          positions[4] = 0.0;
          positions[5] = 0.0;

          // position 2
          positions[6] = 0.0;
          positions[7] = -1.0;
          positions[8] = 0.0;

          // position 3
          positions[9] = 1.0;
          positions[10] = 0.0;
          positions[11] = 0.0;

          // position 4
          positions[12] = 0.0;
          positions[13] = 0.0;
          positions[14] = 1.0;
          var indices = new Uint16Array(6 * 3);
          // back triangle
          indices[0] = 4;
          indices[1] = 2;
          indices[2] = 3;

          // left triangle
          indices[3] = 4;
          indices[4] = 3;
          indices[5] = 0;

          // right triangle
          indices[6] = 4;
          indices[7] = 0;
          indices[8] = 1;

          // bottom triangle
          indices[9] = 4;
          indices[10] = 1;
          indices[11] = 2;
          // bottom triangle
          indices[12] = 1;
          indices[13] = 2;
          indices[14] = 3;

          // bottom triangle
          indices[15] = 1;
          indices[16] = 3;
          indices[17] = 0;

          // 1.3 定义纹理数组
        var sts = new Float32Array([
              0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
              0.0, 1.0, 0.5, 0.5,
          ]);
        return {
          indices:indices,
          positions:positions,
          sts:sts
        };
      }
      //创建顶点着色器
      function creaateVertexShader(){
          var vertexShader =
          `
          attribute vec3 position;
          attribute vec3 normal;
          attribute vec2 st;
          attribute float batchId;
          varying vec3 v_positionEC;
          varying vec3 v_normalEC;
          varying vec2 v_st;
          varying vec4 v_pickColor;
          void main()
          {
              v_positionEC = (czm_modelView * vec4(position, 1.0)).xyz;       // position in eye coordinates
              v_normalEC = czm_normal * normal;                               // normal in eye coordinates
              v_st = st;
              //v_pickColor = czm_batchTable_pickColor(batchId);
              gl_Position = czm_modelViewProjection * vec4(position, 1.0);
          }
          `;
          return vertexShader;
      }
      //创建片源着色器
      function createFragmentShader(){
          var fragmentShader =
          `
          varying vec3 v_positionEC;
          varying vec3 v_normalEC;
          varying vec2 v_st;
          uniform vec4 color;
          varying vec4 v_pickColor;
          uniform sampler2D myImage;
          void main()
          {
              vec3 positionToEyeEC = -v_positionEC;
              vec3 normalEC = normalize(v_normalEC);
          #ifdef FACE_FORWARD
              normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);
          #endif
              czm_materialInput materialInput;
              materialInput.normalEC = normalEC;
              materialInput.positionToEyeEC = positionToEyeEC;
              materialInput.st = v_st;
              vec2 st = materialInput.st;
              czm_material material = czm_getDefaultMaterial(materialInput);
              // float dt_a11 = fract(czm_frameNumber / 100.0) * 3.14159265 * 2.0;
              // float dt_a12 = sin(dt_a11);
              // float vst=smoothstep(0.7, 1.0, dt_a12)+0.4;
              // vec4 colorImage = texture2D(myImage, vec2(fract(st.s- czm_frameNumber*0.003), st.t));
              // material.alpha =mix(0.1,1.0,clamp((1.0-st.t) * color.a,0.0,1.0)) +(1.0-sign(st.t-czm_frameNumber*0.001))*0.2*(1.0-colorImage.r)+0.4 ;
              // material.diffuse =(1.0-colorImage.a)*vec3(1.0,0.0,0.0)+colorImage.rgb*vec3(1.0,1.0,0);

              material.alpha = (mix(0.1, 1.0, clamp((1.0 - st.t) * color.a, 0.0, 1.0)) + (1.0 - sign(st.t - czm_frameNumber * 0.001)) * 0.2 + 0.4) * 0.8;
              material.diffuse = color.rgb;
          #ifdef FLAT
              gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);
          #else
              gl_FragColor = czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);
          #endif
          }
          `;
          return fragmentShader;
      }
      //创建纹理
      function createTexture(tetrahedronPrimitive){
          Cesium.Resource.createIfNeeded(tetrahedronPrimitive._imageUrl).fetchImage().then(function(image){
              var vTexture;
              var context = tetrahedronPrimitive._viewer.scene.context;
          if ( Cesium.defined(image.internalFormat)) {
              vTexture = new  Cesium.Texture({
                  context: context,
                  pixelFormat: image.internalFormat,
                  width: image.naturalWidth,
                  height: image.naturalHeight,
                  source: {
                      arrayBufferView: image.bufferView
                  }
              });
          } else {
              vTexture = new  Cesium.Texture({
                  context: context,
                  source: image
              });
          }
          tetrahedronPrimitive._texture = vTexture;
          });
      }
      //计算矩阵
      function computeModelMatrix(tetrahedronPrimitive){
          let enuMatrix =  Cesium.Transforms.eastNorthUpToFixedFrame(tetrahedronPrimitive._localPosition);
          let scaleMatrix =  Cesium.Matrix4.fromScale(tetrahedronPrimitive._scale);
          let modelMatrix =  Cesium.Matrix4.multiply(enuMatrix, scaleMatrix, new  Cesium.Matrix4());
          tetrahedronPrimitive._scaleMatrix=scaleMatrix;
          tetrahedronPrimitive._enuMatrix=enuMatrix;
          return modelMatrix;
      }
      //计算高度
      function computeHeight(tetrahedronPrimitive){
          let point= Cesium.Cartesian3.fromElements(0,0,tetrahedronPrimitive._distance,new Cesium.Cartesian3());
          let enuPoint = Cesium.Matrix4.multiplyByPoint(tetrahedronPrimitive._enuMatrix, point, new  Cesium.Cartesian3());
          let upPositionEC =  Cesium.Matrix4.multiplyByPoint(tetrahedronPrimitive._viewer.scene.camera._viewMatrix, enuPoint, new  Cesium.Cartesian3());
          let upPositionPC =  Cesium.Matrix4.multiplyByPoint(tetrahedronPrimitive._viewer.scene.camera.frustum.projectionMatrix, upPositionEC, new  Cesium.Cartesian3());
          return  Cesium.Cartesian3.normalize(upPositionPC, new  Cesium.Cartesian3()).z;
      }


      // const center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
        let positions =
        {
          "x": -2481464.959108353,
          "y": 4823824.427904163,
          "z": 3343877.308220879
        };
        
        let colors = [
          new Cesium.Color(1.0,1.0,0.0,1.0),
          new Cesium.Color(1.0,0.0,0.0,0.8),
          new Cesium.Color(0.0,1.0,0.0,0.8),
          new Cesium.Color(0.0,0.0,1.0,0.8),
          new Cesium.Color(0.8, 0.8, 0x0, 0.8)
        ];
        for(let i=0;i<colors.length;i++)
        {
          let pt = new Cesium.Cartesian3(positions.x + i+100, positions.y , positions.z+ i * 100)
          let primitive = new TetrahedronPrimitive({
            position: pt,
            color: colors[i] 
          })
          viewer.scene.primitives.add(primitive);
          primitive.startAnimate();
          if(i === 2)
            viewer.flyTo(primitive);
        }
        
        viewer.camera.setView({
            destination: new Cesium.Cartesian3(
              positions.x, positions.y, positions.z
            ),
            // orientation: {
            //     heading: 6.276226863836136,
            //     pitch: -1.331128445292896,
            //     roll: 0.0001241421687643296
            // }
        });
      }

      function removeSinglePrimitive()
      {
        const primitives = viewer.scene.primitives;
        const length = primitives.length;
        for (let i = 0; i < length; ++i) {
          const p = primitives.get(i);
          // p.show = !p.show;
          if(i === length -1)
            viewer.scene.primitives.remove(p);
        }
      }
  </script>
</body>
</html>

3.2.2 展示结果

4、总结

        总的来说,第一种实现思路方法简单,但需要找到现有的符合自己需求的模型,之后设置旋转和上下浮动效果即可;而第二种实现思路方法更接近底层,需要深入思考,充分理解顶点(Vertex)、三角面(Triangle)、纹理(Texture)、着色器语言(Shaders)、帧动态更新等理论思想,学习Cesium源码是一件极为有趣和快乐的事情,当然需要一定的专业知识背景和先验知识professional knowledge background and prior knowledge)做支撑才能学以致用,深刻领会其精髓。

        正四棱锥(金字塔)结构稳定,拥有坚实的基底,在生物学的食物链、古埃及的墓穴

        尽管并不是每一颗金子都能够闪闪发光,但被周围的沙子所环绕更是一种历练,逆境生长方显生命力之顽强,牢记自己的独特与唯一,坦然面对周围事物,刻在骨子里的坚强终有一日会在芸芸众生中闪耀光芒。愿大家珍惜眼前的一切,以顽强拼搏的奋斗姿态期待和迎接更加光明和美好的未来。
        祝大家国庆节快乐,祖国繁荣昌盛,人民幸福安康!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1055236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

双指针算法——复写零

双指针算法——复写零&#x1f60e; 前言&#x1f64c;复写零板书分析&#xff1a;解题代码&#xff1a;B站视频讲解 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&#xff01;&#xff01;&#…

VUE3照本宣科——认识VUE3

VUE3照本宣科——认识VUE3 前言一、命令创建项目1.中文官网2.菜鸟教程 二、VUE3项目目录结构1.public2.src&#xff08;1&#xff09;assets&#xff08;2&#xff09;components 3. .eslintrc.cjs4. .gitignore5. .prettierrc.json6.index.html7.package.json8.README.md9.vit…

芒果叶病害数据集(用于图像分类,每类500张照片)

1.数据集介绍 数据类型&#xff1a;240x320 像素的芒果叶图像。数据格式&#xff1a;JPG。图像数量&#xff1a;共有4000张图像。其中约有1800张是不同的叶子图像&#xff0c;其余的是通过缩放和旋转进行制备的。考虑的病害&#xff1a;包括七种病害&#xff0c;分别是炭疽病、…

大型项目开发设计文档规范

目录 一、 需求文档分析 二、 需求分析 1.交互层分析 2.功能需求分析 3.数据分析 4.兼容性分析 5.非功能性分析 三、 系统现状分析 1. 判断要开发的功能属于哪个模块&#xff0c;需要与哪几个模块联动&#xff1f; 2. 要开发的功能属于新接口开发&#xff0c;还是既有…

下载安装 VMware 虚拟机

文章目录 基本介绍下载并安装 VMware Workstation创建虚拟机iso镜像下载地址开始系统安装配置选择语言ip和代理盘符和用户及密码远程github软件安装开始安装重启使用 安装 VMware Tools 基本介绍 VMware 是什么&#xff1f;虚拟机是什么&#xff1f;二者有什么关系&#xff1f;…

SEO搜索引擎

利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名&#xff0c;吸引更多的用户访问网站&#xff0c;提高网站的访问量&#xff0c;提高网站的销售能力和宣传能力&#xff0c;从而提升网站的品牌效应 搜索引擎优化的技术手段 黑帽SEO 通过欺骗技术和滥用搜索算法来推销毫不…

使用VBA实现快速模糊查询数据

实例需求&#xff1a;基础数据保存在Database工作表中&#xff0c;如下图所示。 基础数据有37个字段&#xff0c;上图仅展示部分字段内容&#xff0c;下图中黄色字段为需要提取的数据字段。 在Search工作表B1单元格输入查询关键字Title和Genre字段中搜索关键字&#xff0c;包…

nginx-proxy反向代理流程

1.浏览器发送请求数据到nginx。 2.nginx先处理请求头&#xff0c;后处理请求体。 client_header_buffer_size #ginx可设置客户端上传header缓冲区大小 client_body_buffer_size #nginx可设置客户端上传数据缓冲区大小 client_body_t…

Android 10.0 Launcher3定制化之folder文件夹文件居中显示的功能实现

1.概述 在10.0的系统产品开发中,在对Launcher3的定制开发中的功能,在最近的产品项目中,有需求要求带默认文件夹功能,所以需要对文件夹的ui做定制化功能的修改在文件夹全屏以后,需要对子文件部分做居中处理,在居中显示比较美观,接下来就来处理居中显示的部分. 如图: 2.…

UX设计VSUI设计

UX设计在近年来国内蓬勃发展,许多人对其产生了浓厚的兴趣。那么我们应该如何通过自学来系统地学习UX设计呢?话不多说&#xff0c;上干货&#xff01; 1、 深入了解UX设计行业 在开始学习之前,需要深入了解UX设计师的工作内容和行业发展前景。确定这是自己想要从事的职业后,再…

Armv8/Armv9 Cache知识大纲分享--思维导图

关键词&#xff1a;cache学习、mmu学习、cache资料、mmu资料、arm资料、armv8资料、armv9资料、 trustzone视频、tee视频、ATF视频、secureboot视频、安全启动视频、selinux视频&#xff0c;cache视频、mmu视频&#xff0c;armv8视频、armv9视频、FF-A视频、密码学视频、RME/CC…

Arm Cache学习资料大汇总

关键词&#xff1a;cache学习、mmu学习、cache资料、mmu资料、arm资料、armv8资料、armv9资料、 trustzone视频、tee视频、ATF视频、secureboot视频、安全启动视频、selinux视频&#xff0c;cache视频、mmu视频&#xff0c;armv8视频、armv9视频、FF-A视频、密码学视频、RME/CC…

【Java接口性能优化】skywalking使用

skywalking使用 提示&#xff1a;微服务中-skywalking使用 文章目录 skywalking使用一、进入skywalking主页二、进入具体服务1.查看接口 一、进入skywalking主页 二、进入具体服务 可以点击列表或搜索后&#xff0c;点击进入具体服务 依次选择日期、小时、分钟 1.查看接口 依次…

Kubernetes(K8s):容器编排的未来是什么?

文章目录 Kubernetes的核心概念和工作原理1. 节点&#xff08;Nodes&#xff09;2. 容器3. Pod4. 控制器5. 服务 Kubernetes为什么成为容器编排的首选工具&#xff1f;1. 自动化和可扩展性2. 多云支持3. 生态系统和社区4. 云原生开发 未来趋势&#xff1a;K8s如何继续发展和演进…

Moleculer微服务02

1.安装 Moleculer cli npm i moleculer-cli -g 2.创建微服务项目 moleculer init project micro-moleculer2.1 使用开发工具打开项目&#xff0c;执行命令npm run dev&#xff0c;在您的浏览器中打开 http://localhost:3000/ 如果您喜欢作者的话&#xff0c;帮忙点下关注&am…

Leetcode 69.x的平方根

给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。 由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。 注意&#xff1a;不允许使用任何内置指数函数和算符&#xff0c;例如 pow(x, 0.5) 或者 x ** 0.5 。 示例 1&#xff1…

微服务moleculer01

1.官网地址&#xff1a; Moleculer - Progressive microservices framework for Node.js 2. github代码地址&#xff1a; GitHub - moleculerjs/moleculer: :rocket: Progressive microservices framework for Node.js Moleculer是基于Node.js的一款快速、多功能的微服务框…

docker 安装本地starrocks测试环境

安装文档 Quick start: Deploy StarRocks with Docker deploy_in_docker StarRocks Docs Quick start: Deploy StarRocks with Docker deploy_in_docker StarRocks Docs 镜像版本 https://hub.docker.com/r/starrocks/allin1-ubuntu/tags?page1 docker安装starrocks

【软件工程_UML—StartUML作图工具】startUML怎么画interface接口

StartUML作图工具怎么画interface接口 初试为圆形 &#xff0c;点击该接口在右下角的设置中->Format->Stereotype Display->Label&#xff0c;即可切换到想要的样式 其他方式 在class diagram下&#xff0c;左侧有interface图标&#xff0c;先鼠标左键选择&#xff0…

【多线程进阶】常见的锁策略

文章目录 前言1. 乐观锁 vs 悲观锁2. 轻量级锁 vs 重量级锁3. 自旋锁 vs 挂起等待锁4. 读写锁 vs 互斥锁5. 公平锁 vs 非公平锁6. 可重入锁 vs 不可重入锁总结 前言 本章节所讲解的锁策略不仅仅是局限于 Java . 任何和 “锁” 相关的话题, 都可能会涉及到以下内容. 这些特性主…