12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042 |
-
- import * as THREE from "../../libs/three.js/build/three.module.js";
- import math from "./utils/math.js";
- import browser from "./utils/browser.js";
- import cameraLight from "./utils/cameraLight.js";
- import {Utils} from "../utils.js";
- import Common from "./utils/Common.js";
- import {BinaryLoader} from "../loader/BinaryLoader.js";
- import {Features} from "../Features.js";
- import {PointAttribute,PointAttributeTypes} from "../loader/PointAttributes.js";
- import {ProfileWindow} from "../viewer/profile.js";
- import {XHRFactory} from "../XHRFactory.js";
- import {ClipTask, ClipMethod} from "../defines.js";
- import {VolumeTool} from "../utils/VolumeTool.js";
- import {Box3Helper} from "../utils/Box3Helper.js";
- import {KeyCodes} from "../KeyCodes.js";
- import {HQSplatRenderer} from "../viewer/HQSplatRenderer.js";
- import {LRU} from "../LRU.js";
- import {ExtendPointCloudMaterial} from '../materials/ExtendPointCloudMaterial.js'
-
- import {PointCloudOctreeGeometry, PointCloudOctreeGeometryNode} from '../PointCloudOctreeGeometry.js'
- import {Shaders} from "../../build/shaders/shaders.js";
-
- import {LineSegmentsGeometry} from '../../libs/three.js/lines/LineSegmentsGeometry.js'
- import {LineGeometry} from '../../libs/three.js/lines/LineGeometry.js'
- KeyCodes.BACKSPACE = 8
- //注意,这时候Potree.js中export的内容还不在Potree变量中
- var texLoader = new THREE.TextureLoader()
- {//defines:
- Potree.defines = {}
- Potree.defines.Buttons = {// MouseEvent.buttons
- //buttons,设置按下了鼠标哪些键,是一个3个比特位的二进制值,默认为0。1表示按下主键(通常是左键),2表示按下次要键(通常是右键),4表示按下辅助键(通常是中间的键)。
- NONE:0,//add
-
- LEFT: 0b0001,
- RIGHT: 0b0010,
- MIDDLE: 0b0100
- };
- /* 如果访问的是button, 用THREE.MOUSE来判断:
- button,设置按下了哪一个鼠标按键,默认为0。-1表示没有按键,0表示按下主键(通常是左键),1表示按下辅助键(通常是中间的键),2表示按下次要键(通常是右键)
- */
-
- Potree.browser = browser
- /////////// add //////////////////////////////////
- Potree.defines.GLCubeFaces = {
- GL_TEXTURE_CUBE_MAP_POSITIVE_X: 0,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 1,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 2,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 3,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 4,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 5
- };
- Potree.defines.PanoSizeClass = {
- BASE: 1,
- STANDARD: 2,
- HIGH: 3,
- ULTRAHIGH: 4
- };
- Potree.defines.PanoRendererEvents = {
- PanoRenderComplete: "panorama.render.complete",
- TileRenderFailure: "panorama.tile.render.failed",
- TileRenderSuccess: "panorama.tile.render.success",
- TileUploadAttempted: "panorama.tile.upload.attempted",
- UploadAttemptedForAllTiles: "panorama.upload.attempted.all.tiles",
- ZoomLevelRenderStarted: "panorama.zoom.render.started"
- };
- Potree.defines.SceneRendererEvents = {
- ContextCreated: "scene-renderer-context-created",
- AfterRender: "after-render",
- MemoryUsageUpdated: "scene-renderer-memory-usage-updated"
- };
- Potree.defines.TileDownloaderEvents = {
- TileDownloadSuccess: "tiledownloader.download.success",
- TileDownloadFailure: "tiledownloader.download.failure",
- PanoDownloadComplete: "tiledownloader.pano.download.complete"
- };
- Potree.defines.Vectors = {
- UP: new THREE.Vector3(0,1,0),
- DOWN: new THREE.Vector3(0,-1,0),
- LEFT: new THREE.Vector3(-1,0,0),
- RIGHT: new THREE.Vector3(1,0,0),
- FORWARD: new THREE.Vector3(0,0,-1),
- BACK: new THREE.Vector3(0,0,1)
- };
- /* var Vectors2 = {}
- for(var i in Vectors){
- Vectors2[i] = math.convertVector.YupToZup(Vectors[i])
- }
- */
- Potree.defines.DownloadStatus = Object.freeze({
- None: 0,
- Queued: 1,
- ForceQueued: 2,
- Downloading: 3,
- Downloaded: 4,
- DownloadFailed: 5
- });
- Potree.defines.ModelManagerEvents = {
- ModelAdded: "model-added",
- ActiveModelChanged: "active-model-changed"
- };
- Potree.defines.PanoramaEvents = {
- Enter: 'panorama.enter',
- Exit: 'panorama.exit',
- LoadComplete: "panorama.load.complete",
- LoadFailed: "panorama.load.failed",
- TileLoaded: "panorama.tile.loaded",
- VideoRendered: "panorama.video.rendered"
- };
-
- ClipTask.SHOW_INSIDE_Big = 4
- }
- {//Features
- let gl_
- Features.EXT_DEPTH = {
- isSupported: function (gl) {
- gl = gl || gl_
- gl_ = gl
- if(browser.detectIOS()){
- let {major,minor,patch} = browser.iosVersion()
- if(major == 15 && minor == 4 && patch == 1){
- console.warn('检测到是ios15.4.1, 关闭EXT_frag_depth')//该版本ext_depth有问题,导致clear错乱。没有解决办法先关闭。
- return false
- }
- }
- return gl instanceof WebGL2RenderingContext || gl.getExtension('EXT_frag_depth'); //shader中的GL_EXT_frag_depth需要判断一下detectIOS吗。。
- }
- }
-
- }
- Utils.loadSkybox = function(path, oldSky ) {
- let camera, scene, parent , cameraOrtho
- if(!oldSky){
- parent = new THREE.Object3D("skybox_root");
- camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 100000);
- cameraOrtho = new THREE.OrthographicCamera(-1, 1, 1, -1, Potree.config.view.near, Potree.settings.cameraFar);
- if(!window.axisYup) camera.up.set(0, 0, 1);//add
- scene = new THREE.Scene();
-
- let skyboxBgWidth = Potree.config.skyboxBgWidth
- let skyGeometry = new THREE.BoxBufferGeometry(skyboxBgWidth,skyboxBgWidth,skyboxBgWidth)
- let skybox = new THREE.Mesh(skyGeometry, new THREE.ShaderMaterial({
- vertexShader: Shaders['skybox.vs'],
- fragmentShader: Shaders['skybox.fs'],
- side: THREE.BackSide,
- uniforms:{
- tDiffuse: {
- type: "t",
- value: null
- },
- matrix:{
- type: "m4",
- value: new THREE.Matrix4
- }
- },
- depthTest:false,
- depthWrite:false
- }) );
- scene.add(skybox);
- scene.traverse(n => n.frustumCulled = false);
- // z up
- //scene.rotation.x = Math.PI / 2;
- parent.children.push(camera);
- camera.parent = parent;
-
- }else{
- camera = oldSky.camera,
- scene = oldSky.scene
- parent = oldSky.parent
- cameraOrtho = oldSky.cameraOrtho
- }
-
- let texture = texLoader.load( path, ()=>{
- console.log('loadSkybox成功',path)
- texture.wrapS = THREE.RepeatWrapping;
- texture.flipY = false
- texture.magFilter = THREE.LinearFilter
- texture.minFilter = THREE.LinearFilter
- scene.children[0].material.uniforms.tDiffuse.value = texture
- viewer.dispatchEvent('content_changed')
- },null,(e)=>{//error
- console.error('loadSkybox失败',path)
- });
-
- return {camera, scene, parent, cameraOrtho};
- };
-
- Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera, viewer, pointclouds, pickParams = {} ) {
- //getIntersectByDepthTex
- /* let result = viewer.edlRenderer.depthTexSampler.sample(viewport, mouse)//add
- if(result != 'unsupport')return result
- */
-
-
-
- if(!pointclouds || pointclouds.length == 0)return
- //console.log('getMousePointCloudIntersection')
- let renderer = viewer.renderer;
-
-
-
-
- if(viewport){ //转换到类似整个画面时
- /*let mouseInViewport = Utils.convertNDCToScreenPosition(pointer, null, viewport.resolution.x, viewport.resolution.y)
- pickParams.x = mouseInViewport.x //mouse.x / viewport.width;
- pickParams.y = mouseInViewport.y //renderer.domElement.clientHeight - mouse.y / viewport.height; */
- pickParams.x = mouse.x;
- pickParams.y = viewport.resolution.y - mouse.y;
- }else{
- pickParams.x = mouse.x;
- pickParams.y = renderer.domElement.clientHeight - mouse.y;
- }
-
- //console.log('getMousePointCloudIntersection')
-
- /* if(!raycaster){
- raycaster = new THREE.Raycaster();
- raycaster.setFromCamera(pointer, camera);
- } */
-
- let raycaster = new THREE.Raycaster();
- raycaster.setFromCamera(pointer, camera);
- let ray = raycaster.ray;
-
- let selectedPointcloud = null;
- let closestDistance = Infinity;
- let closestIntersection = null;
- let closestPoint = null;
-
-
-
- //-----------add--------------------
- let old_clipBoxes_in = new Map()
- let old_clipBoxes_out = new Map()
- let old_bigClipInBox = new Map()
- let old_highlightBoxes = new Map()
-
- //bigClipInBox 最好也写下
- let density
- let sizeType
- let size = new Map()
- let visiMap = new Map()
- let needsUpdate = false;
-
- if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos') { //(无深度图) 测量或全景模式提高精准度,因为漫游的
- density = Potree.settings.pointDensity
- Potree.settings.pointDensity = 'magnifier'
-
- pointclouds.forEach(e=>{//因为全景模式的pointSizeType是fixed所以要还原下
- visiMap.set(e,e.visible)
- e.visible = Potree.Utils.getObjVisiByReason(e, 'datasetSelection'); //先将隐藏的点云显示
- if(!e.visible)return
- size.set(e, e.temp.pointSize)
- sizeType = e.material.pointSizeType
- e.material.pointSizeType = Potree.config.material.pointSizeType
-
- e.changePointSize(Potree.config.material.realPointSize*2, true)//更改点云大小到能铺满为止,否则容易识别不到
- })
- needsUpdate = true
- }else{
- if(viewer.viewports.filter(e=>!e.noPointcloud && e.active).length>1 || pickParams.cameraChanged){//在pick时相机和渲染时不一样的话
- viewport.beforeRender && viewport.beforeRender()
- needsUpdate = true //不updatePointClouds的话hover久了会不准 因node是错的
- //但依旧需要camera真的移动到那个位置才能加载出点云
- }
- }
-
- if(!pickParams.pickClipped){// 无视clipBoxes
- for(let pointcloud of pointclouds){
- old_clipBoxes_in.set(pointcloud, pointcloud.clipBoxes_in)
- old_clipBoxes_out.set(pointcloud, pointcloud.clipBoxes_in)
- old_bigClipInBox.set(pointcloud, pointcloud.bigClipInBox)
- old_highlightBoxes.set(pointcloud, pointcloud.highlightBoxes)
- pointcloud.material.setClipBoxes(null, [],[],[])
- }
- needsUpdate = true
- }
-
- if(needsUpdate){
- Potree.updatePointClouds(pointclouds, camera, viewport.resolution ); //最好只更新pick的范围的resolution
- }
- //------------------------------------------------
-
-
- let allPointclouds = []
- for(let pointcloud of pointclouds){
-
- let point = pointcloud.pick(viewer, viewport, camera, ray, pickParams );
-
-
-
- if(!point){
- continue;
- }
- allPointclouds.push(pointcloud)
-
-
- let distance = camera.position.distanceTo(point.position);
- if (distance < closestDistance) {
- closestDistance = distance;
- selectedPointcloud = pointcloud;
- closestIntersection = point.position;
- closestPoint = point;
- }
- }
- //恢复
- if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos'){
- Potree.settings.pointDensity = density
-
- pointclouds.forEach(e=>{
- if(e.visible){
- e.material.pointSizeType = sizeType
- e.changePointSize(size.get(e))
- }
- e.visible = visiMap.get(e)
- })
- }else{
- /* if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
- viewport.afterRender && viewport.afterRender()
- } */
- }
- if(!pickParams.pickClipped){//add
- for(let pointcloud of pointclouds){
- pointcloud.material.setClipBoxes(old_bigClipInBox.get(pointcloud), old_clipBoxes_in.get(pointcloud), old_clipBoxes_out.get(pointcloud), old_highlightBoxes.get(pointcloud))
- }
- }
- if (selectedPointcloud) {
- return {
- location: closestIntersection,
- distance: closestDistance,
- pointcloud: selectedPointcloud,
- point: closestPoint,
- pointclouds: allPointclouds, //add
- normal: new THREE.Vector3().fromArray(closestPoint.normal )//add
- };
- } else {
- return null;
- }
-
- };
- Utils.pixelsArrayToDataUrl = function(pixels, width, height, compressRatio = 0.7) {
- let canvas = document.createElement('canvas');
- canvas.width = width;
- canvas.height = height;
- let context = canvas.getContext('2d');
- pixels = new pixels.constructor(pixels);
- /* for (let i = 0; i < pixels.length; i++) {
- pixels[i * 4 + 3] = 255;
- } */
- // flip vertically
- let bytesPerLine = width * 4;
- for(let i = 0; i < parseInt(height / 2); i++){
- let j = height - i - 1;
- let lineI = pixels.slice(i * bytesPerLine, i * bytesPerLine + bytesPerLine);
- let lineJ = pixels.slice(j * bytesPerLine, j * bytesPerLine + bytesPerLine);
- pixels.set(lineJ, i * bytesPerLine);
- pixels.set(lineI, j * bytesPerLine);
- }
-
-
-
- let imageData = context.createImageData(width, height);
- imageData.data.set(pixels);
- context.putImageData(imageData, 0, 0);
- let dataURL = canvas.toDataURL(compressRatio);
- return dataURL;
- }
- Utils.renderTargetToDataUrl = function(renderTarget, width, height, renderer, compressRatio = 0.7){
- let pixelCount = width * height;
- let buffer = new Uint8Array(4 * pixelCount);
- renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer);
- var dataUrl = Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
- return dataUrl
-
- }
- Utils.mouseToRay = function(pointer, camera ){
-
- let vector = new THREE.Vector3(pointer.x, pointer.y, 1);
- let origin = new THREE.Vector3(pointer.x, pointer.y, -1); //不能用camera.position,在orbitCamera时不准
- vector.unproject(camera);
- origin.unproject(camera);
- let direction = new THREE.Vector3().subVectors(vector, origin).normalize();
- let ray = new THREE.Ray(origin, direction);
- return ray;
- }
- Utils.getPos2d = function(point, camera, dom, viewport){//获取一个三维坐标对应屏幕中的二维坐标
- var pos
- if(math.closeTo(camera.position, point, 1e-5) ){ //和相机位置重合时显示会四处飘,看是要改成一直显示中间还是隐藏?
- pos = new THREE.Vector3(0,0,1.5); //1.5是为了不可见
- }else{
- pos = point.clone().project(camera) //比之前hotspot的计算方式写得简单 project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
- }
-
-
- var x,y,left,top;
- x = (pos.x + 1) / 2 * dom.clientWidth * viewport.width;
- y = (1 - (pos.y + 1) / 2) * dom.clientHeight * viewport.height;
- left = viewport.left * dom.clientWidth;
- top = (1- viewport.bottom - viewport.height) * dom.clientHeight;
-
- var inSight = pos.x <= 1 && pos.x >= -1 //是否在屏幕中
- && pos.x <= 1 && pos.y >= -1
-
- return {
- pos: new THREE.Vector2(left+x,top+y) ,// 屏幕像素坐标
- vector: pos, //(范围 -1 ~ 1)
- trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点 参见Tag.update
- inSight : inSight, //在屏幕范围内可见,
- posInViewport: new THREE.Vector2(x,y)
- };
- }
- Utils.screenPass = new function () {
- this.screenScene = new THREE.Scene();
- this.screenQuad = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2, 1));
- this.screenQuad.material.depthTest = true;
- this.screenQuad.material.depthWrite = true;
- this.screenQuad.material.transparent = true;
- this.screenScene.add(this.screenQuad);
- this.camera = new THREE.Camera();
- this.render = function (renderer, material, target) {
- this.screenQuad.material = material;
- if (typeof target === 'undefined') {
- renderer.render(this.screenScene, this.camera);
- } else {
- let oldTarget = renderer.getRenderTarget()
- renderer.setRenderTarget(target)
- renderer.clear()
- renderer.render(this.screenScene, this.camera);
- renderer.setRenderTarget(oldTarget)
- }
- };
- }();
- //add
- Utils.computePointcloudsBound = function(pointclouds){
- var boundingBox = new THREE.Box3();
- pointclouds.forEach(pointcloud=>{
- pointcloud.updateBound()
- boundingBox.union(pointcloud.bound2)
- })
- var boundSize = boundingBox.getSize(new THREE.Vector3)
- var center = boundingBox.getCenter(new THREE.Vector3)
- return {boundSize, center, boundingBox}
- }
- Utils.convertScreenPositionToNDC = function(pointer, mouse, width, height) {
- return pointer = pointer || new THREE.Vector2,
- pointer.x = mouse.x / width * 2 - 1,
- pointer.y = 2 * -(mouse.y / height) + 1,
- pointer
- }
- Utils.convertNDCToScreenPosition = function(pointer, mouse, width, height) {
- return mouse = mouse || new THREE.Vector2,
- mouse.x = Math.round((pointer.x + 1 ) / 2 * width),
- mouse.y = Math.round(-(pointer.y - 1 ) / 2 * height),
- mouse
- }
- Utils.getOrthoCameraMoveVec = function(pointerDelta, camera ){//获取当camera为Ortho型时 屏幕点1 到 屏幕点2 的三维距离
-
- let cameraViewWidth = camera.right / camera.zoom
- let cameraViewHeight = camera.top / camera.zoom
- let moveVec = new THREE.Vector3;
- moveVec.set( pointerDelta.x * cameraViewWidth , pointerDelta.y * cameraViewHeight , 0).applyQuaternion(camera.quaternion)
- return moveVec
- }
- Utils.VectorFactory = {
- fromArray : function(t) {
- if (t) {
- if (t.length < 2 || t.length > 3)
- console.error("Wrong number of ordinates for a point!");
- return 3 === t.length ? (new THREE.Vector3).fromArray(t) : (new THREE.Vector2).fromArray(t)
- }
- },
- fromArray3 : function(t) {
- if (t) {
- if (3 !== t.length)
- console.error("Wrong number of ordinates for a point!");
- return (new THREE.Vector3).fromArray(t)
- }
- },
- fromArray2 : function(t) {
- if (t) {
- if (2 !== t.length)
- console.error("Wrong number of ordinates for a point!");
- return (new THREE.Vector2).fromArray(t)
- }
- },
- toString : function(t) {
- return t.x.toFixed(8) + "," + t.y.toFixed(8) + "," + t.z.toFixed(3)
- }
- }
-
- Utils.QuaternionFactory = {
- rot90 : (new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.Math.degToRad(-90)),
- fromArray : function(t) {
- if (t) {
- if (4 !== t.length)
- console.error("Wrong number of ordinates for a quaternion!");
- return new THREE.Quaternion(t[1],t[2],t[3],t[0]).multiply(this.rot90)
- }
- }
- ,
- toArray : function(t) {
- if (t) {
- var e = t.clone().multiply(a).toArray();
- return [e[3], e[0], e[1], e[2]]
- }
- }
- ,
- fromLonLat : function(t) {
- if (t)
- return (new THREE.Quaternion).setFromEuler(new THREE.Euler(t.lon,t.lat,0))
- }
- ,
- toLonLat : function(t) {
- if (t) {
- var e = (new THREE.Euler).setFromQuaternion(t);
- return {
- lon: e.x,
- lat: e.y
- }
- }
- }
-
-
- }
-
- Utils.datasetPosTransform = function(o={}){
-
- let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
- let tranMatrix
- if(pointcloud){
- if(Potree.settings.editType == 'merge'){
- tranMatrix = o.fromDataset ? pointcloud.matrixWorld : new THREE.Matrix4().copy(pointcloud.matrixWorld).invert()
- }else{
- tranMatrix = o.fromDataset ? pointcloud.transformMatrix : pointcloud.transformInvMatrix
- }
- }else{
- if(Potree.settings.intersectOnObjs){
- let object = o.object || viewer.objs.children.find(e=>e.dataset_id == o.datasetId)
- if(object){
- tranMatrix = o.fromDataset ? object.matrixWorld : new THREE.Matrix4().copy(object.matrixWorld).invert()
- }
- }
- }
- if(tranMatrix){
- return (new THREE.Vector3).copy(o.position).applyMatrix4(tranMatrix)
- }else{
- if(o.datasetId != void 0){
- console.error(`datasetPosTransform找不到datasetId为${o.datasetId}的数据集或模型,请检查数据, 模型未创建或删除`)
- //很可能是旧的热点,需要删除
- }
- }
-
- }
- Utils.datasetRotTransform = function(o={}){
- let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
- if(pointcloud){
- var matrix, newMatrix, result
-
- if(o.rotation){
- matrix = new THREE.Matrix4().makeRotationFromEuler(o.rotation)
- }else if(o.quaternion){
- matrix = new THREE.Matrix4().makeRotationFromQuaternion(o.quaternion)
- }else if(o.matrix){
- matrix = o.matrix.clone()
- }else{
- return
- }
- let rotateMatrix = o.fromDataset ? pointcloud.rotateMatrix : pointcloud.rotateInvMatrix
- newMatrix = new THREE.Matrix4().multiplyMatrices(rotateMatrix, matrix )
-
- if(o.getRotation){
- result = new THREE.Euler().setFromRotationMatrix(newMatrix)
- }else if(o.getQuaternion){
- result = new THREE.Quaternion().setFromRotationMatrix(newMatrix)
- }else if(o.getMatrix){
- result = newMatrix
- }
-
- return result
-
- }
-
- }
- Utils.isInsideFrustum = function(bounding, camera){// bounding是否在视野范围内有可见部分(视野就是一个锥状box)
- let frustumMatrix = new THREE.Matrix4
- frustumMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
-
- let frustum = new THREE.Frustum();
- frustum.setFromProjectionMatrix(frustumMatrix)
-
- if(bounding instanceof THREE.Sphere){
- return frustum.intersectsSphere(bounding)
- }else{
- return frustum.intersectsBox(bounding)
- }
- }
- Utils.isIntersectBox = function(object, boxMatrix){//object是否有在box中的部分。 object可以是点或者bounding, box原为1*1*1,但可能形变
- //let frustum = new THREE.Frustum();
- //frustum.setFromProjectionMatrix(boxMatrixInverse) --错
-
- let px = new THREE.Vector3(+0.5, 0, 0).applyMatrix4(boxMatrix);
- let nx = new THREE.Vector3(-0.5, 0, 0).applyMatrix4(boxMatrix);
- let py = new THREE.Vector3(0, +0.5, 0).applyMatrix4(boxMatrix);
- let ny = new THREE.Vector3(0, -0.5, 0).applyMatrix4(boxMatrix);
- let pz = new THREE.Vector3(0, 0, +0.5).applyMatrix4(boxMatrix);
- let nz = new THREE.Vector3(0, 0, -0.5).applyMatrix4(boxMatrix);
- let pxN = new THREE.Vector3().subVectors(nx, px).normalize();
- let nxN = pxN.clone().multiplyScalar(-1);
- let pyN = new THREE.Vector3().subVectors(ny, py).normalize();
- let nyN = pyN.clone().multiplyScalar(-1);
- let pzN = new THREE.Vector3().subVectors(nz, pz).normalize();
- let nzN = pzN.clone().multiplyScalar(-1);
- let pxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pxN, px);
- let nxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nxN, nx);
- let pyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pyN, py);
- let nyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nyN, ny);
- let pzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pzN, pz);
- let nzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nzN, nz);
- let frustum = new THREE.Frustum(pxPlane, nxPlane, pyPlane, nyPlane, pzPlane, nzPlane);
-
-
-
-
- if(object instanceof THREE.Box3){
- var boxBound = new THREE.Box3(
- new THREE.Vector3(-0.5,-0.5,-0.5), new THREE.Vector3(0.5,0.5,0.5),
- ).applyMatrix4(boxMatrix) //large boundingbox
- if(!object.intersectsBox(boxBound))return
- return frustum.intersectsBox(object) //根据该函数, 若存在某个plane在box上的对应点都在plane背面,则不相交. 可得知在box构成的frustum倾斜时不准确,不相交也判断为相交,甚至不如bound相交准确。所以前面加步骤排除下,但仍不完全准确。(可在裁剪中将box放置到数据集上方旋转下校验)
- }else if(object instanceof Array){//点合集, 只能粗略计算下
- let sphere = new THREE.Sphere()
- sphere.setFromPoints(object)
- return this.isIntersectBox(sphere, boxMatrix)
- }else if(object instanceof THREE.Sphere){
- return frustum.intersectsSphere(object)
- }else if(object instanceof THREE.Vector3){
- return frustum.containsPoint(object)
- }else if(object instanceof THREE.Matrix4){//第一个参数如果和第二个参数一样都是box的worldMatrix
-
- }
- /* containsPoint: ƒ containsPoint( point )
- intersectsBox: ƒ intersectsBox( box )
- intersectsObject: ƒ intersectsObject( object )//geo
- intersectsSphere: ƒ intersectsSphere( sphere )
- intersectsSprite: ƒ intersectsSprite( sprite )
- */
- }
- Utils.getIntersect = function (camera, meshes, pointer, raycaster) {
- //获取鼠标和meshes交点
- camera.updateMatrixWorld()
- if(!raycaster){//getMouseIntersect
- raycaster = new THREE.Raycaster()
- var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
- end = new THREE.Vector3(pointer.x, pointer.y, 1).unproject(camera)
- var dir = end.sub(origin).normalize()
- raycaster.set(origin, dir)
- }
-
- meshes.forEach(e=>{
- raycaster.layers.enable(math.getBaseLog(e.layers.mask,2))
- })
- var n = raycaster.intersectObjects(meshes)
- if (0 === n.length) return null
- return n[0]
- }
- Utils.addOrRemoveDefine = function(material, defineName, type, value=''){
- let defines = material.defines
- if(type == 'add'){
- if(defines[defineName] != void 0 && defines[defineName] == value)return
- defines[defineName] = value
- }else{
- if(defines[defineName] != void 0)return;
- delete defines[defineName]
- }
- material.needsUpdate = true;
- }
- Utils.makeTexDontResize = function(map){//避免贴图因非2的次方而缩小。小心使用
- if(!map || !map.image){
- return console.log('!map || !map.image', map, map&&map.image)
- }
- if(THREE.Math.isPowerOfTwo(map.image.width ) && THREE.Math.isPowerOfTwo(map.image.height ))return
- map.wrapS = map.wrapT = THREE.ClampToEdgeWrapping; //原默认 RepeatWrapping
- map.minFilter = THREE.LinearFilter; // or THREE.NearestFilter 原默认 LinearMipmapLinearFilter
- map.needsUpdate = true
- }
- Utils.updateVisible = function(object, reason, ifShow, level=0, type){//当所有加入的条件都不为false时才显示. reason='force'一般是强制、临时的
- if(!object.unvisibleReasons) object.unvisibleReasons = []; //如果length>0代表不可见
- if(!object.visibleReasons) object.visibleReasons = []; //在同级时,优先可见
-
-
- var update = function(){
-
- //先按从高到低的level排列
- object.unvisibleReasons = object.unvisibleReasons.sort((a,b)=>b.level-a.level)
- object.visibleReasons = object.visibleReasons.sort((a,b)=>b.level-a.level)
- var maxVisiLevel = object.visibleReasons[0] ? object.visibleReasons[0].level : -1
- var maxunVisiLevel = object.unvisibleReasons[0] ? object.unvisibleReasons[0].level : -1
-
- var shouldVisi = maxVisiLevel >= maxunVisiLevel
- var visiBefore = object.visible
-
-
- if(visiBefore != shouldVisi){
- object.visible = shouldVisi
- object.dispatchEvent({
- type: 'isVisible',
- visible: shouldVisi,
- reason,
- })
- }
-
-
- }
-
-
-
- if(ifShow){
- var index = object.unvisibleReasons.findIndex(e=>e.reason == reason)
- if(index > -1){
- type = 'cancel'
- object.unvisibleReasons.splice(index, 1);
- }
-
- if(type == 'add' ){
- if(!object.visibleReasons.some(e=>e.reason == reason)){
- object.visibleReasons.push({reason,level})
- }
- }
- }else{
- var index = object.visibleReasons.findIndex(e=>e.reason == reason)
- if(index > -1){
- type = 'cancel'
- object.visibleReasons.splice(index, 1);
- }
-
- if(type != 'cancel' ){
- if(!object.unvisibleReasons.some(e=>e.reason == reason)){
- object.unvisibleReasons.push({reason,level})
- }
- }
- }
-
- update()
-
- }
-
-
-
-
- Utils.getObjVisiByReason = function(object,reason){//获取在某条件下是否可见. 注: 用户在数据集选择可不可见为"datasetSelection"
- if(object.visible)return true
- else{
- return !object.unvisibleReasons || !object.unvisibleReasons.some(e=>e.reason == reason)
- }
- }
-
- Utils.setCameraLayers = function(camera, enableLayers, extraEnableLayers=[]){//add
- camera.layers.disableAll()
- enableLayers.concat(extraEnableLayers).forEach(e=>{
- let layer = Potree.config.renderLayers[e]
- if(layer == void 0){
- console.error('setCameraLayer没找到layer!');
- return
- }
- camera.layers.enable(layer)
- })
- }
- Utils.setObjectLayers = function(object, layerName){//add
- let layer = Potree.config.renderLayers[layerName]
- if(layer == void 0){
- console.error('setCameraLayer没找到layer!');
- return
- }
- object.traverse(e=>{
- e.layers.set(layer)
- })
- }
- BinaryLoader.prototype.load = function(node, callback){//解析点云
- if (node.loaded) {
- return;
- }
- let url = node.getURL();
- if (this.version.equalOrHigher('1.4')) {
- url += '.bin';
- }
- url += '?m='+node.pcoGeometry.timeStamp //add
-
- let xhr = XHRFactory.createXMLHttpRequest();
- xhr.open('GET', url, true);
- xhr.responseType = 'arraybuffer';
- xhr.overrideMimeType('text/plain; charset=x-user-defined');
- xhr.onreadystatechange = () => {
- if (xhr.readyState === 4) {
- if((xhr.status === 200 || xhr.status === 0) && xhr.response !== null){
- let buffer = xhr.response;
- this.parse(node, buffer, callback);
- } else {
- //console.error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
- throw new Error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
- }
- }
- };
-
- try {
- xhr.send(null);
- } catch (e) {
- console.log('fehler beim laden der punktwolke: ' + e);
- }
- }
- PointAttribute.RGBA_PACKED = new PointAttribute("rgba", PointAttributeTypes.DATA_TYPE_INT8, 4);
- PointAttribute.COLOR_PACKED = PointAttribute.RGBA_PACKED;
- PointAttribute.INTENSITY = new PointAttribute("intensity", PointAttributeTypes.DATA_TYPE_UINT16, 1);
- PointAttribute.CLASSIFICATION = new PointAttribute("classification", PointAttributeTypes.DATA_TYPE_UINT8, 1);
- PointAttribute.GPS_TIME = new PointAttribute("gps-time", PointAttributeTypes.DATA_TYPE_DOUBLE, 1);
- ProfileWindow.prototype.initTHREE = function(){
- this.renderer = new THREE.WebGLRenderer({alpha: true, premultipliedAlpha: false});
- this.renderer.setClearColor(0x000000, 0);
- this.renderer.setSize(10, 10);
- this.renderer.autoClear = false;
- this.renderArea.append($(this.renderer.domElement));
- this.renderer.domElement.tabIndex = '2222';
- $(this.renderer.domElement).css('width', '100%');
- $(this.renderer.domElement).css('height', '100%');
- {
- let gl = this.renderer.getContext();
- if(gl.createVertexArray == null){
- let extVAO = gl.getExtension('OES_vertex_array_object');
- if(!extVAO){
- throw new Error("OES_vertex_array_object extension not supported");
- }
- gl.createVertexArray = extVAO.createVertexArrayOES.bind(extVAO);
- gl.bindVertexArray = extVAO.bindVertexArrayOES.bind(extVAO);
- }
-
- }
- this.camera = new THREE.OrthographicCamera(-1000, 1000, 1000, -1000, -1000, 1000);
- this.camera.up.set(0, 0, 1);
- this.camera.rotation.order = "ZXY";
- this.camera.rotation.x = Math.PI / 2.0;
- this.scene = new THREE.Scene();
- this.profileScene = new THREE.Scene();
- let sg = new THREE.SphereGeometry(1, 16, 16);
- let sm = new THREE.MeshNormalMaterial();
- this.pickSphere = new THREE.Mesh(sg, sm);
- this.scene.add(this.pickSphere);
- this.viewerPickSphere = new THREE.Mesh(sg, sm);
- }
- //Potree_update_visibility
- Potree.updatePointClouds = function(pointclouds,camera, areaSize ){
- viewer.addTimeMark('updateClouds','start')
-
-
- for (let pointcloud of pointclouds) {
- let start = performance.now();
- for (let profileRequest of pointcloud.profileRequests) {
- profileRequest.update();
- let duration = performance.now() - start;
- if(duration > 5){
- break;
- }
- }
- let duration = performance.now() - start;
- }
-
-
- let result = Potree.updateVisibility(pointclouds, camera, areaSize );
- for (let pointcloud of pointclouds) {
- //pointcloud.updateMaterial(pointcloud.material, pointcloud.visibleNodes, camera, renderer);//转移到渲染时
- pointcloud.updateVisibleBounds();
- }
- Potree.lru.freeMemory();//即Potree.lru 能看到所有在加载的node
-
- viewer.addTimeMark('updateClouds','end')
- return result;
- };
-
- Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
- let frustums = {};
- let camObjPositions = {}
- let priorityQueue = new BinaryHeap(function (x) { return 1 / x.weight; });//二叉堆。
-
- viewer.addTimeMark('visiStructure','start')
- //camera.updateMatrixWorld();
- let viewI = camera.matrixWorldInverse;
- let proj = camera.projectionMatrix;
- let view = camera.matrixWorld;
- let projViewI = new THREE.Matrix4().multiply(proj).multiply(viewI)
-
- /* let list = pointclouds // stopWhenAllUsed = !viewer.lastFrameChanged
- let min = 5, max = Math.max(20 , Math.round(list.length / 10 ))
- let result = Common.batchHandling.getSlice('pcGetFrustum', list, { min,max, durBound1: 3, durBound2: 10} ) //iphonex稳定后大概在7-10。
- */
-
-
-
- for (let i = 0; i < pointclouds.length; i++) {
- let pointcloud = pointclouds[i];
- if (!pointcloud.initialized()) {
- continue;
- }
-
- /* let info = history.get(pointcloud)
- if() */
-
-
- pointcloud.numVisibleNodes = 0;
- pointcloud.numVisiblePoints = 0;
- pointcloud.deepestVisibleLevel = 0;
- pointcloud.visibleNodes = [];
- pointcloud.visibleGeometry = [];
- // 因漫游模式而隐藏的话 依旧需要加入visibleNodes,因为pick需要
- /* if (pointcloud.visible && pointcloud.root !== null) {
- priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
- } */
-
- if (pointcloud.visible || !pointcloud.hasDepthTex && pointcloud.unvisibleReasons && pointcloud.unvisibleReasons.length == 1 && pointcloud.unvisibleReasons[0].reason == 'displayMode' && pointcloud.root !== null) {//改 visible ->
- priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
- }else{
- continue
- }
-
-
- // frustum in object space
-
- let frustum = new THREE.Frustum();
-
- let world = pointcloud.matrixWorld;
-
- // use close near plane for frustum intersection
- /* let frustumCam = camera.clone();
- frustumCam.zoom = camera.zoom //add
- frustumCam.near = Math.min(camera.near, 0.1);
- frustumCam.updateProjectionMatrix(); */ //----没用到frustumCam,删了
-
- let fm = new THREE.Matrix4().multiply(projViewI).multiply(world);
- frustum.setFromProjectionMatrix(fm);
- frustums[i] = frustum //frustums.push(frustum);
- // camera position in object space
-
- let worldI = pointcloud.matrixWorldInverse
- let camMatrixObject = new THREE.Matrix4().multiply(worldI).multiply(view);
- let camObjPos = new THREE.Vector3().setFromMatrixPosition(camMatrixObject);
- camObjPositions[i] = camObjPos//camObjPositions.push(camObjPos);
-
- // hide all previously visible nodes
- // if(pointcloud.root instanceof PointCloudOctreeNode){
- // pointcloud.hideDescendants(pointcloud.root.sceneNode);
- // }
- if (pointcloud.root.isTreeNode()) {
- pointcloud.hideDescendants(pointcloud.root.sceneNode);
- }
- for (let j = 0; j < pointcloud.boundingBoxNodes.length; j++) {
- pointcloud.boundingBoxNodes[j].visible = false;
- }
- }
- viewer.addTimeMark('visiStructure','end')
-
- return {
- 'frustums': frustums,
- 'camObjPositions': camObjPositions,
- 'priorityQueue': priorityQueue
- };
- };
- Potree.updateVisibility = function(pointclouds, camera, areaSize){
- let numVisibleNodes = 0;
- let numVisiblePoints = 0;
- let numVisiblePointsInPointclouds = new Map(pointclouds.map(pc => [pc, 0]));
- let visibleNodes = [];
- let visibleGeometry = [];
- let unloadedGeometry = [];
- let lowestSpacing = Infinity;
- // calculate object space frustum and cam pos and setup priority queue
- let s = Potree.updateVisibilityStructures(pointclouds, camera, areaSize);//得到相机可见范围
- let frustums = s.frustums;
- let camObjPositions = s.camObjPositions;
- let priorityQueue = s.priorityQueue;
- let loadedToGPUThisFrame = 0;
-
- let domWidth = areaSize.x; //renderer.domElement.clientWidth;
- let domHeight = areaSize.y;//renderer.domElement.clientHeight;
- let fov = (camera.fov * Math.PI) / 180;
- let slope = Math.tan(fov / 2);
- let projFactor0 = (0.5 * domHeight) / slope ;
-
-
- // check if pointcloud has been transformed
- // some code will only be executed if changes have been detected
- if(!Potree._pointcloudTransformVersion){
- Potree._pointcloudTransformVersion = new Map();
- }
- let pointcloudTransformVersion = Potree._pointcloudTransformVersion;
- for(let pointcloud of pointclouds){
- if(pointcloud.hasDepthTex ? !pointcloud.visible : !Potree.Utils.getObjVisiByReason(pointcloud, 'datasetSelection')){//改 visible ->
- continue;
- }
-
- //if(!pointcloud.visible) continue
- pointcloud.updateMatrixWorld();
- if(!pointcloudTransformVersion.has(pointcloud)){
- pointcloudTransformVersion.set(pointcloud, {number: 0, transform: pointcloud.matrixWorld.clone()});
- }else{
- let version = pointcloudTransformVersion.get(pointcloud);
- if(!version.transform.equals(pointcloud.matrixWorld)){
- version.number++;
- version.transform.copy(pointcloud.matrixWorld);
- pointcloud.dispatchEvent({
- type: "transformation_changed",
- target: pointcloud
- });
- }
- }
- }
-
-
- while (priorityQueue.size() > 0) {
- let element = priorityQueue.pop(); //取出权重最大的一个
-
- let node = element.node;
- let parent = element.parent;
- let pointcloud = pointclouds[element.pointcloud];
- // { // restrict to certain nodes for debugging
- // let allowedNodes = ["r", "r0", "r4"];
- // if(!allowedNodes.includes(node.name)){
- // continue;
- // }
- // }
- let box = node.getBoundingBox();
- let frustum = frustums[element.pointcloud];
- let camObjPos = camObjPositions[element.pointcloud];
- if(!frustum) continue //add
- let insideFrustum = frustum.intersectsBox(box);
- let maxLevel = pointcloud.maxLevel == void 0 ? Infinity : pointcloud.maxLevel;
- let level = node.getLevel();
- let visible = insideFrustum;
- visible = visible && !(numVisiblePoints + node.getNumPoints() > Potree.pointBudget);
- visible = visible && !(numVisiblePointsInPointclouds.get(pointcloud) + node.getNumPoints() > pointcloud.pointBudget); // pointcloud.pointBudget一直是Infinity
- visible = visible && level <= maxLevel; //< 改为 <=
- //visible = visible || node.getLevel() <= 2;
- let intersectBox = (clipBox)=>{
- let pcWorldInverse = pointcloud.matrixWorld.clone().invert();
- let toPCObject = pcWorldInverse.multiply(clipBox.box.matrixWorld); //box乘上点云逆矩阵
- /* let px = new THREE.Vector3(+0.5, 0, 0).applyMatrix4(pcWorldInverse);
- let nx = new THREE.Vector3(-0.5, 0, 0).applyMatrix4(pcWorldInverse);
- let py = new THREE.Vector3(0, +0.5, 0).applyMatrix4(pcWorldInverse);
- let ny = new THREE.Vector3(0, -0.5, 0).applyMatrix4(pcWorldInverse);
- let pz = new THREE.Vector3(0, 0, +0.5).applyMatrix4(pcWorldInverse);
- let nz = new THREE.Vector3(0, 0, -0.5).applyMatrix4(pcWorldInverse);
- let pxN = new THREE.Vector3().subVectors(nx, px).normalize();
- let nxN = pxN.clone().multiplyScalar(-1);
- let pyN = new THREE.Vector3().subVectors(ny, py).normalize();
- let nyN = pyN.clone().multiplyScalar(-1);
- let pzN = new THREE.Vector3().subVectors(nz, pz).normalize();
- let nzN = pzN.clone().multiplyScalar(-1);
- let pxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pxN, px);
- let nxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nxN, nx);
- let pyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pyN, py);
- let nyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nyN, ny);
- let pzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pzN, pz);
- let nzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nzN, nz);
- //if(window.debugdraw !== undefined && window.debugdraw === true && node.name === "r60"){
- // Potree.utils.debugPlane(viewer.scene.scene, pxPlane, 1, 0xFF0000);
- // Potree.utils.debugPlane(viewer.scene.scene, nxPlane, 1, 0x990000);
- // Potree.utils.debugPlane(viewer.scene.scene, pyPlane, 1, 0x00FF00);
- // Potree.utils.debugPlane(viewer.scene.scene, nyPlane, 1, 0x009900);
- // Potree.utils.debugPlane(viewer.scene.scene, pzPlane, 1, 0x0000FF);
- // Potree.utils.debugPlane(viewer.scene.scene, nzPlane, 1, 0x000099);
- // Potree.utils.debugBox(viewer.scene.scene, box, new THREE.Matrix4(), 0x00FF00);
- // Potree.utils.debugBox(viewer.scene.scene, box, pointcloud.matrixWorld, 0xFF0000);
- // Potree.utils.debugBox(viewer.scene.scene, clipBox.box.boundingBox, clipBox.box.matrixWorld, 0xFF0000);
- // window.debugdraw = false;
- //}
- let frustum = new THREE.Frustum(pxPlane, nxPlane, pyPlane, nyPlane, pzPlane, nzPlane);
- let intersects = frustum.intersectsBox(box); //node的bounding
-
- return !!intersects */
-
-
- return Potree.Utils.isIntersectBox(box, pcWorldInverse)
-
-
- }
- //改 总共两种box : 可见和不可见(都是并集)
-
-
-
- let clipBoxes_in = pointcloud.material.clipBoxes_in;
- let clipBoxes_out = pointcloud.material.clipBoxes_out;
- let bigClipInBox = pointcloud.material.bigClipInBox
-
- if(visible && bigClipInBox){//不在剪裁下载的框内
- if(!intersectBox(bigClipInBox)){
- visible = false;
- }
- }
-
-
- if(visible && clipBoxes_in.length > 0){//当有可见box时,需要在任一可见box内才可见
- let visi = false;
- for(let i = 0, length=clipBoxes_in.length; i < length; i++){
- if(intersectBox(clipBoxes_in[i])){
- visi = true;
- break;
- }
- }
- if(!visi){
- visible = false
- }
- }
-
-
- //outside不做处理。因为node必须完全在clipBox内才能完全隐藏,而这里的intersect只能识别出部分在clipBox内。因而只能说明不在任意一个box内绝对可见,没有意义,这里需要找出不可见的。
- /* if(visible && clipBoxes_out.length > 0){ //当有不可见box时,不在所有不可见box内才可见
- let visi = true;
- for(let i = 0,length=clipBoxes_out.length; i < length; i++){
- if(intersectBox(clipBoxes_out[i])){
- visi = false;
- break;
- }
- }
- if(!visi){
- visible = false
- }
- }
- */
- // visible = ["r", "r0", "r06", "r060"].includes(node.name);
- // visible = ["r"].includes(node.name);
- if (node.spacing) {
- lowestSpacing = Math.min(lowestSpacing, node.spacing);
- } else if (node.geometryNode && node.geometryNode.spacing) {
- lowestSpacing = Math.min(lowestSpacing, node.geometryNode.spacing);
- }
- if (numVisiblePoints + node.getNumPoints() > Potree.pointBudget) {
- break;
- }
- if (!visible) {
- continue;
- }
- // TODO: not used, same as the declaration?
- // numVisibleNodes++;
- numVisiblePoints += node.getNumPoints();
- let numVisiblePointsInPointcloud = numVisiblePointsInPointclouds.get(pointcloud);
- numVisiblePointsInPointclouds.set(pointcloud, numVisiblePointsInPointcloud + node.getNumPoints());
- pointcloud.numVisibleNodes++;
- pointcloud.numVisiblePoints += node.getNumPoints();
- if (node.isGeometryNode() && (!parent || parent.isTreeNode())) {
- if (node.isLoaded() && loadedToGPUThisFrame < 2) {
- node = pointcloud.toTreeNode(node, parent);
- loadedToGPUThisFrame++;
- } else {
- //console.log('unloadedGeometry',node)
- unloadedGeometry.push({pointcloud,node}); //加载点云。虽然还没加载,但也计入了visibleNodes,只是无children,numPoints=0
- visibleGeometry.push(node);
- }
- }
- if (node.isTreeNode()) {
- Potree.lru.touch(node.geometryNode);//在缓存中计入点云
- node.sceneNode.visible = true;
- node.sceneNode.material = pointcloud.material;
- visibleNodes.push(node);
- pointcloud.visibleNodes.push(node);
- if(node._transformVersion === undefined){
- node._transformVersion = -1;
- }
- let transformVersion = pointcloudTransformVersion.get(pointcloud);
- if(node._transformVersion !== transformVersion.number){
- node.sceneNode.updateMatrix();
- //node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);
- node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);
-
- node._transformVersion = transformVersion.number;
-
- }
-
- if (pointcloud.showBoundingBox && !node.boundingBoxNode && node.getBoundingBox) {
- let boxHelper = new Box3Helper(node.getBoundingBox());
- boxHelper.matrixAutoUpdate = false;
- pointcloud.boundingBoxNodes.push(boxHelper);
- node.boundingBoxNode = boxHelper;
- node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
- } else if (pointcloud.showBoundingBox) {
- node.boundingBoxNode.visible = true;
- node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
- } else if (!pointcloud.showBoundingBox && node.boundingBoxNode) {
- node.boundingBoxNode.visible = false;
- }
- // if(node.boundingBoxNode !== undefined && exports.debug.allowedNodes !== undefined){
- // if(!exports.debug.allowedNodes.includes(node.name)){
- // node.boundingBoxNode.visible = false;
- // }
- // }
- }
- // add child nodes to priorityQueue 由近及远、由大及小逐渐加载
- let children = node.getChildren();
- for (let i = 0; i < children.length; i++) {
- let child = children[i];
- let weight = 0;
- if(camera.isPerspectiveCamera){
- let sphere = child.getBoundingSphere();
- let center = sphere.center;
- let dd = sphere.center.distanceToSquared(camObjPos);
-
- const addPow = 0.25 //0-0.5,正常原本是0. 数字越大近处加载越快。但会造成远处加载慢甚至因pointBudge限制不加载
- let distance = Math.pow(dd,0.5+addPow)//Math.sqrt(dd); //提高距离权重,为了提高近处加载速度。 某些场景近处加载慢优化明显,如SS-t-cqCAL6rJ5i
-
- //let attenuateDis = 10;//add
- let radius = sphere.radius;
-
- let projFactor = projFactor0 / distance
- let screenPixelRadius = radius * projFactor;
-
- /* if(distance > attenuateDis){
- screenPixelRadius -= (distance - attenuateDis) * Math.sqrt(radius) * projFactor0 * 0.002
- } */
-
- //screenPixelRadius 和 domHeight 成正比,所以手机横屏后screenPixelRadius会变小。这是正常的,因为vhov不变,相同物体高度在横屏后高度变小,所需要的密度不需要那么高了。但hfov横屏后扩大,所以可见的node范围变大,又增加了一些可见node;只是总体的可见node还是减少了。
- //使用hfov和domWidth计算结果相同。
- if(screenPixelRadius < pointcloud.minimumNodePixelSize / Math.pow(dd,addPow)){ //理论上因手机像素小,更不容易堆叠铺满,minimumNodePixelSize应该除以window.deviceRatio 但会造成加载过多,而内存小
- continue;
- }
- //如果能得到该方向上的密度,也就是node数量,密度大的远处少加载,因为被遮挡了显示也没有意义,就好了。
- weight = screenPixelRadius;
- if(distance - radius < 0){
- weight = Number.MAX_VALUE;
- }
- } else {
- // TODO ortho visibility
- //let bb = child.getBoundingBox();
- let sphere = child.getBoundingSphere();
- //let diagonal = bb.max.clone().sub(bb.min).length();
- const reduce = 0 //0-0.5,正常原本是0.
- if( sphere.radius * /* Math.pow( */camera.zoom/* ,1-reduce) */ < pointcloud.minimumNodePixelSize ){
- continue;
- }
-
- let distance = sphere.center.distanceToSquared(camObjPos); //先加载中间然后四周
- weight = sphere.radius / distance;
-
- //weight = diagonal;
- }
- priorityQueue.push({pointcloud: element.pointcloud, node: child, parent: node, weight: weight}); //貌似好像二叉堆中子节点和父节点没什么关系,就只是为了方便排序层层遍历
- }
- //手机上像素点更小,所以远处感觉会更稀疏
- }// end priority queue loop
- { // update DEM 这是什么
- let maxDEMLevel = 4;
- let candidates = pointclouds.filter(p => (p.generateDEM && p.dem instanceof Potree.DEM));
- for (let pointcloud of candidates) {
- let updatingNodes = pointcloud.visibleNodes.filter(n => n.getLevel() <= maxDEMLevel);
- pointcloud.dem.update(updatingNodes);
- }
- }
-
-
-
-
- if(unloadedGeometry.length){//加载点云
-
- /* for (let i = 0; i < Math.min(Potree.maxNodesLoading, unloadedGeometry.length); i++) {
- unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry);
- } */
-
- let maxNodesLoading = Common.getBestCount('unloadedGeometry', viewer.lastFrameChanged?1:3, 6, 4, 15 /* , true */ )//dur在iphoneX中静止有7,pc是2 //!lastFrameChanged静止时加速下载
- //THREE.Math.clamp(Math.round(9 - dur), 1, 6 )
-
- //主要在手机端有效果。不改之前在展示的点云较多时前进会卡。
- for (let i = 0; i < Math.min(maxNodesLoading, unloadedGeometry.length); i++) {
- unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry);
- }
- }
-
-
-
-
- //add:
- Potree.numVisiblePoints = numVisiblePoints
-
- return {
- visibleNodes: visibleNodes,
- numVisiblePoints: numVisiblePoints,
- lowestSpacing: lowestSpacing
- };
- };
- /*
- note:
- 缓存中的点数 Potree.lru.numPoints 一般会 大于 每个点云显示点总数的numVisiblePoints
- 当超出缓冲区最大点云数时,加载的点云节点会被dispose彻底消除;否则,隐藏的节点就会等待再次被使用显示
- 由于加载按照由近及远、由大及小的顺序,要降低卡顿,就只需要降低Potree.pointBudget即可。但目前只设置了三个层次;另外提供maxLevel细节调节,能显示更均匀. 最好多一个调节pointBudge的滑动条
-
- Potree.lru.numPoints
- Potree.numVisiblePoints
- viewer.scene.pointclouds[0].visibleNodes.length
- */
-
-
-
-
-
-
- {//HQSplatRenderer
- let oldInit = HQSplatRenderer.prototype.init;
- HQSplatRenderer.prototype.init = function(){
- oldInit()
- viewer.addEventListener('resize',this.resize.bind(this))
- }
-
- HQSplatRenderer.prototype.resize = function(e){
- this.rtDepth.setSize(e.canvasWidth, e.canvasHeight);
- this.rtAttribute.setSize(e.canvasWidth, e.canvasHeight);
- }
-
- HQSplatRenderer.prototype.clear = function(params={}){
- this.init();
- const {renderer, background} = this.viewer;
- if(background === "skybox"){
- renderer.setClearColor(0x000000, 0);
- } else if (background === 'gradient') {
- renderer.setClearColor(0x000000, 0);
- } else if (background === 'black') {
- renderer.setClearColor(0x000000, 1);
- } else if (background === 'white') {
- renderer.setClearColor(0xFFFFFF, 1);
- } else {
- renderer.setClearColor(0x000000, 0);
- }
- params.target || renderer.clear();
- this.clearTargets(params);
- }
- HQSplatRenderer.prototype.render = function(params={}) {
- this.init();
- const viewer = this.viewer;
- const camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
- const {width, height} = params.width ? params : this.viewer.renderer.getSize(new THREE.Vector2());
- viewer.renderer.setRenderTarget(params.target||null);
- viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
- //params.target || this.resize(width, height);
- const visiblePointClouds = viewer.scene.pointclouds.filter(pc => pc.visible);
- const originalMaterials = new Map();
- for(let pointcloud of visiblePointClouds){
- originalMaterials.set(pointcloud, pointcloud.material);
- if(!this.attributeMaterials.has(pointcloud)){
- let attributeMaterial = new ExtendPointCloudMaterial();
- this.attributeMaterials.set(pointcloud, attributeMaterial);
- }
- if(!this.depthMaterials.has(pointcloud)){
- let depthMaterial = new ExtendPointCloudMaterial();
- depthMaterial.setDefine("depth_pass", "#define hq_depth_pass");
- depthMaterial.setDefine("use_edl", "#define use_edl");
- this.depthMaterials.set(pointcloud, depthMaterial);
- }
- }
- { // DEPTH PASS
- for (let pointcloud of visiblePointClouds) {
- let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
- let material = originalMaterials.get(pointcloud);
- let depthMaterial = this.depthMaterials.get(pointcloud);
- depthMaterial.size = material.size;
- depthMaterial.minSize = material.minSize;
- depthMaterial.maxSize = material.maxSize;
- depthMaterial.pointSizeType = material.pointSizeType;
- depthMaterial.visibleNodesTexture = material.visibleNodesTexture;
- depthMaterial.weighted = false;
- depthMaterial.screenWidth = width;
- depthMaterial.shape = PointShape.CIRCLE;
- depthMaterial.screenHeight = height;
- depthMaterial.uniforms.visibleNodes.value = material.visibleNodesTexture;
- depthMaterial.uniforms.octreeSize.value = octreeSize;
- depthMaterial.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(...pointcloud.scale.toArray());
- depthMaterial.classification = material.classification;
- depthMaterial.uniforms.classificationLUT.value.image.data = material.uniforms.classificationLUT.value.image.data;
- depthMaterial.classificationTexture.needsUpdate = true;
- depthMaterial.uniforms.uFilterReturnNumberRange.value = material.uniforms.uFilterReturnNumberRange.value;
- depthMaterial.uniforms.uFilterNumberOfReturnsRange.value = material.uniforms.uFilterNumberOfReturnsRange.value;
- depthMaterial.uniforms.uFilterGPSTimeClipRange.value = material.uniforms.uFilterGPSTimeClipRange.value;
- depthMaterial.uniforms.uFilterPointSourceIDClipRange.value = material.uniforms.uFilterPointSourceIDClipRange.value;
- depthMaterial.clipTask = material.clipTask;
- depthMaterial.clipMethod = material.clipMethod;
- depthMaterial.setClipBoxes(material.clipBoxes);
- depthMaterial.setClipPolygons(material.clipPolygons);
- pointcloud.material = depthMaterial;
- }
-
- viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, (params.rtEDL || this.rtDepth), {
- clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
- });
- }
- { // ATTRIBUTE PASS
- for (let pointcloud of visiblePointClouds) {
- let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
- let material = originalMaterials.get(pointcloud);
- let attributeMaterial = this.attributeMaterials.get(pointcloud);
- attributeMaterial.size = material.size;
- attributeMaterial.minSize = material.minSize;
- attributeMaterial.maxSize = material.maxSize;
- attributeMaterial.pointSizeType = material.pointSizeType;
- attributeMaterial.activeAttributeName = material.activeAttributeName;
- attributeMaterial.visibleNodesTexture = material.visibleNodesTexture;
- attributeMaterial.weighted = true;
- attributeMaterial.screenWidth = width;
- attributeMaterial.screenHeight = height;
- attributeMaterial.shape = PointShape.CIRCLE;
- attributeMaterial.uniforms.visibleNodes.value = material.visibleNodesTexture;
- attributeMaterial.uniforms.octreeSize.value = octreeSize;
- attributeMaterial.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(...pointcloud.scale.toArray());
- attributeMaterial.classification = material.classification;
- attributeMaterial.uniforms.classificationLUT.value.image.data = material.uniforms.classificationLUT.value.image.data;
- attributeMaterial.classificationTexture.needsUpdate = true;
- attributeMaterial.uniforms.uFilterReturnNumberRange.value = material.uniforms.uFilterReturnNumberRange.value;
- attributeMaterial.uniforms.uFilterNumberOfReturnsRange.value = material.uniforms.uFilterNumberOfReturnsRange.value;
- attributeMaterial.uniforms.uFilterGPSTimeClipRange.value = material.uniforms.uFilterGPSTimeClipRange.value;
- attributeMaterial.uniforms.uFilterPointSourceIDClipRange.value = material.uniforms.uFilterPointSourceIDClipRange.value;
- attributeMaterial.elevationGradientRepeat = material.elevationGradientRepeat;
- attributeMaterial.elevationRange = material.elevationRange;
- attributeMaterial.gradient = material.gradient;
- attributeMaterial.matcap = material.matcap;
- attributeMaterial.intensityRange = material.intensityRange;
- attributeMaterial.intensityGamma = material.intensityGamma;
- attributeMaterial.intensityContrast = material.intensityContrast;
- attributeMaterial.intensityBrightness = material.intensityBrightness;
- attributeMaterial.rgbGamma = material.rgbGamma;
- attributeMaterial.rgbContrast = material.rgbContrast;
- attributeMaterial.rgbBrightness = material.rgbBrightness;
- attributeMaterial.weightRGB = material.weightRGB;
- attributeMaterial.weightIntensity = material.weightIntensity;
- attributeMaterial.weightElevation = material.weightElevation;
- attributeMaterial.weightRGB = material.weightRGB;
- attributeMaterial.weightClassification = material.weightClassification;
- attributeMaterial.weightReturnNumber = material.weightReturnNumber;
- attributeMaterial.weightSourceID = material.weightSourceID;
- attributeMaterial.color = material.color;
- attributeMaterial.clipTask = material.clipTask;
- attributeMaterial.clipMethod = material.clipMethod;
- attributeMaterial.setClipBoxes(material.clipBoxes);
- attributeMaterial.setClipPolygons(material.clipPolygons);
- pointcloud.material = attributeMaterial;
- }
-
- let gl = this.gl;
- //viewer.renderer.setRenderTarget(null);
- viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, this.rtAttribute, {
- clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
- //material: this.attributeMaterial,
- blendFunc: [gl.SRC_ALPHA, gl.ONE],
- //depthTest: false,
- depthWrite: false
- });
- }
- for(let [pointcloud, material] of originalMaterials){
- pointcloud.material = material;
- }
-
-
-
-
-
- if(viewer.background === "skybox"){
- viewer.renderer.setClearColor(0x000000, 0);
- viewer.renderer.clear();
- viewer.skybox.camera.rotation.copy(viewer.scene.cameraP.rotation);
- viewer.skybox.camera.fov = viewer.scene.cameraP.fov;
- viewer.skybox.camera.aspect = viewer.scene.cameraP.aspect;
-
- viewer.skybox.parent.rotation.x = 0;
- viewer.skybox.parent.updateMatrixWorld();
- viewer.skybox.camera.updateProjectionMatrix();
- viewer.renderer.render(viewer.skybox.scene, viewer.skybox.camera);
- } else if (viewer.background === 'gradient') {
- viewer.renderer.setClearColor(0x000000, 0);
- viewer.renderer.clear();
- viewer.renderer.render(viewer.scene.sceneBG, viewer.scene.cameraBG);
- } else if (viewer.background === 'black') {
- viewer.renderer.setClearColor(0x000000, 1);
- viewer.renderer.clear();
- } else if (viewer.background === 'white') {
- viewer.renderer.setClearColor(0xFFFFFF, 1);
- viewer.renderer.clear();
- } else {
- viewer.renderer.setClearColor(0x000000, 0);
- viewer.renderer.clear();
- }
-
- { // NORMALIZATION PASS
- let normalizationMaterial = this.useEDL ? this.normalizationEDLMaterial : this.normalizationMaterial;
- if(this.useEDL){
- normalizationMaterial.uniforms.edlStrength.value = viewer.edlStrength;
- normalizationMaterial.uniforms.radius.value = viewer.edlRadius;
- normalizationMaterial.uniforms.screenWidth.value = width;
- normalizationMaterial.uniforms.screenHeight.value = height;
- normalizationMaterial.uniforms.uEDLMap.value = (params.rtEDL || this.rtDepth).texture;
- }
- normalizationMaterial.uniforms.uWeightMap.value = this.rtAttribute.texture;
- normalizationMaterial.uniforms.uDepthMap.value = this.rtAttribute.depthTexture;
-
- Utils.screenPass.render(viewer.renderer, normalizationMaterial);
- }
- viewer.renderer.render(viewer.scene.scene, camera);
- viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer});
- viewer.renderer.render(viewer.scene.sceneOverlay, camera);// add 透明贴图层
- viewer.renderer.clearDepth();
- viewer.transformationTool.update();
- if(!params.target){
-
-
- //测量线
- viewer.dispatchEvent({type: "render.pass.perspective_overlay",viewer: viewer, camera});
- viewer.renderer.render(viewer.overlay, camera);//从 viewer.renderDefault搬过来,为了reticule不遮住测量线
- }
- viewer.renderer.render(viewer.controls.sceneControls, camera);
- viewer.renderer.render(viewer.clippingTool.sceneVolume, camera);
- viewer.renderer.render(viewer.transformationTool.scene, camera);
- viewer.renderer.setViewport(width - viewer.navigationCube.width,
- height - viewer.navigationCube.width,
- viewer.navigationCube.width, viewer.navigationCube.width);
- viewer.renderer.render(viewer.navigationCube, viewer.navigationCube.camera);
- viewer.renderer.setViewport(0, 0, width, height);
-
- viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
- viewer.renderer.setRenderTarget(null)
- }
-
- }
-
-
- //PointCloudOctreeGeometry.js
- PointCloudOctreeGeometryNode.prototype.loadHierachyThenPoints = function(pointcloud){
- let node = this;
- // load hierarchy
- let callback = function (node, hbuffer) {
- let tStart = performance.now();
- let view = new DataView(hbuffer);
- let stack = [];
- let children = view.getUint8(0);
- let numPoints = view.getUint32(1, true);
- node.numPoints = numPoints;
- stack.push({children: children, numPoints: numPoints, name: node.name});
- let decoded = [];
- let offset = 5;
- while (stack.length > 0) {
- let snode = stack.shift();
- let mask = 1;
- for (let i = 0; i < 8; i++) {
- if ((snode.children & mask) !== 0) {
- let childName = snode.name + i;
- let childChildren = view.getUint8(offset);
- let childNumPoints = view.getUint32(offset + 1, true);
- stack.push({children: childChildren, numPoints: childNumPoints, name: childName});
- decoded.push({children: childChildren, numPoints: childNumPoints, name: childName});
- offset += 5;
- }
- mask = mask * 2;
- }
- if (offset === hbuffer.byteLength) {
- break;
- }
- }
- // console.log(decoded);
- let nodes = {};
- nodes[node.name] = node;
- let pco = node.pcoGeometry;
- let maxLevel_ = 0
- for (let i = 0; i < decoded.length; i++) {
- let name = decoded[i].name;
- let decodedNumPoints = decoded[i].numPoints;
- let index = parseInt(name.charAt(name.length - 1));
- let parentName = name.substring(0, name.length - 1);
- let parentNode = nodes[parentName];
- let level = name.length - 1;
- maxLevel_ = Math.max(maxLevel_,level)//add
-
- let boundingBox = Utils.createChildAABB(parentNode.boundingBox, index);
- let currentNode = new PointCloudOctreeGeometryNode(name, pco, boundingBox);
- currentNode.level = level;
- currentNode.numPoints = decodedNumPoints;
- currentNode.hasChildren = decoded[i].children > 0;
- currentNode.spacing = pco.spacing / Math.pow(2, level);
- parentNode.addChild(currentNode);
- nodes[name] = currentNode;
- }
- pco.dispatchEvent({type:'updateNodeMaxLevel',level:maxLevel_});//add
- let duration = performance.now() - tStart;
- if(duration > 5){
- /* let msg = `duration: ${duration}ms, numNodes: ${decoded.length}`;
- console.log(msg); */
- }
- node.loadPoints();
- };
- if ((node.level % node.pcoGeometry.hierarchyStepSize) === 0) {
- // let hurl = node.pcoGeometry.octreeDir + "/../hierarchy/" + node.name + ".hrc";
- let hurl = node.pcoGeometry.octreeDir + '/' + node.getHierarchyPath() + '/' + node.name + '.hrc';
- hurl += '?m='+node.pcoGeometry.timeStamp //add
-
- let xhr = XHRFactory.createXMLHttpRequest();
- xhr.open('GET', hurl, true);
- xhr.responseType = 'arraybuffer';
- xhr.overrideMimeType('text/plain; charset=x-user-defined');
- xhr.onreadystatechange = () => {
- if (xhr.readyState === 4) {
- if (xhr.status === 200 || xhr.status === 0) {
- let hbuffer = xhr.response;
- callback(node, hbuffer);
- } else {
- console.log('Failed to load file! HTTP status: ' + xhr.status + ', file: ' + hurl);
- Potree.numNodesLoading--;
- }
- }
- };
- try {
- xhr.send(null);
- } catch (e) {
- console.log('fehler beim laden der punktwolke: ' + e);
- }
- }
- }
- PointCloudOctreeGeometryNode.prototype.loadPoints = function(){
- let name = this.name
- this.pcoGeometry.loader.load(this, ()=>{//callback
- viewer.dispatchEvent('pointcloud_changed')
-
-
- //console.log('loadPoints success ', name)
- });
- }
- //加载点云成功->准备渲染画面->更新点云可见性updateVisibility->请求加载新的点云
-
- PointCloudOctreeGeometryNode.prototype.traverse = function(t, e){//add from navvis 25.js
- void 0 === e && (e = !0);
- for (var n, i = e ? [this] : []; void 0 !== (n = i.pop()); ) {
- t(n);
- for (var o = 0, r = n.children; o < r.length; o++) {
- var a = r[o];
- null !== a && i.push(a)
- }
- }
- }
- Object.assign( PointCloudOctreeGeometry.prototype, THREE.EventDispatcher.prototype );
- LRU.prototype.freeMemory = function(){
-
- if (this.elements <= 1) {
- return;
- }
- let memoryRatio = browser.isMobile ? 2 : 5;
- //改成navvis的,使用pointBudget,否则四屏点云闪烁。 (似乎要比updateVisiblede的node时限制要宽些,作为缓存继续存着。否则会闪烁)
- let max = viewer.viewports.length * memoryRatio * Potree.pointBudget
-
- for (; this.numPoints > max; ) {
- var node = this.getLRUItem();
- node && this.disposeDescendants(node); //this.disposeSubtree(node)
- }
-
- }
- /*
- LRU.prototype.disposeSubtree = function(t) {//add from navvis 25.js 和原来的disposeDescendants功能一样
- var e = [t];
- t.traverse((function(t) {
- t.loaded && e.push(t)
- }));
- for (var n = 0, i = e; n < i.length; n++) {
- var o = i[n];
- o.dispose(),
- this.remove(o)
- }
- }*/
- VolumeTool.prototype.update = function(){}
- VolumeTool.prototype.startInsertion = function(args = {}){
-
- let volume;
-
- if(args.type){
- volume = new args.type();
- }else{
- volume = new Potree.BoxVolume(Object.assign(args,{clip:true}) );
- }
- volume.highlight = true
- volume.name = args.name || 'Volume-'+args.clipTask;
- volume.isNew = true
- viewer.transformObject(null)//先清空
- //console.log('startInsertion',volume.uuid)
- let oldVisiBoxes
- if(args.clipTask == Potree.ClipTask.SHOW_INSIDE){ //如果是显示类型,需要将所有同类型的解除效果,否则看不到效果。 (或者可以在添加非第一个时去除highlight效果,会更自然,但看不清全貌)
- oldVisiBoxes = viewer.scene.volumes.filter(v => v.clipTask == Potree.ClipTask.SHOW_INSIDE && !v.highlight )
- oldVisiBoxes.forEach(box=>box.highlight = true)
- }
-
-
- let updatePose = ()=>{ //保证在视野中的大小一致:
- let camera = this.viewer.scene.getActiveCamera();
- let w = math.getScaleForConstantSize({
- width2d: 300,
- camera , position:volume.getWorldPosition(new THREE.Vector3()) ,
- resolution: viewer.mainViewport.resolution//2
- })
- /* let wp = volume.getWorldPosition(new THREE.Vector3()).applyMatrix4(camera.matrixWorldInverse);
- // let pp = new THREE.Vector4(wp.x, wp.y, wp.z).applyMatrix4(camera.projectionMatrix);
- let w = Math.abs((wp.z / 3));*/
- if(!isNaN(w))volume.scale.set(w, w, w);
-
-
- {//使水平朝向与camera一致
- let direction = viewer.mainViewport.view.direction.setZ(0)
- volume.quaternion.copy(math.getQuaByAim(direction))
- }
-
- }
- this.dispatchEvent({
- type: 'start_inserting_volume',
- volume: volume
- });
- updatePose()
- this.viewer.scene.addVolume(volume);
- this.scene.add(volume);
-
-
-
-
- let drag = e => {
-
- let I = Utils.getMousePointCloudIntersection(
- viewer.mainViewport,
- viewer.inputHandler.mouse,
- viewer.inputHandler.pointer,
- this.viewer.scene.getActiveCamera(),
- this.viewer,
- this.viewer.scene.pointclouds,
- {pickClipped: args.clipTask == Potree.ClipTask.SHOW_OUTSIDE } //无视clip状态
- );
-
- var worldPos = I && I.location
- if(!worldPos){
- return
- }
-
- volume.position.copy(worldPos);
-
- updatePose()
- };
-
-
-
-
- let cancel = ()=>{
- end('remove')
- }
- let end = (e) => {
- if(e.button == THREE.MOUSE.RIGHT && e.pressDistance<=Potree.config.clickMaxDragDis) {//remove
- e = 'remove'
- }
- //console.log('end',volume.uuid, e)
- if(e != 'remove' && (!e.isAtDomElement || e.pressDistance>Potree.config.clickMaxDragDis))return continueDrag()
- volume.removeEventListener('drag', drag);
- volume.removeEventListener('drop', end);
- this.viewer.removeEventListener('cancel_insertions', cancel);
- volume.isNew = false
- viewer.removeEventListener('camera_changed', updatePose)
- if(e == 'remove'){
- viewer.scene.removeVolume(volume); //删除没完成的
- }else{
- viewer.transformObject(volume)
- volume.highlight = false
-
- }
-
- volume.dispatchEvent({type:'createFinish', success:e != 'remove' })
- oldVisiBoxes && oldVisiBoxes.forEach(box=>box.highlight = false)
- };
-
- let continueDrag = ( )=>{
- //console.log('continueDrag',volume.uuid )
- var timer = setTimeout(()=>{//等 drag=null之后 //右键拖拽结束后需要重新得到drag
- if(volume.parent && volume.isNew){
- viewer.inputHandler.startDragging( volume , {notPressMouse:true}
- /* {endDragFun: e.drag.endDragFun, notPressMouse:e.drag.notPressMouse, dragViewport:e.drag.dragViewport} */
- )
- }
- },1)
- return timer
- }
-
- volume.addEventListener('drag', drag);
- volume.addEventListener('drop', end);
-
- this.viewer.addEventListener('cancel_insertions', cancel);
- viewer.addEventListener('camera_changed', updatePose)
-
- this.viewer.inputHandler.startDragging(volume, {notPressMouse:true});
-
- return volume;
- }
- LineGeometry.prototype.setPositions = function( array ) { //xzw改成类似LineSegments的多段线 (第二个点和第三个点之间是没有线段的, 所以不用在意线段顺序)
- const points = new Float32Array( array );
- LineSegmentsGeometry.prototype.setPositions.call(this, points );
- return this;
- }
-
|