123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 |
- import * as THREE from "../../../../libs/three.js/build/three.module.js";
- import {transitions, easing, lerp} from '../../utils/transitions.js'
- import TileUtils from './tile/TileUtils.js'
-
- import math from '../../utils/math.js'
- import {TextSprite} from '../../objects/TextSprite.js'
- import Sprite from '../../objects/Sprite.js'
- import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
- let { PanoRendererEvents, PanoramaEvents, PanoSizeClass} = Potree.defines
- var texLoader = new THREE.TextureLoader()
-
- const markerOpacitys ={
- default : 0.4,
- hovered : 1,
- }
- const labelProp = {
- sizeInfo: {minSize : 200 , maxSize : 250, nearBound : 0.8, farBound : 10},
- backgroundColor:{r: 255, g: 255, b: 255, a: 0.4 },
- textColor:{r: 0, g: 0, b: 0, a: 1 },
- borderRadius: 15,
- renderOrder:10,
- useDepth:true,
- clipDistance: 30, maxClipFactor:0.3, occlusionDistance:3,
- }
- const labelProp2 = {
- //sizeInfo: {minSize : 200 , maxSize : 250, nearBound : 0.8, farBound : 10},
- backgroundColor:{r: 255, g: 255, b: 255, a: 0 },
- textColor:{r:255 , g: 255, b: 255, a: 1 },
- textBorderColor:{r:30 , g:30, b: 30, a: 1 },
- textBorderThick:3,
- dontFixOrient:true,
- renderOrder:10,
- fontsize:30,
- }
-
- let markerTex
- //显示全景图时marker没有被遮挡,如果需要,要换成depthBasicMaterial 或者直接把skybox的深度修改(拿到深度贴图后更如此)
- let planeGeo = new THREE.PlaneBufferGeometry(0.4,0.4);
- let sg = new THREE.SphereGeometry(0.1, 8, 8);
- let smHovered = new THREE.MeshBasicMaterial({/* side: THREE.BackSide, */color: 0xff0000});
- let sm = new THREE.MeshBasicMaterial({/* side: THREE.BackSide */});
- var rot90 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), Math.PI/2 ); //使用的是刚好适合全景图的,给cube贴图需要转90°
- //var rot90 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), -Math.PI/2 ); //4dkk->navvis
- //var rot901 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,1,0), -Math.PI/2 ); //整张球幕图要旋转下
- //rot90 = new THREE.Quaternion().multiplyQuaternions( rot901, rot90)
- const rotQua2 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), Math.PI )
- var old = null;
- /*
- 转成四维看看的axis:
- var a = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.Math.degToRad(-90)) 因为四维的要绕y转90
- 这里的quaternion.multiply(a);
-
- 先乘再换顺序 w : q.w, x:q.x , y:-q.z, z:q.y
- */
- //暂时直接用4dkkconsole输出的数据
- class Panorama extends THREE.EventDispatcher{
- constructor(o, images360){
- super()
- this.id = o.id; //唯一标识
- this.images360 = images360
- this.visible = true //for updateVisible
- this.enabled = true//是否可以走
- this.addEventListener('isVisible',(e)=>{//是否显示该点的mesh(不显示也能走)
- //console.log('pano isVisible', this.id, e.visible)
- Potree.Utils.updateVisible(this.marker, 'panoVisi', e.visible)
- Potree.settings.showPanoMesh && (this.mesh.visible = e.visible)
- if(e.reason == 'screenshot' || e.visible){
- this.label && (this.label.visible = e.visible)//截图时隐藏下
- }
- this.label2 && Potree.Utils.updateVisible(this.label2, 'panoVisi', e.visible)
- })
-
-
- /*
- 漫游点可见性:新
- level reason 类型
- 2(最高)buildingChange(不在此楼层) unvisible
- 1 ifShowMarker(marker显示开关) unvisible
- 0 pointcloudVisi(隐藏了数据集) unvisible
- */
-
-
- if(Potree.settings.editType == 'pano'){//漫游点拼合编辑
- this.uuid = this.originID = o.uuid //对应4dkk中的id,可能不连续
- this.index = o.index //下标, 用于visibles
-
-
- this.pointcloud = viewer.scene.pointclouds.find(e=>e.panoUuid == o.uuid)
- this.pointcloud.panos.push(this)
- this.sid = this.pointcloud.dataset_id + '|' + this.uuid //不会更改的标记 用于entity.panos里的标记
-
- delete o.pointcloud
- this.panoData = o
-
- /* //数据中原本的位置朝向
- this.dataPosition = new THREE.Vector3().copy(o.pose.translation)
- this.dataQuaternion = new THREE.Quaternion().copy(o.pose.rotation)
- this.dataRotation = new THREE.Euler().setFromQuaternion(this.dataQuaternion) */
-
-
- //因为位置朝向随着点云位置改变,所以直接改变点云,这里清零
- this.originPosition = new THREE.Vector3()
- this.quaternion = new THREE.Quaternion().copy(rotQua2);
-
- this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion
- this.quaternion2 = this.quaternion.clone()
- this.quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion, rot90);//全景图和Cube的水平采样起始坐标相差90度,cubeTex转90度
-
-
-
- const height = 1.4; //相机高度
- this.originFloorPosition = this.originPosition.clone()
- this.originFloorPosition.z -= height
-
-
-
- }else{
- this.originPosition = new THREE.Vector3().fromArray(o.dataset_location) //完全对应vision.txt的translation
- this.originFloorPosition = new THREE.Vector3().fromArray(o.dataset_floor_location)
-
- this.originID = parseInt(o.file_id)//"file_id":"00022" 对应是4dkk的id --来自vision.txt
-
- this.pointcloud = o.pointcloud //viewer.scene.pointclouds.find(e=>e.dataset_id == o.dataset_id) || viewer.scene.pointclouds[0]
- this.pointcloud.panos.push(this)
-
- //this.sid = this.pointcloud.sceneCode + '|' + this.originID //不会更改的标记
- this.sid = this.pointcloud.dataset_id + '|' + this.originID //不会更改的标记
- //全景图和Cube的水平采样起始坐标相差90度
-
-
-
- /* if(from4dkk){
- var qua = o.dataset_orientation
-
- var quaternion = new THREE.Quaternion().fromArray(qua)
- quaternion = new THREE.Quaternion().multiplyQuaternions(quaternion, rot901);//整张球幕图要旋转下 因为在4dkk里转过,还原。如果是tiles的不用
- this.quaternion = new THREE.Quaternion(quaternion.x, -quaternion.z, quaternion.y, quaternion.w) //转化坐标
-
- }else{ */
-
-
- var qua = o.dataset_orientation //完全对应vision.txt的rotation
- qua = [qua[1], qua[2], qua[3], qua[0]]
- this.quaternion = new THREE.Quaternion().fromArray(qua)
- this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion
- this.quaternion2 = this.quaternion.clone()
- this.quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion, rot90);//全景图和Cube的水平采样起始坐标相差90度,cubeTex转90度
-
- this.rotation4dkk = new THREE.Euler().setFromQuaternion(this.quaternion4dkk)
-
-
- }
-
-
-
- this.neighbours = [];
-
- this.rotation = new THREE.Euler().setFromQuaternion(this.quaternion)
- this.build()
- this.transformByPointcloud() //初始化位移
-
- {//tile
- this.minimumTiledPanoLoaded = !1;
- this.highestPartialTileRenderOpCompleted = 0;
- this.highestFullTileRenderOpCompleted = 0;
- this.shouldRedrawOnBaseLoaded = !1;
- this.resolutionPromise = {}
- this.tiledPanoRenderTarget = null;
- this.zoomed = !1;
-
-
-
-
- images360.panoRenderer.addEventListener(PanoRendererEvents.TileRenderSuccess, this.onTileRendered.bind(this));
- images360.panoRenderer.addEventListener(PanoRendererEvents.PanoRenderComplete, this.onPanoRendered.bind(this));
- images360.panoRenderer.addEventListener(PanoRendererEvents.TileRenderFailure, this.onTileRenderFail.bind(this));
- images360.panoRenderer.addEventListener(PanoRendererEvents.UploadAttemptedForAllTiles, this.onUploadAttemptedForAllTiles.bind(this));
-
- }
-
-
-
- this.addEventListener('hoverOn', (e)=>{//from Map
- if(!e.byMainView){
- this.hoverOn(e)
- }
- })
-
- this.addEventListener('hoverOff', (e)=>{
- if(!e.byMainView){
- this.hoverOff(e)
- }
- })
-
-
- }
-
- get noNeighbour(){//是否绝对到不到的孤立点
-
- for(let i=0,j=this.images360.panos.length; i<j; i++){
- if(this.images360.neighbourMap[this.id][i] !== false ){
- return false
- }
- }
- return true
-
- //return this.neighbours.length == 0
- }
- setEnable(enable){//是否可以走
- Potree.Utils.updateVisible(this, 'isEnabled', enable) //令所有marker不可见
- this.enabled = enable
- viewer.dispatchEvent('content_changed')
- //如果当前在全景模式且在这个点,需要切换显示吗? 目前用不到
- }
-
- loadDepthImg(){
- if(!this.pointcloud.hasDepthTex || this.depthTex || this.depthTexLoading)return
- this.depthTexLoading = true
- let mapping = Potree.settings.isLocal2 ? '' : this.pointcloud.datasetData.mapping //非离线包的话加mapping
- let src
- if(Potree.settings.urls.templates.depthTex){
- src = Potree.Common.replaceAll(Potree.settings.urls.templates.depthTex, '{sceneCode}', this.pointcloud.sceneCode) + `/${this.originID}.png`
- }else{
- let prefix = Potree.settings.urls.getPrefix(1,this.pointcloud)//Potree.settings.urls.laserOSSRoot || this.pointcloud.prop?.raw?.laserOssRoot || Potree.settings.urls.prefix1
- src = `${prefix}/${mapping?(mapping+'/'):''}${Potree.settings.webSite}/${this.pointcloud.sceneCode}/data/${this.pointcloud.sceneCode}/depthmap/${this.originID}.png`
- }
- //console.log('开始下载depthImg', this.id)
- let texture = texLoader.load( src, ()=>{
- this.depthTex = texture
- this.dispatchEvent({type:'loadedDepthImg', loaded:true})
- this.images360.dispatchEvent({type:'loadedDepthImg', pano:this})
- this.depthTexLoading = false
- this.images360.updateDepthTex(this)
-
- },null,(e)=>{//error
- console.error('loadDepthImg失败, 数据集sceneCode'+ this.pointcloud.sceneCode, this.id )
- this.pointcloud.hasDepthTex = false
- this.dispatchEvent({type:'loadedDepthImg' })
- });
- texture.wrapS = THREE.RepeatWrapping;
- texture.flipY = false
- texture.magFilter = THREE.LinearFilter
- texture.minFilter = THREE.LinearFilter
- texture.generateMipmaps = false
-
-
- //平均一张0.75M。2048*1024。 和tile一样加载后永不删除,是否会造成崩溃?
- }
-
-
- /* loadTypeImg(type){
- if(!this['has_'+type] || this[type+'Tex'] || this[type+'Loading'])return
-
-
- let url = `${Potree.settings.urls.prefix1}/testdata/${Potree.settings.number}/data/${this.pointcloud.sceneCode}/imagemap/${this.originID}_${type}.png`
- //let url = `${Potree.settings.urls.prefix1}/testdata/${Potree.settings.number}/data/${this.pointcloud.sceneCode}/imagemap/${this.originID}_temp.png`
-
-
- let texture = texLoader.load( url, ()=>{
- this[type+'Tex'] = texture
- this.dispatchEvent({type:'loaded_'+type, loaded:true})
- this.images360.dispatchEvent({type:'loaded_'+type, pano:this})
- this[type+'Loading'] = false
-
- },null,(e)=>{//error
- console.error('load '+type+'Img失败, 数据集sceneCode'+ this.pointcloud.sceneCode, this.id )
- this['has_'+type] = false
- this['loadFailed_'+type] = false
- this.dispatchEvent({type:'loaded_'+type })
- });
- texture.wrapS = THREE.RepeatWrapping;
- texture.flipY = false
- texture.magFilter = THREE.LinearFilter
- texture.minFilter = THREE.LinearFilter
- texture.generateMipmaps = false
-
-
- } */
- loadTypeImg(type){
- if(!this['has_'+type] || this[type+'Tex'] || this[type+'Loading'])return
-
-
- let url = this.pointcloud.typesUrl + `${this.originID}_${type}.png`
- //let url = `${Potree.settings.urls.prefix1}/testdata/${this.pointcloud.sceneCode}/data/${this.pointcloud.sceneCode}/imagemap/${this.originID}_temp.png`
-
- let range = {min:Infinity, max:-Infinity, minPixel:null, maxPixel:null}
- let pixels
- let getRangeFun = (type == 'ir' || type == 'temp') && function(uint16Value, index, pixelCount){
- if(type == 'ir'){
- pixels || (pixels = new Uint16Array(pixelCount))
- pixels[index] = uint16Value
- }
-
-
- if(uint16Value != 0 && uint16Value < range.min){
- range.min = uint16Value
- range.minPixel_ = index
- }
- if(uint16Value != 0 && uint16Value > range.max){
- range.max = uint16Value
- range.maxPixel_ = index
- }
-
- }
-
- let texture = Potree.Common.load16bitPngTex(url,()=>{
- this[type+'Tex'] = texture
- if(getRangeFun){
- if(type == 'ir'){
- let p = [range.minPixel_, range.maxPixel_].map(index=>{
- let row = Math.floor(index / texture.image.width)
- let col = index % texture.image.width
- return {x:col,y:row}
- })
- range.minPixel = p[0]
- range.maxPixel = p[1]
-
-
- let pixelCount = texture.image.width * texture.image.height
- const stopMemberCount = 50;
-
-
- (['min','max']).forEach(name =>{
- let value = range[name]
- let groups = []
- let isNeigh = (A,B)=>{
- return (Math.abs(A.x - B.x)<=1 || Math.abs(A.x - B.x) == texture.image.width-1) && Math.abs(A.y - B.y)<=1
- }
- for(let i=0;i<pixelCount;i++){
- if(Math.abs(value - pixels[i]) == 0 ){
- let row = Math.floor(i / texture.image.width)
- let col = i % texture.image.width
- let data = {x:col, y:row, value: pixels[i]}
- Potree.Common.pushToGroupAuto([data], groups, isNeigh )
- if(groups.some(e=>e.length > stopMemberCount && e.some(e=>e==range[name]))){
- break
- }
- }
- }
- let groups2 = groups.filter(e=>e.length>1)
- if(groups2.length < 3) groups2 = groups
- groups2.forEach(group=>{//x的因边界不好写,就只判断y尽量接近中间且范围不大不小即可
- group.sort((a,b)=>{return a.y-b.y})
- let minY = group[0].y
- let maxY = group[group.length-1].y
- let centerY = (minY + maxY) / 2
- let rectRatio = (maxY - minY) * 1//除非竖的一列,否则一般y范围越大越好 Math.abs(2 - Potree.math.getBaseLog(maxY - minY, group.length)) //范围圆润度, 最好个数是y范围的平方
- group.score = group.length * 0.2 + rectRatio - Math.abs(texture.image.height/2 - centerY) * 0.5 //y尽量接近中间
-
- group.center = group[Math.floor(group.length/2)] //忽略是否横向的中间
- })
- groups2.sort((b,a)=>{return a.score - b.score})
- range[name+'Pixel'] = groups2[0]?.center
- //range[name+'PixelGroup'] = groups2
- //console.log('groups2', this.id, name,groups2)
- })
-
- }
- range.min /= 10, range.max /= 10
- texture.image.range = range
- viewer.gatherTempRange(type,range)
-
- }
-
-
-
-
- this.images360.waitDelTexDataList.push(texture)
- this.dispatchEvent({type:'loaded_'+type, loaded:true})
- this.images360.dispatchEvent({type:'loaded_'+type, pano:this})
- this[type+'Loading'] = false
- },(e)=>{
- console.error('load '+type+'Img失败, 数据集sceneCode'+ this.pointcloud.sceneCode, e, this.id )
- this['has_'+type] = false
- this['loadFailed_'+type] = false
- this.dispatchEvent({type:'loaded_'+type })
- }, getRangeFun)
-
-
- texture.wrapS = THREE.RepeatWrapping;
- texture.flipY = false
- texture.magFilter = THREE.LinearFilter
- texture.minFilter = THREE.LinearFilter
- texture.generateMipmaps = false
-
-
- }
- build(){
-
- { // orientation
- //add
- //var quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion, rot901);//改 为球目全
- //quaternion.premultiply(rot90)
- this.panoMatrix = new THREE.Matrix4().makeRotationFromQuaternion(this.quaternion)
- this.oriPanoMatrix = this.panoMatrix.clone()
-
- if(this.quaternion2)this.oriPanoMatrix2 = new THREE.Matrix4().makeRotationFromQuaternion(this.quaternion2)
-
-
- //console.log(this.quaternion)
- //this.quaternion = quaternion
- }
-
-
- let marker = new THREE.Mesh(planeGeo, this.getMarkerMat() ) //new Sprite({mat:this.getMarkerMat(), dontFixOrient:true })
- marker.name = 'marker_'+this.id
- marker.up.set(0,0,1)
-
- this.addEventListener('changeMarkerTex',(e)=>{
- marker.material.map = markerTex[e.name]
- })
-
- this.marker = marker
- marker.pano = this;
- this.images360.node.add(marker)
- Potree.settings.isTest && this.addLabel()
-
-
- marker.addEventListener('mouseover', this.hoverOn.bind(this));
- marker.addEventListener('mouseleave', this.hoverOff.bind(this));
- }
-
-
-
-
- transformByPointcloud(){
- this.ceilZ = null //need reset
- let position = this.originPosition.clone().applyMatrix4(this.pointcloud.transformMatrix);//也可以用datasetPosTransform算
- let floorPosition = this.originFloorPosition.clone().applyMatrix4(this.pointcloud.transformMatrix);
- this.setPosition(position, floorPosition)
- this.panoMatrix = new THREE.Matrix4().multiplyMatrices(this.pointcloud.rotateMatrix, this.oriPanoMatrix )
- //this.panoMatrix2 = Potree.Utils.datasetRotTransform({fromDataset:true, pointcloud:this.pointcloud, matrix:this.oriPanoMatrix, getMatrix:true}) //和上一行结果一样
- //quaternion也变下
- if(this.oriPanoMatrix2){
- this.panoMatrix2 = new THREE.Matrix4().multiplyMatrices(this.pointcloud.rotateMatrix, this.oriPanoMatrix2 )//供DepthImageSampler使用
- this.panoMatrix2Inverse = this.panoMatrix2.clone().invert();
- }
- this.dispatchEvent('rePos')
- }
-
- setPosition(position, floorPosition){
- this.position = position
- this.floorPosition = floorPosition
- //this.mesh.position.copy(this.position)
- this.marker.position.copy(this.floorPosition)
- this.marker.lookAt(position) //融合页面marker可能跟随模型倾斜
-
- let upVec = new THREE.Vector3().subVectors(position, floorPosition).normalize().multiplyScalar(0.04*this.pointcloud.scale.x)
- this.marker.position.add(upVec) //this.marker.position.z+=0.04//会被点云遮住
-
-
- if(this.label){
- if(Potree.settings.editType == 'pano'){
- this.label.position.copy(this.position)
- }else{
- this.label.position.copy(this.floorPosition)
- }
- this.label.position.z+=0.14
- this.label.updatePose()
- }
-
-
- }
-
-
- /* getRealPos(){//当整体移动以后
- return this.position.clone().applyMatrix4(viewer.scene.scene.matrix)
- } */
-
- getMarkerMat(){
- if(!markerTex) {
- markerTex = {
- default:texLoader.load( Potree.resourcePath+'/textures/marker.png' ),
- ring:texLoader.load( Potree.resourcePath+'/textures/marker2.png' )
- }
- markerTex.default.anisotropy = 4 // 各向异性过滤 .防止倾斜模糊
- markerTex.ring.anisotropy = 4
- //有可能被点云遮住吗。
-
- }
- let mat = new DepthBasicMaterial({opacity: markerOpacitys.default, side: THREE.DoubleSide , map:markerTex.default ,transparent:true,
- clipDistance: 2, occlusionDistance:1, //不能设置太短,因为过渡时深度不准确
- useDepth: !!( Potree.settings.useDepthTex && this.pointcloud.hasDepthTex || Potree.settings.modelSkybox && this.pointcloud.is4dkkModel ),
- autoDepthTest: true,
- //改为DepthBasicMaterial是因为原Basic的材质在有深度图时过渡会先隐藏后出现。 注:没有深度图时全景模式的marker无法遮挡
- })
- mat.mapTransparent = true
-
- return mat
-
- }
-
-
-
-
- hoverOn(e={}) {
- //console.log("hoverOn " + this.id )
- transitions.start(lerp.property(this.marker.material, "opacity", markerOpacitys.hovered,()=>{
- viewer.dispatchEvent('content_changed')
- }), this.marker.visible ? 250 : 0)
- if(!e.byMap) this.dispatchEvent({type:'hoverOn', byMainView:true})
- if(!e.byImages360) this.images360.dispatchEvent({type:'markerHover', hovered:true, pano:this})
- }
-
- hoverOff(e={}){
- //console.log("hoverOff " + this.id )
- transitions.start(lerp.property(this.marker.material, "opacity", markerOpacitys.default,()=>{
- viewer.dispatchEvent('content_changed')
- }), this.marker.visible ? 250 : 0)
- if(!e.byMap) this.dispatchEvent({type:'hoverOff', byMainView:true})
- if(!e.byImages360) this.images360.dispatchEvent({type:'markerHover', hovered:false, pano:this})
- }
-
-
-
- setZoomed(zoomed){
- this.zoomed = zoomed;
- Potree.settings.displayMode == 'showPanos' && this.updateSkyboxForZoomLevel(); //放大后换成zoomTarget贴图
- viewer.dispatchEvent({type:'panoSetZoom', zoomed})
-
- }
-
-
- enter(){
- this.entered = true
- this.setZoomed(!1)
- viewer.dispatchEvent({type:PanoramaEvents.Enter, oldPano:old, newPano:this } )
- old = this
- //console.log("enter pano "+ this.id)
- }
- exit(){
- this.clearWaitDeferreds();
- this.minimumTiledPanoLoaded = !1;
- this.tiledPanoRenderTarget = null;
- this.setZoomed(!1);
- this.images360.panoRenderer.deactivateTiledPano(this);
- this.highestPartialTileRenderOpCompleted = 0;
- this.highestFullTileRenderOpCompleted = 0;
- this.depthTex && this.depthTex.dispose() //贴图不使用后先dispose,下次到该点时会自动还原
- this.entered = false //add
-
- //console.log("exit pano "+ this.id)
-
- viewer.dispatchEvent({type:PanoramaEvents.Exit, pano:this});
- }
-
-
- updateSkyboxForZoomLevel(){
- if(this.minimumTiledPanoLoaded){
- this.images360.updateProjectedPanos();
- }
-
- }
-
- getSkyboxTexture(){
-
- if(this.minimumTiledPanoLoaded)
- {
- if(this.zoomed && this.images360.qualityManager.maxRenderTargetSize > this.images360.qualityManager.maxNavPanoSize)//change 如果放大后和不放大都是2k就不用这个
- {
- return this.images360.panoRenderer.zoomRenderTarget.texture;
- }
- else
- {
-
- this.tiledPanoRenderTarget.texture.mapping = THREE.UVMapping//add
- return this.tiledPanoRenderTarget.texture;
- }
- }
- else
- {
- return null;
- }
-
- }
-
-
-
- isLoaded(e){
- if (e && "string" == typeof e)
- console.error("Wrong panoSize given to Panorama.isLoaded(); a tiled pano uses PanoSizeClass");
- return !!this.minimumTiledPanoLoaded && (!e || this.highestFullTileRenderOpCompleted >= e)//改:原本是:this.highestPartialTileRenderOpCompleted >= e, 希望这代表全部加载完
-
- }
- getWaitDeferred(size){//获取不同size的tile贴图的promiss
- var t = this.resolutionPromise[this.id];
- t || (t = {}, this.resolutionPromise[this.id] = t);
- var i = t[size];
- return i || (i = {
- deferred: $.Deferred(),
- active: !1
- },
- t[size] = i),
- i
- }
-
- clearWaitDeferreds(){
- var e = this.resolutionPromise[this.id];
- e || (e = {},
- this.resolutionPromise[this.id] = e);
- for (var t in e)
- if (e.hasOwnProperty(t)) {
- var i = e[t];
- i.active = !1,
- i.deferred = $.Deferred()
- }
- }
- resetWaitDeferred(e){
- var t = this.getWaitDeferred(e);
- t.active = !1;
- t.deferred = $.Deferred();
- }
- onTileRendered(ev){
- ev.id === this.id && this.dispatchEvent({
- type:PanoramaEvents.TileLoaded,
- size:ev.panoSize, index:ev.tileIndex, count:ev.totalTiles
- });
- }
- onPanoRendered(ev) {
- if(ev.id === this.id)
- {
- this.minimumTiledPanoLoaded = !0;
- this.updateSkyboxForZoomLevel();//更新贴图 setProjected
- ev.panoSize > this.highestPartialTileRenderOpCompleted && (this.highestPartialTileRenderOpCompleted = ev.panoSize);//应该是更新最高获取到的Partial size
- ev.updateFullComplete && ev.panoSize > this.highestFullTileRenderOpCompleted && (this.highestFullTileRenderOpCompleted = ev.panoSize); //应该是更新最高获取到的Full size
- //this.dispatchEvent("load", ev.panoSize);
- viewer.ifAllLoaded( this);
- this.dispatchEvent({type:PanoramaEvents.LoadComplete, size:ev.panoSize, count:ev.totalTiles});
- }
- }
-
- onTileRenderFail(ev) {
- ev.id === this.id && this.dispatchEvent({type:PanoramaEvents.LoadFailed });
- }
- onUploadAttemptedForAllTiles(ev) {
- if (ev.id === this.id) {
- var n = this.images360.qualityManager.getPanoSize(PanoSizeClass.BASE);
- if(ev.panoSize === n && this.shouldRedrawOnBaseLoaded) //shouldRedrawOnBaseLoaded一直是false。在4dkk里只有初始点在quickstart后变为true。
- {
- this.shouldRedrawOnBaseLoaded = !1;
- this.panoRenderer.resetRenderStatus(this.id, !0, !1);
- this.panoRenderer.renderPanoTiles(this.id, null, !0, !0);
- }
- }
- }
-
-
- addLabel(){
- this.removeTextLabel()
- this.label = new TextSprite(Object.assign({},
- labelProp, {text: this.id + "("+this.originID+")"}) //{text: `id:${this.id}, dataset:${this.pointcloud.name}, 4dkkId:${this.originID}`}
- );
- this.images360.node.add(this.label);
- this.floorPosition && this.label.position.copy(this.floorPosition)
- }
-
- addLabel2(){
- if(this.label2)return
- this.label2 = new TextSprite(Object.assign({},
- labelProp2, {text: /* this.originID */ parseInt(this.id)+1 }) //{text: `id:${this.id}, dataset:${this.pointcloud.name}, 4dkkId:${this.originID}`}
- );
- //this.images360.node.add(this.label2);
- this.marker.add(this.label2)
-
- //this.floorPosition && this.label2.position.copy(this.floorPosition)
- let s = 0.2
- this.label2.scale.set(s,s,s)
- Potree.Utils.updateVisible(this.label2, 'notDisplay', false)
- Potree.Utils.updateVisible(this.label2, 'panoVisi', this.visible)
-
-
-
- //Potree.Utils.setObjectLayers(this.label2, 'bothMapAndScene')
- }
-
- removeTextLabel(){
- if(this.label){
- this.label.parent.remove(this.label);
- }
- }
-
- dispose(){
-
- let i = viewer.images360.panos.indexOf(this);
- if(i==-1)return
- viewer.images360.panos.splice(i,1);
-
- i = this.pointcloud.panos.indexOf(this)
- this.pointcloud.panos.splice(i,1);
-
-
- this.marker.parent.remove(this.marker)
-
- this.removeTextLabel()
- if(this.depthTex) this.depthTex.dispose()
-
-
- this.dispatchEvent('dispose')
- //删除tile贴图、depthTex等以后再写
- }
-
-
- getCeilHeight(){//天花板高度值 (假设不存在depth为0的点,所有为0的要么是在盲区,要么是无穷远。)
-
- if(this.ceilZ == void 0){
- //const depthTiming = Potree.timeCollect.depthSampler.median //pc firefox达到4. chrome为0.01
-
-
- //用三个间隔120度散开,和中心垂直线成一定夹角的三个向量去求 最高高度 (不求平均的原因:万一是0不好算)
-
- let rotMat = new THREE.Matrix4().makeRotationX((Potree.config.depthTexUVyLimit+0.01)*Math.PI)// 角度不能小于天花板中空的半径
-
- let dir0 = new THREE.Vector3(0,0,1).applyMatrix4(rotMat)
-
- let dirs = [
- dir0,
- dir0.clone().applyMatrix4(new THREE.Matrix4().makeRotationZ(Math.PI*2 / 3)),
- dir0.clone().applyMatrix4(new THREE.Matrix4().makeRotationZ(-Math.PI*2 / 3))
- ];
-
-
- /* if(depthTiming < 1){
- let rotMat1 = new THREE.Matrix4().makeRotationZ(Math.PI*2 / 3);
- dirs.push(dirs[0].clone().applyMatrix4(rotMat1))
- }
- if(depthTiming < 0.3){
- let rotMat2 = new THREE.Matrix4().makeRotationZ(-Math.PI*2 / 3);
- dirs.push(dirs[0].clone().applyMatrix4(rotMat2));
- } */
-
- let zs = dirs.map(dir_=>{
- let dir = dir_.clone().applyMatrix4(this.panoMatrix2) //pano不一定是垂直的, 需要把之前的dirInPano先转成真实的dir,防止超出角度限制
- let intersect = viewer.images360.getIntersect(this, dir)
- let z = intersect ? intersect.location.z : Infinity/* this.position.z+skyHeight */ //没有intersect代表可能是天空
- return z
- })
- zs.sort((a,b)=>{return b-a});//得最大值 (不用中位数的原因:在屋檐处,如果仅有一个intersect是天空,因到了室外所以也用天空高度)
-
-
- this.ceilZ = zs[0]
- let min = this.position.z + 1 // 防止意外太低
- this.ceilZ = Math.max(min, this.ceilZ)
- //console.log(this.id, 'ceilZ:', this.ceilZ )
- }
-
- return this.ceilZ
-
-
- }
-
- };
-
- Panorama.prototype.loadTiledPano = function() {
- //var downloads = [] , t = [];
- var downloaded = {} , eventAdded = {}, latestPartialRequest = {}; //每个pano对应一组这些
-
- return function(size, dirs, fov, o, a, download) {
- var dir = dirs.datasetsLocal.find(e=>e.datasetId == this.pointcloud.dataset_id).direction;
- //var dir = dirs
-
-
- null !== o && void 0 !== o || (o = !0),
- null !== a && void 0 !== a || (a = !0);
- var l = this.getWaitDeferred(size)
- , c = l.deferred
- , h = null
- , u = null;
- fov && ("number" == typeof fov ? h = fov : (h = fov.hFov, u = fov.vFov))
-
- if (!this.isLoaded(size)) {
- //console.log('loadTiledPano', this.id, size, fov)
- if (!l.active) {
- l.active = !0
- let name = this.id + ":" + size
- downloaded[name] = downloaded[name] || []
- /*
- this.downloaded = downloaded
- this.latestPartialRequest = latestPartialRequest
- */
- latestPartialRequest[name] = null
-
- if (fov) {
- let tileArr = []//add
- var d = TileUtils.matchingTilesInDirection(this, size, dir, h, u, tileArr);
-
- latestPartialRequest[name] = tileArr
- downloaded[name].forEach((e)=>{
- let item = latestPartialRequest[name].find(a=>e.faceTileIndex == a.faceTileIndex && e.face == a.face)
- if(item){
- item.loaded = true
- }
- })
- if(!latestPartialRequest[name].some(e=>!e.loaded)){//所需要的全部加载成功
- //let total = TileUtils.getTileCountForSize(size)
- //this.onPanoRendered(this.id, size, total, !0);
- c.resolve(size/* , total */);
- this.resetWaitDeferred(size)
- //console.log('该部分早已经加载好了'+size, this.id)
- latestPartialRequest[name] = null
- }
-
- //console.log("Loading partial pano: " + this.id + " with " + d + " tiles")
- }
- if(!eventAdded[this.id]) {
- eventAdded[this.id] = !0
-
- this.addEventListener(PanoramaEvents.LoadComplete, function(ev/* e, t */) {//本次任务全部加载完毕
-
- //console.warn('点位(可能部分)下载完成 ', 'id:'+this.id, 'size:'+ev.size )
-
- var i = this.getWaitDeferred(ev.size).deferred;//"pending"为还未完成
- i && "pending" === i.state() && this.highestPartialTileRenderOpCompleted >= ev.size && (i.resolve(ev.size, ev.count),
- this.resetWaitDeferred(ev.size))//恢复active为false
-
- }.bind(this))
-
- this.addEventListener(PanoramaEvents.LoadFailed, function(ev) {
- var t = this.getWaitDeferred(e).deferred;
- t && "pending" === t.state() && this.highestPartialTileRenderOpCompleted >= ev.t && (t.reject(ev.t),
- this.resetWaitDeferred(ev.t))//恢复active为false
- }.bind(this))
-
- this.addEventListener(PanoramaEvents.TileLoaded, function(ev/* t, i, n */) {//每张加载完时
-
- //console.log('tileLoaded', 'id:'+this.id, 'size:'+ev.size, 'tileIndex:'+ev.index )
- let tileIndex = ev.index
- let total = ev.count
- let size = ev.size
- let name = this.id + ":" + size
- downloaded[name] = downloaded[name] || [] //不是所有的加载都是从loadTiledPano获取的所以会有未定义的情况
-
- let {faceTileIndex,face} = TileUtils.getTileLocation(size, tileIndex, {})
- downloaded[name].push({faceTileIndex,face})
- var r = this.getWaitDeferred(size).deferred;
- if (r && "pending" === r.state()) {
- r.notify(size, tileIndex, total);
- if(latestPartialRequest[name]){
- let item = latestPartialRequest[name].find(e=>e.faceTileIndex == faceTileIndex && e.face == face)
- item && (item.loaded = true )
-
- if(!latestPartialRequest[name].some(e=>!e.loaded)){//所需要的局部tiles全部加载成功
- this.onPanoRendered(this.id, size, total, !0); //onPanoRendered还会触发 PanoramaEvents.LoadComplete
- r.resolve(size, total);
- this.resetWaitDeferred(size)
- //console.log('该部分加载好了'+size, this.id)
- latestPartialRequest[name] = null
- }
-
- }
- }
- viewer.dispatchEvent('content_changed')
-
-
- /* var r = this.getWaitDeferred(ev.size).deferred;
- if (r && "pending" === r.state()) {
- r.notify(ev.size, ev.index, ev.count);
-
- var o = downloads[this.id + ":" + ev.size];
- if(o){//如果有规定下载哪些tile,只需要下载这些tile则LoadComplete
- o.tileCount++
-
- if(o.tileCount === o.targetTileCount){//达到下载目标数
- this.onPanoRendered(this.id, ev.size, ev.count, !0);
- r.resolve(ev.size, ev.count);
- this.resetWaitDeferred(ev.size)
- }
- }
- } */
- }.bind(this))
- }
- }
- this.images360.tileDownloader.clearForceQueue()
- this.images360.tileDownloader.forceQueueTilesForPano(this, size, dir, h, u, download)
- this.tiledPanoRenderTarget = this.images360.panoRenderer.activateTiledPano(this, this.images360.qualityManager.getMaxNavPanoSize(), o)
- this.images360.panoRenderer.renderPanoTiles(this.id, dirs, a) //将512的先贴上
-
- }else{
- //console.log('早已经全加载好了' +size, this.id)
- c.resolve(size)
- }
- return c.promise()
- }
- }()
- /*
- 经观察发现,navvis的也存在的问题是点云和全景有微小的偏差,导致远处的热点在全景和点云上看位置差别感大,比如一个在路上一个在天空上。
- */
- export default Panorama
|