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

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.modelUrlscale: 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;}}// initfunction initPage() {// 切换自己的tokenCesium.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着色器对象 textureScalefragmentShader: '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);}//创建commandfunction createCommand(context,tetrahedronPrimitive) {var translucent = false;var closed = true;var vs = creaateVertexShader();var fs = createFragmentShader();// 借用一下Appearance.getDefaultRenderStatevar 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,});}//创建vertexArrayfunction 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_FANindices: 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 0positions[0] = 0.0;positions[1] = 1.0;positions[2] = 0.0;// position 1positions[3] = -1.0;positions[4] = 0.0;positions[5] = 0.0;// position 2positions[6] = 0.0;positions[7] = -1.0;positions[8] = 0.0;// position 3positions[9] = 1.0;positions[10] = 0.0;positions[11] = 0.0;// position 4positions[12] = 0.0;positions[13] = 0.0;positions[14] = 1.0;var indices = new Uint16Array(6 * 3);// back triangleindices[0] = 4;indices[1] = 2;indices[2] = 3;// left triangleindices[3] = 4;indices[4] = 3;indices[5] = 0;// right triangleindices[6] = 4;indices[7] = 0;indices[8] = 1;// bottom triangleindices[9] = 4;indices[10] = 1;indices[11] = 2;// bottom triangleindices[12] = 1;indices[13] = 2;indices[14] = 3;// bottom triangleindices[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 coordinatesv_normalEC = czm_normal * normal;                               // normal in eye coordinatesv_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_FORWARDnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);#endifczm_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 FLATgl_FragColor = vec4(material.diffuse + material.emission, material.alpha);#elsegl_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.xdnf.cn/news/146586.html

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

相关文章

Leetcode 69.x的平方根

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

深度学习 二:COVID 19 Cases Prediction (Regression)

Deep Learning 1. 回归算法思路2. 代码2.1 基础操作2.2 定义相关函数2.3.1 定义图像绘制函数2.3.2 数据集加载及预处理2.3.3 构造数据加载器2.3.4 构建前馈神经网络&#xff08;Feedforward Neural Network&#xff09;模型2.3.5 神经网络的训练过程2.3.6 模型评估2.3.7 模型测…

ECharts多个数据视图进行自适应大小的解决方案

项目场景&#xff1a; 在制作数据视图时经常会遇到多个数据视图的情况&#xff0c;在多个数据视图的情况下做自适应是比较麻烦的&#xff0c;这里就详细的分析一下该如何去制作&#xff0c;分享一下我的解决办法及思路。 定义 DOM 容器 这里需要注意一个地方&#xff0c;在定…

mac openssl 版本到底怎么回事 已解决

在mac 安装node多版本的时候&#xff0c;有可能把原有的 openssl1.1 版本 直接要再一次升级了&#xff0c;无奈的 php环境 编译器是 openssl 1.1 还是 3.0 &#xff0c;今天来个底朝天的找问题。 brew search openssl 有安装 三个版本。 但是错误提示 是第二个版本。 brew …

B058-SpringBoot

目录 springboot概念与作用入门案例springboot运行方式热部署配置文件Profile多环境支持整合测试-springboot-testSpringboot-web1.返回json数据2.返回页面&#xff08;模板技术&#xff09;thymeleaf1.导入thymeleaf依赖2.模板文件3.controller4.启动类 SSM整合1.导包2.项目目…

【动态规划】动态规划经典例题 力扣牛客

文章目录 跳台阶 BM63 简单跳台阶扩展 JZ71 简单打家结舍 LC198 中等打家劫舍2 LC213中等最长连续递增序列 LC674 简单乘积最大子数组LC152 中等最长递增子序列LC300 中等最长重复子数组LC718最长公共子串NC BM66最长公共子序列LC1143 中等完全平方数LC279零钱兑换 LC322 中等单…

QT的ui设计中改变样式表的用法

在QT的ui设计中,我们右键会弹出一个改变样式表的选项,很多人不知道这个是干什么的。 首先我们来看下具体的界面 首先我们说一下这个功能具体是干嘛的, 我们在设置很多控件在界面上之后,常常都是使用系统默认的样式,但是当有些时候为了美化界面我们需要对一些控件进行美化…

【数据结构】链表与LinkedList

作者主页&#xff1a;paper jie 的博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《JAVA数据结构》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精…

小程序编译器性能优化之路

作者 | 马可 导读 小程序编译器是百度开发者工具中的编译构建模块&#xff0c;用来将小程序代码转换成运行时代码。旧版编译器由于业务发展&#xff0c;存在编译慢、内存占用高的问题&#xff0c;我们对编译器做了一次大规模的重构&#xff0c;采用自研架构&#xff0c;做了多线…

链表经典面试题(一)

面试题 1.反转链表的题目2.反转链表的图文分析3.反转链表的代码实现 1.反转链表的题目 2.反转链表的图文分析 我们在实现反转链表的时候,是将后面的元素变前面&#xff0c;前面的元素变后面&#xff0c;那么我们是否可以理解为&#xff0c;用头插法的思想来完成反转链表呢&…

Cannot download sources:IDEA源码无法下载

问题 Swagger的相关包&#xff0c;无法看到注释&#xff1b; 在class文件的页面&#xff0c;点击下载源码&#xff0c;源码下载不了&#xff0c;IDEA报下面的错误。 报错 Cannot download sources Sources not found for: io.swagger.core.v3:swagger-annotations:2.2.9 解决…

读者写者问题—内含408真题

读者写者问题—含408 一、问题描述 一个数据问价或记录可以被多个进程共享&#xff0c;我们把只读该文件的进程称为“读者进程”&#xff0c;其他进程为“写者进程”。允许多个进程同时读一个共享对象&#xff0c;但不允许一个写者进程和其他写者进程或读者进程同时访问共享对…

点亮一个LED+LED闪烁+LED流水灯——“51单片机”

各位CSDN的uu们好呀&#xff0c;这是小雅兰的最新专栏噢&#xff0c;最近小雅兰学习了51单片机的知识&#xff0c;所以就想迫不及待地分享出来呢&#xff01;&#xff01;&#xff01;下面&#xff0c;让我们进入51单片机的世界吧&#xff01;&#xff01;&#xff01; 点亮一个…

Linux基础命令汇总

用户管理 su 切换用户&#xff1a;su 用户名 logname 显示当前用户的登录用户名&#xff1a;logname useradd 创建用户&#xff1a;useradd 用户名创建用户时指定用户的主组&#xff1a;useradd -g 组名 用户名 usermod 添加附属组&#xff1a;usermod -G 组…

2023年8月嵌入式项目开发专题总汇

一、前言 本文介绍基于嵌入式系统和C语言开发的系列项目。这些项目涵盖了多个领域&#xff0c;从自动化控制到游戏开发&#xff0c;从计算机网络到物联网应用。通过这些项目的开发过程&#xff0c;将深入探讨各种技术和解决方案&#xff0c;并分享相关经验和知识。 在本文中&…

cesium 雷达扫描 (线行扩散效果)

cesium 雷达扫描 (线行扩散效果) 1、实现方法 使用ellipse方法加载圆型,修改ellipse中material方法来实现效果 2、示例代码 2.1、 <!DOCTYPE html> <html lang="en"><head><<

分类预测 | Matlab实现BES-ELM秃鹰搜索算法优化极限学习机分类预测

分类预测 | Matlab实现BES-ELM秃鹰搜索算法优化极限学习机分类预测 目录 分类预测 | Matlab实现BES-ELM秃鹰搜索算法优化极限学习机分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 Matlab实现BES-ELM秃鹰搜索算法优化极限学习机分类预测&#xff08;完整源码和数…

【CVPR 2023】DSVT: Dynamic Sparse Voxel Transformer with Rotated Sets

文章目录 开场白效果意图 重点VoxelNet: End-to-End Learning for Point Cloud Based 3D Object DetectionX-Axis DSVT LayerY-Axis DSVT Layer Dynamic Sparse Window AttentionDynamic set partitionRotated set attention for intra-window feature propagation.Hybrid wind…

优维低代码实践:应用级配置

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 优维…

[NOIP2012 提高组] 开车旅行

[NOIP2012 提高组] 开车旅行 题目描述 小 A \text{A} A 和小 B \text{B} B 决定利用假期外出旅行&#xff0c;他们将想去的城市从 $1 $ 到 n n n 编号&#xff0c;且编号较小的城市在编号较大的城市的西边&#xff0c;已知各个城市的海拔高度互不相同&#xff0c;记城市 …