赞
踩
本章我们来讲解下如何添加货架货物和显示各类信息的侧边栏。效果如下图所示:
2019.11.26 更新:我最近建立了个人网站,大家可以访问下面的链接查看演示
3D仓库演示
2019.11.28 更新:代码和图片资源等已上传至GitHub
https://github.com/xiao149/ThreeJsDemo
其中货架的层数和每层的货位数量是可以自定义的,比如我这边就是三层每层两个货位。方便起见我在每个货位上都放置了货物,大家当然可以自行选择。左上角的侧边栏使用了ThreeJs官方的dat.gui,这里为了演示也只是随便列了几个信息,当点击货物时相关信息便会显示出来。
因为我本身主要从事JAVA后台的开发,对前台一知半解,所以这部分写得不好也请各位轻喷,或许是受JAVA对象类的影响,我想在JS中也创建对象,比如货架的对象,货位的对象。奈何我水平有限,不知如何在JS中创建对象,只能用一些比较“愚蠢”的方式实现:
//创建货架对象 function shelf(storageZoneId, shelfId, shelfName, planeLength , planeWidth , planeHeight , holderLength , holderWidth , holderHeight , positionX , positionY , positionZ , layerNum , columnNum) { this.storageZoneId=storageZoneId; this.shelfId=shelfId; this.shelfName=shelfName; this.planeLength=planeLength; this.planeWidth=planeWidth; this.planeHeight=planeHeight; this.holderLength=holderLength; this.holderWidth=holderWidth; this.holderHeight=holderHeight; this.positionX=positionX; this.positionY=positionY; this.positionZ=positionZ; this.layerNum=layerNum; this.columnNum=columnNum; } //根据货架编码获取货架对象 function getShelfById(shelfId) { for(var i = 0; i < shelfSize; i++){ if(shelfList[i].shelfId == shelfId){ return shelfList[i]; } } } //创建货位对象 function storageUnit(storageZoneId, shelfId, shelfName, inLayerNum , inColumnNum , positionX , positionY , positionZ, storageUnitId) { this.storageZoneId=storageZoneId; this.shelfId=shelfId; this.shelfName=shelfName; this.inLayerNum=inLayerNum; this.inColumnNum=inColumnNum; this.positionX=positionX; this.positionY=positionY; this.positionZ=positionZ; this.storageUnitId=storageUnitId; } //根据货架ID、层数、列数获取货位对象 function getStorageUnitById(shelfId,inLayerNum,inColumnNum) { for(var i = 0; i < storageUnitSize; i++){ if(storageUnitList[i].shelfId == shelfId && storageUnitList[i].inLayerNum == inLayerNum && storageUnitList[i].inColumnNum == inColumnNum){ return storageUnitList[i]; } } } //根据库位编码获取货位对象 function getStorageUnitByUnitId(storageUnitId) { for(var i = 0; i < storageUnitSize; i++){ if(storageUnitList[i].storageUnitId == storageUnitId){ return storageUnitList[i]; } } }
上述的创建货架货位对象有点像创建JAVA类的初始化,对象的获取也是仿照了JAVA的GET方法。这样在需要创建货架货位的地方只需要调用对象的初始化方法,赋予相应的值。在需要获取对象的地方调用GET方法就好了。
我们创建的货架没有使用外部导入的3D模型,全部使用ThreeJs创建各类长方体拼接而成,比如单层货架就是一个长方体作货架板面,再加上四个小长方体作支架。代码如下:
//region 货架货位 /** 放置单层货架 */ /** x,y,z 整个模型在场景中的位置 */ /** plane_x,plane_y,plane_z 货架板面的长高宽 */ /** holder_x,holder_y,holder_z 货架支架的长高宽 */ /** scene,name,num 要添加的场景,货架的名字,单层货架的库位数量 */ function addRack(x,y,z,plane_x,plane_y,plane_z,holder_x,holder_y,holder_z,scene,name,num) { var plane = new THREE.BoxGeometry( plane_x, plane_y, plane_z/num ); var gz = []; for(var i = 0; i < num; i++){ gz.push( z + plane_z/num/2 + (plane_z/num)*i ); var obj = new THREE.Mesh( plane, RackMat ); obj.position.set(x , y, gz[i]) ; var msg = name+"$"+(2-i); var storageUnitId = msg.split("$")[1] + "$" + msg.split("$")[3] + "$" + msg.split("$")[4]; //添加货位 var storageUnit_obj = new storageUnit(msg.split("$")[0], msg.split("$")[1], msg.split("$")[2], msg.split("$")[3], msg.split("$")[4], x, y, gz[i], storageUnitId); storageUnitList.push(storageUnit_obj); storageUnitSize++; var Unit = getStorageUnitById(msg.split("$")[1],msg.split("$")[3],msg.split("$")[4]); obj.name = "货位"+"$"+Unit.storageUnitId; scene.add(obj); } var holder = new THREE.BoxGeometry( holder_x, holder_y, holder_z ); var obj2 = new THREE.Mesh( holder, RackMat2 ); var obj3 = new THREE.Mesh( holder, RackMat2 ); var obj4 = new THREE.Mesh( holder, RackMat2 ); var obj5 = new THREE.Mesh( holder, RackMat2 ); obj2.position.set(x-plane_x/2+holder_x/2,y-holder_y/2-plane_y/2,z+holder_z/2); obj3.position.set(x+plane_x/2-holder_x/2,y-holder_y/2-plane_y/2,z+holder_z/2); obj4.position.set(x-plane_x/2+holder_x/2,y-holder_y/2-plane_y/2,z+plane_z-holder_z/2); obj5.position.set(x+plane_x/2-holder_x/2,y-holder_y/2-plane_y/2,z+plane_z-holder_z/2); scene.add(obj2);scene.add(obj3);scene.add(obj4);scene.add(obj5); } /** 放置一叠货架 */ /** stack_num 货架的叠数 */ function addStackOfRack(x,y,z,plane_x,plane_y,plane_z,holder_x,holder_y,holder_z,scene,name,num,stack_num) { for(var i = 0; i < stack_num; i++){ addRack(x,y*(i+1),z,plane_x,plane_y,plane_z,holder_x,holder_y,holder_z,scene,name+"$"+(i+1),num); } } /** 根据货架配置添加货架 */ function addShelf(scene) { var shelf_list = new Array(); shelf_list.push({StorageZoneId:'Z1',shelfId:'A2',shelfName:'货架A2',x:0,y:27,z:0}); shelfSize = shelf_list.length; for(var i = 0; i < shelfSize; i++){ var shelf_obj = new shelf(shelf_list[i].StorageZoneId, shelf_list[i].shelfId, shelf_list[i].shelfName, PLANE_LENGTH,PLANE_WIDTH,PLANE_HEIGHT, HOLDER_LENGTH,HOLDER_WIDTH,HOLDER_HEIGHT, shelf_list[i].x, shelf_list[i].y, shelf_list[i].z, LAYER_NUM,COLUMN_NUM); shelfList.push(shelf_obj); } for(var i = 0;i < shelfSize; i++){ addStackOfRack(shelfList[i].positionX,shelfList[i].positionY,shelfList[i].positionZ,shelfList[i].planeLength,shelfList[i].planeHeight,shelfList[i].planeWidth,shelfList[i].holderLength,shelfList[i].holderHeight,shelfList[i].holderWidth,scene,shelfList[i].storageZoneId+"$"+shelfList[i].shelfId+"$"+shelfList[i].shelfName,shelfList[i].columnNum,shelfList[i].layerNum); } }
在HTML文件的init()
方法中添加addShelf(scene);
就可以实现添加货架的功能啦。
在addShelf
方法中我原本是读取数据库货架的配置的,但是既然拿出来展示了肯定就不能用数据库了,所以我只能写死一些数据。
var shelf_list = new Array();
shelf_list.push({StorageZoneId:'Z1',shelfId:'A2',shelfName:'货架A2',x:0,y:27,z:0});
这行是添加一个货架,参数的意义是:货架所在的库区、货架的编号、货架的中文名、货架的xyz位置。效果如下:
点击货位能以高亮显示,并显示出货位的信息:货位&货架编码&货位的所在层&所在列。
若是想添加多个货架也很简单,在addShelf
方法里加上:
var shelf_list = new Array();
shelf_list.push({StorageZoneId:'Z1',shelfId:'A1',shelfName:'货架A1',x:-100,y:27,z:0});
shelf_list.push({StorageZoneId:'Z1',shelfId:'A2',shelfName:'货架A2',x:0,y:27,z:0});
shelf_list.push({StorageZoneId:'Z1',shelfId:'A3',shelfName:'货架A3',x:100,y:27,z:0});
需要几个货架就在shelf_list
里添加几个。效果如下:
在我的设计中,货物是跟货位绑定的,一个货位上可能会放很多箱的货物,为了显示简洁方便,我们统一成一个大箱子,然后双击这个大箱子弹出画面显示里面的详细信息(这章暂不讲解),Modules.js
代码如下:
//region 货物 /** 放置单个货物 */ function addCargo(x,y,z,box_x,box_y,box_z,scene,name) { var geometry = new THREE.BoxGeometry( box_x, box_y, box_z ); var obj = new THREE.Mesh( geometry, CargoMat ); obj.position.set(x,y,z); obj.name = name; scene.add(obj); } /** 添加单个货位上的货物 */ function addOneUnitCargos(shelfId,inLayerNum,inColumnNum,scene) { var storageUnit = getStorageUnitById(shelfId,inLayerNum,inColumnNum); var shelf = getShelfById(storageUnit.shelfId); var storageUnitid = storageUnit.storageUnitId; var x = storageUnit.positionX; var y = storageUnit.positionY + 8 + shelf.planeHeight/2; var z = storageUnit.positionZ; addCargo(x,y,z,16,16,16,scene,"货物"+"$"+storageUnitid) } //endregion
在HTML的init()
方法中添加:
//添加货物
for(var i = 1; i <= 3; i++){
for(var j = 1; j <= 2; j++){
for(var k = 1; k <= 3; k++) {
addOneUnitCargos("A" + k, i, j, scene);
}
}
}
效果如下,点击货物箱子也会显示货物的信息,跟货位类似也是:货物&货架编码&货物的所在层&所在列。
首先在HTML中引入这个JS
<script src="./ThreeJs/js/dat.gui.min.js"></script>
然后添加这个方法,大家可以自定义需要显示的内容。我这里添加了四个标签,每个都添加了.listen()
监听事件,这样就可以在点击到物体的时候改变侧边栏上的内容。
// 初始化GUI
function initGui() {
options = new function () {
this.batchNo ='';this.qty = 0;this.qtyUom ='';this.qty2 = 0;
};
var gui = new dat.GUI();
gui.domElement.style = 'position:absolute;top:50px;left:0px;height:600px';
gui.add(options, 'batchNo').name("物料批号:").listen();
gui.add(options, 'qty').name("数量:").listen();
gui.add(options, 'qtyUom').name("单位:").listen();
gui.add(options, 'qty2').name("件数:").listen();
}
在init()
中添加initGui()
就ok了
我们回到ThreeJs_Composer.js
这个自定义的JS,我们需要在鼠标点击事件里添加代码实现:
var Msg = intersects[0].object.name.split("$");
if(Msg[0] == "货物") {
_options.batchNo = "一个货物";
_options.qty = "100";
_options.qtyUom = "kg";
_options.qty2 = "10";
}
这里限定了只有点击到货物时,侧边栏_options
才会更新,一般数据也是从数据库取出来的,这里我仅仅为了演示写死了一些数据。完成后效果如下:
最近陆续有朋友来加我微信交流评论,说实话当初我写文章只是为了记录下自己的历程免得以后忘记,看到这么多朋友催更交流我感到很开心。就如大家所说,ThreeJs网上的资料实在太过杂乱,很难从啥都不会开始学习,我虽然只是个后台程序猿,但也愿意贡献自己的一份力量帮助大家共同学习。因为我是从事仓库系统的开发,3D仓库显示只是其中的一小部分功能,到这章为止已经是我现在能做到的全部内容了。未来可能会开发其他的内容,比如场景切换等等。最后还是要谢谢大家支持!
我跟广大学习ThreeJs的初学者一样,仍带着懵懂的心去探索这片新大陆,CSDN上的许多前辈都给了我很多关键的灵感和技术方法,如果大家有兴趣,也可以互相交流成长,欢迎大家指导咨询。PS:大家有兴趣可以点进去我的头像,陆陆续续也写了十来篇了。
链接:使用ThreeJs从零开始构建3D智能仓库——第一章: 点我跳转.
链接:使用ThreeJs从零开始构建3D智能仓库——第二章: 点我跳转.
链接:使用ThreeJs从零开始构建3D智能仓库——第三章: 点我跳转.
链接:使用ThreeJs从零开始构建3D智能仓库——第四章: 点我跳转.
链接:使用ThreeJs从零开始构建3D智能仓库——第五章: 点我跳转.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。