potree.shim.js 73 KB

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