uniapp开发app框架在提升开发效率中的独特优势与应用探索
793
2022-09-30
基于webgl(threejs)的路面编辑
楔子
在很多应用中,特别是一些园区类的应用。 都需要对园区的地面 环境进行展示,路面就是地面的一部分。 通常的做法是,都是建模的时候把相关的元素都建好,然后导入到展示系统中进行展示。 不过有些情况下,可能建模并不太方便,所以三维编辑器可以直接进行简单的路面编辑显得挺有必要。
路面对象扩展
简单的路面希望能够通过一个路径来生成。 我们知道在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级别得尝试,如果要做一个强度得路面编辑器系统,可能要考虑得还有很多,比如多车道效果,更重得衔接形状等等。这在后续得产品中会持续强化相关功能。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~