threejs实战数字孪生园区开源(threejs+vue3+vite)

这篇具有很好参考价值的文章主要介绍了threejs实战数字孪生园区开源(threejs+vue3+vite)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Hello大家好,我是日拱一卒的攻城师不浪,专注前端、后端、AI学习、2D3D、GIS等学习沉淀,这是2024年输出的第10/100篇文章,欢迎志同道合的朋友一起学习交流;

公众号:攻城师不浪
绿泡泡:brown_7778

视频效果

threejs数字孪生园区

前言

近两年,web3D的势头逐渐兴起。

例如得物的VR穿戴,贝壳的VR游览,高德地图的3D白模建筑以及VR导航,懂车帝的汽车3D展示等等,这些功能都需要具备一定的3D开发能力。

web3D最直接的需求就是前几年兴起的数字孪生概念,也有很多大厂单独成立了数字孪生部门去抢赛道。

可能有的同学还不知道数字孪生的概念,我将用最通俗易懂的语言去解释:

数字孪生:就好比你有一个双胞胎兄弟,你们长得一模一样,但一个是活在现实里的真人,另一个是活在电脑里的虚拟人。这个虚拟的兄弟,就是你的“数字孪生”。在现实世界中,数字孪生通常指的是通过各种数据和先进的技术手段,创建一个真实物体或系统的虚拟副本。这个副本不仅外观和原型一样,而且还能模拟和反映原型在现实世界中的行为和状态。比如,一座大楼、一辆汽车,甚至是整个城市,都可以有自己的数字孪生。

OK,言归正传,写这篇文章的起因,也是因为前段时间,公司有这方面的需求,需要给公司的园区做一个数字孪生,放在公司的展厅进行展示。

做数字孪生肯定就要涉及3D,在对比了众多3D开发引擎(unreal,unity,Babylonjs,threejs)之后,发现threejs的开发成本是最低的。

所以我就被委以重任,从零开始学习threejs开发。一开始是先在官网上学基础,例如相机视角矩阵法线射线交叉3D坐标系光线Shader材质模型加载等等。

说实话,对于我这一直写2D的选手来说,确实一脸懵逼,这还没涉及到写更有难度的粒子效果GLSL呢。。。

所以就想着去网上能不能找到相关实战代码,但是网上关于threejs实战开发的案例实在是少之又少,而且大部分都要收费,废了九牛二虎之力才找到了一个实战开发threejs-park项目(由于项目过去很久了,开源的找不到了,找到的同学可以帮忙在评论区@一下),感觉还不错,因此就仿照着他的项目,自己一边熟悉一边梳理,最终改成了threejs+vue3+vite的一个项目。

项目概览

threejs数字孪生开源,二三维可视化,开源,数据可视化

可以看出项目的核心是封装了一些Threejs常用到的基类,这些都封装好之后,再理解一下3D里的一些概念类的东西,剩下的就是纯JS逻辑了。

Viewer视角

这个是threejs里最重要的一个元素,俗称视角,也就是说我们在3D场景里,肯定是需要一个视角去观看场景的,所以它是最基础且必不可少的。

export default class Viewer {
  /**
   * 
   * @param {*} id 场景容器id
   */
  constructor(id) {
    Cache.enabled = true // 开启缓存
    this.id = id
    this.renderer = undefined
    this.scene = undefined
    this.camera = undefined
    this.controls = undefined
    this.animateEventList = []
    this.#initViewer()
  }
  #initViewer() {
    this.#initRenderer()
    this.#initCamera()
    this.#initScene()
    this.#initControl()
    this.#initSkybox()
    this.#initLight()

    const animate = () => {
      requestAnimationFrame(animate)
      this.#updateDom()
      this.#renderDom()
      // 全局的公共动画函数,添加函数可同步执行
      this.animateEventList.forEach(
        event => {
          event.fun && event.content && event.fun(event.content)
        })
    }

    animate()
  }
  /**
   * 创建初始化场景界面
   */
  #initRenderer() {
    // 获取画布dom
    this.viewerDom = document.getElementById(this.id)
    // 初始化渲染器
    this.renderer = new WebGLRenderer({
      // logarithmicDepthBuffer: true, // true/false 表示是否使用对数深度缓冲,true性能不好
      antialias: true, // true/false表示是否开启反锯齿
      alpha: true, // true/false 表示是否可以设置背景色透明
      precision: "highp", // highp/mediump/lowp 表示着色精度选择
      premultipliedAlpha: true, // true/false 表示是否可以设置像素深度(用来度量图像的分辨率)
    })
    this.renderer.clearDepth(); // 设置深度缓冲区
    this.renderer.shadowMap.enabled = true // 场景中的阴影自动更新
    this.viewerDom.appendChild(this.renderer.domElement) // 将渲染器添加到画布中
    // 二维标签
    this.labelRenderer = new CSS2DRenderer() // 标签渲染器
    this.labelRenderer.domElement.style.zIndex = 2
    this.labelRenderer.domElement.style.position = 'absolute'
    this.labelRenderer.domElement.style.top = '0px'
    this.labelRenderer.domElement.style.left = '0px'
    this.labelRenderer.domElement.style.pointerEvents = 'none'// 避免HTML标签遮挡三维场景的鼠标事件
    this.viewerDom.appendChild(this.labelRenderer.domElement)

    // 三维标签
    this.css3DRenderer = new CSS3DRenderer() // 标签渲染器
    this.css3DRenderer.domElement.style.zIndex = 0
    this.css3DRenderer.domElement.style.position = 'absolute'
    this.css3DRenderer.domElement.style.top = '0px'
    this.css3DRenderer.domElement.style.left = '0px'
    this.css3DRenderer.domElement.style.pointerEvents = 'none'// 避免HTML标签遮挡三维场景的鼠标事件
    this.viewerDom.appendChild(this.css3DRenderer.domElement)
  }
  /**
   * 渲染相机
   */
  #initCamera() {
    this.camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 500000) // 透视相机
    this.camera.position.set(50, 0, 50) // 相机位置
    this.camera.lookAt(0, 0, 0) // 设置相机方向
  }
  /**
   * 渲染场景
   */
  #initScene() {
    this.scene = new Scene()
    this.css3dScene = new Scene()
    this.scene.background = new Color('rgb(5,24,38)')
  }
} 

这个类的一些核心代码,包括初始化场景相机控制器光线等,代码里的注释很详细,我就不一一解释了。

Lights光线

一个3D场景,肯定是需要光线去照亮场景以及场景中的物体的,因此光线因素也是必不可少的。

而threejs中又把光线分成了环境光平行光点光源锥形光源矩形光源等诸多概念,这些我们都在项目中有实际使用到。

import SunLensflare from './SunLensflare.js'
import DirectionalLight from './DirectionalLight.js'
import AmbientLight from './AmbientLight.js'
import PointLight from './PointLight.js'
import SpotLight from './SpotLight.js'
import RectAreaLight from './RectAreaLight.js'

export default class Lights {
  constructor(viewer) {
    this.viewer = viewer
    this.lightList = []
  }

  /**
   * 添加平行光源
   * @param option
   */
  addDirectionalLight(position = [200, 200, 200], option = { color: 'rgb(255,255,255)' }) {
    const directionalLight = new DirectionalLight(this.viewer, position, option)
    this.lightList.push(directionalLight)
    return directionalLight
  }

  /**
   * 添加环境光源
   */
  addAmbientLight() {
    const ambientLight = new AmbientLight(this.viewer)
    this.lightList.push(ambientLight)
    return ambientLight
  }

  /**
   * 添加点状光源
   * @param option
   */
  addPointLight(position = [0, 40, 0], option = { color: 'rgb(255,255,255)' }) {
    const pointLight = new PointLight(this.viewer, position, option)
    this.lightList.push(pointLight)
    return pointLight
  }

  /**
   * 添加锥形光源
   * @param option
   */
  addSpotLight(position = [0, 40, 0], option = { color: 'rgb(255,255,255)' }) {
    const pointLight = new SpotLight(this.viewer, position, option)
    this.lightList.push(pointLight)
    return pointLight
  }

  /**
   * 添加矩形光源
   * @param option
   */
  addRectAreaLight(position = [0, 40, 0], option = { color: 'rgb(255,255,255)' }) {
    const rectAreaLight = new RectAreaLight(this.viewer, position, option)
    this.lightList.push(rectAreaLight)
    return rectAreaLight
  }

  /**
   * 添加炫光
   * @param x
   * @param y
   * @param z
   */
  addSunLensflare(x = 200, y = 200, z = 200) {
    this.sunLensflare = new SunLensflare(this.viewer)
    this.sunLensflare.addToScene(x, y, z)
  }

  /**
   * 移除灯光
   * @param light 灯光
   */
  removeLight(light) {
    this.viewer.scene.remove(light)
  }
}

Models模型

3D场景中,会由大大小小的各种3D模型组合而成,例如房子、道路、车、树、路灯等,这些都是加载3D模型渲染展示。

一些常见的3D模型格式

  • OBJ:这是一个非常普遍的3D模型格式,可以包含多种类型的数据,如顶点纹理坐标法线。OBJ文件通常用于交换数据,因为它们可以被多种3D软件读取和编辑。
  • FBX:Filmbox格式(FBX)是一个多功能的3D文件格式,广泛用于游戏开发和电影制作。它支持复杂的模型数据,包括动画骨骼纹理等。
  • BLEND:Blender的原生文件格式,Blender是一个开源的3D创建套件,支持全面的3D建模、动画、模拟等功能。
  • GLTFGLB:GL Transmission Format(GLTF)是一种用于3D场景和模型的高效跨平台的文件格式。它旨在为Web移动设备提供高性能的3D内容。
  • 3DS:3D Studio Max的原生格式,虽然主要用于Max软件,但也可以被其他3D软件导入和使用。

下面封装了一个threejs支持的比较好的加载模型GLTF及GLB的类:

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import DsModel from './DsModel'

/**
 * 模型加载类(只能加载GLTF及GLB格式)
 */
export default class ModelLoader {
  constructor(viewer) {
    this.viewer = viewer
    this.scene = viewer.scene
    this.loaderGLTF = new GLTFLoader() // 加载gltf模型
    this.loaderFBX = new FBXLoader() // 加载fbx模型
    this.dracoLoader = new DRACOLoader() // 加载draco模型(加载基于Google Draco压缩格式的3D模型的类)
    this.dracoLoader.setDecoderPath('/js/draco/') // 设置draco模型解码器路径
    this.loaderGLTF.setDRACOLoader(this.dracoLoader) // 设置draco模型加载器
  }
  /**
      * 添加模型数据
      * @param url 模型的路径
      * @param callback 返回模型对象,常用一些功能挂接在模型对象上
      * @param progress 返回加载进度,还有问题,需要修改
      */
  loadModelToScene(url, callback, progress) {
    this.loadModel(url, model => {
      this.scene.add(model.object) // 加载模型
      callback?.(model)
    }, num => {
      progress?.(num) // 加载进度
    })
  }
  /**
    * 加载模型
    * @param url 模型路径
    * @param callback 回调模型
    * @param progress 返回加载进度
    */
  loadModel(url, callback, progress) {
    let loader = this.loaderGLTF
    if (url.indexOf('.fbx') !== -1) {
      loader = this.loaderFBX
    }
    loader.load(url, model => {
      callback?.(new DsModel(model, this.viewer))
    }, xhr => {
      progress?.((xhr.loaded / xhr.total).toFixed(2))
    }, (error) => {
      console.error('模型渲染报错:', error)
    })
  }
}

Event鼠标事件

再就是我们需要操作场景中的某些元素,例如:楼体分层,这时就需要鼠标事件去监听,点击的时候我需要计算出当前点击的具体楼层,需要用到射线求交等知识。

import * as THREE from 'three'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'

export default class ThreeMouseEvent {
  constructor(viewer, isSelect, callback, type = 'click') {
    this.viewer = viewer
    this.isSelect = isSelect
    this.callback = callback
    this.type = type
    this.composer = new EffectComposer(this.viewer.renderer)
    return this
  }
  startSelect() {
    this.stopSelect()
    this.bingEvent = this.#event.bind(this, this)
    this.viewer.renderer.domElement.addEventListener(this.type, this.bingEvent)
  }
  stopSelect() {
    this.viewer.renderer.domElement.removeEventListener(this.type, this.bingEvent)
  }
  #event(that, event) {
    const raycaster = new THREE.Raycaster() // 创建射线
    const mouse = new THREE.Vector2() // 创建鼠标坐标
    mouse.x = (event.offsetX / that.viewer.renderer.domElement.clientWidth) * 2 - 1
    mouse.y = -(event.offsetY / that.viewer.renderer.domElement.clientHeight) * 2 + 1
    raycaster.setFromCamera(mouse, that.viewer.camera) // 设置射线的起点和终点
    // TODO: 第一个参数是否需要外部传入,减小监听范围
    const intersects = raycaster.intersectObject(that.viewer.scene, true) // 检测射线与模型是否相交
    if (intersects.length > 0 && intersects[0]) {
      that.callback(intersects[0].object, intersects[0].point)
    }
  }
}

最后

以上,我只列出了实战项目里需要用到的一些关键代码,当这些基础的类封装好之后,那我们基本上就可以构建出一个简单的3D场景。

开源项目地址:https://github.com/day-day-dreamer/threejs-learning

将以上开源项目里的代码照着撸一遍,并理解其中的一些基础概念,对于threejs入门来说足够了,做一些小项目来说足以应对!

最后,如果觉得项目对你有帮助,希望可以随手点一个star,激励我去开源更多优秀的代码。

如果有在做数字孪生或者GIS方面的同学也可以加我交流:brown_7778,我有更多开源代码可以送你。

如果觉得文章对你有帮助,也欢迎一键三连👏👏👏,你的鼓励是支持我持续原创下去的动力~文章来源地址https://www.toymoban.com/news/detail-853753.html

到了这里,关于threejs实战数字孪生园区开源(threejs+vue3+vite)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 智慧园区如何搭乘数字孪生这列快车?

    无论是2022年的火爆的元宇宙还是今年出圈的ChatGPT,都体现着数字技术嵌入社会生活是大趋势,数字孪生作为智能技术的一大亮点,它在智慧园区中的应用会是怎样呢?今天我们就来聊一聊! (全文3000字,预计阅读7分钟) 数字孪生、智慧园区,哇!看起来好难懂的概念!别

    2024年02月16日
    浏览(39)
  • 智慧园区楼宇合集 | 图扑数字孪生管控系统

    智慧园区是指将物联网、大数据、人工智能等技术应用于传统建筑和基础设施,以实现对园区的全面监控、管理和服务的一种建筑形态。通过将园区内设备、设施和系统联网,实现数据的传输、共享和响应,提高园区的管理效率和运营效益,为居住者和使用者提供更加智能化

    2024年02月16日
    浏览(62)
  • 产业园区数字孪生3d可视化全景展示方案

    随着数字经济的发展,数字技术给企业发展带来了机遇的同时,也为企业管理带来挑战。比如园区运维,不仅体量大,复杂的运维管理系统,落地难度也较高。那么如何通过数字化手段重塑园区运营,打通园区各业务数据孤岛,实现多系统业务联动,提升园区管理效率、创新

    2024年02月09日
    浏览(46)
  • Sovit3D智慧园区:数字孪生园区大屏一体化管理平台

    随着全球物联网、移动互联网、云计算、大数据等新一轮信息技术的迅速发展和深入应用,推动产业升级和发展数字经济成为重要发力点。而产业园区作为产业升级转型的重要载体,建设智慧园区的需求高速增长。智慧园区在加强信息基础设施建设的同时,注重创新化、生态

    2024年01月17日
    浏览(35)
  • 数字孪生平台3d模型制作-threejs

    threejs简化和封装了wegGL开发过程。 那么,js呢,它能写高效的3D程序吗?几年前写3D最好的世c++,js的计算能力随谷歌vs引擎得到增强。浏览器对threejs的支持,谷歌最佳。 thingjs threejs unity3D 物联网可视化平台 轻量级软件库 游戏引擎 支撑数十栋建筑园应用级,可支撑从地球到城

    2024年02月12日
    浏览(32)
  • 图扑数字孪生助力智慧冷链园区实现大数据实时监控

    近年来,业界学者及企业就智慧冷链物流展开深入研究,2010 年 IBM 发布的《智慧的未来供应链》研究报告中提出智慧供应链概念,并由此延伸出智慧物流概念,即智慧物流是以信息化为依托并广泛应用物联网、人工智能、大数据、云计算等技术工具,在物流价值链上的 6 项基

    2024年02月01日
    浏览(46)
  • 于vue3+vite+element pro + pnpm开源项目

    河码桌面是一个基于vue3+vite+element pro + pnpm 创建的monorepo项目,项目采用的是类操作系统的web界面,操作起来简单又方便,符合用户习惯,又没有操作系统的复杂! 有两个两个分支,一个是web版本,一个是electron,只需要将分支切换到electron即可,下面有electron的效果图。 web开

    2024年02月12日
    浏览(32)
  • 手摸手教你Vite+Vue3项目初始化及开源部署到GItee

    本片文章主要记录项目的环境,项目搭建。 在开始本次学习中,鉴于你有前端三件套和vue的知识基础。 文档创建于2023年5月20日,大家都去过情人节了~我在肝代码! 环境的搭建 node版本使用18.16.0。 目前(2023.05.20)的稳定版本,这里推荐使用nvm来管理node的版本。Nvm使用教程

    2024年02月04日
    浏览(46)
  • Vite + Vue3 + Ts 【免key、免账号实战本地运行GPT】

    🐔 前期回顾 Vue3 + Ts + Vite —— 封装庆祝彩屑纷飞 示例_彩色之外的博客-CSDN博客 封装 彩屑纷飞 示例 https://blog.csdn.net/m0_57904695/article/details/131718019?spm=1001.2014.3001.5501 目录  🌍 公网  🛹 本地  🪂  源码  🐔  GPT-4 有识图功能 移动版  🤺 移动版APK安装包  免魔法合集GPT、

    2024年02月16日
    浏览(40)
  • 【vue3-element-admin 】基于 Vue3 + Vite4 + TypeScript + Element-Plus 从0到1搭建后台管理系统(前后端开源@有来开源组织)

    vue3-element-admin 是基于 vue-element-admin 升级的 Vue3 + Element Plus 版本的后台管理前端解决方案,技术栈为 Vue3 + Vite4 + TypeScript + Element Plus + Pinia + Vue Router 等当前主流框架。 相较于其他管理前端框架,vue3-element-admin 的优势在于 一有一无 ( 有 配套后端、 无 复杂封装): 配套完整 J

    2023年04月21日
    浏览(89)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包