楔子

在很多利用中,特地是一些园区类的利用。 都须要对园区的高空 环境进行展现,路面就是高空的一部分。
通常的做法是,都是建模的时候把相干的元素都建好,而后导入到展现零碎中进行展现。
不过有些状况下,可能建模并不太不便,所以三维编辑器能够间接进行简略的路面编辑显得挺有必要。

路面对象扩大

简略的路面心愿可能通过一个门路来生成。 咱们晓得在threejs中有通过门路生成管路的对象,参考文章WebGL管网展现(及TubeGeometry优化),管路的横截面是一个圆形。 路线的横截面冀望是一个矩形,因而,咱们能够仿照管路的思路制作一个相似的对象PathRectGeometry,只是计算顶点的时候,横截面不再应用圆形,而是应用一个矩形,代码如下:

 let points = [new Vec3(-width/2,-height/2,0),new Vec3(-width/2,height/2,0),        new Vec3(width/2,height/2,0),new Vec3(width/2,-height/2,0)]             if(!scope.clockwise) {                points = [new Vec3(-width/2,-height/2,0),new Vec3(width/2,-height/2,0),                    new Vec3(width/2,height/2,0),new Vec3(-width/2,height/2,0)];            }      for( let j = 0;j <= points.length;j ++) {        let jj = j == points.length ? 0 : j;         let point = points[jj];        let radius = Math.hypot(point.x,point.y);        const sin = point.y / radius;        const cos = point.x / radius;          normal.x = ( cos * N.x + sin * B.x );                normal.y = ( cos * N.y + sin * B.y );                normal.z = ( cos * N.z + sin * B.z );                normal.normalize();                normals.push( 0,1,0 );            // vertex                vertex.x = P.x + radius * normal.x;                vertex.y = P.y + radius * normal.y;                vertex.z = P.z + radius * normal.z;                vertices.push( vertex.x, vertex.y, vertex.z );      }

通过PathRectGeometry创建对象的成果如下图所示:

路面编辑

通过在立体下面打点来构建直线和贝塞尔曲线,而后通过构建得线条了生成门路,通过门路就能够生成路面成果,

 graph.getView().addEventListener("click", (event) => {        let now = new Date().getTime();        if (t != 0 && now - t < 500) {          return;        }        t = now;        if (path) {          let pos = graph.getPositionOnPlaneByEvent(event, plane);          constraintsHorizontalOrVertical(path, pos);          path.lineTo(pos.x, pos.y, pos.z);          tempPath = path.clone(tempPath);          tempRoad.geometry.path = tempPath;        }      })

大略得过程如下所示:


在生成得门路上,会有很多控制点,拖动控制点能够二次批改门路:

生成连接处

两条路得连接处会有斑马线之类得,点击生成斑马线,能够通过算法主动计算斑马线,

// 找到road1 到road2的joint    function createJointShape(road1, road2) {      let path = road1.geometry.path;      let path2 = road2.geometry.path;      let lastPoint = path.points.at(-1);      let lastCurve = path.curves.at(-1);      let curves = path2.curves;      console.log(curves);      let minCurve, minDist = Infinity,        minPoint      for (let i = 0; i < curves.length; i++) {        let curve = curves[i];        if (curve.type == "LineCurve3") {          let {            dist,            point          } = findClosestPoint(lastPoint, curve.v1, curve.v2);          if (dist < minDist) {            minDist = dist;            minPoint = point;            minCurve = curve;          }        }      }      console.log(minCurve, minDist, minPoint);      let v1 = lastCurve.v1,        v2 = lastCurve.v2;      let tagent = new dt.Vec3().subVectors(v2, v1);      let up = new dt.Vec3(0, 1, 0);      let cross = new dt.Vec3().cross(up, tagent);      cross.normalize();      let halfRoadWidth = 50;      cross.multiplyScalar(halfRoadWidth);      let cross2 = cross.clone().multiplyScalar(3.0);      let p1 = lastPoint.clone().add(cross),        p2 = lastPoint.clone().sub(cross);      let sub = new dt.Vec3().subVectors(minPoint, lastPoint);      console.log(sub.length(), minDist, halfRoadWidth)      sub.setLength(minDist - halfRoadWidth);      let joinPoint = new dt.Vec3().addVectors(lastPoint, sub);      let halfSub = sub.clone().multiplyScalar(0.75);      let p3Center = p1.clone().add(halfSub);      let p4Center = p2.clone().add(halfSub);      let p3 = joinPoint.clone().add(cross2);      let p4 = joinPoint.clone().sub(cross2)      let newPath = new dt.ShapePath();      newPath.moveTo(p2.x, p2.z);      newPath.quadraticCurveTo(p4Center.x, p4Center.z, p4.x, p4.z);      newPath.lineTo(p3.x, p3.z);      newPath.quadraticCurveTo(p3Center.x, p3Center.z, p1.x, p1.z);      // newPath.closePath();      // let geo = new dt.PathTubeGeometry(newPath, 64, 2);      // let tube = new dt.Mesh(geo);      let shapePath = newPath;      const simpleShapes = shapePath.toShapes(true);      var texture = graph.loadTexture("./road/001.jpg", {        wrapT: dt.RepeatWrapping,        wrapS: dt.RepeatWrapping,      });      texture.repeat.set(1 / 100, 1 / 100);      texture.anisotropy = 16;      let m1 = new dt.BasicMaterial({        //  flatShading:true,        map: texture,        // envMap:envMap,        // reflectivity:0.4,        color: 0xffffff,        toneMapped: false,      });      var geometry = new dt.ExtrudeGeometry(simpleShapes, {        depth: 1,        bevelEnabled: false,        vertical: true,      });      var mesh = new dt.Mesh(geometry, m1);      window.graph.getDataManager().add(mesh);      road1.add(mesh);    }

如下图所示:

结语

本文所示只是一个demo级别得尝试,如果要做一个强度得路面编辑器零碎,可能要思考得还有很多,比方多车道成果,更重得连接形态等等。这在后续得产品中会继续强化相干性能。

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