Threejs制作服务器机房冷却结构

简介: 这篇文章详细介绍了如何使用Three.js来创建一个服务器机房的冷却结构模型,包括设计和实现机房内冷却系统的可视化表现。

这节再绘制一个机房的结构,因为内容比较简单,就只使用一个章节来介绍,

先来一张效果图,

需要两个模型:一个冷却设备,一个服务器机箱,我这里是从网上找来的,首先我们搭建一个场景,

 initScene(){
      this.scene = new THREE.Scene();
    },
    initCamera(){
      this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
      this.camera.position.set(200,-100,200);
      this.camera.lookAt(200,200,0);
      this.camera.up.set(0, 0, 1);   // <=== spin // around Z-axis
    },
    initLight(){
      //添加两个平行光
      const directionalLight1 = new THREE.DirectionalLight(0xffffff, 1.5);
      directionalLight1.position.set(-300,-300,600)
      this.scene.add(directionalLight1);
      const directionalLight2 = new THREE.DirectionalLight(0xffffff, 1.5);
      directionalLight2.position.set(600,200,600)
      this.scene.add(directionalLight2);
    },
 initRenderer(){
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.container = document.getElementById("container")
      this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
      this.renderer.setClearColor('#FFFFFF', 1.0);
      this.container.appendChild(this.renderer.domElement);
    },
    initControl(){
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);

      this.controls.enableDamping = true;
      this.controls.maxPolarAngle = Math.PI / 2.2;      // // 最大角度
      this.controls.target = new THREE.Vector3(200, 200, 0);
      this.camera.position.set(200, -100, 200);
      this.camera.lookAt(200, 200, 0);
    },
    initAnimate() {

      requestAnimationFrame(this.initAnimate);
      this.renderer.render(this.scene, this.camera);
    },

然后添加房间,为了效果更真实,我们会创建一个房间,把服务器放在房间里,把冷却塔放在外面,创建方法和mes中的类似,只不过这个不用设计门了,可以直接搭建四堵墙和地板

 floor:{floorWidth:600, floorLength:600,depth:1},
      wall:{wallWidth:150, wallLength:300,wallHeight:20},
      offsetValue:200,

initFloor(){
      let floorGeometry = new THREE.BoxGeometry( this.floor.floorWidth,this.floor.floorLength,this.floor.depth);
      let floorMaterial = new THREE.MeshPhysicalMaterial({color:'#FFFFFF'});
      let textureFloor = new THREE.TextureLoader().load('/static/images/floor.jpg', function (texture) {
        texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
      })
      floorMaterial.map = textureFloor
      let floor = new THREE.Mesh( floorGeometry, floorMaterial );
      floor.name = '地板';
      floor.position.set(this.floor.floorWidth/2,this.floor.floorLength/2,0)
      this.scene.add(floor)
    },
    //初始化墙壁
    createCubeWall() {
      let materialTie = new THREE.MeshPhysicalMaterial({color: '#BBBBBB'});  //前  0xafc0ca :灰色
      let textureWall = new THREE.TextureLoader().load('/static/images/wall.jpg', function (texture) {
        texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
      })
      materialTie.map = textureWall
      let wallList = []
      let wall1 = {width:this.wall.wallLength, height:2, depth:this.wall.wallHeight, angle:0, matArrayB:materialTie, x:this.wall.wallLength/2+this.offsetValue, y:+this.offsetValue, z:this.wall.wallHeight/2, name:"墙面"};
      let wall2 = {width:this.wall.wallLength, height:2, depth:this.wall.wallHeight, angle:1, matArrayB:materialTie, x:this.wall.wallLength/2+200, y:this.wall.wallWidth+this.offsetValue, z:(this.wall.wallHeight/2), name:"墙面"};
      let wall3 = {width:this.wall.wallWidth, height:2, depth:this.wall.wallHeight, angle:1.5, matArrayB:materialTie, x:this.offsetValue, y:this.wall.wallWidth/2+this.offsetValue, z:(this.wall.wallHeight/2), name:"墙面"};
      let wall4 = {width:this.wall.wallWidth, height:2, depth:this.wall.wallHeight, angle:1.5, matArrayB:materialTie, x:this.wall.wallLength+this.offsetValue, y:(this.wall.wallWidth/2)+this.offsetValue, z:(this.wall.wallHeight/2), 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;
        this.scene.add(cube);
      }
    },

然后添加两个设备,一个冷却设备,一个服务器主机柜,要注意调整位置,保持一个在房间内一个在房间外,后续会通过冷凝管连接两个设备

initDevice(){
      const loader = new GLTFLoader()
      loader.load("/static/models/server.glb", (gltf) => {
        this.server = gltf.scene;
        this.server.scale.set(0.3,0.3,0.3);
        this.server.position.set(300,300,0);
        this.server.rotation.x = Math.PI/2
        this.server.rotation.y = Math.PI/2
        this.scene.add(this.server)   // 加入场景
      })
      loader.load("/static/models/tower.glb", (gltf) => {
        this.tower = gltf.scene;
        this.tower.scale.set(20,20,20);
        this.tower.position.set(300,400,30);
        this.tower.rotation.x = Math.PI/2
        this.scene.add(this.tower)   // 加入场景
      })
    },

添加好设备后,我们就得到这样的场景,

然后需要添加管道给这两个设备连接起来,并且其中一个为蓝色一个为红色,之前有讲过Threejs绘制管道效果,可以就把那部分拿过来使用,配置好每个坐标点,这里用两个方法一个绘制冷水,一个绘制热水,并且让水流动起来,这部分开发可以参考之前的章节,不过要调整水管的接入点,如果想要直角管,可以在点数组中添加两个拐弯点的坐标,就可以避免后续的点的影响,以达到直角管道的效果。

代码如下:

initColdTube(){
      const path = new THREE.CatmullRomCurve3([
        new THREE.Vector3(350, 300, 10),
        new THREE.Vector3(380, 300, 10),
        new THREE.Vector3(380, 300, 10),
        new THREE.Vector3(380, 400, 10),
        new THREE.Vector3(380, 400, 10),
        new THREE.Vector3(320, 400, 7),
      ]);
      let geometry1 = new THREE.TubeGeometry(path, 100, 1, 25, false);
      let textureLoader = new THREE.TextureLoader();
      let texture = textureLoader.load('/static/images/cold.png')
      texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
      this.coldMaterial = new THREE.MeshBasicMaterial({
        map:texture,
        transparent: false,
      }); //材质对象Material
      let mesh1 = new THREE.Mesh(geometry1, this.coldMaterial); //网格模型对象Mesh
      this.scene.add(mesh1); //网格模型添加到场景
      let tubeGeometry2 = new THREE.TubeGeometry(path, 100, 2, 25, false);
      let tubeMaterial2 = new THREE.MeshPhongMaterial({
        color: 0xaaaaaa,
        transparent: true,
        opacity: 0.5,
      });
      let tube2 = new THREE.Mesh(tubeGeometry2, tubeMaterial2);
      this.scene.add(tube2);
    },
    initHotTube(){
      const path = new THREE.CatmullRomCurve3([
        new THREE.Vector3(300, 300, 10),
        new THREE.Vector3(230, 300, 10),
        new THREE.Vector3(230, 300, 10),
        new THREE.Vector3(230, 300, 53),
        new THREE.Vector3(230, 300, 53),
        new THREE.Vector3(230, 400, 53),
        new THREE.Vector3(230, 400, 53),
        new THREE.Vector3(270, 400, 53),
      ]);
      let geometry1 = new THREE.TubeGeometry(path, 100, 1, 25, false);
      let textureLoader = new THREE.TextureLoader();
      let texture = textureLoader.load('/static/images/hot.png')
      texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
      this.hotMaterial = new THREE.MeshBasicMaterial({
        map:texture,
        transparent: false,
      }); //材质对象Material
      let mesh1 = new THREE.Mesh(geometry1, this.hotMaterial); //网格模型对象Mesh
      this.scene.add(mesh1); //网格模型添加到场景
      let tubeGeometry2 = new THREE.TubeGeometry(path, 100, 2, 25, false);
      let tubeMaterial2 = new THREE.MeshPhongMaterial({
        color: 0xaaaaaa,
        transparent: true,
        opacity: 0.5,
      });
      let tube2 = new THREE.Mesh(tubeGeometry2, tubeMaterial2);
      this.scene.add(tube2);
    },

然后再给服务器和冷却设备添加状态和名字,用上个章节中给产线设备添加名字的方式:

initMachineName(x,y,z,name){//创建设备信息
      const earthDiv = document.createElement('div');
      earthDiv.className = "label";
      earthDiv.innerHTML = "<div style='border:1px #FFFFFF solid;border-radius: 5px;width:90px;padding-left:10px'>" +
          "<span style='font-size: 12px;color:#FFFFFF'>"+name+"</span><br/>" +
          "<span style='font-size: 12px;color:#FFFFFF'>运行正常</span><br/>" +
          "<span style='color:green;font-size: 12px;'>温度18℃</span>" +
          "</div>";
      const earthLabel = new CSS2DObject(earthDiv);
      earthLabel.position.set(x,y,z);//相对于父级元素的位置
      this.scene.add(earthLabel);

      this.labelRenderer = new CSS2DRenderer();
      this.labelRenderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(this.labelRenderer.domElement)
      //设置样式
      this.labelRenderer.domElement.style.position = 'fixed';
      this.labelRenderer.domElement.style.top = '0px';
      this.labelRenderer.domElement.style.left = '0px';
      this.labelRenderer.domElement.style.zIndex = '10';//设置层级
    },

最终效果如下:
WechatIMG125.jpg
机房冷却

这里不支持上传视频,我就只能上传个图片了,如果想看动态效果可以私我,我发给你视频。

这样一共不到250代码,一个简单的机房数字孪生场景就做好了,如果需要源码可以在评论区留下邮箱,也可以私信一起交流学习。

相关文章
|
5月前
请问单位机房自建服务器,如何备案?
事业单位,领导要求自建web服务器,服务器放在单位机房,请问如何备案?如何域名在阿里云购买,如何备案。
|
5月前
|
前端开发 应用服务中间件 nginx
Next.js 创建项目到服务器部署(目录结构介绍、项目结构Demo、开发细节注意)
Next.js 创建项目到服务器部署(目录结构介绍、项目结构Demo、开发细节注意)
851 0
|
弹性计算 安全 定位技术
阿里云服务器机房具体地址在哪?查询方法来了
阿里云服务器机房具体地址在哪?查看详细地址方法太牛了
8643 2
阿里云服务器机房具体地址在哪?查询方法来了
|
2月前
|
存储 数据挖掘 索引
服务器数据恢复—LeftHand存储结构和P4500存储数据恢复案例
LeftHand存储支持RAID5、RAID6、RAID10磁盘阵列,同时还支持卷快照,卷动态扩容等。下面简单聊一下LeftHand存储的结构和一个LeftHand p4500存储中磁盘阵列数据恢复案例。
服务器数据恢复—LeftHand存储结构和P4500存储数据恢复案例
|
3月前
|
存储 数据挖掘 Linux
服务器数据恢复—机房搬迁导致服务器无法识别raid的数据恢复案例
某单位机房搬迁,将所有服务器和存储搬迁到新机房并重新连接线路,启动所有机器发现其中有一台服务器无法识别RAID,提示未做初始化操作。 发生故障的这台服务器安装LINUX操作系统,配置了NFS+FTP作为单位内部的文件服务器使用。服务器为ProLiant DL380系列服务器,通过hp smart array控制器挂载了一组由14块SCSI硬盘组成的RAID5磁盘阵列。该raid5磁盘阵列采用双循环的校验方式。 北亚企安数据恢复工程师到达现场后对故障服务器进行了初检,经过检测发现raid信息丢失。
服务器数据恢复—机房搬迁导致服务器无法识别raid的数据恢复案例
|
3月前
|
存储 数据挖掘
服务器数据恢复—LeftHand存储结构&数据恢复案例
服务器存储数据恢复环境&故障: 该LeftHand存储中有三组raid,两个卷,12块物理硬盘。 该存储中raid出现故障,管理员执行了强制上线的操作后raid依然不可用。
服务器数据恢复—LeftHand存储结构&数据恢复案例
机房构建---服务器必须搭配显示器,接口使用VGA的线,必备基础设施之显示器
机房构建---服务器必须搭配显示器,接口使用VGA的线,必备基础设施之显示器
|
5月前
|
存储 算法 安全
【服务器数据恢复】HP EVA存储结构&原理&数据恢复方案
EVA是虚拟化存储,在工作过程中,EVA存储中的数据会不断地迁移,再加上运行在EVA上的应用都比较繁重,磁盘负载高,很容易出现故障。EVA是通过大量磁盘的冗余空间和故障后rss冗余磁盘动态迁移保护数据。但是如果磁盘掉线数量到达一个临界点,EVA存储就会崩溃。
【服务器数据恢复】HP EVA存储结构&原理&数据恢复方案
|
5月前
|
存储 缓存 物联网
DP读书:鲲鹏处理器 架构与编程(二)服务器与处理器——高性能处理器的并行组织结构、ARM处理器
DP读书:鲲鹏处理器 架构与编程(二)服务器与处理器——高性能处理器的并行组织结构、ARM处理器
310 0
|
5月前
|
关系型数据库 MySQL 数据库
mysq优化---mysql执行计划解释、优化查询、数据库结构、服务器
mysq优化---mysql执行计划解释、优化查询、数据库结构、服务器