123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262 |
-
- 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'
- import {ExtendView} from '../viewer/ExtendView.js'
- import {ExtendScene} from '../viewer/ExtendScene.js'
-
- KeyCodes.BACKSPACE = 8
- //注意,这时候Potree.js中export的内容还不在Potree变量中
- var texLoader = new THREE.TextureLoader()
- texLoader.crossOrigin = "anonymous"
- {//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)
- };
-
- Potree.defines.gs3d = {
- DepthMapRange : 1 << 16,
- MemoryPageSize : 65536,
- BytesPerFloat : 4,
- BytesPerInt : 4,
- MaxScenes : 32,
- ProgressiveLoadSectionSize : 262144,
- ProgressiveLoadSectionDelayDuration : 15,
- SphericalHarmonics8BitCompressionRange : 3
- }
-
- 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_, webgl2Support
- Features.EXT_DEPTH = {
- isSupported: function (gl) {
-
- gl = gl || gl_
- gl_ = gl
- if(browser.detectIOS()){
- let {major,minor,patch} = browser.iosVersion()
- //console.warn('iosVersion',major,minor,patch)
-
- if(major == 15 && minor == 4 && patch == 1){
- console.warn('检测到是ios15.4.1, 关闭EXT_frag_depth')//该版本ext_depth有问题,导致clear错乱。没有解决办法先关闭。
- return false
- }
- }
- return (typeof WebGL2RenderingContext != 'undefined' && gl instanceof WebGL2RenderingContext) || gl.getExtension('EXT_frag_depth'); //shader中的GL_EXT_frag_depth需要判断一下detectIOS吗。。
- }
- }
-
- /* Features.getMaxMapSize = (gl)=>{
- // 查询最大立方体贴图纹理尺寸
- gl = gl || gl_
- gl_ = gl
-
- let info = {
- cubeMap: gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE),
- tex: gl.getParameter( gl.MAX_TEXTURE_SIZE )
- }
- if(info.cubeMap < 4096){
- console.warn('cubeMap最大仅支持', info.cubeMap)
- }
- return info
- } */
- Features.webgl2RealSupport = ()=>{
- if(webgl2Support != void 0){
- return webgl2Support
- }
-
- let gl
- try {
- var canvas = document.createElement('canvas')
- if(window.WebGL2RenderingContext){ //遇到有设备(iphone8 plus ios14.1 型号MQ8F2CH/A)直接获取webgl2后会点云和全景图闪烁,WebGL2RenderingContext和得到的context是undefined。但是为何4dkk不会闪烁
- gl = canvas.getContext('webgl2') //麒麟系统chromium 128 到这一步才获取失败 如果直接对最终的canvas获取webgl2,会造成多viewport无法单独渲染以及clearAlpha透明失败
- }
- }catch (e) {
- console.log(e)
- }
- webgl2Support = !!gl
- return webgl2Support
- }
-
-
- }
- Utils.loadSkybox = function(path, oldSky, callback ) {
- 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
- callback && callback()
- 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.filter(e=>Potree.Utils.getObjVisiByReason(e, 'datasetSelection')).length == 0)return
- //console.log('getMousePointCloudIntersection')
- let renderer = viewer.renderer;
- let resolution = pickParams.resolution || viewport?.resolution || renderer.getSize(new THREE.Vector2)
-
-
- if(pickParams.ifCenter){
- pickParams.x = Math.round(resolution.x / 2)
- pickParams.y = Math.round(resolution.y / 2)
- }else{
- /* if(viewport){ //转换到类似整个画面时
- pickParams.x = mouse.x;
- pickParams.y = viewport.resolution.y - mouse.y;
- }else{
- pickParams.x = mouse.x;
- pickParams.y = renderer.domElement.clientHeight - mouse.y;
- } */
-
- pickParams.x = mouse.x;
- pickParams.y = resolution.y - 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()
- let old_visibleNodes = new Map()
-
- //bigClipInBox 最好也写下
- let density
- let sizeType
- let size = new Map()
- let visiMap = new Map()
- let needsUpdate = false;
- if(pickParams.measuring || Potree.settings.displayMode == 'showPanos') { //测量或无深度图时的全景模式提高精准度. (全景模式有深度图时不会执行到这)
- density = Potree.settings.pointDensity
- Potree.settings.pointDensity = 'magnifier' //加载最高level
-
- 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_out)
- old_bigClipInBox.set(pointcloud, pointcloud.bigClipInBox)
- old_highlightBoxes.set(pointcloud, pointcloud.highlightBoxes)
- pointcloud.material.setClipBoxes(null, [],[],[])
- }
- needsUpdate = true
- }
-
- if(needsUpdate) {
- for(let pointcloud of pointclouds){
- old_visibleNodes.set(pointcloud, pointcloud.visibleNodes)
- }
-
- if(window.notViewOffset){
- Potree.updatePointClouds(pointclouds, camera, viewport.resolution );
- }else{
- //尽量减少点云加载的范围,集中在pick的空间(这部分以外还是会加载一些散点的)
- let viewWidth = Math.max(pickParams.pickWindowSize||80, 80) //viewer.magnifier ? viewer.magnifier.viewport.resolution.x : 200
- let camera_ = camera.clone()
- camera_.setViewOffset( resolution.x, resolution.y, pickParams.x-viewWidth/2, ( resolution.y - pickParams.y)-viewWidth/2, viewWidth, viewWidth ); //注意offsetY是从上到下,和一般的不同
- Potree.updatePointClouds(pointclouds, camera_, 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.measuring || 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(needsUpdate){
- for(let pointcloud of pointclouds){ //不恢复的话(尤其cameraChanged时),在下次render前,再次pick可能是错的。表现为多数据集刚开始reticule消失了,直到ifPointBlockedByIntersect停止
- pointcloud.visibleNodes = old_visibleNodes.get(pointcloud)
- }
- }
-
-
-
-
-
- if (selectedPointcloud) {
- let localNormal = closestPoint.normal && new THREE.Vector3().fromArray(closestPoint.normal)
- return {
- location: closestIntersection,
- distance: closestDistance,
- pointcloud: selectedPointcloud,
- point: closestPoint,
- pointclouds: allPointclouds, //add
- localNormal: localNormal,
- normal: localNormal?.clone().applyMatrix4(selectedPointcloud.rotateMatrix)//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, viewport , dom, renderer ){//获取一个三维坐标对应屏幕中的二维坐标
- var pos
- if(math.closeTo(viewport.camera.position, point, 1e-5) ){ //和相机位置重合时显示会四处飘,看是要改成一直显示中间还是隐藏?
- pos = new THREE.Vector3(0,0,1.5); //1.5是为了不可见
- }else{
- pos = point.clone().project(viewport.camera) //比之前hotspot的计算方式写得简单 project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
- }
-
- let size = renderer && renderer.getSize(new THREE.Vector2) //如果是渲染到renderTarget上,resolution和dom的大小不一致。如果输出的结果给前端2d用,就使用clinetWidth,如果自己场景用,用renderer.size
- let w = renderer ? size.x : dom.clientWidth
- let h = renderer ? size.y : dom.clientHeight
-
-
- var x,y,left,top;
- x = (pos.x + 1) / 2 * w * viewport.width;
- y = (1 - (pos.y + 1) / 2) * h * viewport.height;
- left = viewport.left * w;
- top = (1- viewport.bottom - viewport.height) * h;
-
- 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.getPointerPosAtHeight = function(planeZ=0, pointer, camera=viewer.mainViewport.camera){
- 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)
- let r = (planeZ - origin.z)/dir.z
- let x = r * dir.x + origin.x
- let y = r * dir.y + origin.y
- return {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, composer) {
- this.screenQuad.material = material;
-
- if (typeof target === 'undefined') {
- (composer || renderer).render(this.screenScene, this.camera);
- } else {
- let oldTarget = renderer.getRenderTarget()
- renderer.setRenderTarget(target);
- //renderer.clear(); //有时候不能clear,如renderBG后再
- (composer || 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 object = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
- || o.object || viewer.objs.children.find(e=>e.dataset_id == o.datasetId)
- if(object){
- 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 ? object.rotateMatrix : object.rotateInvMatrix
- if(!rotateMatrix){
- rotateMatrix = new THREE.Matrix4().makeRotationFromEuler(object.rotation) //如果是没有漫游点的模型,在此临时获取一个,但和有漫游点的比会有所不同,因为没有初始旋转(如转90度)
- if(o.toDataset){
- rotateMatrix.invert()
- }
- }
- 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交点
-
- if(!raycaster){//getMouseIntersect
- camera.updateMatrixWorld()
- 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(2,e.layers.mask))
- })
- 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.generateMipmaps = false
- map.needsUpdate = true
- }
- Utils.updateVisible = function(object, reason, ifShow, level=0, type, needRender=true){//当所有加入的条件都不为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,
- })
- needRender && viewer.dispatchEvent('content_changed')
- }
-
-
- }
-
-
-
- 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()
-
- }
- /*
- 复杂案例: 如果物体默认隐藏, 当符合任何一个其他条件时可见,则可:
- Potree.Utils.updateVisible(this, "default", false, 0 ) //默认隐藏
- Potree.Utils.updateVisible(this, 条件名, ifShow, 1, ifShow?'add':'cancel' ) //其他的条件
- */
-
- 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!', e);
- return
- }
- camera.layers.enable(layer)
- })
- }
- Utils.setObjectLayers = function(object, layerName){//add
- let layer = Potree.config.renderLayers[layerName]
- if(layer == void 0){
- console.error('setObjectLayers没找到layer!',layerName);
- return
- }
- object.traverse(e=>{
- e.layers.set(layer)
- })
- }
-
-
-
- Utils.imgAddText = async (img, text, labelInfo)=>{
-
- let label = new Potree.TextSprite(Object.assign({//如果直接在canvas里写字,要另外写很多和canvas.drawText有关的,所以还是借助textSprite吧
- backgroundColor: { r: 0, g: 0, b: 0, a: 0 },
- textColor: { r: 255, g: 255, b: 255, a: 1 },
- margin:{x:3,y:3},
- renderOrder: 50, fontsize : 20,
- text,
- },labelInfo))
-
- let labelImg = new Image
- labelImg.src = label.sprite.material.map.image.toDataURL('image/png')
-
- return new Promise((resolve,reject)=>{
- labelImg.onload = ()=>{
- if(labelInfo.horizonCenter){//水平居中(对img来说)
- labelInfo.leftRatioToImg = 0.5 - (labelImg.width / img.width)/2
- }
- let result = Common.imgAddLabel(img,labelImg,labelInfo)
- label.dispose()
- resolve(result)
- }
- })
-
- }
- Utils.combineImgs = async (imgs, compressRatio, width, height)=>{//拼合图片,顺序从上到下从左到右, 每张图大小不一定一致,但同列的宽一致,同行宽一致
- return new Promise((resolve,reject)=>{
- let item = imgs[0][0]
-
- let wc=imgs.length, hc=imgs[0].length, loadCount = 0, amount = wc * hc
-
- width = width || imgs.reduce((w,c)=>w + c[0].width, 0), //相加得到的可能比想要得到的大几个像素,之后会重叠
- height = height || imgs[0].reduce((w,c)=>w + c.height, 0)
- let canvas = document.createElement('canvas')
- canvas.width = width
- canvas.height = height
- let context = canvas.getContext('2d')
-
- for(let i=0;i<wc;i++){
- for(let j=0;j<hc;j++){
- let img = new Image
- img.src = imgs[i][j].dataUrl
- img.index = {i,j}
- img.onload = ()=>{
- loadCount++
- context.drawImage(img, img.index.i * img.width, img.index.j * img.height, img.width, img.height)
- if(loadCount == amount){
- var dataUrl = canvas.toDataURL('image/png',compressRatio)
- context.clearRect(0,0,width,height)
- resolve(dataUrl)
- }
- }
- }
- }
- })
-
- }
- 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 {
- node.loadFailed = 'status:'+xhr.status+",url:"+url
- Potree.numNodesLoading--;
- //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) {
- node.loadFailed = 'catchError'
- Potree.numNodesLoading--;
- console.error('加载点云node出错 ', url, 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 camObjDirs = {} //add
- let priorityQueue = new BinaryHeap(function (x) { return -x.weight /* 1 / x.weight; */ });//二叉堆。 改,之前的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);
-
- let quaternion = new THREE.Quaternion().setFromRotationMatrix(camMatrixObject)
- let camDir = (new THREE.Vector3(0,0,-1)).applyQuaternion(quaternion)
- camObjDirs[i] = camDir
-
- // 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,
- camObjDirs
- };
- };
- 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 camObjDirs = s.camObjDirs
-
-
-
- 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 camObjDir = camObjDirs[element.pointcloud];
-
-
- let insideFrustum = frustum.intersectsBox(box);
- let maxLevel = pointcloud.maxLevel == void 0 ? Infinity : pointcloud.maxLevel;
- let minLevel = pointcloud.minLevel == void 0 ? 0 : pointcloud.minLevel; //add
-
- 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 /* && level >= minLevel */ ; //< 改为 <=
- //visible = visible || node.getLevel() <= 2;
- let pcWorldInverse = pointcloud.matrixWorld.clone().invert();
- /* let m = pcWorldInverse.elements
- let pcWorldInvM3 = new THREE.Matrix3().set(m[0],m[4],m[12],m[1],m[5],m[13],m[3],m[7],m[15]) //去掉z的
- */
- //pointcloud.pcMatrix3 = new THREE.Matrix3().set(m[0],m[4],m[12],m[1],m[5],m[13],m[3],m[7],m[15]) //去掉z的
-
-
- let intersectBox = (clipBox)=>{
- let toPCObject = pcWorldInverse.clone().multiply(clipBox.box.matrixWorld); //box乘上点云逆矩阵
- return Potree.Utils.isIntersectBox(box, toPCObject)
- }
- //改 总共两种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){
- let prism = pointcloud.material.activeAttributeName == 'prismHeight' && pointcloud.material.prisms && pointcloud.material.prisms.find(e=>e.computing)
- if(prism){
- let bound = box.clone().applyMatrix4(pointcloud.matrixWorld)
- if(bound.intersectsBox(prism.prismBound)){
- /* //node box是否包含points中的一个点
- let box2 = new THREE.Box2().copy(box)
- let points2d = prisms.points.map(e=>new THREE.Vector2().copy(e).applyMatrix3(pcWorldInvM3))
- let intersect = points2d.some(e=>{
- return box2.containsPoint(e)
- })
-
- if(!intersect){
- //或者多边形中是否包含node box中的一个点
- intersect = [
- new THREE.Vector2(box.min.x, box.min.y),
- new THREE.Vector2(box.max.x, box.max.y),
- new THREE.Vector2(box.min.x, box.max.y),
- new THREE.Vector2(box.max.x, box.min.y),
- ].some(e=>{
- if(math.isPointInArea(points2d, null, e) ){
- return true
- }
-
- })
- //z是不是在外层已经判断好了?
- if(!intersect){
- visible = false
- }
- } */
- //会有两个互不包含点但是交叉了的情况,所以就不仔细判断了(如横竖两个矩形构成十字架)
- }else visible = false
-
- }
- }
- 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) {
- viewer.dispatchEvent({type:'overPointBudget', restQueueSize: priorityQueue.size(), numVisiblePoints} )
- 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;
- /* level >= minLevel && */visibleNodes.push(node);
- /* level >= minLevel && */pointcloud.visibleNodes.push(node);
-
- //if(Potree.settings.sortNodesDis){//add
- if(pointcloud.material.opacity < 1 && Potree.settings.notAdditiveBlending ){
- let nodePos = node.getBoundingSphere().center;
- let toCam = new THREE.Vector3().subVectors(nodePos, camObjPos)
- toCam.projectOnVector(camObjDir)
- node.disSqToCamZ_ = toCam.lengthSq()
- }
- 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 colorHue = level / (maxLevel+1)
- let s = 0.1 + level / (maxLevel+1)
- let color = (new THREE.Color()).setHSL(colorHue, s, s)
-
- let boxHelper = new Box3Helper(node.getBoundingBox(),color);
- 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);
-
-
- let addPow = 0.2//viewer.mainViewport.view.isFlying() ? 0 : 0.5 //0-0.5,正常原本是0. 数字越大近处加载越快。但会造成远处加载慢甚至因pointBudge限制不加载。 isFlying:漫游时需要尽量加载一下远处的点云
- //addPow *= window.devicePixelRatio //devicePixelRatio高的手机需要优先加载最近的高级点云,减少远处的中高级点云。
- 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;
- }
- weight = screenPixelRadius;
-
- if( !sphere.containsPoint(camObjPos) ){ //add 优先加载屏幕中央的点云(手机端缩小离远效果明显,不会那么稀疏)
- let dir = new THREE.Vector3().subVectors(center, camObjPos).normalize()
- let cos = 1+dir.dot(camObjDir) //0-2
- weight *= cos/2//Math.pow(cos,0.5) //幂越高,旁边的容易加载不到,出现缺块 如SS-t-7DUfWAUZ3V
- }
-
- if(distance - radius < 0){
- weight = Number.MAX_VALUE;
- }
-
- //如果能得到每个方向上的密度,也就是node数量,密度大的远处少加载,因为被遮挡了显示也没有意义,就好了。
- } 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
-
-
- /* let vec = new THREE.Vector3().subVectors(sphere.center, camObjPos)
- let disOnCamDir = vec.dot(camObjDir)
- let vecOnCamDir = camObjDir.clone().multiplyScalar(disOnCamDir)
- let vecSide = new THREE.Vector3().subVectors(vec, vecOnCamDir) //在屏幕上从中心到该node的向量
- let disSide = vecSide.length()
- //weight = sphere.radius / disSide * camera.zoom - disOnCamDir * 2; //如果用除的,ortho的camera离远了的话dis的影响就小了
-
- weight = sphere.radius / ( disSide * 0.1 + disOnCamDir * 14 )
- */
-
- //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);
- }
- }
-
-
-
-
- unloadedGeometry = unloadedGeometry.filter(e=>!e.loadFailed) //过滤加载失败的,否则有失败的就无法发送加载完成
-
- if(unloadedGeometry.length){//加载点云
- let idleCount = Common.getBestCountFPS('unloadedGeometry', false, 1, 3) //即使静止,因为加载不仅影响这一帧,所以低fps还是加载少一些
- let maxNodesLoading = Common.getBestCount('unloadedGeometry', viewer.lastFrameChanged?1:idleCount, idleCount+4, 3, 14 /* , true */ )//dur在iphoneX中静止有7,pc是2 //!lastFrameChanged静止时加速下载
- //THREE.Math.clamp(Math.round(9 - dur), 1, 6 )
- //console.log('unloadedGeometry', unloadedGeometry.length)
- //主要在手机端有效果。不改之前在展示的点云较多时前进会卡。
- for (let i = 0; i < Math.min(maxNodesLoading, unloadedGeometry.length); i++) {
- unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry);
- }
- if(!Potree.pointsLoading){
- Potree.pointsLoading = true
- //console.log('startLoad')
- viewer.dispatchEvent('startLoadPoints')
- }
- }else{
- if(Potree.pointsLoading){
- Potree.pointsLoading = false
- //console.log('load done!')
- setTimeout(()=>{
- Potree.pointsLoading || viewer.dispatchEvent('pointsLoaded')
- },document.hidden ? 3000 : 50) //hidden时可能好几秒才更新一次,所以这个并不准
- }
- }
-
-
- Potree.unloadedGeometry = unloadedGeometry
-
-
- //add:
- Potree.numVisiblePoints = numVisiblePoints
- Potree.visibleNodes = visibleNodes
-
-
- //if(Potree.settings.sortNodesDis){
- //let s = performance.now()
- for(let pointcloud of pointclouds){
- if(pointcloud.material.opacity < 1 && Potree.settings.notAdditiveBlending ){//排序。如果能所有点云一起排序更好,这样遮挡更正确
- pointcloud.visibleNodes.sort((a,b)=>{return b.disSqToCamZ_ - a.disSqToCamZ_})
- }
- }
- //console.log(performance.now() - s)
- //}
-
-
- return {
- visibleNodes: visibleNodes,
- numVisiblePoints: numVisiblePoints,
- lowestSpacing: lowestSpacing
- };
- };
- Potree.numVisiblePoints = 0
- /*
- 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 = THREE.Math.clamp( viewer.viewports.length * memoryRatio * Potree.pointBudget, 0, Potree.settings.maxLRUPoints)
-
- for (; this.numPoints > max; ) {
- var node = this.getLRUItem();
- node && this.disposeDescendants(node);
- }
-
- }
- 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 => {
- if(e.hoverViewport.name == 'mapViewport')return
- 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;
- }
-
- Object.assign(ExtendView.prototype, THREE.EventDispatcher.prototype)
- Object.assign(ExtendScene.prototype, THREE.EventDispatcher.prototype );
-
|