• webgl(threejs)生成房间楼层


    楔子

    在很多数字孪生项目中,都会涉及到楼层的建模。楼层的建模由于结构繁多,如果都是建模师进行手动建模,工作量会比较大。而楼层本身的结构,可以抽象成可以通过路径构造的对象(这和之前的文章提及的的管路以及道路类似),这方便我们通过代码的方式来生成房间楼层。

    墙体几何对象PathCubeGeometry

    楼层一般分成墙体和地板两个部分,首先来看下墙体对象。 以threejs为基础,扩展一个几何对象PathCubeGeometry。 该对象通过一个Path3D路径来构造一个墙的几何体,该几何体可以分成start,end,top,bottom,outside,inside等几个表面分组,这样就方便给内表面和外表面,以及顶面等设置不同的材质贴图的效果。 主要代码如下:

        this.vert = vert;
        this.rawUV = rawUV;
        this.pathU = pathU;
    
        this.indices =  []
        this.vertices = [];
        this.uvs = [],
        this.normals = [];
    
        this.generateSideWall(vert,inner,outer,innerTop, outerTop, true,closed);
        this.generateSideWall(vert,inner,outer,innerTop, outerTop, false,closed);
    
    
        this.generateTopBottom(vert,inner,outer,innerTop,outerTop,true,closed);
        this.generateTopBottom(vert,inner,outer,innerTop,outerTop,false,closed);
    
        if(!closed) {
            this.generateAZSide(vert,inner,outer,innerTop,outerTop,true);
            this.generateAZSide(vert,inner,outer,innerTop,outerTop,false);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    通过PathCubeGeometry,我们可以方便的构建墙体,比如如下示例代码:

    const materials = [m1, m2, m3, m3, m3, m3];
    const points = json.outerWall.path;
    const p0 = points[0];
    const path = new Path3D();
    const scale = 20;
    path.moveTo(p0.x * scale, p0.y * scale, p0.z * scale);
    for (let i = 1; i < points.length; i++) {
    let p = points[i];
        path.lineTo(p.x * scale, p.y * scale, p.z * scale);
    }
    path.closePath();
    cosnt patCube = new PathCubeGeometry(path, 10, 50, 32, 500);
    const mesh = new dt.Mesh(patCube, materials);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    首先通过Path3D构造一个路径(路径来源于传入的一系列点points),然后通过路径构造一个结合体对象PathCubeGeometry,最后生成实体,效果如下图所示:

    在这里插入图片描述

    门和窗

    构造门和窗的难度不大,一般都通过立方体 + 贴图的方式就可以生成。比如如下代码可以生成一个双开门:

    function createDoor(pos) {
      var cube = new CubeGeometry(200, 400, 5);
      var material = createMaterial(graph, {
        color: 0xffffff,
        flatShading: true,
        map: "./images/glass-wall6.png",
        transparent: true,
      });
    
      material.map.repeat.set(0.5, 1);
      var leftDoor = new Mesh(cube, material);
      leftDoor.position.copy(pos.clone().sub(new Vec3(100)));
      leftDoor.attr("type", "left_door");
      leftDoor._type = "left_door";
      dataModel.add(leftDoor);
    
      var rightDoor = new Mesh(cube, material);
      rightDoor.position.copy(pos.clone().add(new Vec3(100)));
      rightDoor._type = "right_door";
      dataModel.add(rightDoor);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    创建的门的效果如下图所示:

    在这里插入图片描述

    创建单开门和窗户的思路是一致的。不过难点的地方是门窗所在的位置,墙体本身需要挖洞。挖洞需要使用BSP功能。

    BSP挖洞

    BSP操作可以对模型进行交集 并集 差集的操作。 要在墙上挖洞,可以在墙的几何体上进行差集操作,比如减去一个立方体,这样就可以在墙面上生成一个方型的洞。
    在THREEJS上面,有一个开源的BSP包,THREEBSP。

    代码如下所示:

    var csg = new CSG().setFromGeometry(patCube);
    var csg2 = new CSG().setFromGeometry(cubeGeometry);
    var csg3 = new CSG().setFromGeometry(cubeGeometry2);
    csg.subtractOperand(csg2);
    csg.subtractOperand(csg3);
    var geometry = csg.toGeometry();
    var mesh = new Mesh(geometry, materials);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    最后生成的效果如下图所示:
    在这里插入图片描述

    在把创建好的门和窗放到相应的挖洞位置,效果如下所示:

    在这里插入图片描述

    创建地板

    在threejs中,通过ExtrudeGeometry可以创建地板的几何体,然后指定地板的材质,既可以创建一个地板对象 代码如下所示:

      var path = new ShapePath();
      var texture = graph.loadTexture("./images/floor.jpg", {
        wrapT: RepeatWrapping,
        wrapS: RepeatWrapping,
      });
      texture.repeat.set(1 / 400, 1 / 400);
      texture.anisotropy = 16;
    
      let m1 = new BasicMaterial({
        map: texture,
        color: 0xffffff,
        toneMapped: false,
      });
      const simpleShapes = path.toShapes(true);
    
      var geometry = new ExtrudeGeometry(simpleShapes, {
        depth: 1,
        bevelEnabled: false,
        vertical: true,
      });
      var mesh = new Mesh(geometry, [m1, m1]);
      dataModel.add(mesh);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    最终的效果如下所示:

    在这里插入图片描述

    结语

    本文介绍了通过代码生成楼层的功能,其中用到了PathCubeGeometry,ExtrudeGeometry,BSP相关技术,其中PathCubeGeometry由于需要自己构建,会稍晚难点; ExtrudeGeometry是threejs本身就存在的对象,BSP也可以找到开源的包可以使用。

    如果你有好的思路,也欢迎和我交流。关注公号“ITMan彪叔” 可以添加作者微信进行交流,及时收到更多有价值的文章。

  • 相关阅读:
    源码深度剖析SpringBoot启动流程中开启OpenFeign的入口(ImportBeanDefinitionRegistrar详解)
    List-带头结点的双向循环链表
    软考知识汇总-计算机系统
    1027. 最长等差数列(leetcode)
    MIT6.S081Lab2:system calls
    【 解决jsoncpp被多重引入问题add_library cannot create imported target “JsonCpp::JsonCpp“】
    Matlab:Matlab编程语言的简介、安装、学习路线(几十项代码编程案例分析)之详细攻略
    cuda系列详细教程-花絮
    软件需求工程R 第十一、十二、十三章
    活动聊天机器人如何革新活动行业
  • 原文地址:https://blog.csdn.net/netcy/article/details/126440045