楔子
在很多数字孪生我的项目中,都会波及到楼层的建模。楼层的建模因为构造繁多,如果都是建模师进行手动建模,工作量会比拟大。而楼层自身的构造,能够形象成能够通过门路结构的对象 (这和之前的文章提及的的管路以及路线相似),这不便咱们通过代码的形式来生成房间楼层。
墙体几何对象 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);
}
通过 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);
首先通过 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);
}
创立的门的成果如下图所示:
创立单开门和窗户的思路是统一的。不过难点的中央是门窗所在的地位,墙体自身须要挖洞。挖洞须要应用 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);
最初生成的成果如下图所示:
在把创立好的门和窗放到相应的挖洞地位,成果如下所示:
创立地板
在 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);
最终的成果如下所示:
结语
本文介绍了通过代码生成楼层的性能,其中用到了 PathCubeGeometry,ExtrudeGeometry,BSP 相干技术,其中 PathCubeGeometry 因为须要本人构建,会稍晚难点; ExtrudeGeometry 是 threejs 自身就存在的对象,BSP 也能够找到开源的包能够应用。
如果你有好的思路,也欢送和我交换。关注公号“ITMan 彪叔”能够增加作者微信进行交换,及时收到更多有价值的文章。