Cesium clipping planes 3dtiles模型剖切 3dtiles模型贴地 vue代码

这篇具有很好参考价值的文章主要介绍了Cesium clipping planes 3dtiles模型剖切 3dtiles模型贴地 vue代码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


介绍

使用Cesium的clippingPlanes实现对3dtiles模型的剖切效果。
相关官方文档地址:ClippingPlaneCollection、Cesium3DTileset
官方Demo地址:3D Tiles Clipping Planes
官方介绍:Cesium Feature Highlight: Clipping Planes


一、效果

clippingplane出剖面,3d,vue.js,前端

二、实现步骤

1.add3DTiles()

函数用于加载和显示3D Tiles模型以及剪切平面clipping planes。
在函数内部,首先创建了一个 Cesium.PrimitiveCollection 对象,用于容纳3D Tiles的各个元素。
然后,定义了一个 Cesium.ClippingPlaneCollection 对象,用于存储裁剪平面的信息,并设置了一些裁剪平面的属性。
接着,创建了一个 Cesium.Cesium3DTileset 对象,该对象表示一个3D Tiles数据集,同时将裁剪平面集合传递给这个对象。
最后,将3D Tiles添加到 PrimitiveCollection 中,再将 PrimitiveCollection 添加到Cesium场景的 primitives 中。

代码如下:

add3DTiles() {
        let _this = this
        let tileset = _this.tileset;
        // 启用地形深度测试
        viewer.scene.globe.depthTestAgainstTerrain = true;
      //创建一个primitiveCollection
        var primitiveCollection = new Cesium.PrimitiveCollection();
        let clippingPlanes = _this.clippingPlanes
        // 定义一个ClippingPlaneCollection类,用来存储裁剪面
         clippingPlanes = new Cesium.ClippingPlaneCollection({
            planes: [
                new Cesium.ClippingPlane(
                    new Cesium.Cartesian3(0.0, 0.0, -1.0),
                    0.0
                ),
            ],
            edgeColor : Cesium.Color.RED,
            edgeWidth: 1.0, // 模型被裁切部分的截面线宽
        });
        _this.clippingPlanes = clippingPlanes;
      // 创建一个3D Tileset
         tileset = new Cesium.Cesium3DTileset({
            url:"http://data.mars3d.cn/3dtiles/qx-dyt/tileset.json",
            clippingPlanes: clippingPlanes,
             skipLevelOfDetail: true,
             preferLeaves: true,
             maximumMemoryUsage: 1024,
        });
             _this.tileset = tileset;
        // 将3D Tileset添加到PrimitiveCollection中
         primitiveCollection.add(tileset);
        // 将PrimitiveCollection添加到场景中
        viewer.scene.primitives.add(primitiveCollection);
        viewer.zoomTo(tileset);
      var heightOffset = 6305.8;
      
      //3d tileset模型加载后
        tileset.readyPromise.then(function(tileset) {
        // Position tileset
        var boundingSphere = tileset.boundingSphere;
        var radius = boundingSphere.radius;
        //用于调整模型位置使其贴地
        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,new Cesium.HeadingPitchRange(0.5, -0.2, radius * 4.0))
        viewer.scene.camera.flyToBoundingSphere(tileset.boundingSphere, { duration: 2.0 });
        //处理与裁剪面(clippingPlanes)的位置和瓦片集(tileset)根节点的模型矩阵之间的关系,以确保裁剪面的位置正确与瓦片集对齐
            if (
                !Cesium.Matrix4.equals(
                    tileset.root.transform,
                    Cesium.Matrix4.IDENTITY
                )
            ) {
                // The clipping plane is initially positioned at the tileset's root transform.
                // Apply an additional matrix to center the clipping plane on the bounding sphere center.
                const transformCenter = Cesium.Matrix4.getTranslation(
                    tileset.root.transform,
                    new Cesium.Cartesian3()
                );
                const transformCartographic = Cesium.Cartographic.fromCartesian(
                    transformCenter
                );
                const boundingSphereCartographic = Cesium.Cartographic.fromCartesian(
                    tileset.boundingSphere.center
                );
                const height =
                    boundingSphereCartographic.height - transformCartographic.height;
                clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(
                    new Cesium.Cartesian3(0.0, 0.0, height)
                );
            }

              //加载切面到场景中
          for (var i = 0; i < clippingPlanes.length; ++i) {
              // 创建一个新的plane对象
              var plane = new Cesium.ClippingPlane(
                  clippingPlanes.get(i).normal,
                  clippingPlanes.get(i).distance
                  )
              const planeEntities = viewer.entities.add({
                      position:  boundingSphere.center,
                      plane: {
                          dimensions: new Cesium.Cartesian2(radius * 2.5, radius * 2.5),
                          material: Cesium.Color.WHITE.withAlpha(0.1),
                          plane: new Cesium.CallbackProperty(_this.createPlaneUpdateFunction(plane,i), false),
                          outline: true,
                          outlineColor: Cesium.Color.WHITE,
                      },
                  });
             _this.planeEntities.push(planeEntities);
              }
          return tileset;
      })
    },

2.createPlaneUpdateFunction()

使用回调函数创建了平面的更新函数,以便根据鼠标操作动态更新平面的位置。

代码如下:

createPlaneUpdateFunction(plane,i) {
        let _this = this
            return function () {
                plane.distance = _this.targetY;
                _this.clippingPlanes.get(i).distance = _this.targetY-_this.heightOffset
                return plane;

            };
        },

3.mouseHandler()

定义了鼠标在3D视图中的交互事件处理程序。它包括以下事件处理程序:
LEFT_DOWN:注册了鼠标左键点击事件,如果点击到了一个剪切面对象,则选择该剪切面对象,更改其外观,并禁用了默认的鼠标输入。
LEFT_UP:注册了鼠标左键释放事件,恢复所选剪切面的外观,并重新启用了默认的鼠标输入。
MOUSE_MOVE:注册了鼠标移动事件,计算鼠标在垂直方向上的移动距离,并更新 _this.targetY,用来控制剪切面高度的属性。

代码如下:

mouseHandler(){
        let _this = this;
        let selectedPlane;
        // 注册鼠标按下事件
        viewer.screenSpaceEventHandler.setInputAction(function (movement) {
            var pickedObject = scene.pick(movement.position);
            if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id) && Cesium.defined(pickedObject.id.plane)) {
                selectedPlane = pickedObject.id.plane;
                selectedPlane.material = Cesium.Color.WHITE.withAlpha(0.05);//改变选中切面的颜色
                selectedPlane.outlineColor = Cesium.Color.WHITE;
                scene.screenSpaceCameraController.enableInputs = false; // 取消默认的鼠标一切输入事件
            }
        }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

// 注册鼠标松开事件
        viewer.screenSpaceEventHandler.setInputAction(function () {
            if (Cesium.defined(selectedPlane)) {
                selectedPlane.material = Cesium.Color.WHITE.withAlpha(0.1);//恢复选中前面的颜色
                selectedPlane.outlineColor = Cesium.Color.WHITE;
                selectedPlane = undefined;
            }
            scene.screenSpaceCameraController.enableInputs = true; // 恢复默认的鼠标一切输入事件
        }, Cesium.ScreenSpaceEventType.LEFT_UP);

// 注册鼠标移动事件
        viewer.screenSpaceEventHandler.setInputAction(function (movement) {
            if (Cesium.defined(selectedPlane)) {
                var deltaY = movement.startPosition.y - movement.endPosition.y; // 计算鼠标移动的过程中产生的垂直高度距离
                _this.targetY += deltaY;
            }
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    },

难点总结

需要特别注意的难点是,为了使3dtiles模型贴地,需要有一个高度偏移量heightOffset

 var heightOffset = 6305.8;
      
      //3d tileset模型加载后
        tileset.readyPromise.then(function(tileset) {
        // Position tileset
        var boundingSphere = tileset.boundingSphere;
        var radius = boundingSphere.radius;
        //用于调整模型位置使其贴地
        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);

这个高度偏移量导致了,实际起剪切效果的剪切面clippingPlanes 和 加载到场景中用于鼠标操控的剪切面plane需要处于不同的高度上,高度应该相差一个heightOffset。
举个例子来讲,当可见可操控的剪切面plane的distance=0时,该剪切面正好与模型相交,但此时实际起剪切效果的剪切面clippingPlanes,需要distance=-heightOffest才能有对应的剪切效果出现。

因此,在createPlaneUpdateFunction()函数中,需要分别控制plane.distance和 _this.clippingPlanes.get(i).distance。


 plane.distance = _this.targetY;
 _this.clippingPlanes.get(i).distance = _this.targetY-_this.heightOffset
           

由于上述的需要,又引出了第二个难点:在 JavaScript 中,变量之间赋值时,如果它们引用的是同一个对象或引用类型,那么修改其中一个变量会影响到另一个变量,因为它们实际上引用的是相同的内存地址。
在分别控制plane.distance和 _this.clippingPlanes.get(i).distance的过程中就遇到了这样的问题。

一开始在加载剪切面到场景中时,plane直接等于clippingPlanes.get(i),这就导致了plane.distance 和 _this.clippingPlanes.get(i).distance,一直互相影响,保持相同的值。

    //加载切面到场景中
          for (var i = 0; i < clippingPlanes.length; ++i) {
             
              // plane直接等于clippingPlanes.get(i)
              var plane = clippingPlanes.get(i),
              
              const planeEntities = viewer.entities.add({
                      position:  boundingSphere.center,
                      plane: {
                          dimensions: new Cesium.Cartesian2(radius * 2.5, radius * 2.5),
                          material: Cesium.Color.WHITE.withAlpha(0.1),
                          plane: new Cesium.CallbackProperty(_this.createPlaneUpdateFunction(plane,i), false),
                          outline: true,
                          outlineColor: Cesium.Color.WHITE,
                      },
                  });
             _this.planeEntities.push(planeEntities);
              }
          return tileset;

为了分别控制plane.distance和 _this.clippingPlanes.get(i).distance,给他们赋不同的值,需要创建一个新的plane对象。这样就能正确实现剪切效果了。正确代码如下所示。


              //加载切面到场景中
          for (var i = 0; i < clippingPlanes.length; ++i) {
              // 创建一个新的plane对象
              var plane = new Cesium.ClippingPlane(
                  clippingPlanes.get(i).normal,
                  clippingPlanes.get(i).distance
                  )
              const planeEntities = viewer.entities.add({
                      position:  boundingSphere.center,
                      plane: {
                          dimensions: new Cesium.Cartesian2(radius * 2.5, radius * 2.5),
                          material: Cesium.Color.WHITE.withAlpha(0.1),
                          plane: new Cesium.CallbackProperty(_this.createPlaneUpdateFunction(plane,i), false),
                          outline: true,
                          outlineColor: Cesium.Color.WHITE,
                      },
                  });
             _this.planeEntities.push(planeEntities);
              }
          return tileset;

主要代码

主要vue代码如下所示文章来源地址https://www.toymoban.com/news/detail-855964.html


<script>
export default {
  data() {
    return {
        viewers: null,

        targetY: 0,
        planeEntities:[],
        selectedPlane:undefined,
        clippingPlanes:undefined,
        tileset: undefined,
        heightOffset:6305.8,

    };
  },

    methods: {
        
    // 初始化viewer后的传入回调:添加底图和清除加载动画
    created() {
        //TODO 添加三维模型
        this.addMoudleText();
        this.mouseHandler();
    },
	mouseHandler(){
	     let _this = this;
	     let selectedPlane;
	     // 注册鼠标按下事件
	     viewer.screenSpaceEventHandler.setInputAction(function (movement) {
	         var pickedObject = scene.pick(movement.position);
	         if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id) && Cesium.defined(pickedObject.id.plane)) {
	             selectedPlane = pickedObject.id.plane;
	             selectedPlane.material = Cesium.Color.WHITE.withAlpha(0.05);//改变选中切面的颜色
	             selectedPlane.outlineColor = Cesium.Color.WHITE;
	             scene.screenSpaceCameraController.enableInputs = false; // 取消默认的鼠标一切输入事件
	         }
	     }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
	
	// 注册鼠标松开事件
	     viewer.screenSpaceEventHandler.setInputAction(function () {
	         if (Cesium.defined(selectedPlane)) {
	             selectedPlane.material = Cesium.Color.WHITE.withAlpha(0.1);//恢复选中前面的颜色
	             selectedPlane.outlineColor = Cesium.Color.WHITE;
	             selectedPlane = undefined;
	         }
	         scene.screenSpaceCameraController.enableInputs = true; // 恢复默认的鼠标一切输入事件
	     }, Cesium.ScreenSpaceEventType.LEFT_UP);
	
	// 注册鼠标移动事件
	     viewer.screenSpaceEventHandler.setInputAction(function (movement) {
	         if (Cesium.defined(selectedPlane)) {
	             var deltaY = movement.startPosition.y - movement.endPosition.y; // 计算鼠标移动的过程中产生的垂直高度距离
	             _this.targetY += deltaY;
	         }
	     }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
	 },
    add3DTiles() {
        let _this = this
             let tileset = _this.tileset;
        // 启用地形深度测试
        viewer.scene.globe.depthTestAgainstTerrain = true;
      //创建一个primitiveCollection
        var primitiveCollection = new Cesium.PrimitiveCollection();
             let clippingPlanes = _this.clippingPlanes
        // 定义一个ClippingPlaneCollection类,用来存储裁剪面
         clippingPlanes = new Cesium.ClippingPlaneCollection({
            planes: [
                new Cesium.ClippingPlane(
                    new Cesium.Cartesian3(0.0, 0.0, -1.0),
                    0.0
                ),
            ],
            edgeColor : Cesium.Color.RED,
            edgeWidth: 1.0, // 模型被裁切部分的截面线宽
        });
             _this.clippingPlanes = clippingPlanes;
      // 创建一个3D Tileset
         tileset = new Cesium.Cesium3DTileset({
            url:"http://data.mars3d.cn/3dtiles/qx-dyt/tileset.json",
            clippingPlanes: clippingPlanes,
             skipLevelOfDetail: true,
             preferLeaves: true,
             maximumMemoryUsage: 1024,
        });
             _this.tileset = tileset;
             console.log("tileset",tileset)
        // 将3D Tileset添加到PrimitiveCollection中
         primitiveCollection.add(tileset);
        // 将PrimitiveCollection添加到场景中
        viewer.scene.primitives.add(primitiveCollection);
        viewer.zoomTo(tileset);
      var heightOffset = 6305.8;

        tileset.readyPromise.then(function(tileset) {
        // Position tileset
        var boundingSphere = tileset.boundingSphere;
        var radius = boundingSphere.radius;

        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);
        // var modelMatrix = tileset.modelMatrix

        viewer.zoomTo(tileset,new Cesium.HeadingPitchRange(0.5, -0.2, radius * 4.0))
        // viewer.flyTo(tileset)
        viewer.scene.camera.flyToBoundingSphere(tileset.boundingSphere, { duration: 2.0 });
            if (
                !Cesium.Matrix4.equals(
                    tileset.root.transform,
                    Cesium.Matrix4.IDENTITY
                )
            ) {
                // The clipping plane is initially positioned at the tileset's root transform.
                // Apply an additional matrix to center the clipping plane on the bounding sphere center.
                const transformCenter = Cesium.Matrix4.getTranslation(
                    tileset.root.transform,
                    new Cesium.Cartesian3()
                );
                const transformCartographic = Cesium.Cartographic.fromCartesian(
                    transformCenter
                );
                const boundingSphereCartographic = Cesium.Cartographic.fromCartesian(
                    tileset.boundingSphere.center
                );
                const height =
                    boundingSphereCartographic.height - transformCartographic.height;
                clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(
                    new Cesium.Cartesian3(0.0, 0.0, height)
                );
            }

              //加载切面到场景中
          for (var i = 0; i < clippingPlanes.length; ++i) {
              var plane = new Cesium.ClippingPlane(
                  clippingPlanes.get(i).normal,
                  clippingPlanes.get(i).distance
                  )// 创建一个新的plane对象
              const planeEntities = viewer.entities.add({
                      position:  boundingSphere.center,
                      plane: {
                          dimensions: new Cesium.Cartesian2(radius * 2.5, radius * 2.5),
                          material: Cesium.Color.WHITE.withAlpha(0.1),
                          plane: new Cesium.CallbackProperty(_this.createPlaneUpdateFunction(plane,i), false),
                          outline: true,
                          outlineColor: Cesium.Color.WHITE,
                      },
                  });
             _this.planeEntities.push(planeEntities);
              }
          return tileset;
      })
    },
        createPlaneUpdateFunction(plane,i) {
        let _this = this
            return function () {
                plane.distance = _this.targetY;
                _this.clippingPlanes.get(i).distance = _this.targetY-_this.heightOffset
                return plane;

            };
        },
    addMoudleText() {
      this.add3DTiles();
    }
</script>

到了这里,关于Cesium clipping planes 3dtiles模型剖切 3dtiles模型贴地 vue代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Cesium地图上加载3DTiles模型

    1,使用Blender创建模型: 官网下载Blender:https://www.blender.org/,在Github上下载Building Tools插件,通过编辑-偏好设置-插件-安装,导入压缩包使用,这个可以自己创建小房子,文件-导出为obj格式 2,将.obj转成3dtiles格式: 1,第一种方法通过加载本地文件展示: 1,github下载ObjTo3

    2024年02月03日
    浏览(29)
  • Cesium:3DTiles三维模型高度调整

            地形遮挡属性          如下两张图所示,输入高度值,根据需要调整模型高度。例如:针对近地面的管线数据,可能有一部分是埋在地下的,那么,如果开启了地形遮挡属性(即:设置为true,默认是false),那么,在进行场景渲染加载模型切片时,就会进行深度测

    2024年02月11日
    浏览(73)
  • Cesium加载3Dtiles模型-大疆智图

    Cesium加载3Dtiles模型步骤: (一)如果您使用的是大疆智图,则该软件可以直接输出3Dtiles格式(B3DM切片)的数据,如图所示:   (二)如果您使用的是CC(Smart3D),该软件可以输出OSGB格式的数据,我们可以借助: 1.osg2cesiumApp v1.3软件来将我们的OSGB倾斜摄影数据转换成3Dtil

    2024年02月11日
    浏览(26)
  • cesium——加载3DTiles,模型的选中,高亮效果

    3DTiles是一种用于组织和传输大规模地理数据的规范,旨在提供一种高效、可扩展的方式来加载和显示复杂的3D模型。它革新了地理数据可视化领域,为创建逼真的三维地图提供了新的可能性。 3DTiles采用了一种层次化的数据结构,将地理信息按照空间范围划分成小块,类似于

    2024年02月07日
    浏览(33)
  • cesium-影像图&地形图&3dtiles模型

    ImageryLayer类: Cesium.ImageryLayer类用于表示Cesium中的影像图层,它就相当于皮毛、衣服,将数据源包裹在内,它需要数据源(imageryProvider)为其提供内在丰富的地理空间信息和属性信息,同时,通过该类还能设置影像图层相关属 性。 常用属性如下: name(名称), alpha(透明度) bri

    2024年02月06日
    浏览(61)
  • 解决cesium中3dtiles模型随视角移动

    我们在使用cesium的时候有时会遇到一个问题就是模型导入之后,模型没有固定住会随着视角的变化而移动,研究发现模型在地底下。我认为是建模的问题有可能是建模软件使用的坐标不是wgs84导致高程不一的原因,但我没试过。 解决方案是:1.打开深度检测 2.手动把模型提上

    2024年02月16日
    浏览(28)
  • 【Cesium】3Dtiles建筑模型分层渲染的思路

    真的很久没有更新过博客了,最近入职了新公司,要做一个新的项目,使用到cesium,翻阅外网和国内各大网站,发现资料真的很少。国内很多资料都是翻译外网的,所以,没去过外网的同学,其实去不去也没必要了。而国内的环境真的是一筹莫展:要么就是有经验的人二次封

    2024年02月05日
    浏览(23)
  • cesium加载显示点云及倾斜模型(3dtiles)

            在cesium加载并显示点云或者倾斜模型之前,需要将不同格式的数据转为3dtiles,具体参考倾斜、点云转3dtiles(osgb、las转3dtiles)切片         转换完成后就可以写代码将其加载到cesium地球上。         有时候加载完成并不能贴地显示,或者贴地显示的具体位置和底

    2024年04月23日
    浏览(26)
  • Cesium将Point渲染到3dtiles模型表面上

    1、功能需求:将point点渲染到三维模型表面上; 2、代码实现: 第一步,绘制点对象,entity 第二步,根据经纬度坐标(没有高度值),获取该经纬度在三维模型表面上的高度值

    2024年02月11日
    浏览(21)
  • Cesium示例程序学习和讲解(4)-调整3DTiles模型高度

    本节主要讲解的内容? 在三维场景中如何加载3dtiles模型,如何调整模型在场景中的高度 涉及的主要接口有? Cesium3DTileset、HeadingPitchRange、Cartographic、Matrix4 介绍下HeadingPitchRange接口接相关参数介绍? 当使用Cesium框架进行三维场景渲染时,常常需要在场景中创建相机视图。而

    2024年02月10日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包