楔子
在很多利用中,特地是一些园区类的利用。 都须要对园区的高空 环境进行展现,路面就是高空的一部分。
通常的做法是,都是建模的时候把相干的元素都建好,而后导入到展现零碎中进行展现。
不过有些状况下,可能建模并不太不便,所以三维编辑器能够间接进行简略的路面编辑显得挺有必要。
路面对象扩大
简略的路面心愿可能通过一个门路来生成。 咱们晓得在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彪叔” 能够增加作者微信进行交换,及时收到更多有价值的文章。