import * as THREE from "../../../libs/three.js/build/three.module.js"; import DepthBasicMaterial from "../materials/DepthBasicMaterial.js"; import math from "../utils/math.js"; const geo = new THREE.PlaneBufferGeometry(1,1) export default class Sprite extends THREE.Mesh{ constructor(options={}){ super(geo, options.mat || new DepthBasicMaterial(options))/* ({map:options.map, useDepth:options.useDepth})) */ this.root = options.root || this; this.renderOrder = options.renderOrder != void 0 ? options.renderOrder : 4; this.pickOrder = options.pickOrder || 0 this.sizeInfo = options.sizeInfo this.dontFixOrient = options.dontFixOrient this.options = options this.position.y = options.disToLine || 0 //离线距离 this.matrixAutoUpdate = false; this.matrixMap = new Map() if(this.root != this){ this.matrixMapRoot = new Map() this.root.matrixAutoUpdate = false; } this.visiMap = new Map() this.name = options.name || 'sprite' this.useViewport = null this.viewports = options.viewports//指定更新的viewports this.visible_ = true let clear = (e)=>{ this.matrixMap.clear()//清空后在所有viewport上都必须更新才能渲染 //this.needsUpdate = true } viewer.mapViewer && viewer.mapViewer.addEventListener("camera_changed", clear) viewer.addEventListener("camera_changed", clear) /* if(viewer.viewports.length == 1){//直接更新。如果有多个不在这更新,在"render.begin" this.update(e) } */ let applyMatrix = (e)=>{ this.applyMatrix(e) } viewer.addEventListener("raycaster", applyMatrix) //before render viewer.addEventListener("render.begin", applyMatrix) //before render viewer.addEventListener("render.begin2", applyMatrix) viewer.addEventListener("cameraSetLayers", applyMatrix) this.addEventListener('dispose', ()=>{ viewer.mapViewer && viewer.mapViewer.removeEventListener("camera_changed", clear) viewer.removeEventListener("camera_changed", clear) viewer.removeEventListener("raycaster", applyMatrix) //before render viewer.removeEventListener("render.begin", applyMatrix) viewer.removeEventListener("render.begin2", applyMatrix) }) } set visible(v){ let oldV = this.visible_ this.visible_ = v if(v && !oldV){ this.matrixMap && this.matrixMap.clear() //this.update() //update内有unableCompute会无限回调 } } get visible(){ return this.visible_ } realVisible(viewport, interactables/* , raycaster */){ if(interactables){ if(!interactables.some((object)=>{//interactables中是否能找到this let finded object.traverse((object)=>{ if(object == this){ finded = true return {stopContinue:true} } }) return finded }))return } /* if(interactables && viewport.name == 'mapViewport'){ console.log(this) } */ if(!(/* raycaster || */viewport.camera).layers.test(this.layers)){//如地图上一般不可见测量线 return false } if(!this.visible && this.unvisibleReasons && this.unvisibleReasons.some(e=>e.reason != 'unableCompute')){ return false } let v = true let parent = this.parent let lastParent = this while(parent){ if(parent.visible === false){ v = false break; } lastParent = parent parent = parent.parent } if(v && !(lastParent instanceof THREE.Scene)){//已被删除 v = false } /* if(!this.latestRealVisi && v){//变为可见后先update this.latestRealVisi = true setTimeout(()=>{ this.update() },1)//延迟 防止无限调用 return false } this.latestRealVisi = v */ return v; } waitUpdate(){ this.matrixMap.clear()//清空后在所有viewport上都必须更新才能渲染 //viewer.dispatchEvent('content_changed') } update(e={}){ if(!e.viewport){ let viewports = this.viewports || viewer.viewports if(!viewports)return viewports.forEach(view=>{ this.update({viewport:view}) }) return; } if(!this.root || ! this.realVisible(e.viewport, e.interactables) /* this.visible */ )return if(this.viewports && !this.viewports.includes(e.viewport) )return if(e.viewport.name == 'magnifier')return let camera = e.viewport.camera //rotation if(!this.dontFixOrient){ //orthoCamera一般要加dontFixOrient let orient2dAngle if(this.root.lineDir){ this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的 this.root.updateMatrixWorld(true) let center = this.root.getWorldPosition(new THREE.Vector3()) //由于两个端点容易在屏幕外,所以使用center和center加dir let setVisi = (state)=>{ this.visiMap.set(e.viewport, state) Potree.Utils.updateVisible(this, 'unableCompute', !!state) } let r1 = Potree.Utils.getPos2d(center, e.viewport, viewer.renderArea, viewer.renderer); if(!r1.trueSide)return setVisi(false);// 但这句会使realVisible为false从而无法更新//console.error('!r1.trueSide') //中心点如果在背面直接不渲染了 let r2, point2 let p2State = '', len=1, p2StateHistory = [] while(p2State != 'got' && p2StateHistory.length<10){ point2 = center.clone().add(this.root.lineDir.clone().multiplyScalar(len)); r2 = Potree.Utils.getPos2d(point2, e.viewport , viewer.renderArea, viewer.renderer ); if(!r2.trueSide){ //很少遇到点2在背面的 if(!p2StateHistory.includes('tooLong-reverse')){ p2State = 'tooLong-reverse' //先尝试反向 len = -len }else{ p2State = 'tooLong' len = len / 2 } }else{ let dis = r2.pos.distanceTo(r1.pos) if(math.closeTo(dis,0)){ //console.log('dis == 0') setVisi(false) return break } if(dis<10 && !p2StateHistory.includes('tooLong')){//和r1的屏幕距离太近,要加长,否则精度过低 p2State = 'tooShort' len = 100/dis * len }else{ p2State = 'got'; break; } } p2StateHistory.push(p2State) } //console.log(p2StateHistory,len) if(!r2.trueSide){ return setVisi(false)//, console.log(' !r2.trueSide', ) } let p1 = r1.pos, p2 = r2.pos if(p2StateHistory.filter(e=>e == 'tooLong-reverse').length%2 == 1){//反,for marker p2 = r1.pos, p1 = r2.pos } let vec = new THREE.Vector2().subVectors(p1,p2); orient2dAngle = -vec.angle() //根据测量线在屏幕上的角度在旋转label,使之和屏幕上的二维线平行。 let y = Math.abs(this.position.y) let facePlane = this.root.measure && this.root.measure.facePlane let eyeDir = new THREE.Vector3().subVectors(center,camera.position) let clockWise = facePlane && facePlane.normal.dot(eyeDir/* e.viewport.view.direction */) < 0 if(p1.x < p2.x){ orient2dAngle += Math.PI //避免字是倒着的情况。(使字一直在线的下方) clockWise != void 0 && (this.position.y = clockWise ? y : -y) }else{ clockWise != void 0 && (this.position.y = clockWise ? -y : y) //使area类型的edgeLabel都在外侧 } //this.parent.text && console.log(this.parent.text, clockWise, this.position.y, e.viewport.name /* THREE.Math.radToDeg(angle), p1.x < p2.x */ ) setVisi(true) } let parentQua = this.root.parent.getWorldQuaternion(new THREE.Quaternion) this.root.quaternion.multiplyQuaternions(parentQua.invert(),camera.quaternion) //乘上parentQua.invert()是为了中和掉父结点的qua,使只剩下camera.quaternion if(orient2dAngle){ let qua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), orient2dAngle) this.root.quaternion.multiply(qua) } } //scale var info = this.sizeInfo if(info){ this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的 this.root.updateMatrixWorld(true) var scale if(info.nearBound == void 0 && info.farBound != void 0 || info.nearBound != void 0 && info.farBound == void 0){//仅限制最大或最小的话,不判断像素大小,直接限制mesh的scale //这个判断也可以写到getScaleForConstantSize里,可以更严谨控制像素宽度,这里只简单计算大小 var dis = camera.position.distanceTo(this.root.getWorldPosition(new THREE.Vector3())) if(info.farBound == void 0 && dis < info.nearBound){ scale = info.scale * dis / info.nearBound }else if(info.nearBound == void 0 && dis > info.farBound){ scale = info.scale * dis / info.farBound }else{ scale = info.scale } }else{ scale = math.getScaleForConstantSize($.extend(info,{//规定下最小最大像素 camera , position:this.root.getWorldPosition(new THREE.Vector3()) , resolution: e.viewport.resolution//2 })) } if(!isNaN(scale)){ this.root.scale.set(scale, scale, scale); } } this.updateMatrix(); //this.root.updateMatrixWorld(true) //console.log(this.root.text, this.root.matrix.elements) this.matrixMap.set(e.viewport, this.matrix.clone()) if(this.root != this){ this.root.updateMatrix(); //因this.position可能在两个viewport不同 this.matrixMapRoot.set(e.viewport, this.root.matrix.clone()) } this.needsUpdate = false this.useViewport = e.viewport } applyMatrix(e){ if(!e)e = {viewport:viewer.mainViewport}//随便写一个viewport let visi = this.visiMap.get(e.viewport) //还原可见性 Potree.Utils.updateVisible(this, 'unableCompute', visi == false ? false : true ); /* if(e.viewport.name == 'mapViewport' && visi && this.visiMap.get(viewer.mainViewport) == false){ console.log(1) } */ if(e.viewport.name == 'magnifier')return if(this.viewports && !this.viewports.includes(e.viewport) )return if( !this.root || !this.realVisible(e.viewport, e.interactables) )return var matrix = this.matrixMap.get(e.viewport); if(!matrix){ this.update(e) matrix = this.matrixMap.get(e.viewport); if(!matrix)return } if(e.viewport == this.useViewport){ return } this.useViewport = e.viewport this.matrix.copy(matrix) if(this.root != this){ var matrix2 = this.matrixMapRoot.get(e.viewport); this.root.matrix.copy(matrix2) } e.raycaster && this.root.updateMatrixWorld(true)//渲染前会自动updateMatrixWorld,但raycaster不会 //console.log(this.root.name + e.viewport.name + " : "+this.root.matrixWorld.elements) } setUniforms(name,value){ this.material.setUniforms(name,value) } dispose(){ this.removeAllListeners() this.parent && this.parent.remove(this) this.dispatchEvent('dispose') } } /* let orient2d if(this.lineDir){ this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的 this.root.updateMatrixWorld(true) let center = this.root.getWorldPosition(new THREE.Vector3()) //由于两个端点容易在屏幕外,所以使用center和center加dir let lineDir = this.lineDir.clone(); let r1 = Potree.Utils.getPos2d(center, camera, viewer.renderArea, e.viewport); if(!r1.trueSide)return Potree.Utils.updateVisible(this, 'unableCompute', false);// 但这句会使realVisible为false从而无法更新//console.error('!r1.trueSide') //中心点如果在背面直接不渲染了 let r2, point2 let p2State = '', len=1, p2StateHistory = [] while(p2State != 'got' && p2StateHistory.length<10){ point2 = center.clone().add(lineDir.multiplyScalar(len)); r2 = Potree.Utils.getPos2d(point2, camera, viewer.renderArea, e.viewport); if(!r2.trueSide){ //很少遇到点2在背面的 if(!p2StateHistory.includes('tooLong-reverse')){ p2State = 'tooLong-reverse' //先尝试反向 len = -len }else{ p2State = 'tooLong' len = len / 2 } }else{ let dis = r2.pos.distanceTo(r1.pos) if(dis == 0){ //console.log('dis == 0') Potree.Utils.updateVisible(this, 'unableCompute', false) return break } if(dis<10 && !p2StateHistory.includes('tooLong')){//和r1的屏幕距离太近,要加长,否则精度过低 p2State = 'tooShort' len = 100/dis * len }else{ p2State = 'got'; break; } } p2StateHistory.push(p2State) } //console.log(p2StateHistory,len) if(!r2.trueSide){ return Potree.Utils.updateVisible(this, 'unableCompute', false)//, console.log(' !r2.trueSide', ) } Potree.Utils.updateVisible(this, 'unableCompute', true) let p1 = r1.pos, p2 = r2.pos let vec = new THREE.Vector2().subVectors(p1,p2); let angle = -vec.angle() //根据测量线在屏幕上的角度在旋转label,使之和屏幕上的二维线平行。 if(p1.x < p2.x) angle += Math.PI //避免字是倒着的情况 orient2d = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), angle) //console.log(this.parent.text, THREE.Math.radToDeg(angle), p1.x < p2.x ) } let parentQua = this.root.parent.getWorldQuaternion(new THREE.Quaternion) this.root.quaternion.multiplyQuaternions(parentQua.invert(),camera.quaternion) //乘上parentQua.invert()是为了中和掉父结点的qua,使只剩下camera.quaternion if(this.lineDir){ this.root.quaternion.multiply(orient2d) } */