4

ThreeJs绘制数字孪生仓库场景

 7 months ago
source link: https://blog.51cto.com/BakerZhuang/9580666
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

ThreeJs绘制数字孪生仓库场景

精选 原创

BakerZhuang 2024-02-04 11:19:36 博主文章分类:threeJs ©著作权

文章标签 i++ 初始化 3D 文章分类 JavaScript 前端开发 阅读数172

  之前有做过关于threejs开发的一些小功能项,最近正好在做一个仓库相关的3D场景,这里贴出核心代码和大家分享下。

        首先要做3D场景,除了基础的组件要引入生成外,要先加入地板,在地板上添加一些3D模型达到各种各样的效果,所以首先插入地板,这里用的是vue框架,所以和原始的html使用方法上有一些区别,地板我这里也是创建了一个立体,只不过长和宽很大,高度只有1,所以看起来像一个地板,其次就是给地板添加一些纹理贴图,使地板看起来更真实一些,然后设置地板位置,最终加入到场景scene中,为了方便扩展性更好,这里把地面的宽高厚度设置为变量,方便后续修改

initFloor(){
      let floorGeometry = new THREE.BoxGeometry(         
      this.floor.floorLength,this.floor.floorWidth,this.floor.floorDepth);
      let texture = new THREE.TextureLoader().load( '/static/images/floor.jpg' )
      texture.wrapS = THREE.RepeatWrapping
      texture.wrapT = THREE.RepeatWrapping
      texture.repeat.set(5,5)
      let cubeMaterial = new THREE.MeshLambertMaterial( {
        map:texture
      } );
      let floor = new THREE.Mesh( floorGeometry, cubeMaterial );
      floor.name = '地板';
      floor.position.set(this.floor.floorLength/2,this.floor.floorWidth/2,0)
      scene.add(floor)
},
ThreeJs绘制数字孪生仓库场景_i++

添加完地面后,开始添加墙面,没有墙面的话会显得物体比较突兀,而且场地没有边界感,如果是模拟的墙可以直接添加四面墙,不用考虑窗户和门,这里从简开发,就只添加四面墙,先设置好每面墙的高度和宽度,同样这里将墙体的相关参数设置为变量,方便后期修改。

//创建墙面 
createCubeWall() {
      let materialTie = [];
      materialTie.push(new THREE.MeshPhongMaterial({color: 0xafc0ca}));  //前  0xafc0ca :灰色
      materialTie.push(new THREE.MeshPhongMaterial({color: 0x9cb2d1}));  //后  0x9cb2d1:淡紫
      materialTie.push(new THREE.MeshPhongMaterial({color: 0xd6e4ec}));  //上  0xd6e4ec: 偏白色
      materialTie.push(new THREE.MeshPhongMaterial({color: 0xd6e4ec}));  //下
      materialTie.push(new THREE.MeshPhongMaterial({color: 0xafc0ca}));  //左   0xafc0ca :灰色
      materialTie.push(new THREE.MeshPhongMaterial({color: 0xafc0ca}));  //右

      let wallList = []
      let wall1 = {width:this.floor.floorLength, height:3, depth:20, angle:0, matArrayB:materialTie, x:this.floor.floorLength/2, y:0, z:10, name:"墙面"};
      let wall2 = {width:this.floor.floorLength, height:3, depth:20, angle:1, matArrayB:materialTie, x:this.floor.floorLength/2, y:this.floor.floorWidth, z:10, name:"墙面"};
      let wall3 = {width:this.floor.floorWidth, height:3, depth:20, angle:1.5, matArrayB:materialTie, x:0, y:(this.floor.floorWidth/2), z:10, name:"墙面"};
      let wall4 = {width:this.floor.floorWidth, height:3, depth:20, angle:1.5, matArrayB:materialTie, x:this.floor.floorLength, y:(this.floor.floorWidth/2), z:10, name:"墙面"};
      wallList.push(wall1);wallList.push(wall2);wallList.push(wall3);wallList.push(wall4);
      for(let i=0;i<wallList.length;i++){
        let cubeGeometry = new THREE.BoxGeometry(wallList[i].width, wallList[i].height, wallList[i].depth);
        let cube = new THREE.Mesh(cubeGeometry, wallList[i].matArrayB);
        cube.position.x = wallList[i].x;
        cube.position.y = wallList[i].y;
        cube.position.z = wallList[i].z;
        cube.rotation.z += wallList[i].angle * Math.PI; //-逆时针旋转,+顺时针
        cube.name = wallList[i].name;
        scene.add(cube);
      }
    },
ThreeJs绘制数字孪生仓库场景_i++_02

再接着就是添加一些货架,货架不推荐使用建模的方式开发,因为后续一但货架的尺寸发生了改变,那么就需要对模型重新改动再引入进来,太麻烦了,尽量使用threejs提供的建模方式进行绘制,因为需求的关系这里需要两两货架并拢,所以代码会显得有些乱,货架包括了四条腿,层板,五个模型,这里对五个模型的相关参数都设置为变量的方式,方便后面快速调整货架的模型,仓库也不会只有一个货架,这里用了循环,实现12排货架,每排两组货架,每组三个货架,

//初始化货架    
initShelf(){
      for(let n=0;n<2;n++) {
        let offsetX = 60;
        for (let i = 0; i < 12; i++) {
          if(i%2 === 1){
            offsetX  = offsetX + 45;
          }else{
            offsetX = offsetX + 25;
            this.addPaTrack(offsetX, this.indistanceY+n*180, 0,true,"car_"+n+"_"+i)
          }
          for (let j = 0; j < 3; j++) {
            let shelfName = '货架' + j+"上"
            this.shelfList.push({
              shelfName: shelfName,
              planeWidth: this.plane.planeWidth,
              planeHeight: this.plane.planeHeight,
              planeLength: this.plane.planeLength,
              holderLength: this.holder.holderLength,
              holderHeight: this.holder.holderHeight,
              holderWidth: this.holder.holderWidth,
              positionX: offsetX,
              positionY: this.indistanceY + (j * 60)+n*180,
              positionZ: this.holder.holderHeight + 2,
              layerNum: this.layerNum,
              columnNum: this.columnNum
            });
          }
        }
      }
      for(let i = 0;i < this.shelfList.length; i++){
        for(let j = 0; j < this.shelfList[i].layerNum; j++){
          this.addShelf(
              this.shelfList[i].positionX,
              this.shelfList[i].positionY,
              this.shelfList[i].positionZ*(j+1),
              this.shelfList[i].planeWidth,
              this.shelfList[i].planeLength,
              this.shelfList[i].planeHeight,
              this.shelfList[i].holderLength,
              this.shelfList[i].holderWidth,
              this.shelfList[i].holderHeight,
              scene,
              this.shelfList[i].shelfName+"$"+j,
              this.shelfList[i].columnNum);
        }
      }
    },
    addShelf(x,y,z,plane_x,plane_y,plane_z,holder_x,holder_y,holder_z,scene,name,num){
      let RackMat2 = new THREE.MeshPhongMaterial({color:0xFFFFFF});
      let plane = new THREE.BoxGeometry( plane_x, plane_y/num,plane_z, );
      let gz = [];
      for(let i = 0; i < num; i++){
        gz.push( y + plane_y/num/2 + (plane_y/num)*i );
        let obj = new THREE.Mesh( plane, RackMat2 );
        obj.position.set(x, gz[i], z) ;
        scene.add(obj);
      }
      let holder = new THREE.BoxGeometry( holder_x, holder_y, holder_z );
      let obj2 = new THREE.Mesh( holder, RackMat2, 0 );
      let obj3 = new THREE.Mesh( holder, RackMat2, 0 );
      let obj4 = new THREE.Mesh( holder, RackMat2, 0 );
      let obj5 = new THREE.Mesh( holder, RackMat2, 0 );
      obj2.position.set(x-plane_x/2+holder_x/2,y+holder_y/2,z-holder_z/2-plane_z/2,);
      obj3.position.set(x+plane_x/2-holder_x/2,y+holder_y/2, z-holder_z/2-plane_z/2, );
      obj4.position.set(x-plane_x/2+holder_x/2,y+plane_y-holder_y/2,z-holder_z/2-plane_z/2 );
      obj5.position.set(x+plane_x/2-holder_x/2,y+plane_y-holder_y/2, z-holder_z/2-plane_z/2 );
      scene.add(obj2);scene.add(obj3);scene.add(obj4);scene.add(obj5);
    },
ThreeJs绘制数字孪生仓库场景_初始化_03

有了货架还需要在货架上防止货物,货物可以根据货架的位置动态计算货物放置的位置,先做一个专门添加货物的功能,在做一个初始化货架的方法,在初始化货架中根据需求添加货物,再循环调用生成货物的方法添加多个货物。

//初始化货架
initCube(){
      for(let q=0; q<this.shelfList.length;q++){
        for(let i=0;i<this.layerNum;i++){
          for(let j=0;j<this.columnNum;j++){
            let shorageName = this.shelfList[q].shelfName+"_"+i+"层_"+j+"列"
            let x = this.shelfList[q].positionX;
            let y = this.shelfList[q].positionY + (this.box.boxDepth) + j*(this.plane.planeLength/3)
            let z = this.shelfList[q].positionZ + (this.box.boxDepth/2) + i*(this.holder.holderHeight+this.plane.planeHeight)
            this.addCube(x-6,y,z,"货物在"+"_"+shorageName+"_1")
            this.addCube(x+5,y,z,"货物在"+"_"+shorageName+"_2")
          }
        }
      }
    },
    //新增货架
    addCube(x,y,z,name){
      const loader = new GLTFLoader()
      loader.load("/static/model/box.glb", (gltf) => {
        gltf.scene.position.set(x, y, z+1)   // 模型位置
        gltf.scene.rotation.x = Math.PI / 2    // x轴旋转
        gltf.scene.scale.set(0.6, 0.4, 0.5)   // 模型位置
        gltf.scene.name = name
        scene.add(gltf.scene)
      })
    },
ThreeJs绘制数字孪生仓库场景_初始化_04

好了这里一个简单的仓库模型就好了,可以根据具体需求定制化开发一些其他功能,实现更好的效果。

  • 收藏
  • 评论
  • 分享
  • 举报

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK