import * as THREE from "../../libs/three.js/build/three.module.js"; import math from './math'; import {Line2} from "../../libs/three.js/lines/Line2.js"; import {LineGeometry} from "../../libs/three.js/lines/LineGeometry.js"; import {LineMaterial} from "../../libs/three.js/lines/LineMaterial.js"; //画线等函数--by 许钟文 import {Features} from "../Features.js"; var defaultColor = new THREE.Color(1,1,1);//config.applicationName == "zhiHouse" ? Colors.zhiBlue : Colors.lightGreen; var LineDraw = { createLine: function (posArr, o={}) { //多段普通线 (第二个点和第三个点之间是没有线段的, 所以不用在意线段顺序) var mat = o.mat || new THREE[o.deshed ? "LineDashedMaterial" : "LineBasicMaterial"]({ lineWidth: o.lineWidth || 1, //windows无效。 似乎mac/ios上粗细有效 ? color: o.color || defaultColor, transparent: o.dontAlwaysSeen ? false : true, depthTest: o.dontAlwaysSeen ? true : false, dashSize : o.dashSize || 0.1, gapSize: o.gapSize || 0.1 }) var line = new THREE.LineSegments(new THREE.BufferGeometry, mat); line.renderOrder = o.renderOrder || 4 this.moveLine(line, posArr) return line; }, moveLine: function (line, posArr) { if(posArr.length == 0)return let position = [] posArr.forEach(e=>position.push(e.x,e.y,e.z)) line.geometry.setAttribute('position', new THREE.Float32BufferAttribute(new Float32Array(position), 3)); line.geometry.attributes.position.needsUpdate = true; line.geometry.computeBoundingSphere(); if(line.material instanceof THREE.LineDashedMaterial){ line.computeLineDistances() } } , /* 为line创建用于检测鼠标的透明mesh,实际是个1-2段圆台。 由于近大远小的原因,假设没有透视畸变、创建的是等粗的圆柱的话, 所看到的线上每个位置的粗细应该和距离成反比。所以将圆柱改为根据距离线性渐变其截面半径的圆台,在最近点(相机到线的垂足)最细。如果最近点在线段上,则分成两段圆台,否则一段。 */ createBoldLine:function(points, o){ o = o || {} var cylinder = o && o.cylinder; var CD = points[1].clone().sub(points[0]); var rotate = function(){//根据端点旋转好模型 cylinder.lastVector = CD;//记录本次的端点向量 var AB = new THREE.Vector3(0,-1,0) var axisVec = AB.clone().cross(CD).normalize(); //得到垂直于它们的向量,也就是旋转轴 var rotationAngle = AB.angleTo(CD); cylinder.quaternion.setFromAxisAngle( axisVec, rotationAngle ) } if(o && o.type == "init"){ cylinder = new THREE.Mesh() cylinder.material = o.mat if(CD.length() == 0)return cylinder; rotate() } if(CD.length() == 0)return cylinder; if(o.type != "update"){ var CDcenter = points[0].clone().add(points[1]).multiplyScalar(.5); cylinder.position.copy(CDcenter); if(!cylinder.lastVector || o.type == "moveAndRotate")rotate() else if(cylinder.lastVector && CD.angleTo(cylinder.lastVector)>0) rotate()//线方向改了or线反向了 重新旋转一下模型 if(config.isEdit && !objects.mainDesign.editing )return cylinder;//节省初始加载时间? } //为了保证线段任何地方的可检测点击范围看起来一样大,更新圆台的结构(但是在镜头边缘会比中心看起来大) var height = points[0].distanceTo(points[1]); var standPos = o && o.standPos || objects.player.position; var k = config.isMobile ? 20 : 40; var dis1 = points[0].distanceTo(standPos); var dis2 = points[1].distanceTo(standPos); var foot = math.getFootPoint(standPos, points[0], points[1]);//垂足 if(o.constantBold || objects.player.mode != "panorama"){ var width = 0.1//0.08; var pts = [new THREE.Vector2(width ,height/2),new THREE.Vector2(width ,-height/2)] }else if(foot.clone().sub(points[0]).dot( foot.clone().sub(points[1]) ) > 0){//foot不在线段上 var pts = [new THREE.Vector2(dis1 / k,height/2),new THREE.Vector2(dis2 / k,-height/2)] }else{//在线段上的话,要在垂足这加一个节点,因它距离站位最近,而两端较远 var dis3 = foot.distanceTo(standPos); var len = foot.distanceTo(points[0]) var pts = [new THREE.Vector2(dis1 / k,height/2), new THREE.Vector2(dis3 / k,height/2-len), new THREE.Vector2(dis2 / k,-height/2)] } cylinder.geometry && cylinder.geometry.dispose();//若不删除会占用内存 cylinder.geometry = new THREE.LatheBufferGeometry( pts, 4/* Math.min(dis1,dis2)<10?4:3 */ ) cylinder.renderOrder = 2; return cylinder; }, updateBoldLine:function(cylinder, points, type, standPos, constantBold){ this.createBoldLine(points,{type:type, cylinder : cylinder, standPos:standPos, constantBold}) //type:move:平移 会改长短 , type:update根据距离和角度更新 不改长短 }, createFatLineMat : function(o){ var supportExtDepth = !!Features.EXT_DEPTH.isSupported() var mat = new LineMaterial( { color: o.color || 0xffffff, lineWidth: o.lineWidth || 5, // in pixels //vertexColors: THREE.VertexColors,//THREE.VertexColors, resolution: o.resolution || new THREE.Vector2(100,100),// to be set by renderer, eventually //viewportOffset: o.viewportOffset, transparent:true, //o.dontAlwaysSeen ? false : true, depthTest: false,// o.alwaysShow ? false : true,//o.dontAlwaysSeen ? true : false depthWrite:false, dashSize : o.dashSize || 0.1, gapSize: o.gapSize || 0.1, useDepth: !!o.useDepth, dashed: o.dashWithDepth ? supportExtDepth && !!o.dashed : !!o.dashed, dashWithDepth:!!o.dashWithDepth,//只在被遮住的部分显示虚线 supportExtDepth, /* transparent:o.dontAlwaysSeen ? false : true, depthTest:o.dontAlwaysSeen ? true : false */ /* polygonOffset : true,//是否开启多边形偏移 for not cover the lineMesh polygonOffsetFactor : -o.width*2.5 || -5 ,//多边形偏移因子 polygonOffsetUnits : -4.0,//多边形偏移单位 */ } ); //if(o.dashed)(mat.defines.USE_DASH = "") var opa = 0 Object.defineProperty( mat, "opacity", { get: function () { return opa; }, set: function(o){ mat.uniforms.opacity.value = opa = o; } }) mat.opacity = o.opacity != void 0 ? o.opacity : 1; return mat; }, /* 创建可以改变粗细的线。 */ createFatLine : function(posArr, o){ var geometry = new LineGeometry(); geometry.setPositions( posArr ); geometry.setColors( o.color || [1,1,1]); var matLine = o.material || this.createFatLineMat(o); var line = new Line2( geometry, matLine ); //line.computeLineDistances(); if(line.material.defines.USE_DASH != void 0){ //line.geometry.verticesNeedUpdate = true; //line.geometry.computeBoundingSphere(); line.computeLineDistances(); } line.scale.set( 1, 1, 1 ); line.renderOrder = 2; return line; }, moveFatLine: function(line, posArr){ var geometry = line.geometry; geometry.setPositions( [ ...posArr[0].toArray(), ...posArr[1].toArray(), ]); if(line.material.defines.USE_DASH != void 0){ //line.geometry.verticesNeedUpdate = true; //line.geometry.computeBoundingSphere(); line.computeLineDistances(); } }, updateLine: function(line, posArr){ if(line instanceof Line2){ LineDraw.moveFatLine(line,posArr) }else{ LineDraw.moveLine(line,posArr) } } } var MeshDraw = { getShape:function(points, holes){ var shape = new THREE.Shape(); shape.moveTo( points[0].x, points[0].y ); for(var i=1,len=points.length; i{ var holePath = new THREE.Path() holePath.moveTo( points[0].x, points[0].y ) for(var i=1,len=points.length; i{ if(currentIndex == 0)return 0 return total + currentValue.distanceTo(arr[currentIndex-1]); },0) extrudePath = new THREE.CatmullRomCurve3(extrudePath, closed , 'catmullrom' /* 'centripetal' */ , tension) } var extrudeSettings = { steps: height != void 0 ? 1 : Math.round(length/0.3), depth: height, extrudePath, }; var geometry = new THREE.ExtrudeBufferGeometry( shape, extrudeSettings ); return geometry; }, getUnPosPlaneGeo : function(){//获取还没有赋值位置的plane geometry var e = new Uint16Array([0, 1, 2, 0, 2, 3]) // , t = new Float32Array([-.5, -.5, 0, .5, -.5, 0, .5, .5, 0, -.5, .5, 0]) , i = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]) , g = new THREE.BufferGeometry; g.setIndex(new THREE.BufferAttribute(e, 1)), //g.addAttribute("position", new n.BufferAttribute(t, 3)), g.setAttribute("uv", new THREE.BufferAttribute(i, 2)) return function(){ return g } }(), getPlaneGeo : function(A,B,C,D){ var geo = this.getUnPosPlaneGeo().clone(); var pos = new Float32Array([ A.x, A.y, A.z, B.x, B.y, B.z, C.x, C.y, C.z, D.x, D.y, D.z ]) geo.addAttribute("position", new THREE.BufferAttribute(pos, 3)) geo.computeVertexNormals() geo.computeBoundingSphere() //for raycaster return geo; }, drawPlane : function(A,B,C,D, material){ var wall = new THREE.Mesh(this.getPlaneGeo(A,B,C,D), material); return wall; }, movePlane: function(mesh, A,B,C,D){ var pos = new Float32Array([ A.x, A.y, A.z, B.x, B.y, B.z, C.x, C.y, C.z, D.x, D.y, D.z ]) mesh.geometry.addAttribute("position", new THREE.BufferAttribute(pos, 3)) mesh.geometry.computeBoundingSphere()//for checkIntersect } } export {LineDraw, MeshDraw} ;