首页 > 其他分享 >前端菜鸡流水账日记 -- threejs和cesium

前端菜鸡流水账日记 -- threejs和cesium

时间:2024-05-28 16:30:26浏览次数:12  
标签:流水账 threejs const -- 模型 entity2 viewer let Cesium

哈喽哇大家,今天来点不一样的,主要是因为今天没有后台系统的修改,所作的修改是在以cesium为基础的项目上,用threejs渲染一个模型,并且可以具有显示/隐藏的功能,那下边就让我们来看看怎么实现的把~

---------------------------------------------------------------------------------------------------------------------------------

思路:

1.下载对应的threejs库,并且引入

2.进行基础配置,比如相机、光照等等

3.引入模型

4.调整模型的位置大小

5.来进行显示/隐藏的操作

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

详细的代码:

1.下载

npm i threejs  //下载threejs库

// 引入threejs
import * as THREE from 'three';

//解码器的引入,如果不需要可以不写,写的话需要注意路径
import { GLTFLoader } from 'three/examples/jsm/Addons.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';

2.配置初始化(有一段可以不需要加,如果需要调整的话在加,可以根据需要选择,我的代码是用到了的,所以选择一起分享出来了)

// 初始化场景
const threeRenderer = new THREE.WebGLRenderer(); // 创建Three.js的渲染器

// 设置渲染器尺寸
threeRenderer.setSize(window.innerWidth, window.innerHeight);

// 将渲染器的canvas添加到DOM中
document.body.appendChild(threeRenderer.domElement);

//------------------------------------------- 

//这一段如果不是cesium和threejs相结合的可以不用加,主要是为了让两者的场景一开始就渲染到某一个位置以及视角的角度的调整,正常的只需要调整下边的相机就可以了

const cesiumCamera = viewer.camera;  // 管理cesium的场景视角和投影
    // 设置Cesium相机到一个初始位置
    console.log(cesiumCamera, 'cececeeeeeeeeeeee')
    // x: 116.646994,
    // z: 35.421154
    viewer.camera.flyTo({
      // destination: Cesium.Cartesian3.fromDegrees(0, 0, 1000), // 示例位置为经度0,纬度0,高度1000米
      // destination: Cesium.Cartesian3.fromDegrees(116.646994, 0, 35.421154), // 示例位置为经度0,纬度0,高度1000米
      // 飞过去了  ---高度原来为2000
      // destination: Cesium.Cartesian3.fromDegrees(-74.006015, 40.712728, 2000), // 经度-74.006015,纬度40.712728,高度2000米(纽约市中心)      // destination: position,
      destination: Cesium.Cartesian3.fromDegrees(116.612584231, 35.420733404, 2000), // 经度-74.006015,纬度40.712728,高度2000米(纽约市中心)      // destination: position,
      // ----------------
      orientation: {
        heading: Cesium.Math.toRadians(0), // 偏航角,0表示正北
        pitch: Cesium.Math.toRadians(-15), // 俯仰角,负数表示向上看,这里设置为-45度
        roll: Cesium.Math.toRadians(0), // 保持相机的翻滚角不变
      },
      // ----------------
      // 添加延时确保相机到位
      // duration: 0, // 立即到达  0改为1  ---改成1 就会变成灰色背景,不展示cesium渲染的东西
      duration: 1, // 延时1秒
    });
  
    
    document.getElementById('modelView').appendChild(threeRenderer.domElement);
//-------------------------------------------

// 初始化threejs的场景、相机
const threeScene = new THREE.Scene();  //创建新的场景,是指所有三维物体和相机要存在得空间
// 创建相机,透视相机,视野角度为75 
const threeCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  
// threeCamera.position.set(100,200,600)  //默认相机位置,三维空间中得这些坐标上  //旧
threeCamera.position.z = 1000; // 初始设置相机位置 //新
threeCamera.lookAt(new THREE.Vector3(0, 0, 0)); // 相机看向场景中心 //新

// 添加环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 色温和强度可调整
threeScene.add(ambientLight);

3-4.引模型和调整大小(引入的这个模型是,展示在cesium场景中的模型,和普通的threejs引入还不太一样,用到了创建cesium的实体,如果不创建实体,其实就是threejs的模型类型,但是只有创建实体才可以在ceisum场景中看到,所以可以根据需要选择,另外就是,模型的路径要换成自己的)

 // 使用GLTFLoader加载模型
    const loader = new GLTFLoader();
     // 加载draco解码器
     const dracdloader = new DRACOLoader();
     dracdloader.setDecoderPath('./draco/glft/');

    loader.setDRACOLoader(dracdloader);
    let model;
    let entity2;
    loader.load(
      // 资源路径 -- 要对应自己代码的路径
      '../models/car.glb', 
      // 加载成功回调
      function (gltf) {
        // 获取模型在地球上的笛卡尔位置
        // let longitude = -74.006015; // 例如:东经104.06度
        // let latitude = 40.712728;  // 例如:北纬30.67度
        // let height = -1000;   // 模型相对于海平面的高度(单位:米)
        let longitude = 116.612584231; // 例如:东经104.06度
        let latitude = 35.420733404;  // 例如:北纬30.67度
        let height = 2000;   // 模型相对于海平面的高度(单位:米)

        const cartesianPosition = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
    
        // 创建Cesium实体
        const entity = viewer.entities.add({
          position: cartesianPosition,
          model: {
            uri: '../models/car.glb', // 使用加载的模型URL
            scale: 100.0, // 根据需要调整模型大小
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 让模型贴合地面
          },
        });

        console.log('Model materials:', entity.model.material); // 打印模型材料信息
        
        // ----------------点击事件
        
        // 创建一个ScreenSpaceEventHandler实例来处理点击事件
        const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

        // 定义点击事件处理函数
        function onLeftClick(movement) {
          const pickedObject = viewer.scene.pick(movement.position);
          if (Cesium.defined(pickedObject) && pickedObject.id === entity) {
            // 当点击的实体是我们刚刚添加的模型实体时,弹出提示框
            alert('模型被点击了!');
            console.log('点击了模型',entity2)
            viewer.entities.remove(entity2);
            entity2 = undefined; // 可选:清除引用以帮助垃圾回收
            console.log('entity2',entity2)
            // entity2.show = false  //可行
            // entity2.show = !entity2.show
          }
        }

          // 注册鼠标左键点击事件
          handler.setInputAction(onLeftClick, Cesium.ScreenSpaceEventType.LEFT_CLICK);
        // -----------------------

        // 删除Three.js的模型渲染
        threeScene.remove(model);
        document.getElementById('modelView').removeChild(threeRenderer.domElement);
        threeRenderer.dispose();
    
        console.log('模型加载成功了,并已添加到Cesium场景中');
      },
      undefined,(error) => {
        console.log('Error loading model:',error);
      }
    )

这一段代码中还有一个解码器,作用是如果模型过大的话就需要这个来进行一下操作,可以理解为压缩或者解压缩这中,下边也会有详细的解码器需要的配置的,上述代码中还有一个点击模型会出现一个警告框的事件,不需要的可以忽略

5.根据需要实现是否展示和隐藏,我遇到的场景是用if(isShow){} else {} 来进行判断的

let entity2 = null  //定义在最外边,否则容易出错

const loader2 = new GLTFLoader();
      if (isShow) {
        loader2.load(
          // 资源路径
          '../models/car.glb', 
          function (gltf) {
           let longitude2 = 116.593474298; // 例如:东经104.06度
           let latitude2 = 35.400849354;  // 例如:北纬30.67度
           let height2 = 2000;   // 模型相对于海平面的高度(单位:米)
           const cartesianPosition = Cesium.Cartesian3.fromDegrees(longitude2, latitude2, height2);
            // 创建Cesium实体
            entity2 = viewer.entities.add({
             position: cartesianPosition,
             model: {
               uri: '../models/car.glb', // 使用加载的模型URL
               scale: 100.0, // 根据需要调整模型大小
               heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 让模型贴合地面
             },
           });
           console.log(entity2,'222222222222222');
         },
         undefined,(error) => {
           console.log('Error loading model:',error);
         }
       )
       
      } else {
        if (entity2 !== undefined) { // 检查entity2是否已定义
          // console.log('entity2', entity2);
          viewer.entities.remove(entity2);
          entity2 = undefined; // 可选:清除引用以帮助垃圾回收
          // console.log('entity222', entity2);
        }

大概的代码就是这样的,用if将这个模型给抱起来,如果不符合的话就移除模型,需要注意的是,虽然他已经是else的了,但是并不影响需要在里边再次做判断,我就会老觉得已经是else了,就肯定是写上就是不展示的,但是事实不是这样的,有些时候还是要做判断,像这个一样,所以一定要多想多看一下

---------------------------------------------------------------------------------------------------------------------------------

至于viewer.entities.remove这个的作用  viewer.entities.remove 是 CesiumJS 库中用于从场景中删除特定实体(Entity)的方法。viewer.entities 是一个实体集合,其中包含了你在场景中添加的所有实体,如点、线、面、模型等。当你调用 viewer.entities.remove(entity) 时,你会从这个集合中移除指定的 entity,进而从3D视图中删除对应的可视化元素。 例如,在你提供的代码片段中,entity2 是一个包含模型(car.glb)的实体。当 isShow 变为 false 时,如果 entity2 已经被定义并且添加到 viewer.entities 集合中,viewer.entities.remove(entity2) 就会被调用来从3D场景中移除这个模型。这样,模型就不会再显示在Cesium的地球视图上了。 此外,移除实体还可以帮助释放内存,特别是当不再需要该实体时,因为Cesium会继续跟踪和更新场景中所有的实体,即使它们不在视口中。通过删除不必要的实体,可以优化性能和减少内存占用。

补充一点:

viewer.scene.primitives.remove 是 CesiumJS 中用于从场景的 primitives 集合中移除特定3D图元(Primitive)的方法。viewer.scene.primitives 包含了直接添加到场景中的所有非实体(Entity)3D图形对象,如几何体、3D Tiles、Billboard集等。 在你提供的代码片段中,viewer.scene.primitives.remove(wsgwDom6); 是用来从场景中移除之前通过 Cesium.Cesium3DTileset.fromUrl 加载的3D Tiles图层 wsgwDom6。这将导致整个3D Tiles图层及其包含的所有瓦片从3D视图中消失。通常,当不再需要3D Tiles图层或者需要更新图层时,会使用这个方法。移除图层也有助于释放内存,特别是对于大型3D数据集,因为它们可能会占用大量内存。

对应的解码器的资源我已经进行绑定了,但是貌似只能绑定一个,所以有需要的话,也可以私我拿都可以的

通过以上的操作,就可以实现渲染一个模型,以及控制他的显隐状态了,同样的也是我真实遇到的,也是研究了好久的,可能有些地方不正确和不专业,欢迎大家多多提意见,共同进步,有需要的小伙伴可以按需使用哈

标签:流水账,threejs,const,--,模型,entity2,viewer,let,Cesium
From: https://blog.csdn.net/weixin_69868770/article/details/139265275

相关文章

  • Day19学习Java
    什么是注解java.annotation包Annotation是从JDK1.5开始引入的新技术,注解即可以对程序员解释又可以对程序解释注解与注释的区别注释:对程序员解释代码信息注解:对程序和程序员解释代码信息注解的所用不是程序本身,可以对程序作出解释(与注释(comment)类似)可以被其他程序......
  • 最新版本MathType的优势
    一份订阅,多平台可用只需订阅一次,即可在Windows、macOS、LMS平台或任何其他桌面或基于Web的环境上使用MathType。安全和GDPR合规性严格遵守所有最新的安全和GDPR标准,保护您的计算机免受风险。无忧迁移顺畅无忧地保留工作内容,并像使用旧版本MathType一样继......
  • GoldWave专业音频编辑软件
    GoldWave是一款易上手的专业数字音频编辑软件。从最简单的录制和编辑到最复杂的音频处理,恢复,增强和转换,它可以完成所有工作。音频编辑包括剪切、复制、粘贴、Trim和替换、编写。GoldWave强大的音频编辑功能,让您在几秒钟内切片,切块和合并大型音频文件。Mix和Crossfade歌曲一......
  • 盲盒小程序后台管理系统开发中的技术挑战与解决方案
    一、引言盲盒小程序后台管理系统是保障盲盒业务高效运作的关键。然而,在开发过程中,我们不可避免地会遇到一系列技术挑战。本文将针对数据同步、库存管理和订单处理等方面的技术挑战,提出相应的解决方案。二、数据同步挑战与解决方案挑战:在盲盒小程序中,数据同步是一个复杂而......
  • Springboot计算机毕业设计学生考勤管理微信小程序【附源码】开题+论文+mysql+程序+部
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,高校教学管理日益向数字化、智能化方向转变。传统的考勤管理方式不仅效率低下,而且容易出现误差,已无法满足现代高校管理的需求......
  • 盲盒小程序后台管理系统开发挑战及应对策略
    一、引言随着盲盒市场的不断壮大,盲盒小程序后台管理系统的开发成为了关键的一环。然而,在开发过程中,我们面临着数据同步、库存管理和订单处理等一系列技术挑战。本文将详细探讨这些挑战,并提出相应的应对策略。二、数据同步挑战与应对策略挑战:在盲盒小程序中,数据同步是一个......
  • SpringBoot修改内置的Tomcat版本
    springboot内置tomcat各版本漏洞及修复情况参考链接:https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core打开项目,找到pom.xml文件找到对应节点,按以下步骤修改:1、pom添加tomcat版本信息   <properties>       <java.version>1.8</java.ver......
  • II. 在 Google Colab 上运行 NeRF
     一、运行官方数据集直接跟着NeRF(NeuralRadianceFields)tutorialusinggooglecolab这个视频操作即可,顺便验证一下CoLab作为以后深度学习环境的可行性。二、训练自己的数据博主是以SilicaGGO,他自己拍摄的二次元玩偶。工程链接:kewa123/nerf_pl作者建议的拍摄方......
  • 原生js实现表头拖拽效果
    使用原生js实现表头拖拽效果方法独立jq,使用面向对象方法,可以改造成ts嵌入vue项目中或者拓展el-table表头固定,不影响el-table排序的拖拽问题代码如下,有不足之处的请帮忙指出<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>原生实现table拖拽滚动</titl......
  • lua拼接字符串
    在Lua中,拼接字符串可以使用多种方法,包括使用..操作符、string.format函数,或者使用循环和table.concat函数。下面是一些常见的字符串拼接示例:使用..操作符localpart1="Hello"localpart2="World"localresult=part1..""..part2print(result)--输出"HelloWorld......