potree.shim.js 77 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import {config, settings} from "./settings.js";
  3. import math from "./utils/math.js";
  4. import browser from "./utils/browser.js";
  5. import cameraLight from "./utils/cameraLight.js";
  6. import {Utils} from "../utils.js";
  7. import Common from "./utils/Common.js";
  8. import {BinaryLoader} from "../loader/BinaryLoader.js";
  9. import {Features} from "../Features.js";
  10. import {PointAttribute,PointAttributeTypes} from "../loader/PointAttributes.js";
  11. import {ProfileWindow} from "../viewer/profile.js";
  12. import {XHRFactory} from "../XHRFactory.js";
  13. import {ClipTask, ClipMethod} from "../defines.js";
  14. import {VolumeTool} from "../utils/VolumeTool.js";
  15. import {Box3Helper} from "../utils/Box3Helper.js";
  16. import {KeyCodes} from "../KeyCodes.js";
  17. import {HQSplatRenderer} from "../viewer/HQSplatRenderer.js";
  18. import {LRU} from "../LRU.js";
  19. import {ExtendPointCloudMaterial} from '../materials/ExtendPointCloudMaterial.js'
  20. import {PointCloudOctreeGeometry, PointCloudOctreeGeometryNode} from '../PointCloudOctreeGeometry.js'
  21. import {Shaders} from "../../build/shaders/shaders.js";
  22. import {LineSegmentsGeometry} from '../../libs/three.js/lines/LineSegmentsGeometry.js'
  23. import {LineGeometry} from '../../libs/three.js/lines/LineGeometry.js'
  24. import {ExtendView} from '../viewer/ExtendView.js'
  25. import {ExtendScene} from '../viewer/ExtendScene.js'
  26. KeyCodes.BACKSPACE = 8
  27. //注意,这时候Potree.js中export的内容还不在Potree变量中
  28. var texLoader = new THREE.TextureLoader()
  29. {//defines:
  30. Potree.defines = {}
  31. Potree.defines.Buttons = {// MouseEvent.buttons
  32. //buttons,设置按下了鼠标哪些键,是一个3个比特位的二进制值,默认为0。1表示按下主键(通常是左键),2表示按下次要键(通常是右键),4表示按下辅助键(通常是中间的键)。
  33. NONE:0,//add
  34. LEFT: 0b0001,
  35. RIGHT: 0b0010,
  36. MIDDLE: 0b0100
  37. };
  38. /* 如果访问的是button, 用THREE.MOUSE来判断:
  39. button,设置按下了哪一个鼠标按键,默认为0。-1表示没有按键,0表示按下主键(通常是左键),1表示按下辅助键(通常是中间的键),2表示按下次要键(通常是右键)
  40. */
  41. Potree.browser = browser
  42. /////////// add //////////////////////////////////
  43. /* Potree.defines.GLCubeFaces = {
  44. GL_TEXTURE_CUBE_MAP_POSITIVE_X: 0,
  45. GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 1,
  46. GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 2,
  47. GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 3,
  48. GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 4,
  49. GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 5
  50. };
  51. Potree.defines.PanoSizeClass = {
  52. BASE: 1,
  53. STANDARD: 2,
  54. HIGH: 3,
  55. ULTRAHIGH: 4
  56. };
  57. Potree.defines.TileDownloaderEvents = {
  58. TileDownloadSuccess: "tiledownloader.download.success",
  59. TileDownloadFailure: "tiledownloader.download.failure",
  60. PanoDownloadComplete: "tiledownloader.pano.download.complete"
  61. };*/
  62. Potree.defines.PanoRendererEvents = {
  63. PanoRenderComplete: "panorama.render.complete",
  64. TileRenderFailure: "panorama.tile.render.failed",
  65. TileRenderSuccess: "panorama.tile.render.success",
  66. TileUploadAttempted: "panorama.tile.upload.attempted",
  67. UploadAttemptedForAllTiles: "panorama.upload.attempted.all.tiles",
  68. ZoomLevelRenderStarted: "panorama.zoom.render.started"
  69. };
  70. Potree.defines.SceneRendererEvents = {
  71. ContextCreated: "scene-renderer-context-created",
  72. AfterRender: "after-render",
  73. MemoryUsageUpdated: "scene-renderer-memory-usage-updated"
  74. };
  75. Potree.defines.Vectors = {
  76. UP: new THREE.Vector3(0,1,0),
  77. DOWN: new THREE.Vector3(0,-1,0),
  78. LEFT: new THREE.Vector3(-1,0,0),
  79. RIGHT: new THREE.Vector3(1,0,0),
  80. FORWARD: new THREE.Vector3(0,0,-1),
  81. BACK: new THREE.Vector3(0,0,1)
  82. };
  83. /* var Vectors2 = {}
  84. for(var i in Vectors){
  85. Vectors2[i] = math.convertVector.YupToZup(Vectors[i])
  86. }
  87. */
  88. Potree.defines.DownloadStatus = Object.freeze({
  89. None: 0,
  90. Queued: 1,
  91. ForceQueued: 2,
  92. Downloading: 3,
  93. Downloaded: 4,
  94. DownloadFailed: 5
  95. });
  96. Potree.defines.ModelManagerEvents = {
  97. ModelAdded: "model-added",
  98. ActiveModelChanged: "active-model-changed"
  99. };
  100. Potree.defines.PanoramaEvents = {
  101. Enter: 'panorama.enter',
  102. Exit: 'panorama.exit',
  103. LoadComplete: "panorama.load.complete",
  104. LoadFailed: "panorama.load.failed",
  105. TileLoaded: "panorama.tile.loaded",
  106. VideoRendered: "panorama.video.rendered"
  107. };
  108. ClipTask.SHOW_INSIDE_Big = 4
  109. }
  110. {//Features
  111. let gl_
  112. Features.EXT_DEPTH = {
  113. isSupported: function (gl) {
  114. gl = gl || gl_
  115. gl_ = gl
  116. if(browser.detectIOS()){
  117. let {major,minor,patch} = browser.iosVersion()
  118. if(major == 15 && minor == 4 && patch == 1){
  119. console.warn('检测到是ios15.4.1, 关闭EXT_frag_depth')//该版本ext_depth有问题,导致clear错乱。没有解决办法先关闭。
  120. return false
  121. }
  122. }
  123. return (typeof WebGL2RenderingContext != 'undefined' && gl instanceof WebGL2RenderingContext) || gl.getExtension('EXT_frag_depth'); //shader中的GL_EXT_frag_depth需要判断一下detectIOS吗。。
  124. }
  125. }
  126. }
  127. Utils.loadSkybox = function(path, oldSky ) {
  128. let camera, scene, parent , cameraOrtho
  129. if(!oldSky){
  130. parent = new THREE.Object3D("skybox_root");
  131. camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 100000);
  132. cameraOrtho = new THREE.OrthographicCamera(-1, 1, 1, -1, Potree.config.view.near, Potree.settings.cameraFar);
  133. if(!window.axisYup) camera.up.set(0, 0, 1);//add
  134. scene = new THREE.Scene();
  135. let skyboxBgWidth = Potree.config.skyboxBgWidth
  136. let skyGeometry = new THREE.BoxBufferGeometry(skyboxBgWidth,skyboxBgWidth,skyboxBgWidth)
  137. let skybox = new THREE.Mesh(skyGeometry, new THREE.ShaderMaterial({
  138. vertexShader: Shaders['skybox.vs'],
  139. fragmentShader: Shaders['skybox.fs'],
  140. side: THREE.BackSide,
  141. uniforms:{
  142. tDiffuse: {
  143. type: "t",
  144. value: null
  145. },
  146. matrix:{
  147. type: "m4",
  148. value: new THREE.Matrix4
  149. }
  150. },
  151. depthTest:false,
  152. depthWrite:false
  153. }) );
  154. scene.add(skybox);
  155. scene.traverse(n => n.frustumCulled = false);
  156. // z up
  157. //scene.rotation.x = Math.PI / 2;
  158. parent.children.push(camera);
  159. camera.parent = parent;
  160. }else{
  161. camera = oldSky.camera,
  162. scene = oldSky.scene
  163. parent = oldSky.parent
  164. cameraOrtho = oldSky.cameraOrtho
  165. }
  166. let texture = texLoader.load( path, ()=>{
  167. console.log('loadSkybox成功',path)
  168. texture.wrapS = THREE.RepeatWrapping;
  169. texture.flipY = false
  170. texture.magFilter = THREE.LinearFilter
  171. texture.minFilter = THREE.LinearFilter
  172. scene.children[0].material.uniforms.tDiffuse.value = texture
  173. viewer.dispatchEvent('content_changed')
  174. },null,(e)=>{//error
  175. console.error('loadSkybox失败',path)
  176. });
  177. return {camera, scene, parent, cameraOrtho};
  178. };
  179. Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera, viewer, pointclouds, pickParams = {} ) {
  180. //getIntersectByDepthTex
  181. /* let result = viewer.edlRenderer.depthTexSampler.sample(viewport, mouse)//add
  182. if(result != 'unsupport')return result
  183. */
  184. if(!pointclouds || pointclouds.length == 0)return
  185. //console.log('getMousePointCloudIntersection')
  186. let renderer = viewer.renderer;
  187. if(viewport){ //转换到类似整个画面时
  188. /*let mouseInViewport = Utils.convertNDCToScreenPosition(pointer, null, viewport.resolution.x, viewport.resolution.y)
  189. pickParams.x = mouseInViewport.x //mouse.x / viewport.width;
  190. pickParams.y = mouseInViewport.y //renderer.domElement.clientHeight - mouse.y / viewport.height; */
  191. pickParams.x = mouse.x;
  192. pickParams.y = viewport.resolution.y - mouse.y;
  193. }else{
  194. pickParams.x = mouse.x;
  195. pickParams.y = renderer.domElement.clientHeight - mouse.y;
  196. }
  197. //console.log('getMousePointCloudIntersection')
  198. /* if(!raycaster){
  199. raycaster = new THREE.Raycaster();
  200. raycaster.setFromCamera(pointer, camera);
  201. } */
  202. let raycaster = new THREE.Raycaster();
  203. raycaster.setFromCamera(pointer, camera);
  204. let ray = raycaster.ray;
  205. let selectedPointcloud = null;
  206. let closestDistance = Infinity;
  207. let closestIntersection = null;
  208. let closestPoint = null;
  209. //-----------add--------------------
  210. let old_clipBoxes_in = new Map()
  211. let old_clipBoxes_out = new Map()
  212. let old_bigClipInBox = new Map()
  213. let old_highlightBoxes = new Map()
  214. //bigClipInBox 最好也写下
  215. let density
  216. let sizeType
  217. let size = new Map()
  218. let visiMap = new Map()
  219. let needsUpdate = false;
  220. if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos') { //(无深度图) 测量或全景模式提高精准度,因为漫游的
  221. density = Potree.settings.pointDensity
  222. Potree.settings.pointDensity = 'magnifier'
  223. pointclouds.forEach(e=>{//因为全景模式的pointSizeType是fixed所以要还原下
  224. visiMap.set(e,e.visible)
  225. e.visible = Potree.Utils.getObjVisiByReason(e, 'datasetSelection'); //先将隐藏的点云显示
  226. if(!e.visible)return
  227. size.set(e, e.temp.pointSize)
  228. sizeType = e.material.pointSizeType
  229. e.material.pointSizeType = Potree.config.material.pointSizeType
  230. e.changePointSize(Potree.config.material.realPointSize*2, true)//更改点云大小到能铺满为止,否则容易识别不到
  231. })
  232. needsUpdate = true
  233. }else{
  234. if(viewer.viewports.filter(e=>!e.noPointcloud && e.active).length>1 || pickParams.cameraChanged){//在pick时相机和渲染时不一样的话
  235. viewport.beforeRender && viewport.beforeRender()
  236. needsUpdate = true //不updatePointClouds的话hover久了会不准 因node是错的
  237. //但依旧需要camera真的移动到那个位置才能加载出点云
  238. }
  239. }
  240. if(!pickParams.pickClipped){// 无视clipBoxes
  241. for(let pointcloud of pointclouds){
  242. old_clipBoxes_in.set(pointcloud, pointcloud.clipBoxes_in)
  243. old_clipBoxes_out.set(pointcloud, pointcloud.clipBoxes_in)
  244. old_bigClipInBox.set(pointcloud, pointcloud.bigClipInBox)
  245. old_highlightBoxes.set(pointcloud, pointcloud.highlightBoxes)
  246. pointcloud.material.setClipBoxes(null, [],[],[])
  247. }
  248. needsUpdate = true
  249. }
  250. if(needsUpdate){
  251. Potree.updatePointClouds(pointclouds, camera, viewport.resolution ); //最好只更新pick的范围的resolution
  252. }
  253. //------------------------------------------------
  254. let allPointclouds = []
  255. for(let pointcloud of pointclouds){
  256. let point = pointcloud.pick(viewer, viewport, camera, ray, pickParams );
  257. if(!point){
  258. continue;
  259. }
  260. allPointclouds.push(pointcloud)
  261. let distance = camera.position.distanceTo(point.position);
  262. if (distance < closestDistance) {
  263. closestDistance = distance;
  264. selectedPointcloud = pointcloud;
  265. closestIntersection = point.position;
  266. closestPoint = point;
  267. }
  268. }
  269. //恢复
  270. if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos'){
  271. Potree.settings.pointDensity = density
  272. pointclouds.forEach(e=>{
  273. if(e.visible){
  274. e.material.pointSizeType = sizeType
  275. e.changePointSize(size.get(e))
  276. }
  277. e.visible = visiMap.get(e)
  278. })
  279. }else{
  280. /* if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
  281. viewport.afterRender && viewport.afterRender()
  282. } */
  283. }
  284. if(!pickParams.pickClipped){//add
  285. for(let pointcloud of pointclouds){
  286. pointcloud.material.setClipBoxes(old_bigClipInBox.get(pointcloud), old_clipBoxes_in.get(pointcloud), old_clipBoxes_out.get(pointcloud), old_highlightBoxes.get(pointcloud))
  287. }
  288. }
  289. if (selectedPointcloud) {
  290. return {
  291. location: closestIntersection,
  292. distance: closestDistance,
  293. pointcloud: selectedPointcloud,
  294. point: closestPoint,
  295. pointclouds: allPointclouds, //add
  296. normal: new THREE.Vector3().fromArray(closestPoint.normal )//add
  297. };
  298. } else {
  299. return null;
  300. }
  301. };
  302. Utils.pixelsArrayToDataUrl = function(pixels, width, height, compressRatio = 0.7) {
  303. let canvas = document.createElement('canvas');
  304. canvas.width = width;
  305. canvas.height = height;
  306. let context = canvas.getContext('2d');
  307. pixels = new pixels.constructor(pixels);
  308. /* for (let i = 0; i < pixels.length; i++) {
  309. pixels[i * 4 + 3] = 255;
  310. } */
  311. // flip vertically
  312. let bytesPerLine = width * 4;
  313. for(let i = 0; i < parseInt(height / 2); i++){
  314. let j = height - i - 1;
  315. let lineI = pixels.slice(i * bytesPerLine, i * bytesPerLine + bytesPerLine);
  316. let lineJ = pixels.slice(j * bytesPerLine, j * bytesPerLine + bytesPerLine);
  317. pixels.set(lineJ, i * bytesPerLine);
  318. pixels.set(lineI, j * bytesPerLine);
  319. }
  320. let imageData = context.createImageData(width, height);
  321. imageData.data.set(pixels);
  322. context.putImageData(imageData, 0, 0);
  323. let dataURL = canvas.toDataURL(compressRatio);
  324. return dataURL;
  325. }
  326. Utils.renderTargetToDataUrl = function(renderTarget, width, height, renderer, compressRatio = 0.7){
  327. let pixelCount = width * height;
  328. let buffer = new Uint8Array(4 * pixelCount);
  329. renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer);
  330. var dataUrl = Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
  331. return dataUrl
  332. }
  333. Utils.mouseToRay = function(pointer, camera ){
  334. let vector = new THREE.Vector3(pointer.x, pointer.y, 1);
  335. let origin = new THREE.Vector3(pointer.x, pointer.y, -1); //不能用camera.position,在orbitCamera时不准
  336. vector.unproject(camera);
  337. origin.unproject(camera);
  338. let direction = new THREE.Vector3().subVectors(vector, origin).normalize();
  339. let ray = new THREE.Ray(origin, direction);
  340. return ray;
  341. }
  342. Utils.getPos2d = function(point, viewport , dom ){//获取一个三维坐标对应屏幕中的二维坐标
  343. var pos
  344. if(math.closeTo(viewport.camera.position, point, 1e-5) ){ //和相机位置重合时显示会四处飘,看是要改成一直显示中间还是隐藏?
  345. pos = new THREE.Vector3(0,0,1.5); //1.5是为了不可见
  346. }else{
  347. 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);
  348. }
  349. var x,y,left,top;
  350. x = (pos.x + 1) / 2 * dom.clientWidth * viewport.width;
  351. y = (1 - (pos.y + 1) / 2) * dom.clientHeight * viewport.height;
  352. left = viewport.left * dom.clientWidth;
  353. top = (1- viewport.bottom - viewport.height) * dom.clientHeight;
  354. var inSight = pos.x <= 1 && pos.x >= -1 //是否在屏幕中
  355. && pos.x <= 1 && pos.y >= -1
  356. return {
  357. pos: new THREE.Vector2(left+x,top+y) ,// 屏幕像素坐标
  358. vector: pos, //(范围 -1 ~ 1)
  359. trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点 参见Tag.update
  360. inSight : inSight, //在屏幕范围内可见,
  361. posInViewport: new THREE.Vector2(x,y)
  362. };
  363. }
  364. Utils.screenPass = new function () {
  365. this.screenScene = new THREE.Scene();
  366. this.screenQuad = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2, 1));
  367. this.screenQuad.material.depthTest = true;
  368. this.screenQuad.material.depthWrite = true;
  369. this.screenQuad.material.transparent = true;
  370. this.screenScene.add(this.screenQuad);
  371. this.camera = new THREE.Camera();
  372. this.render = function (renderer, material, target, composer) {
  373. this.screenQuad.material = material;
  374. if (typeof target === 'undefined') {
  375. (composer || renderer).render(this.screenScene, this.camera);
  376. } else {
  377. let oldTarget = renderer.getRenderTarget()
  378. renderer.setRenderTarget(target);
  379. //renderer.clear(); //有时候不能clear,如renderBG后再
  380. (composer || renderer).render(this.screenScene, this.camera);
  381. renderer.setRenderTarget(oldTarget)
  382. }
  383. };
  384. }();
  385. //add
  386. Utils.computePointcloudsBound = function(pointclouds){
  387. var boundingBox = new THREE.Box3();
  388. pointclouds.forEach(pointcloud=>{
  389. pointcloud.updateBound()
  390. boundingBox.union(pointcloud.bound2)
  391. })
  392. var boundSize = boundingBox.getSize(new THREE.Vector3)
  393. var center = boundingBox.getCenter(new THREE.Vector3)
  394. return {boundSize, center, boundingBox}
  395. }
  396. Utils.convertScreenPositionToNDC = function(pointer, mouse, width, height) {
  397. return pointer = pointer || new THREE.Vector2,
  398. pointer.x = mouse.x / width * 2 - 1,
  399. pointer.y = 2 * -(mouse.y / height) + 1,
  400. pointer
  401. }
  402. Utils.convertNDCToScreenPosition = function(pointer, mouse, width, height) {
  403. return mouse = mouse || new THREE.Vector2,
  404. mouse.x = Math.round((pointer.x + 1 ) / 2 * width),
  405. mouse.y = Math.round(-(pointer.y - 1 ) / 2 * height),
  406. mouse
  407. }
  408. Utils.getOrthoCameraMoveVec = function(pointerDelta, camera ){//获取当camera为Ortho型时 屏幕点1 到 屏幕点2 的三维距离
  409. let cameraViewWidth = camera.right / camera.zoom
  410. let cameraViewHeight = camera.top / camera.zoom
  411. let moveVec = new THREE.Vector3;
  412. moveVec.set( pointerDelta.x * cameraViewWidth , pointerDelta.y * cameraViewHeight , 0).applyQuaternion(camera.quaternion)
  413. return moveVec
  414. }
  415. Utils.VectorFactory = {
  416. fromArray : function(t) {
  417. if (t) {
  418. if (t.length < 2 || t.length > 3)
  419. console.error("Wrong number of ordinates for a point!");
  420. return 3 === t.length ? (new THREE.Vector3).fromArray(t) : (new THREE.Vector2).fromArray(t)
  421. }
  422. },
  423. fromArray3 : function(t) {
  424. if (t) {
  425. if (3 !== t.length)
  426. console.error("Wrong number of ordinates for a point!");
  427. return (new THREE.Vector3).fromArray(t)
  428. }
  429. },
  430. fromArray2 : function(t) {
  431. if (t) {
  432. if (2 !== t.length)
  433. console.error("Wrong number of ordinates for a point!");
  434. return (new THREE.Vector2).fromArray(t)
  435. }
  436. },
  437. toString : function(t) {
  438. return t.x.toFixed(8) + "," + t.y.toFixed(8) + "," + t.z.toFixed(3)
  439. }
  440. }
  441. Utils.QuaternionFactory = {
  442. rot90 : (new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.Math.degToRad(-90)),
  443. fromArray : function(t) {
  444. if (t) {
  445. if (4 !== t.length)
  446. console.error("Wrong number of ordinates for a quaternion!");
  447. return new THREE.Quaternion(t[1],t[2],t[3],t[0]).multiply(this.rot90)
  448. }
  449. }
  450. ,
  451. toArray : function(t) {
  452. if (t) {
  453. var e = t.clone().multiply(a).toArray();
  454. return [e[3], e[0], e[1], e[2]]
  455. }
  456. }
  457. ,
  458. fromLonLat : function(t) {
  459. if (t)
  460. return (new THREE.Quaternion).setFromEuler(new THREE.Euler(t.lon,t.lat,0))
  461. }
  462. ,
  463. toLonLat : function(t) {
  464. if (t) {
  465. var e = (new THREE.Euler).setFromQuaternion(t);
  466. return {
  467. lon: e.x,
  468. lat: e.y
  469. }
  470. }
  471. }
  472. }
  473. Utils.datasetPosTransform = function(o={}){
  474. let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
  475. let tranMatrix
  476. if(pointcloud){
  477. if(Potree.settings.editType == 'merge'){
  478. tranMatrix = o.fromDataset ? pointcloud.matrixWorld : new THREE.Matrix4().copy(pointcloud.matrixWorld).invert()
  479. }else{
  480. tranMatrix = o.fromDataset ? pointcloud.transformMatrix : pointcloud.transformInvMatrix
  481. }
  482. }else{
  483. if(Potree.settings.intersectOnObjs){
  484. let object = o.object || viewer.objs.children.find(e=>e.dataset_id == o.datasetId)
  485. if(object){
  486. tranMatrix = o.fromDataset ? object.matrixWorld : new THREE.Matrix4().copy(object.matrixWorld).invert()
  487. }
  488. }
  489. }
  490. if(tranMatrix){
  491. return (new THREE.Vector3).copy(o.position).applyMatrix4(tranMatrix)
  492. }else{
  493. if(o.datasetId != void 0){
  494. console.error(`datasetPosTransform找不到datasetId为${o.datasetId}的数据集或模型,请检查数据, 模型未创建或删除`)
  495. //很可能是旧的热点,需要删除
  496. }
  497. }
  498. }
  499. Utils.datasetRotTransform = function(o={}){
  500. let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
  501. if(pointcloud){
  502. var matrix, newMatrix, result
  503. if(o.rotation){
  504. matrix = new THREE.Matrix4().makeRotationFromEuler(o.rotation)
  505. }else if(o.quaternion){
  506. matrix = new THREE.Matrix4().makeRotationFromQuaternion(o.quaternion)
  507. }else if(o.matrix){
  508. matrix = o.matrix.clone()
  509. }else{
  510. return
  511. }
  512. let rotateMatrix = o.fromDataset ? pointcloud.rotateMatrix : pointcloud.rotateInvMatrix
  513. newMatrix = new THREE.Matrix4().multiplyMatrices(rotateMatrix, matrix )
  514. if(o.getRotation){
  515. result = new THREE.Euler().setFromRotationMatrix(newMatrix)
  516. }else if(o.getQuaternion){
  517. result = new THREE.Quaternion().setFromRotationMatrix(newMatrix)
  518. }else if(o.getMatrix){
  519. result = newMatrix
  520. }
  521. return result
  522. }
  523. }
  524. Utils.isInsideFrustum = function(bounding, camera){// bounding是否在视野范围内有可见部分(视野就是一个锥状box)
  525. let frustumMatrix = new THREE.Matrix4
  526. frustumMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
  527. let frustum = new THREE.Frustum();
  528. frustum.setFromProjectionMatrix(frustumMatrix)
  529. if(bounding instanceof THREE.Sphere){
  530. return frustum.intersectsSphere(bounding)
  531. }else{
  532. return frustum.intersectsBox(bounding)
  533. }
  534. }
  535. Utils.isIntersectBox = function(object, boxMatrix){//object是否有在box中的部分。 object可以是点或者bounding, box原为1*1*1,但可能形变
  536. //let frustum = new THREE.Frustum();
  537. //frustum.setFromProjectionMatrix(boxMatrixInverse) --错
  538. let px = new THREE.Vector3(+0.5, 0, 0).applyMatrix4(boxMatrix);
  539. let nx = new THREE.Vector3(-0.5, 0, 0).applyMatrix4(boxMatrix);
  540. let py = new THREE.Vector3(0, +0.5, 0).applyMatrix4(boxMatrix);
  541. let ny = new THREE.Vector3(0, -0.5, 0).applyMatrix4(boxMatrix);
  542. let pz = new THREE.Vector3(0, 0, +0.5).applyMatrix4(boxMatrix);
  543. let nz = new THREE.Vector3(0, 0, -0.5).applyMatrix4(boxMatrix);
  544. let pxN = new THREE.Vector3().subVectors(nx, px).normalize();
  545. let nxN = pxN.clone().multiplyScalar(-1);
  546. let pyN = new THREE.Vector3().subVectors(ny, py).normalize();
  547. let nyN = pyN.clone().multiplyScalar(-1);
  548. let pzN = new THREE.Vector3().subVectors(nz, pz).normalize();
  549. let nzN = pzN.clone().multiplyScalar(-1);
  550. let pxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pxN, px);
  551. let nxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nxN, nx);
  552. let pyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pyN, py);
  553. let nyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nyN, ny);
  554. let pzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pzN, pz);
  555. let nzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nzN, nz);
  556. let frustum = new THREE.Frustum(pxPlane, nxPlane, pyPlane, nyPlane, pzPlane, nzPlane);
  557. if(object instanceof THREE.Box3){
  558. var boxBound = new THREE.Box3(
  559. new THREE.Vector3(-0.5,-0.5,-0.5), new THREE.Vector3(0.5,0.5,0.5),
  560. ).applyMatrix4(boxMatrix) //large boundingbox
  561. if(!object.intersectsBox(boxBound))return
  562. return frustum.intersectsBox(object) //根据该函数, 若存在某个plane在box上的对应点都在plane背面,则不相交. 可得知在box构成的frustum倾斜时不准确,不相交也判断为相交,甚至不如bound相交准确。所以前面加步骤排除下,但仍不完全准确。(可在裁剪中将box放置到数据集上方旋转下校验)
  563. }else if(object instanceof Array){//点合集, 只能粗略计算下
  564. let sphere = new THREE.Sphere()
  565. sphere.setFromPoints(object)
  566. return this.isIntersectBox(sphere, boxMatrix)
  567. }else if(object instanceof THREE.Sphere){
  568. return frustum.intersectsSphere(object)
  569. }else if(object instanceof THREE.Vector3){
  570. return frustum.containsPoint(object)
  571. }else if(object instanceof THREE.Matrix4){//第一个参数如果和第二个参数一样都是box的worldMatrix
  572. }
  573. /* containsPoint: ƒ containsPoint( point )
  574. intersectsBox: ƒ intersectsBox( box )
  575. intersectsObject: ƒ intersectsObject( object )//geo
  576. intersectsSphere: ƒ intersectsSphere( sphere )
  577. intersectsSprite: ƒ intersectsSprite( sprite )
  578. */
  579. }
  580. Utils.getIntersect = function (camera, meshes, pointer, raycaster) {
  581. //获取鼠标和meshes交点
  582. if(!raycaster){//getMouseIntersect
  583. camera.updateMatrixWorld()
  584. raycaster = new THREE.Raycaster()
  585. var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
  586. end = new THREE.Vector3(pointer.x, pointer.y, 1).unproject(camera)
  587. var dir = end.sub(origin).normalize()
  588. raycaster.set(origin, dir)
  589. }
  590. meshes.forEach(e=>{
  591. raycaster.layers.enable(math.getBaseLog(2,e.layers.mask))
  592. })
  593. var n = raycaster.intersectObjects(meshes)
  594. if (0 === n.length) return null
  595. return n[0]
  596. }
  597. Utils.addOrRemoveDefine = function(material, defineName, type, value=''){
  598. let defines = material.defines
  599. if(type == 'add'){
  600. if(defines[defineName] != void 0 && defines[defineName] == value)return
  601. defines[defineName] = value
  602. }else{
  603. if(defines[defineName] != void 0)return;
  604. delete defines[defineName]
  605. }
  606. material.needsUpdate = true;
  607. }
  608. Utils.makeTexDontResize = function(map){//避免贴图因非2的次方而缩小。小心使用
  609. if(!map || !map.image){
  610. return console.log('!map || !map.image', map, map&&map.image)
  611. }
  612. if(THREE.Math.isPowerOfTwo(map.image.width ) && THREE.Math.isPowerOfTwo(map.image.height ))return
  613. map.wrapS = map.wrapT = THREE.ClampToEdgeWrapping; //原默认 RepeatWrapping
  614. map.minFilter = THREE.LinearFilter; // or THREE.NearestFilter 原默认 LinearMipmapLinearFilter
  615. map.needsUpdate = true
  616. }
  617. Utils.updateVisible = function(object, reason, ifShow, level=0, type){//当所有加入的条件都不为false时才显示. reason='force'一般是强制、临时的
  618. if(!object.unvisibleReasons) object.unvisibleReasons = []; //如果length>0代表不可见
  619. if(!object.visibleReasons) object.visibleReasons = []; //在同级时,优先可见
  620. var update = function(){
  621. //先按从高到低的level排列
  622. object.unvisibleReasons = object.unvisibleReasons.sort((a,b)=>b.level-a.level)
  623. object.visibleReasons = object.visibleReasons.sort((a,b)=>b.level-a.level)
  624. var maxVisiLevel = object.visibleReasons[0] ? object.visibleReasons[0].level : -1
  625. var maxunVisiLevel = object.unvisibleReasons[0] ? object.unvisibleReasons[0].level : -1
  626. var shouldVisi = maxVisiLevel >= maxunVisiLevel
  627. var visiBefore = object.visible
  628. if(visiBefore != shouldVisi){
  629. object.visible = shouldVisi
  630. object.dispatchEvent({
  631. type: 'isVisible',
  632. visible: shouldVisi,
  633. reason,
  634. })
  635. }
  636. }
  637. if(ifShow){
  638. var index = object.unvisibleReasons.findIndex(e=>e.reason == reason)
  639. if(index > -1){
  640. type = 'cancel'
  641. object.unvisibleReasons.splice(index, 1);
  642. }
  643. if(type == 'add' ){
  644. if(!object.visibleReasons.some(e=>e.reason == reason)){
  645. object.visibleReasons.push({reason,level})
  646. }
  647. }
  648. }else{
  649. var index = object.visibleReasons.findIndex(e=>e.reason == reason)
  650. if(index > -1){
  651. type = 'cancel'
  652. object.visibleReasons.splice(index, 1);
  653. }
  654. if(type != 'cancel' ){
  655. if(!object.unvisibleReasons.some(e=>e.reason == reason)){
  656. object.unvisibleReasons.push({reason,level})
  657. }
  658. }
  659. }
  660. update()
  661. }
  662. /*
  663. 复杂案例: 如果物体默认隐藏, 当符合任何一个其他条件时可见,则可:
  664. Potree.Utils.updateVisible(this, "default", false, 0 ) //默认隐藏
  665. Potree.Utils.updateVisible(this, 条件名, ifShow, 1, ifShow?'add':'cancel' ) //其他的条件
  666. */
  667. Utils.getObjVisiByReason = function(object,reason){//获取在某条件下是否可见. 注: 用户在数据集选择可不可见为"datasetSelection"
  668. if(object.visible)return true
  669. else{
  670. return !object.unvisibleReasons || !object.unvisibleReasons.some(e=>e.reason == reason)
  671. }
  672. }
  673. Utils.setCameraLayers = function(camera, enableLayers, extraEnableLayers=[]){//add
  674. camera.layers.disableAll()
  675. enableLayers.concat(extraEnableLayers).forEach(e=>{
  676. let layer = Potree.config.renderLayers[e]
  677. if(layer == void 0){
  678. console.error('setCameraLayer没找到layer!');
  679. return
  680. }
  681. camera.layers.enable(layer)
  682. })
  683. }
  684. Utils.setObjectLayers = function(object, layerName){//add
  685. let layer = Potree.config.renderLayers[layerName]
  686. if(layer == void 0){
  687. console.error('setCameraLayer没找到layer!');
  688. return
  689. }
  690. object.traverse(e=>{
  691. e.layers.set(layer)
  692. })
  693. }
  694. BinaryLoader.prototype.load = function(node, callback){//解析点云
  695. if (node.loaded) {
  696. return;
  697. }
  698. let url = node.getURL();
  699. if (this.version.equalOrHigher('1.4')) {
  700. url += '.bin';
  701. }
  702. //url += '?m='+node.pcoGeometry.timeStamp //add
  703. let startLoad = (url)=>{
  704. let xhr = XHRFactory.createXMLHttpRequest();
  705. xhr.open('GET', url, true);
  706. xhr.responseType = 'arraybuffer';
  707. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  708. xhr.onreadystatechange = () => {
  709. if (xhr.readyState === 4) {
  710. if((xhr.status === 200 || xhr.status === 0) && xhr.response !== null){
  711. let buffer = xhr.response;
  712. this.parse(node, buffer, callback);
  713. } else {
  714. //console.error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
  715. throw new Error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
  716. }
  717. }
  718. };
  719. try {
  720. xhr.send(null);
  721. } catch (e) {
  722. console.log('fehler beim laden der punktwolke: ' + e);
  723. }
  724. }
  725. Potree.getRealUrl(url, startLoad)
  726. }
  727. PointAttribute.RGBA_PACKED = new PointAttribute("rgba", PointAttributeTypes.DATA_TYPE_INT8, 4);
  728. PointAttribute.COLOR_PACKED = PointAttribute.RGBA_PACKED;
  729. PointAttribute.INTENSITY = new PointAttribute("intensity", PointAttributeTypes.DATA_TYPE_UINT16, 1);
  730. PointAttribute.CLASSIFICATION = new PointAttribute("classification", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  731. PointAttribute.GPS_TIME = new PointAttribute("gps-time", PointAttributeTypes.DATA_TYPE_DOUBLE, 1);
  732. ProfileWindow.prototype.initTHREE = function(){
  733. this.renderer = new THREE.WebGLRenderer({alpha: true, premultipliedAlpha: false});
  734. this.renderer.setClearColor(0x000000, 0);
  735. this.renderer.setSize(10, 10);
  736. this.renderer.autoClear = false;
  737. this.renderArea.append($(this.renderer.domElement));
  738. this.renderer.domElement.tabIndex = '2222';
  739. $(this.renderer.domElement).css('width', '100%');
  740. $(this.renderer.domElement).css('height', '100%');
  741. {
  742. let gl = this.renderer.getContext();
  743. if(gl.createVertexArray == null){
  744. let extVAO = gl.getExtension('OES_vertex_array_object');
  745. if(!extVAO){
  746. throw new Error("OES_vertex_array_object extension not supported");
  747. }
  748. gl.createVertexArray = extVAO.createVertexArrayOES.bind(extVAO);
  749. gl.bindVertexArray = extVAO.bindVertexArrayOES.bind(extVAO);
  750. }
  751. }
  752. this.camera = new THREE.OrthographicCamera(-1000, 1000, 1000, -1000, -1000, 1000);
  753. this.camera.up.set(0, 0, 1);
  754. this.camera.rotation.order = "ZXY";
  755. this.camera.rotation.x = Math.PI / 2.0;
  756. this.scene = new THREE.Scene();
  757. this.profileScene = new THREE.Scene();
  758. let sg = new THREE.SphereGeometry(1, 16, 16);
  759. let sm = new THREE.MeshNormalMaterial();
  760. this.pickSphere = new THREE.Mesh(sg, sm);
  761. this.scene.add(this.pickSphere);
  762. this.viewerPickSphere = new THREE.Mesh(sg, sm);
  763. }
  764. //Potree_update_visibility
  765. Potree.updatePointClouds = function(pointclouds,camera, areaSize ){
  766. viewer.addTimeMark('updateClouds','start')
  767. for (let pointcloud of pointclouds) {
  768. let start = performance.now();
  769. for (let profileRequest of pointcloud.profileRequests) {
  770. profileRequest.update();
  771. let duration = performance.now() - start;
  772. if(duration > 5){
  773. break;
  774. }
  775. }
  776. let duration = performance.now() - start;
  777. }
  778. let result = Potree.updateVisibility(pointclouds, camera, areaSize );
  779. for (let pointcloud of pointclouds) {
  780. //pointcloud.updateMaterial(pointcloud.material, pointcloud.visibleNodes, camera, renderer);//转移到渲染时
  781. pointcloud.updateVisibleBounds();
  782. }
  783. Potree.lru.freeMemory();//即Potree.lru 能看到所有在加载的node
  784. viewer.addTimeMark('updateClouds','end')
  785. return result;
  786. };
  787. Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
  788. let frustums = {};
  789. let camObjPositions = {}
  790. let camObjDirs = {} //add
  791. let priorityQueue = new BinaryHeap(function (x) { return 1 / x.weight; });//二叉堆。
  792. viewer.addTimeMark('visiStructure','start')
  793. //camera.updateMatrixWorld();
  794. let viewI = camera.matrixWorldInverse;
  795. let proj = camera.projectionMatrix;
  796. let view = camera.matrixWorld;
  797. let projViewI = new THREE.Matrix4().multiply(proj).multiply(viewI)
  798. /* let list = pointclouds // stopWhenAllUsed = !viewer.lastFrameChanged
  799. let min = 5, max = Math.max(20 , Math.round(list.length / 10 ))
  800. let result = Common.batchHandling.getSlice('pcGetFrustum', list, { min,max, durBound1: 3, durBound2: 10} ) //iphonex稳定后大概在7-10。
  801. */
  802. for (let i = 0; i < pointclouds.length; i++) {
  803. let pointcloud = pointclouds[i];
  804. if (!pointcloud.initialized()) {
  805. continue;
  806. }
  807. /* let info = history.get(pointcloud)
  808. if() */
  809. pointcloud.numVisibleNodes = 0;
  810. pointcloud.numVisiblePoints = 0;
  811. pointcloud.deepestVisibleLevel = 0;
  812. pointcloud.visibleNodes = [];
  813. pointcloud.visibleGeometry = [];
  814. // 因漫游模式而隐藏的话 依旧需要加入visibleNodes,因为pick需要
  815. /* if (pointcloud.visible && pointcloud.root !== null) {
  816. priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
  817. } */
  818. if (pointcloud.visible || /* !pointcloud.hasDepthTex && */ pointcloud.unvisibleReasons && pointcloud.unvisibleReasons.length == 1 && pointcloud.unvisibleReasons[0].reason == 'displayMode' && pointcloud.root !== null) {//改 visible ->
  819. priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
  820. }else{
  821. continue
  822. }
  823. // frustum in object space
  824. let frustum = new THREE.Frustum();
  825. let world = pointcloud.matrixWorld;
  826. // use close near plane for frustum intersection
  827. /* let frustumCam = camera.clone();
  828. frustumCam.zoom = camera.zoom //add
  829. frustumCam.near = Math.min(camera.near, 0.1);
  830. frustumCam.updateProjectionMatrix(); */ //----没用到frustumCam,删了
  831. let fm = new THREE.Matrix4().multiply(projViewI).multiply(world);
  832. frustum.setFromProjectionMatrix(fm);
  833. frustums[i] = frustum //frustums.push(frustum);
  834. // camera position in object space
  835. let worldI = pointcloud.matrixWorldInverse
  836. let camMatrixObject = new THREE.Matrix4().multiply(worldI).multiply(view);//假设点云无变换的话,相机相对于点云的变换矩阵
  837. let camObjPos = new THREE.Vector3().setFromMatrixPosition(camMatrixObject);
  838. camObjPositions[i] = camObjPos//camObjPositions.push(camObjPos);
  839. let quaternion = new THREE.Quaternion().setFromRotationMatrix(camMatrixObject)
  840. let camDir = (new THREE.Vector3(0,0,-1)).applyQuaternion(quaternion)
  841. camObjDirs[i] = camDir
  842. // hide all previously visible nodes
  843. // if(pointcloud.root instanceof PointCloudOctreeNode){
  844. // pointcloud.hideDescendants(pointcloud.root.sceneNode);
  845. // }
  846. if (pointcloud.root.isTreeNode()) {
  847. pointcloud.hideDescendants(pointcloud.root.sceneNode);
  848. }
  849. for (let j = 0; j < pointcloud.boundingBoxNodes.length; j++) {
  850. pointcloud.boundingBoxNodes[j].visible = false;
  851. }
  852. }
  853. viewer.addTimeMark('visiStructure','end')
  854. return {
  855. 'frustums': frustums,
  856. 'camObjPositions': camObjPositions,
  857. 'priorityQueue': priorityQueue,
  858. camObjDirs
  859. };
  860. };
  861. Potree.updateVisibility = function(pointclouds, camera, areaSize){
  862. let numVisibleNodes = 0;
  863. let numVisiblePoints = 0;
  864. let numVisiblePointsInPointclouds = new Map(pointclouds.map(pc => [pc, 0]));
  865. let visibleNodes = [];
  866. let visibleGeometry = [];
  867. let unloadedGeometry = [];
  868. let lowestSpacing = Infinity;
  869. // calculate object space frustum and cam pos and setup priority queue
  870. let s = Potree.updateVisibilityStructures(pointclouds, camera, areaSize);//得到相机可见范围
  871. let frustums = s.frustums;
  872. let camObjPositions = s.camObjPositions;
  873. let priorityQueue = s.priorityQueue;
  874. let camObjDirs = s.camObjDirs
  875. let loadedToGPUThisFrame = 0;
  876. let domWidth = areaSize.x; //renderer.domElement.clientWidth;
  877. let domHeight = areaSize.y;//renderer.domElement.clientHeight;
  878. let fov = (camera.fov * Math.PI) / 180;
  879. let slope = Math.tan(fov / 2);
  880. let projFactor0 = (0.5 * domHeight) / slope ;
  881. // check if pointcloud has been transformed
  882. // some code will only be executed if changes have been detected
  883. if(!Potree._pointcloudTransformVersion){
  884. Potree._pointcloudTransformVersion = new Map();
  885. }
  886. let pointcloudTransformVersion = Potree._pointcloudTransformVersion;
  887. for(let pointcloud of pointclouds){
  888. if(/* pointcloud.hasDepthTex ? !pointcloud.visible : */ !Potree.Utils.getObjVisiByReason(pointcloud, 'datasetSelection')){//改 visible -> 这一版的深度图不准,就只用在贴图里,pick时需要点云,所以要一直有, 否则但pick时显示的话visibleNodes只能加载出一点点
  889. continue;
  890. }
  891. //if(!pointcloud.visible) continue
  892. pointcloud.updateMatrixWorld();
  893. if(!pointcloudTransformVersion.has(pointcloud)){
  894. pointcloudTransformVersion.set(pointcloud, {number: 0, transform: pointcloud.matrixWorld.clone()});
  895. }else{
  896. let version = pointcloudTransformVersion.get(pointcloud);
  897. if(!version.transform.equals(pointcloud.matrixWorld)){
  898. version.number++;
  899. version.transform.copy(pointcloud.matrixWorld);
  900. pointcloud.dispatchEvent({
  901. type: "transformation_changed",
  902. target: pointcloud
  903. });
  904. }
  905. }
  906. }
  907. while (priorityQueue.size() > 0) {
  908. let element = priorityQueue.pop(); //取出权重最大的一个
  909. let node = element.node;
  910. let parent = element.parent;
  911. let pointcloud = pointclouds[element.pointcloud];
  912. // { // restrict to certain nodes for debugging
  913. // let allowedNodes = ["r", "r0", "r4"];
  914. // if(!allowedNodes.includes(node.name)){
  915. // continue;
  916. // }
  917. // }
  918. let box = node.getBoundingBox();
  919. let frustum = frustums[element.pointcloud];
  920. let camObjPos = camObjPositions[element.pointcloud];
  921. if(!frustum) continue //add
  922. let camObjDir = camObjDirs[element.pointcloud];
  923. let insideFrustum = frustum.intersectsBox(box);
  924. let maxLevel = pointcloud.maxLevel == void 0 ? Infinity : pointcloud.maxLevel;
  925. let level = node.getLevel();
  926. let visible = insideFrustum;
  927. visible = visible && !(numVisiblePoints + node.getNumPoints() > Potree.pointBudget);
  928. visible = visible && !(numVisiblePointsInPointclouds.get(pointcloud) + node.getNumPoints() > pointcloud.pointBudget); // pointcloud.pointBudget一直是Infinity
  929. visible = visible && level <= maxLevel; //< 改为 <=
  930. //visible = visible || node.getLevel() <= 2;
  931. let intersectBox = (clipBox)=>{
  932. let pcWorldInverse = pointcloud.matrixWorld.clone().invert();
  933. let toPCObject = pcWorldInverse.multiply(clipBox.box.matrixWorld); //box乘上点云逆矩阵
  934. /* let px = new THREE.Vector3(+0.5, 0, 0).applyMatrix4(pcWorldInverse);
  935. let nx = new THREE.Vector3(-0.5, 0, 0).applyMatrix4(pcWorldInverse);
  936. let py = new THREE.Vector3(0, +0.5, 0).applyMatrix4(pcWorldInverse);
  937. let ny = new THREE.Vector3(0, -0.5, 0).applyMatrix4(pcWorldInverse);
  938. let pz = new THREE.Vector3(0, 0, +0.5).applyMatrix4(pcWorldInverse);
  939. let nz = new THREE.Vector3(0, 0, -0.5).applyMatrix4(pcWorldInverse);
  940. let pxN = new THREE.Vector3().subVectors(nx, px).normalize();
  941. let nxN = pxN.clone().multiplyScalar(-1);
  942. let pyN = new THREE.Vector3().subVectors(ny, py).normalize();
  943. let nyN = pyN.clone().multiplyScalar(-1);
  944. let pzN = new THREE.Vector3().subVectors(nz, pz).normalize();
  945. let nzN = pzN.clone().multiplyScalar(-1);
  946. let pxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pxN, px);
  947. let nxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nxN, nx);
  948. let pyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pyN, py);
  949. let nyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nyN, ny);
  950. let pzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pzN, pz);
  951. let nzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nzN, nz);
  952. //if(window.debugdraw !== undefined && window.debugdraw === true && node.name === "r60"){
  953. // Potree.utils.debugPlane(viewer.scene.scene, pxPlane, 1, 0xFF0000);
  954. // Potree.utils.debugPlane(viewer.scene.scene, nxPlane, 1, 0x990000);
  955. // Potree.utils.debugPlane(viewer.scene.scene, pyPlane, 1, 0x00FF00);
  956. // Potree.utils.debugPlane(viewer.scene.scene, nyPlane, 1, 0x009900);
  957. // Potree.utils.debugPlane(viewer.scene.scene, pzPlane, 1, 0x0000FF);
  958. // Potree.utils.debugPlane(viewer.scene.scene, nzPlane, 1, 0x000099);
  959. // Potree.utils.debugBox(viewer.scene.scene, box, new THREE.Matrix4(), 0x00FF00);
  960. // Potree.utils.debugBox(viewer.scene.scene, box, pointcloud.matrixWorld, 0xFF0000);
  961. // Potree.utils.debugBox(viewer.scene.scene, clipBox.box.boundingBox, clipBox.box.matrixWorld, 0xFF0000);
  962. // window.debugdraw = false;
  963. //}
  964. let frustum = new THREE.Frustum(pxPlane, nxPlane, pyPlane, nyPlane, pzPlane, nzPlane);
  965. let intersects = frustum.intersectsBox(box); //node的bounding
  966. return !!intersects */
  967. return Potree.Utils.isIntersectBox(box, pcWorldInverse)
  968. }
  969. //改 总共两种box : 可见和不可见(都是并集)
  970. let clipBoxes_in = pointcloud.material.clipBoxes_in;
  971. let clipBoxes_out = pointcloud.material.clipBoxes_out;
  972. let bigClipInBox = pointcloud.material.bigClipInBox
  973. if(visible && bigClipInBox){//不在剪裁下载的框内
  974. if(!intersectBox(bigClipInBox)){
  975. visible = false;
  976. }
  977. }
  978. if(visible && clipBoxes_in.length > 0){//当有可见box时,需要在任一可见box内才可见
  979. let visi = false;
  980. for(let i = 0, length=clipBoxes_in.length; i < length; i++){
  981. if(intersectBox(clipBoxes_in[i])){
  982. visi = true;
  983. break;
  984. }
  985. }
  986. if(!visi){
  987. visible = false
  988. }
  989. }
  990. //outside不做处理。因为node必须完全在clipBox内才能完全隐藏,而这里的intersect只能识别出部分在clipBox内。因而只能说明不在任意一个box内绝对可见,没有意义,这里需要找出不可见的。
  991. /* if(visible && clipBoxes_out.length > 0){ //当有不可见box时,不在所有不可见box内才可见
  992. let visi = true;
  993. for(let i = 0,length=clipBoxes_out.length; i < length; i++){
  994. if(intersectBox(clipBoxes_out[i])){
  995. visi = false;
  996. break;
  997. }
  998. }
  999. if(!visi){
  1000. visible = false
  1001. }
  1002. }
  1003. */
  1004. // visible = ["r", "r0", "r06", "r060"].includes(node.name);
  1005. // visible = ["r"].includes(node.name);
  1006. if (node.spacing) {
  1007. lowestSpacing = Math.min(lowestSpacing, node.spacing);
  1008. } else if (node.geometryNode && node.geometryNode.spacing) {
  1009. lowestSpacing = Math.min(lowestSpacing, node.geometryNode.spacing);
  1010. }
  1011. if (!Potree.settings.pointNoLimit && numVisiblePoints + node.getNumPoints() > Potree.pointBudget) {
  1012. Potree.overPointBudget = true
  1013. viewer.dispatchEvent('overPointBudget');
  1014. break;
  1015. }
  1016. Potree.overPointBudget = false
  1017. if (!visible) {
  1018. continue;
  1019. }
  1020. // TODO: not used, same as the declaration?
  1021. // numVisibleNodes++;
  1022. numVisiblePoints += node.getNumPoints();
  1023. let numVisiblePointsInPointcloud = numVisiblePointsInPointclouds.get(pointcloud);
  1024. numVisiblePointsInPointclouds.set(pointcloud, numVisiblePointsInPointcloud + node.getNumPoints());
  1025. pointcloud.numVisibleNodes++;
  1026. pointcloud.numVisiblePoints += node.getNumPoints();
  1027. if (node.isGeometryNode() && (!parent || parent.isTreeNode())) {
  1028. if (node.isLoaded() && loadedToGPUThisFrame < 2) {
  1029. node = pointcloud.toTreeNode(node, parent);
  1030. loadedToGPUThisFrame++;
  1031. } else {
  1032. //console.log('unloadedGeometry',node)
  1033. unloadedGeometry.push({pointcloud,node}); //加载点云。虽然还没加载,但也计入了visibleNodes,只是无children,numPoints=0
  1034. visibleGeometry.push(node);
  1035. }
  1036. }
  1037. if (node.isTreeNode()) {
  1038. Potree.lru.touch(node.geometryNode);//在缓存中计入点云
  1039. node.sceneNode.visible = true;
  1040. node.sceneNode.material = pointcloud.material;
  1041. visibleNodes.push(node);
  1042. pointcloud.visibleNodes.push(node);
  1043. if(node._transformVersion === undefined){
  1044. node._transformVersion = -1;
  1045. }
  1046. let transformVersion = pointcloudTransformVersion.get(pointcloud);
  1047. if(node._transformVersion !== transformVersion.number){
  1048. node.sceneNode.updateMatrix();
  1049. //node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);
  1050. node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);
  1051. node._transformVersion = transformVersion.number;
  1052. }
  1053. if (pointcloud.showBoundingBox && !node.boundingBoxNode && node.getBoundingBox) {
  1054. let colorHue = level / (maxLevel+1)
  1055. let s = 0.1 + level / (maxLevel+1)
  1056. let color = (new THREE.Color()).setHSL(colorHue, s, s)
  1057. let boxHelper = new Box3Helper(node.getBoundingBox(),color);
  1058. boxHelper.matrixAutoUpdate = false;
  1059. pointcloud.boundingBoxNodes.push(boxHelper);
  1060. node.boundingBoxNode = boxHelper;
  1061. node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
  1062. } else if (pointcloud.showBoundingBox) {
  1063. node.boundingBoxNode.visible = true;
  1064. node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
  1065. } else if (!pointcloud.showBoundingBox && node.boundingBoxNode) {
  1066. node.boundingBoxNode.visible = false;
  1067. }
  1068. // if(node.boundingBoxNode !== undefined && exports.debug.allowedNodes !== undefined){
  1069. // if(!exports.debug.allowedNodes.includes(node.name)){
  1070. // node.boundingBoxNode.visible = false;
  1071. // }
  1072. // }
  1073. }
  1074. // add child nodes to priorityQueue 由近及远、由大及小逐渐加载
  1075. let children = node.getChildren();
  1076. for (let i = 0; i < children.length; i++) {
  1077. let child = children[i];
  1078. let weight = 0;
  1079. if(camera.isPerspectiveCamera){
  1080. let sphere = child.getBoundingSphere();
  1081. let center = sphere.center;
  1082. let dd = sphere.center.distanceToSquared(camObjPos);
  1083. let addPow = viewer.mainViewport.view.isFlying() ? 0 : 0.5 //0-0.5,正常原本是0. 数字越大近处加载越快。但会造成远处加载慢甚至因pointBudge限制不加载。 isFlying:漫游时需要尽量加载一下远处的点云
  1084. //addPow *= window.devicePixelRatio //devicePixelRatio高的手机需要优先加载最近的高级点云,减少远处的中高级点云。
  1085. let distance = Math.pow(dd,0.5+addPow)//Math.sqrt(dd); //提高距离权重,为了提高近处加载速度。 某些场景近处加载慢优化明显,如SS-t-cqCAL6rJ5i
  1086. //let attenuateDis = 10;//add
  1087. let radius = sphere.radius;
  1088. let projFactor = projFactor0 / distance
  1089. let screenPixelRadius = radius * projFactor;
  1090. /* if(distance > attenuateDis){
  1091. screenPixelRadius -= (distance - attenuateDis) * Math.sqrt(radius) * projFactor0 * 0.002
  1092. } */
  1093. //screenPixelRadius 和 domHeight 成正比,所以手机横屏后screenPixelRadius会变小。这是正常的,因为vhov不变,相同物体高度在横屏后高度变小,所需要的密度不需要那么高了。但hfov横屏后扩大,所以可见的node范围变大,又增加了一些可见node;只是总体的可见node还是减少了。
  1094. //使用hfov和domWidth计算结果相同。
  1095. if(screenPixelRadius < pointcloud.minimumNodePixelSize / Math.pow(dd,addPow)){ //理论上因手机像素小,更不容易堆叠铺满,minimumNodePixelSize应该除以window.deviceRatio 但会造成加载过多,而内存小
  1096. continue;
  1097. }
  1098. weight = screenPixelRadius;
  1099. if( !sphere.containsPoint(camObjPos) ){ //add 优先加载屏幕中央的点云(手机端缩小离远效果明显,不会那么稀疏)
  1100. let dir = new THREE.Vector3().subVectors(center, camObjPos).normalize()
  1101. let cos = 1+dir.dot(camObjDir) //0-2
  1102. weight *= cos/2//Math.pow(cos,0.5) //幂越高,旁边的容易加载不到,出现缺块
  1103. }
  1104. if(distance - radius < 0){
  1105. weight = Number.MAX_VALUE;
  1106. }
  1107. //如果能得到每个方向上的密度,也就是node数量,密度大的远处少加载,因为被遮挡了显示也没有意义,就好了。
  1108. } else {
  1109. // TODO ortho visibility
  1110. //let bb = child.getBoundingBox();
  1111. let sphere = child.getBoundingSphere();
  1112. //let diagonal = bb.max.clone().sub(bb.min).length();
  1113. const reduce = 0 //0-0.5,正常原本是0.
  1114. if( sphere.radius * /* Math.pow( */camera.zoom/* ,1-reduce) */ < pointcloud.minimumNodePixelSize ){
  1115. continue;
  1116. }
  1117. let distance = sphere.center.distanceToSquared(camObjPos); //先加载中间然后四周
  1118. weight = sphere.radius / distance;
  1119. //weight = diagonal;
  1120. }
  1121. priorityQueue.push({pointcloud: element.pointcloud, node: child, parent: node, weight: weight}); //貌似好像二叉堆中子节点和父节点没什么关系,就只是为了方便排序层层遍历
  1122. }
  1123. //手机上像素点更小,所以远处感觉会更稀疏
  1124. }// end priority queue loop
  1125. { // update DEM 这是什么
  1126. let maxDEMLevel = 4;
  1127. let candidates = pointclouds.filter(p => (p.generateDEM && p.dem instanceof Potree.DEM));
  1128. for (let pointcloud of candidates) {
  1129. let updatingNodes = pointcloud.visibleNodes.filter(n => n.getLevel() <= maxDEMLevel);
  1130. pointcloud.dem.update(updatingNodes);
  1131. }
  1132. }
  1133. if(unloadedGeometry.length){//加载点云
  1134. /* for (let i = 0; i < Math.min(Potree.maxNodesLoading, unloadedGeometry.length); i++) {
  1135. unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry);
  1136. } */
  1137. let maxNodesLoading = Common.getBestCount('unloadedGeometry', viewer.lastFrameChanged?2:4, 10, 4, 15 /* , true */ )//dur在iphoneX中静止有7,pc是2 //!lastFrameChanged静止时加速下载
  1138. //THREE.Math.clamp(Math.round(9 - dur), 1, 6 )
  1139. //console.log('unloadedGeometry',unloadedGeometry.length, 'maxNodesLoading',maxNodesLoading)
  1140. //主要在手机端有效果。不改之前在展示的点云较多时前进会卡。
  1141. for (let i = 0; i < Math.min(maxNodesLoading, unloadedGeometry.length); i++) {
  1142. unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry);
  1143. }
  1144. if(!Potree.pointsLoading){
  1145. Potree.pointsLoading = true
  1146. //console.log('startLoad')
  1147. viewer.dispatchEvent('startLoadPoints')
  1148. }
  1149. }else{
  1150. if(Potree.pointsLoading){
  1151. Potree.pointsLoading = false
  1152. //console.log('load done!')
  1153. setTimeout(()=>{
  1154. Potree.pointsLoading || viewer.dispatchEvent('pointsLoaded')
  1155. },50)
  1156. }
  1157. }
  1158. //add:
  1159. Potree.numVisiblePoints = numVisiblePoints
  1160. return {
  1161. visibleNodes: visibleNodes,
  1162. numVisiblePoints: numVisiblePoints,
  1163. lowestSpacing: lowestSpacing
  1164. };
  1165. };
  1166. /*
  1167. note:
  1168. 缓存中的点数 Potree.lru.numPoints 一般会 大于 每个点云显示点总数的numVisiblePoints
  1169. 当超出缓冲区最大点云数时,加载的点云节点会被dispose彻底消除;否则,隐藏的节点就会等待再次被使用显示
  1170. 由于加载按照由近及远、由大及小的顺序,要降低卡顿,就只需要降低Potree.pointBudget即可。但目前只设置了三个层次;另外提供maxLevel细节调节,能显示更均匀. 最好多一个调节pointBudge的滑动条
  1171. Potree.lru.numPoints
  1172. Potree.numVisiblePoints
  1173. viewer.scene.pointclouds[0].visibleNodes.length
  1174. */
  1175. {//HQSplatRenderer
  1176. let oldInit = HQSplatRenderer.prototype.init;
  1177. HQSplatRenderer.prototype.init = function(){
  1178. oldInit()
  1179. viewer.addEventListener('resize',this.resize.bind(this))
  1180. }
  1181. HQSplatRenderer.prototype.resize = function(e){
  1182. this.rtDepth.setSize(e.canvasWidth, e.canvasHeight);
  1183. this.rtAttribute.setSize(e.canvasWidth, e.canvasHeight);
  1184. }
  1185. HQSplatRenderer.prototype.clear = function(params={}){
  1186. this.init();
  1187. const {renderer, background} = this.viewer;
  1188. if(background === "skybox"){
  1189. renderer.setClearColor(0x000000, 0);
  1190. } else if (background === 'gradient') {
  1191. renderer.setClearColor(0x000000, 0);
  1192. } else if (background === 'black') {
  1193. renderer.setClearColor(0x000000, 1);
  1194. } else if (background === 'white') {
  1195. renderer.setClearColor(0xFFFFFF, 1);
  1196. } else {
  1197. renderer.setClearColor(0x000000, 0);
  1198. }
  1199. params.target || renderer.clear();
  1200. this.clearTargets(params);
  1201. }
  1202. HQSplatRenderer.prototype.render = function(params={}) {
  1203. this.init();
  1204. const viewer = this.viewer;
  1205. const camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
  1206. const {width, height} = params.width ? params : this.viewer.renderer.getSize(new THREE.Vector2());
  1207. viewer.renderer.setRenderTarget(params.target||null);
  1208. viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
  1209. //params.target || this.resize(width, height);
  1210. const visiblePointClouds = viewer.scene.pointclouds.filter(pc => pc.visible);
  1211. const originalMaterials = new Map();
  1212. for(let pointcloud of visiblePointClouds){
  1213. originalMaterials.set(pointcloud, pointcloud.material);
  1214. if(!this.attributeMaterials.has(pointcloud)){
  1215. let attributeMaterial = new ExtendPointCloudMaterial();
  1216. this.attributeMaterials.set(pointcloud, attributeMaterial);
  1217. }
  1218. if(!this.depthMaterials.has(pointcloud)){
  1219. let depthMaterial = new ExtendPointCloudMaterial();
  1220. depthMaterial.setDefine("depth_pass", "#define hq_depth_pass");
  1221. depthMaterial.setDefine("use_edl", "#define use_edl");
  1222. this.depthMaterials.set(pointcloud, depthMaterial);
  1223. }
  1224. }
  1225. { // DEPTH PASS
  1226. for (let pointcloud of visiblePointClouds) {
  1227. let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
  1228. let material = originalMaterials.get(pointcloud);
  1229. let depthMaterial = this.depthMaterials.get(pointcloud);
  1230. depthMaterial.size = material.size;
  1231. depthMaterial.minSize = material.minSize;
  1232. depthMaterial.maxSize = material.maxSize;
  1233. depthMaterial.pointSizeType = material.pointSizeType;
  1234. depthMaterial.visibleNodesTexture = material.visibleNodesTexture;
  1235. depthMaterial.weighted = false;
  1236. depthMaterial.screenWidth = width;
  1237. depthMaterial.shape = PointShape.CIRCLE;
  1238. depthMaterial.screenHeight = height;
  1239. depthMaterial.uniforms.visibleNodes.value = material.visibleNodesTexture;
  1240. depthMaterial.uniforms.octreeSize.value = octreeSize;
  1241. depthMaterial.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(...pointcloud.scale.toArray());
  1242. depthMaterial.classification = material.classification;
  1243. depthMaterial.uniforms.classificationLUT.value.image.data = material.uniforms.classificationLUT.value.image.data;
  1244. depthMaterial.classificationTexture.needsUpdate = true;
  1245. depthMaterial.uniforms.uFilterReturnNumberRange.value = material.uniforms.uFilterReturnNumberRange.value;
  1246. depthMaterial.uniforms.uFilterNumberOfReturnsRange.value = material.uniforms.uFilterNumberOfReturnsRange.value;
  1247. depthMaterial.uniforms.uFilterGPSTimeClipRange.value = material.uniforms.uFilterGPSTimeClipRange.value;
  1248. depthMaterial.uniforms.uFilterPointSourceIDClipRange.value = material.uniforms.uFilterPointSourceIDClipRange.value;
  1249. depthMaterial.clipTask = material.clipTask;
  1250. depthMaterial.clipMethod = material.clipMethod;
  1251. depthMaterial.setClipBoxes(material.clipBoxes);
  1252. depthMaterial.setClipPolygons(material.clipPolygons);
  1253. pointcloud.material = depthMaterial;
  1254. }
  1255. viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, (params.rtEDL || this.rtDepth), {
  1256. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
  1257. });
  1258. }
  1259. { // ATTRIBUTE PASS
  1260. for (let pointcloud of visiblePointClouds) {
  1261. let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
  1262. let material = originalMaterials.get(pointcloud);
  1263. let attributeMaterial = this.attributeMaterials.get(pointcloud);
  1264. attributeMaterial.size = material.size;
  1265. attributeMaterial.minSize = material.minSize;
  1266. attributeMaterial.maxSize = material.maxSize;
  1267. attributeMaterial.pointSizeType = material.pointSizeType;
  1268. attributeMaterial.activeAttributeName = material.activeAttributeName;
  1269. attributeMaterial.visibleNodesTexture = material.visibleNodesTexture;
  1270. attributeMaterial.weighted = true;
  1271. attributeMaterial.screenWidth = width;
  1272. attributeMaterial.screenHeight = height;
  1273. attributeMaterial.shape = PointShape.CIRCLE;
  1274. attributeMaterial.uniforms.visibleNodes.value = material.visibleNodesTexture;
  1275. attributeMaterial.uniforms.octreeSize.value = octreeSize;
  1276. attributeMaterial.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(...pointcloud.scale.toArray());
  1277. attributeMaterial.classification = material.classification;
  1278. attributeMaterial.uniforms.classificationLUT.value.image.data = material.uniforms.classificationLUT.value.image.data;
  1279. attributeMaterial.classificationTexture.needsUpdate = true;
  1280. attributeMaterial.uniforms.uFilterReturnNumberRange.value = material.uniforms.uFilterReturnNumberRange.value;
  1281. attributeMaterial.uniforms.uFilterNumberOfReturnsRange.value = material.uniforms.uFilterNumberOfReturnsRange.value;
  1282. attributeMaterial.uniforms.uFilterGPSTimeClipRange.value = material.uniforms.uFilterGPSTimeClipRange.value;
  1283. attributeMaterial.uniforms.uFilterPointSourceIDClipRange.value = material.uniforms.uFilterPointSourceIDClipRange.value;
  1284. attributeMaterial.elevationGradientRepeat = material.elevationGradientRepeat;
  1285. attributeMaterial.elevationRange = material.elevationRange;
  1286. attributeMaterial.gradient = material.gradient;
  1287. attributeMaterial.matcap = material.matcap;
  1288. attributeMaterial.intensityRange = material.intensityRange;
  1289. attributeMaterial.intensityGamma = material.intensityGamma;
  1290. attributeMaterial.intensityContrast = material.intensityContrast;
  1291. attributeMaterial.intensityBrightness = material.intensityBrightness;
  1292. attributeMaterial.rgbGamma = material.rgbGamma;
  1293. attributeMaterial.rgbContrast = material.rgbContrast;
  1294. attributeMaterial.rgbBrightness = material.rgbBrightness;
  1295. attributeMaterial.weightRGB = material.weightRGB;
  1296. attributeMaterial.weightIntensity = material.weightIntensity;
  1297. attributeMaterial.weightElevation = material.weightElevation;
  1298. attributeMaterial.weightRGB = material.weightRGB;
  1299. attributeMaterial.weightClassification = material.weightClassification;
  1300. attributeMaterial.weightReturnNumber = material.weightReturnNumber;
  1301. attributeMaterial.weightSourceID = material.weightSourceID;
  1302. attributeMaterial.color = material.color;
  1303. attributeMaterial.clipTask = material.clipTask;
  1304. attributeMaterial.clipMethod = material.clipMethod;
  1305. attributeMaterial.setClipBoxes(material.clipBoxes);
  1306. attributeMaterial.setClipPolygons(material.clipPolygons);
  1307. pointcloud.material = attributeMaterial;
  1308. }
  1309. let gl = this.gl;
  1310. //viewer.renderer.setRenderTarget(null);
  1311. viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, this.rtAttribute, {
  1312. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
  1313. //material: this.attributeMaterial,
  1314. blendFunc: [gl.SRC_ALPHA, gl.ONE],
  1315. //depthTest: false,
  1316. depthWrite: false
  1317. });
  1318. }
  1319. for(let [pointcloud, material] of originalMaterials){
  1320. pointcloud.material = material;
  1321. }
  1322. if(viewer.background === "skybox"){
  1323. viewer.renderer.setClearColor(0x000000, 0);
  1324. viewer.renderer.clear();
  1325. viewer.skybox.camera.rotation.copy(viewer.scene.cameraP.rotation);
  1326. viewer.skybox.camera.fov = viewer.scene.cameraP.fov;
  1327. viewer.skybox.camera.aspect = viewer.scene.cameraP.aspect;
  1328. viewer.skybox.parent.rotation.x = 0;
  1329. viewer.skybox.parent.updateMatrixWorld();
  1330. viewer.skybox.camera.updateProjectionMatrix();
  1331. viewer.renderer.render(viewer.skybox.scene, viewer.skybox.camera);
  1332. } else if (viewer.background === 'gradient') {
  1333. viewer.renderer.setClearColor(0x000000, 0);
  1334. viewer.renderer.clear();
  1335. viewer.renderer.render(viewer.scene.sceneBG, viewer.scene.cameraBG);
  1336. } else if (viewer.background === 'black') {
  1337. viewer.renderer.setClearColor(0x000000, 1);
  1338. viewer.renderer.clear();
  1339. } else if (viewer.background === 'white') {
  1340. viewer.renderer.setClearColor(0xFFFFFF, 1);
  1341. viewer.renderer.clear();
  1342. } else {
  1343. viewer.renderer.setClearColor(0x000000, 0);
  1344. viewer.renderer.clear();
  1345. }
  1346. { // NORMALIZATION PASS
  1347. let normalizationMaterial = this.useEDL ? this.normalizationEDLMaterial : this.normalizationMaterial;
  1348. if(this.useEDL){
  1349. normalizationMaterial.uniforms.edlStrength.value = viewer.edlStrength;
  1350. normalizationMaterial.uniforms.radius.value = viewer.edlRadius;
  1351. normalizationMaterial.uniforms.screenWidth.value = width;
  1352. normalizationMaterial.uniforms.screenHeight.value = height;
  1353. normalizationMaterial.uniforms.uEDLMap.value = (params.rtEDL || this.rtDepth).texture;
  1354. }
  1355. normalizationMaterial.uniforms.uWeightMap.value = this.rtAttribute.texture;
  1356. normalizationMaterial.uniforms.uDepthMap.value = this.rtAttribute.depthTexture;
  1357. Utils.screenPass.render(viewer.renderer, normalizationMaterial);
  1358. }
  1359. viewer.renderer.render(viewer.scene.scene, camera);
  1360. viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer});
  1361. viewer.renderer.render(viewer.scene.sceneOverlay, camera);// add 透明贴图层
  1362. viewer.renderer.clearDepth();
  1363. viewer.transformationTool.update();
  1364. if(!params.target){
  1365. //测量线
  1366. viewer.dispatchEvent({type: "render.pass.perspective_overlay",viewer: viewer, camera});
  1367. viewer.renderer.render(viewer.overlay, camera);//从 viewer.renderDefault搬过来,为了reticule不遮住测量线
  1368. }
  1369. viewer.renderer.render(viewer.controls.sceneControls, camera);
  1370. viewer.renderer.render(viewer.clippingTool.sceneVolume, camera);
  1371. viewer.renderer.render(viewer.transformationTool.scene, camera);
  1372. viewer.renderer.setViewport(width - viewer.navigationCube.width,
  1373. height - viewer.navigationCube.width,
  1374. viewer.navigationCube.width, viewer.navigationCube.width);
  1375. viewer.renderer.render(viewer.navigationCube, viewer.navigationCube.camera);
  1376. viewer.renderer.setViewport(0, 0, width, height);
  1377. viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
  1378. viewer.renderer.setRenderTarget(null)
  1379. }
  1380. }
  1381. //PointCloudOctreeGeometry.js
  1382. PointCloudOctreeGeometryNode.prototype.loadHierachyThenPoints = function(pointcloud){
  1383. let node = this;
  1384. // load hierarchy
  1385. let callback = function (node, hbuffer) {
  1386. let tStart = performance.now();
  1387. let view = new DataView(hbuffer);
  1388. let stack = [];
  1389. let children = view.getUint8(0);
  1390. let numPoints = view.getUint32(1, true);
  1391. node.numPoints = numPoints;
  1392. stack.push({children: children, numPoints: numPoints, name: node.name});
  1393. let decoded = [];
  1394. let offset = 5;
  1395. while (stack.length > 0) {
  1396. let snode = stack.shift();
  1397. let mask = 1;
  1398. for (let i = 0; i < 8; i++) {
  1399. if ((snode.children & mask) !== 0) {
  1400. let childName = snode.name + i;
  1401. let childChildren = view.getUint8(offset);
  1402. let childNumPoints = view.getUint32(offset + 1, true);
  1403. stack.push({children: childChildren, numPoints: childNumPoints, name: childName});
  1404. decoded.push({children: childChildren, numPoints: childNumPoints, name: childName});
  1405. offset += 5;
  1406. }
  1407. mask = mask * 2;
  1408. }
  1409. if (offset === hbuffer.byteLength) {
  1410. break;
  1411. }
  1412. }
  1413. // console.log(decoded);
  1414. let nodes = {};
  1415. nodes[node.name] = node;
  1416. let pco = node.pcoGeometry;
  1417. let maxLevel_ = 0
  1418. for (let i = 0; i < decoded.length; i++) {
  1419. let name = decoded[i].name;
  1420. let decodedNumPoints = decoded[i].numPoints;
  1421. let index = parseInt(name.charAt(name.length - 1));
  1422. let parentName = name.substring(0, name.length - 1);
  1423. let parentNode = nodes[parentName];
  1424. let level = name.length - 1;
  1425. maxLevel_ = Math.max(maxLevel_,level)//add
  1426. let boundingBox = Utils.createChildAABB(parentNode.boundingBox, index);
  1427. let currentNode = new PointCloudOctreeGeometryNode(name, pco, boundingBox);
  1428. currentNode.level = level;
  1429. currentNode.numPoints = decodedNumPoints;
  1430. currentNode.hasChildren = decoded[i].children > 0;
  1431. currentNode.spacing = pco.spacing / Math.pow(2, level);
  1432. parentNode.addChild(currentNode);
  1433. nodes[name] = currentNode;
  1434. }
  1435. pco.dispatchEvent({type:'updateNodeMaxLevel',level:maxLevel_});//add
  1436. let duration = performance.now() - tStart;
  1437. if(duration > 5){
  1438. /* let msg = `duration: ${duration}ms, numNodes: ${decoded.length}`;
  1439. console.log(msg); */
  1440. }
  1441. node.loadPoints();
  1442. };
  1443. if ((node.level % node.pcoGeometry.hierarchyStepSize) === 0) {
  1444. // let hurl = node.pcoGeometry.octreeDir + "/../hierarchy/" + node.name + ".hrc";
  1445. let hurl = node.pcoGeometry.octreeDir + '/' + node.getHierarchyPath() + '/' + node.name + '.hrc';
  1446. //hurl += '?m='+node.pcoGeometry.timeStamp //add
  1447. let startLoad = (hurl)=>{
  1448. let xhr = XHRFactory.createXMLHttpRequest();
  1449. xhr.open('GET', hurl, true);
  1450. xhr.responseType = 'arraybuffer';
  1451. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  1452. xhr.onreadystatechange = () => {
  1453. if (xhr.readyState === 4) {
  1454. if (xhr.status === 200 || xhr.status === 0) {
  1455. let hbuffer = xhr.response;
  1456. callback(node, hbuffer);
  1457. } else {
  1458. console.log('Failed to load file! HTTP status: ' + xhr.status + ', file: ' + hurl);
  1459. Potree.numNodesLoading--;
  1460. }
  1461. }
  1462. };
  1463. try {
  1464. xhr.send(null);
  1465. } catch (e) {
  1466. console.log('fehler beim laden der punktwolke: ' + e);
  1467. }
  1468. }
  1469. Potree.getRealUrl(hurl, startLoad)
  1470. }
  1471. }
  1472. PointCloudOctreeGeometryNode.prototype.loadPoints = function(){
  1473. let name = this.name
  1474. this.pcoGeometry.loader.load(this, ()=>{//callback
  1475. viewer.dispatchEvent('pointcloud_changed')
  1476. //console.log('loadPoints success ', name)
  1477. });
  1478. }
  1479. //加载点云成功->准备渲染画面->更新点云可见性updateVisibility->请求加载新的点云
  1480. PointCloudOctreeGeometryNode.prototype.traverse = function(t, e){//add from navvis 25.js
  1481. void 0 === e && (e = !0);
  1482. for (var n, i = e ? [this] : []; void 0 !== (n = i.pop()); ) {
  1483. t(n);
  1484. for (var o = 0, r = n.children; o < r.length; o++) {
  1485. var a = r[o];
  1486. null !== a && i.push(a)
  1487. }
  1488. }
  1489. }
  1490. Object.assign( PointCloudOctreeGeometry.prototype, THREE.EventDispatcher.prototype );
  1491. LRU.prototype.freeMemory = function(){
  1492. if (this.elements <= 1) {
  1493. return;
  1494. }
  1495. let memoryRatio = browser.isMobile() ? 2 : 5;
  1496. //改成navvis的,使用pointBudget,否则四屏点云闪烁。 (似乎要比updateVisiblede的node时限制要宽些,作为缓存继续存着。否则会闪烁)
  1497. let max = viewer.viewports.length * memoryRatio * Potree.pointBudget
  1498. for (; this.numPoints > max; ) {
  1499. var node = this.getLRUItem();
  1500. node && this.disposeDescendants(node); //this.disposeSubtree(node)
  1501. }
  1502. }
  1503. /*
  1504. LRU.prototype.disposeSubtree = function(t) {//add from navvis 25.js 和原来的disposeDescendants功能一样
  1505. var e = [t];
  1506. t.traverse((function(t) {
  1507. t.loaded && e.push(t)
  1508. }));
  1509. for (var n = 0, i = e; n < i.length; n++) {
  1510. var o = i[n];
  1511. o.dispose(),
  1512. this.remove(o)
  1513. }
  1514. }*/
  1515. VolumeTool.prototype.update = function(){}
  1516. VolumeTool.prototype.startInsertion = function(args = {}){
  1517. let volume;
  1518. if(args.type){
  1519. volume = new args.type();
  1520. }else{
  1521. volume = new Potree.BoxVolume(Object.assign(args,{clip:true}) );
  1522. }
  1523. volume.highlight = true
  1524. volume.name = args.name || 'Volume-'+args.clipTask;
  1525. volume.isNew = true
  1526. viewer.transformObject(null)//先清空
  1527. //console.log('startInsertion',volume.uuid)
  1528. let oldVisiBoxes
  1529. if(args.clipTask == Potree.ClipTask.SHOW_INSIDE){ //如果是显示类型,需要将所有同类型的解除效果,否则看不到效果。 (或者可以在添加非第一个时去除highlight效果,会更自然,但看不清全貌)
  1530. oldVisiBoxes = viewer.scene.volumes.filter(v => v.clipTask == Potree.ClipTask.SHOW_INSIDE && !v.highlight )
  1531. oldVisiBoxes.forEach(box=>box.highlight = true)
  1532. }
  1533. let updatePose = ()=>{ //保证在视野中的大小一致:
  1534. let camera = this.viewer.scene.getActiveCamera();
  1535. let w = math.getScaleForConstantSize({
  1536. width2d: 300,
  1537. camera , position:volume.getWorldPosition(new THREE.Vector3()) ,
  1538. resolution: viewer.mainViewport.resolution//2
  1539. })
  1540. /* let wp = volume.getWorldPosition(new THREE.Vector3()).applyMatrix4(camera.matrixWorldInverse);
  1541. // let pp = new THREE.Vector4(wp.x, wp.y, wp.z).applyMatrix4(camera.projectionMatrix);
  1542. let w = Math.abs((wp.z / 3));*/
  1543. if(!isNaN(w))volume.scale.set(w, w, w);
  1544. {//使水平朝向与camera一致
  1545. let direction = viewer.mainViewport.view.direction.setZ(0)
  1546. volume.quaternion.copy(math.getQuaByAim(direction))
  1547. }
  1548. }
  1549. this.dispatchEvent({
  1550. type: 'start_inserting_volume',
  1551. volume: volume
  1552. });
  1553. updatePose()
  1554. this.viewer.scene.addVolume(volume);
  1555. this.scene.add(volume);
  1556. let drag = e => {
  1557. let I = Utils.getMousePointCloudIntersection(
  1558. viewer.mainViewport,
  1559. viewer.inputHandler.mouse,
  1560. viewer.inputHandler.pointer,
  1561. this.viewer.scene.getActiveCamera(),
  1562. this.viewer,
  1563. this.viewer.scene.pointclouds,
  1564. {pickClipped: args.clipTask == Potree.ClipTask.SHOW_OUTSIDE } //无视clip状态
  1565. );
  1566. var worldPos = I && I.location
  1567. if(!worldPos){
  1568. return
  1569. }
  1570. volume.position.copy(worldPos);
  1571. updatePose()
  1572. };
  1573. let cancel = ()=>{
  1574. end('remove')
  1575. }
  1576. let end = (e) => {
  1577. if(e.button == THREE.MOUSE.RIGHT && e.pressDistance<=Potree.config.clickMaxDragDis) {//remove
  1578. e = 'remove'
  1579. }
  1580. //console.log('end',volume.uuid, e)
  1581. if(e != 'remove' && (!e.isAtDomElement || e.pressDistance>Potree.config.clickMaxDragDis))return continueDrag()
  1582. volume.removeEventListener('drag', drag);
  1583. volume.removeEventListener('drop', end);
  1584. this.viewer.removeEventListener('cancel_insertions', cancel);
  1585. volume.isNew = false
  1586. viewer.removeEventListener('camera_changed', updatePose)
  1587. if(e == 'remove'){
  1588. viewer.scene.removeVolume(volume); //删除没完成的
  1589. }else{
  1590. viewer.transformObject(volume)
  1591. volume.highlight = false
  1592. }
  1593. volume.dispatchEvent({type:'createFinish', success:e != 'remove' })
  1594. oldVisiBoxes && oldVisiBoxes.forEach(box=>box.highlight = false)
  1595. };
  1596. let continueDrag = ( )=>{
  1597. //console.log('continueDrag',volume.uuid )
  1598. var timer = setTimeout(()=>{//等 drag=null之后 //右键拖拽结束后需要重新得到drag
  1599. if(volume.parent && volume.isNew){
  1600. viewer.inputHandler.startDragging( volume , {notPressMouse:true}
  1601. /* {endDragFun: e.drag.endDragFun, notPressMouse:e.drag.notPressMouse, dragViewport:e.drag.dragViewport} */
  1602. )
  1603. }
  1604. },1)
  1605. return timer
  1606. }
  1607. volume.addEventListener('drag', drag);
  1608. volume.addEventListener('drop', end);
  1609. this.viewer.addEventListener('cancel_insertions', cancel);
  1610. viewer.addEventListener('camera_changed', updatePose)
  1611. this.viewer.inputHandler.startDragging(volume, {notPressMouse:true});
  1612. return volume;
  1613. }
  1614. LineGeometry.prototype.setPositions = function( array ) { //xzw改成类似LineSegments的多段线 (第二个点和第三个点之间是没有线段的, 所以不用在意线段顺序)
  1615. const points = new Float32Array( array );
  1616. LineSegmentsGeometry.prototype.setPositions.call(this, points );
  1617. return this;
  1618. }
  1619. Object.assign(ExtendView.prototype, THREE.EventDispatcher.prototype)
  1620. Object.assign(ExtendScene.prototype, THREE.EventDispatcher.prototype );